From 9ea80826581b3ce8081567823e2377b8590917b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludger=20Kr=C3=A4mer?= Date: Wed, 17 Sep 2014 10:39:44 +0200 Subject: fix high memory usage on large download MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit previously the whole response was cached in a NSMutableData which leads to high memory usage on large responses (e.g. downloading a large file). With this patch only the part of the answer that has not yet been read by the caller is cached. Task-number: QTBUG-41356 Change-Id: Ic2fe822552620d8835a2c81f8c76dd170fe6ec97 Reviewed-by: Morten Johan Sørvig --- src/network/access/qnetworkreplynsurlconnectionimpl.mm | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/network/access/qnetworkreplynsurlconnectionimpl.mm b/src/network/access/qnetworkreplynsurlconnectionimpl.mm index 327dbd4ea7..6ed209dff7 100644 --- a/src/network/access/qnetworkreplynsurlconnectionimpl.mm +++ b/src/network/access/qnetworkreplynsurlconnectionimpl.mm @@ -295,7 +295,7 @@ void QNetworkReplyNSURLConnectionImpl::readyReadOutgoingData() if ([response expectedContentLength] != NSURLResponseUnknownLength) { QMetaObject::invokeMethod(replyprivate->q_func(), "downloadProgress", Qt::QueuedConnection, - Q_ARG(qint64, qint64([responseData length])), + Q_ARG(qint64, qint64([responseData length] + replyprivate->bytesRead)), Q_ARG(qint64, qint64([response expectedContentLength]))); } @@ -426,9 +426,7 @@ qint64 QNetworkReplyNSURLConnectionImpl::bytesAvailable() const { Q_D(const QNetworkReplyNSURLConnectionImpl); qint64 available = QNetworkReply::bytesAvailable() + - [[d->urlConnectionDelegate responseData] length] - - d->bytesRead; - + [[d->urlConnectionDelegate responseData] length]; return available; } @@ -440,7 +438,7 @@ bool QNetworkReplyNSURLConnectionImpl::isSequential() const qint64 QNetworkReplyNSURLConnectionImpl::size() const { Q_D(const QNetworkReplyNSURLConnectionImpl); - return [[d->urlConnectionDelegate responseData] length]; + return [[d->urlConnectionDelegate responseData] length] + d->bytesRead; } /*! @@ -450,9 +448,10 @@ qint64 QNetworkReplyNSURLConnectionImpl::readData(char *data, qint64 maxlen) { Q_D(QNetworkReplyNSURLConnectionImpl); qint64 dataSize = [[d->urlConnectionDelegate responseData] length]; - qint64 canRead = qMin(maxlen, dataSize - d->bytesRead); + qint64 canRead = qMin(maxlen, dataSize); const char *sourceBase = static_cast([[d->urlConnectionDelegate responseData] bytes]); - memcpy(data, sourceBase + d->bytesRead, canRead); + memcpy(data, sourceBase, canRead); + [[d->urlConnectionDelegate responseData] replaceBytesInRange:NSMakeRange(0, canRead) withBytes:NULL length:0]; d->bytesRead += canRead; return canRead; } -- cgit v1.2.3 From d64f776a9a41a8d1144397b7b62efbdee8d24857 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 31 Mar 2015 09:17:39 +0200 Subject: Windows: Fallback to 0 samples if ARB::choosePixelFormat() fails with 1 This solves a problem when using a Qt application over remote desktop as if it failed with even 1 sample then it would fallback to GDI which causes an error if the software OpenGL option is used. Change-Id: Ib311a7a657f92aab15277461bc8e040bebbe4753 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsglcontext.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 3348241d37..908bc65843 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -597,6 +597,14 @@ static int choosePixelFormat(HDC hdc, break; if (iAttributes[samplesValuePosition] > 1) { iAttributes[samplesValuePosition] /= 2; + } else if (iAttributes[samplesValuePosition] == 1) { + // Fallback in case it is unable to initialize with any + // samples to avoid falling back to the GDI path + // NB: The sample attributes needs to be at the end for this + // to work correctly + iAttributes[samplesValuePosition - 1] = FALSE; + iAttributes[samplesValuePosition] = 0; + iAttributes[samplesValuePosition + 1] = 0; } else { break; } -- cgit v1.2.3 From 180ee8a8de459b752f739e1a9d56d271303d0302 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 9 Mar 2015 12:34:38 +0100 Subject: Explicitly cast to a uint to fix a compile error When using QtTest inside the notification example for QtAndroidExtras there as a problem with the compilation as it saw it as being an ambiguous check. Therefore doing an explicit case to uint ensures it is not a problem. Change-Id: Ibc9ce4c64292bf5ae7c501c592d8c42a66934b8b Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/testlib/qtestmouse.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h index 0b27537ae4..f29db926a4 100644 --- a/src/testlib/qtestmouse.h +++ b/src/testlib/qtestmouse.h @@ -98,7 +98,7 @@ namespace QTest mouseEvent(MouseRelease, window, button, stateKey, pos); return; } - QTEST_ASSERT(stateKey == 0 || stateKey & Qt::KeyboardModifierMask); + QTEST_ASSERT(uint(stateKey) == 0 || stateKey & Qt::KeyboardModifierMask); stateKey &= static_cast(Qt::KeyboardModifierMask); -- cgit v1.2.3 From 19a91b4a3531d331362fcefd87c43366ae142f57 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Wed, 18 Feb 2015 14:49:44 +0300 Subject: Doc: Fix using Apple-related terminology in Qt Core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the name "OS X" instead of "Mac OS X", "Mac OS" and "OSX", and mention iOS. Replace "Carbon Preferences API" by "CFPreferences API" in the QSettings documentation. Change-Id: Ia7f9fb874276c7c445a1649df521b96ff43daa0c Reviewed-by: Oswald Buddenhagen Reviewed-by: Venugopal Shivashankar Reviewed-by: Topi Reiniö --- src/corelib/doc/src/resource-system.qdoc | 2 +- src/corelib/global/qcompilerdetection.h | 4 +-- src/corelib/global/qnamespace.qdoc | 50 +++++++++++++++---------------- src/corelib/io/qabstractfileengine.cpp | 2 +- src/corelib/io/qdir.cpp | 4 +-- src/corelib/io/qfile.cpp | 4 +-- src/corelib/io/qfileinfo.cpp | 8 ++--- src/corelib/io/qfilesystemengine.cpp | 2 +- src/corelib/io/qfilesystemengine_unix.cpp | 2 +- src/corelib/io/qfilesystemwatcher.cpp | 2 +- src/corelib/io/qfsfileengine.cpp | 4 +-- src/corelib/io/qiodevice.cpp | 2 +- src/corelib/io/qlockfile_unix.cpp | 2 +- src/corelib/io/qloggingcategory.cpp | 2 +- src/corelib/io/qsettings.cpp | 42 +++++++++++++------------- src/corelib/kernel/qcoreapplication.cpp | 4 +-- src/corelib/kernel/qcoreevent.cpp | 4 +-- src/corelib/kernel/qobject.cpp | 2 +- src/corelib/mimetypes/qmimedatabase.cpp | 2 +- src/corelib/plugin/qlibrary.cpp | 8 ++--- src/corelib/plugin/qpluginloader.cpp | 2 +- src/corelib/thread/qthread_unix.cpp | 2 +- src/corelib/tools/qelapsedtimer.cpp | 6 ++-- src/corelib/tools/qstring.cpp | 12 ++++---- src/corelib/tools/qtimezone.cpp | 2 +- 25 files changed, 88 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/corelib/doc/src/resource-system.qdoc b/src/corelib/doc/src/resource-system.qdoc index 91ce8afcf8..b7f84f5b5e 100644 --- a/src/corelib/doc/src/resource-system.qdoc +++ b/src/corelib/doc/src/resource-system.qdoc @@ -136,7 +136,7 @@ \image resources.png Building resources into an application Currently, Qt always stores the data directly in the executable, - even on Windows and Mac OS X, where the operating system provides + even on Windows, OS X, and iOS, where the operating system provides native support for resources. This might change in a future Qt release. diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index d144c4faad..3b9b7934bc 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -902,7 +902,7 @@ # endif // Q_OS_QNX # if (defined(Q_CC_CLANG) || defined(Q_CC_INTEL)) && defined(Q_OS_MAC) && defined(__GNUC_LIBSTD__) \ && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) -// Mac OS X: Apple has not updated libstdc++ since 2007, which means it does not have +// Apple has not updated libstdc++ since 2007, which means it does not have // or std::move. Let's disable these features # undef Q_COMPILER_INITIALIZER_LISTS # undef Q_COMPILER_RVALUE_REFS @@ -918,7 +918,7 @@ # endif # endif # if defined(Q_COMPILER_THREADSAFE_STATICS) && defined(Q_OS_MAC) -// Mac OS X: Apple's low-level implementation of the C++ support library +// Apple's low-level implementation of the C++ support library // (libc++abi.dylib, shared between libstdc++ and libc++) has deadlocks. The // C++11 standard requires the deadlocks to be removed, so this will eventually // be fixed; for now, let's disable this. diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index f7992b436c..3f9526c788 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -111,7 +111,7 @@ shown in any menus unless specifically set by the QAction::iconVisibleInMenu property. Menus that are currently open or menus already created in the native - Mac OS X menubar \e{may not} pick up a change in this attribute. Changes + OS X menubar \e{may not} pick up a change in this attribute. Changes in the QAction::iconVisibleInMenu property will always be picked up. \value AA_NativeWindows Ensures that widgets have native windows. @@ -129,9 +129,9 @@ \value AA_DontUseNativeMenuBar All menubars created while this attribute is set to true won't be used as a native menubar (e.g, the menubar at - the top of the main screen on Mac OS X or at the bottom in Windows CE). + the top of the main screen on OS X or at the bottom in Windows CE). - \value AA_MacDontSwapCtrlAndMeta On Mac OS X by default, Qt swaps the + \value AA_MacDontSwapCtrlAndMeta On OS X by default, Qt swaps the Control and Meta (Command) keys (i.e., whenever Control is pressed, Qt sends Meta, and whenever Meta is pressed Control is sent). When this attribute is true, Qt will not do the flip. \l QKeySequence::StandardKey @@ -294,7 +294,7 @@ \omitvalue KeyboardModifierMask - \note On Mac OS X, the \c ControlModifier value corresponds to + \note On OS X, the \c ControlModifier value corresponds to the Command keys on the Macintosh keyboard, and the \c MetaModifier value corresponds to the Control keys. The \c KeypadModifier value will also be set when an arrow key is pressed as the arrow keys are considered part of the @@ -312,7 +312,7 @@ This enum provides shorter names for the keyboard modifier keys supported by Qt. - \note On Mac OS X, the \c CTRL value corresponds to + \note On OS X, the \c CTRL value corresponds to the Command keys on the Macintosh keyboard, and the \c META value corresponds to the Control keys. @@ -913,34 +913,34 @@ \value WA_MacOpaqueSizeGrip Indicates that the native Carbon size grip should be opaque instead of transparent (the default). This attribute - is only applicable to Mac OS X and is set by the widget's author. + is only applicable to OS X and is set by the widget's author. \value WA_MacShowFocusRect Indicates that this widget should get a QFocusFrame around it. Some widgets draw their own focus halo regardless of this attribute. Not that the QWidget::focusPolicy also plays the main role in whether something is given focus or not, this only controls whether or not this gets the focus - frame. This attribute is only applicable to Mac OS X. + frame. This attribute is only applicable to OS X. \value WA_MacNormalSize Indicates the widget should have the - normal size for widgets in Mac OS X. This attribute is only - applicable to Mac OS X. + normal size for widgets in OS X. This attribute is only + applicable to OS X. \value WA_MacSmallSize Indicates the widget should have the small - size for widgets in Mac OS X. This attribute is only applicable to - Mac OS X. + size for widgets in OS X. This attribute is only applicable to + OS X. \value WA_MacMiniSize Indicates the widget should have the mini - size for widgets in Mac OS X. This attribute is only applicable to - Mac OS X. + size for widgets in OS X. This attribute is only applicable to + OS X. \value WA_MacVariableSize Indicates the widget can choose between alternative sizes for widgets to avoid clipping. - This attribute is only applicable to Mac OS X. + This attribute is only applicable to OS X. \value WA_MacBrushedMetal Indicates the widget should be drawn in the brushed metal style as supported by the windowing system. This - attribute is only applicable to Mac OS X. + attribute is only applicable to OS X. \omitvalue WA_MacMetalStyle @@ -1090,14 +1090,14 @@ \b Warning: This flag must \e never be set or cleared by the widget's author. \value WA_WindowModified Indicates that the window is marked as modified. - On some platforms this flag will do nothing, on others (including Mac OS X + On some platforms this flag will do nothing, on others (including OS X and Windows) the window will take a modified appearance. This flag is set or cleared by QWidget::setWindowModified(). \value WA_WindowPropagation Makes a toplevel window inherit font and palette from its parent. - \value WA_MacAlwaysShowToolWindow On Mac OS X, show the tool window even + \value WA_MacAlwaysShowToolWindow On OS X, show the tool window even when the application is not active. By default, all tool windows are hidden when the application is inactive. @@ -1280,8 +1280,8 @@ \value Key_PageUp \value Key_PageDown \value Key_Shift - \value Key_Control On Mac OS X, this corresponds to the Command keys. - \value Key_Meta On Mac OS X, this corresponds to the Control keys. + \value Key_Control On OS X, this corresponds to the Command keys. + \value Key_Meta On OS X, this corresponds to the Control keys. On Windows keyboards, this key is mapped to the Windows key. \value Key_Alt @@ -1919,7 +1919,7 @@ \value TabFocus the widget accepts focus by tabbing. \value ClickFocus the widget accepts focus by clicking. \value StrongFocus the widget accepts focus by both tabbing - and clicking. On Mac OS X this will also + and clicking. On OS X this will also be indicate that the widget accepts tab focus when in 'Text/List focus mode'. \value WheelFocus like Qt::StrongFocus plus the widget accepts @@ -2012,7 +2012,7 @@ system supports it, a tool window can be decorated with a somewhat lighter frame. It can also be combined with Qt::FramelessWindowHint. - On Mac OS X, tool windows correspond to the + On OS X, tool windows correspond to the \l{http://developer.apple.com/documentation/Carbon/Conceptual/HandlingWindowsControls/hitb-wind_cont_concept/chapter_2_section_2.html}{Floating} class of windows. This means that the window lives on a level above normal windows; it impossible to put a normal @@ -2101,10 +2101,10 @@ \value WindowContextHelpButtonHint Adds a context help button to dialogs. On some platforms this implies Qt::WindowSystemMenuHint for it to work. - \value MacWindowToolBarButtonHint On Mac OS X adds a tool bar button (i.e., + \value MacWindowToolBarButtonHint On OS X adds a tool bar button (i.e., the oblong button that is on the top right of windows that have toolbars). - \value WindowFullscreenButtonHint On Mac OS X adds a fullscreen button. + \value WindowFullscreenButtonHint On OS X adds a fullscreen button. \value BypassGraphicsProxyWidget Prevents the window and its children from automatically embedding themselves into a QGraphicsProxyWidget if the @@ -2128,7 +2128,7 @@ that support _NET_WM_STATE_BELOW atom. If a window always on the bottom has a parent, the parent will also be left on the bottom. This window hint is currently not implemented - for Mac OS X. + for OS X. \value WindowOkButtonHint Adds an OK button to the window decoration of a dialog. Only supported for Windows CE. @@ -2912,7 +2912,7 @@ \value CoarseTimer Coarse timers try to keep accuracy within 5% of the desired interval \value VeryCoarseTimer Very coarse timers only keep full second accuracy - On UNIX (including Linux and Mac OS X), Qt will keep millisecond accuracy + On UNIX (including Linux, OS X, and iOS), Qt will keep millisecond accuracy for Qt::PreciseTimer. For Qt::CoarseTimer, the interval will be adjusted up to 5% to align the timer with other timers that are expected to fire at or around the same time. The objective is to make most timers wake up at the diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 9468464cac..363657ed18 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -299,7 +299,7 @@ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName) the file system (i.e. not a file or directory). \value FileType The file is a regular file to the file system (i.e. not a link or directory) - \value BundleType The file is a Mac OS X bundle implies DirectoryType + \value BundleType OS X and iOS: the file is a bundle; implies DirectoryType \value DirectoryType The file is a directory in the file system (i.e. not a link or file). diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index a5e189a825..4fc2be2ecb 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1818,8 +1818,8 @@ QFileInfoList QDir::drives() } /*! - Returns the native directory separator: "/" under Unix (including - Mac OS X) and "\\" under Windows. + Returns the native directory separator: "/" under Unix + and "\\" under Windows. You do not need to use this function to build file paths. If you always use "/", Qt will translate your paths to conform to the diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index d3411abf10..cbe6baf5cc 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -199,9 +199,9 @@ QAbstractFileEngine *QFilePrivate::engine() const \section1 Platform Specific Issues - File permissions are handled differently on Linux/Mac OS X and + File permissions are handled differently on Unix-like systems and Windows. In a non \l{QIODevice::isWritable()}{writable} - directory on Linux, files cannot be created. This is not always + directory on Unix-like systems, files cannot be created. This is not always the case on Windows, where, for instance, the 'My Documents' directory usually is not writable, but it is still possible to create files in it. diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 98c36f4a82..130d35e984 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -234,7 +234,7 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) isSymLink(). The symLinkTarget() function provides the name of the file the symlink points to. - On Unix (including Mac OS X), the symlink has the same size() has + On Unix (including OS X and iOS), the symlink has the same size() has the file it points to, because Unix handles symlinks transparently; similarly, opening a symlink using QFile effectively opens the link's target. For example: @@ -753,7 +753,7 @@ QString QFileInfo::fileName() const \since 4.3 Returns the name of the bundle. - On Mac OS X this returns the proper localized name for a bundle if the + On OS X and iOS this returns the proper localized name for a bundle if the path isBundle(). On all other platforms an empty QString is returned. Example: @@ -1029,7 +1029,7 @@ bool QFileInfo::isDir() const /*! \since 4.3 Returns \c true if this object points to a bundle or to a symbolic - link to a bundle on Mac OS X; otherwise returns \c false. + link to a bundle on OS X and iOS; otherwise returns \c false. \sa isDir(), isSymLink(), isFile() */ @@ -1050,7 +1050,7 @@ bool QFileInfo::isBundle() const Returns \c true if this object points to a symbolic link (or to a shortcut on Windows); otherwise returns \c false. - On Unix (including Mac OS X), opening a symlink effectively opens + On Unix (including OS X and iOS), opening a symlink effectively opens the \l{symLinkTarget()}{link's target}. On Windows, it opens the \c .lnk file itself. diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp index b06017e57f..d9f3367ef0 100644 --- a/src/corelib/io/qfilesystemengine.cpp +++ b/src/corelib/io/qfilesystemengine.cpp @@ -323,7 +323,7 @@ void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry) } } #elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4) - // BSD4 includes Mac OS X + // BSD4 includes OS X and iOS // ### This will clear all entry flags and knownFlagsMask switch (entry.d_type) diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index bfa4483ca7..0cec40a3ce 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -412,7 +412,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM what |= QFileSystemMetaData::DirectoryType; } if (what & QFileSystemMetaData::HiddenAttribute) { - // Mac OS >= 10.5: st_flags & UF_HIDDEN + // OS X >= 10.5: st_flags & UF_HIDDEN what |= QFileSystemMetaData::PosixStatFlags; } #endif // defined(Q_OS_MACX) diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index 4bca8d90a0..d2be96291c 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -185,7 +185,7 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re the file system monitor. Also note that your process may have other file descriptors open in addition to the ones for files being monitored, and these other open descriptors also count in - the total. Mac OS X 10.5 and up use a different backend and do not + the total. OS X 10.5 and up use a different backend and do not suffer from this issue. diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index a126690240..b0dd3d76cf 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -603,7 +603,7 @@ qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len) result = fread(data + readBytes, 1, size_t(len - readBytes), fh); eof = feof(fh); if (retry && eof && result == 0) { - // On Mac OS, this is needed, e.g., if a file was written to + // On OS X, this is needed, e.g., if a file was written to // through another stream since our last read. See test // tst_QFile::appendAndRead QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream. @@ -875,7 +875,7 @@ bool QFSFileEngine::supportsExtension(Extension extension) const /*! \fn QFileInfoList QFSFileEngine::drives() For Windows, returns the list of drives in the file system as a list - of QFileInfo objects. On unix, Mac OS X and Windows CE, only the + of QFileInfo objects. On Unix and Windows CE, only the root path is returned. On Windows, this function returns all drives (A:\, C:\, D:\, etc.). diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 35911934df..a3e89a7b89 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -669,7 +669,7 @@ bool QIODevice::seek(qint64 pos) For some devices, atEnd() can return true even though there is more data to read. This special case only applies to devices that generate data in direct response to you calling read() (e.g., \c /dev or \c /proc files on - Unix and Mac OS X, or console input / \c stdin on all platforms). + Unix and OS X, or console input / \c stdin on all platforms). \sa bytesAvailable(), read(), isSequential() */ diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index 3ed973494b..bf1015a7be 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -102,7 +102,7 @@ static QBasicAtomicInt fcntlOK = Q_BASIC_ATOMIC_INITIALIZER(-1); /*! \internal Checks that the OS isn't using POSIX locks to emulate flock(). - Mac OS X is one of those. + OS X is one of those. */ static bool fcntlWorksAfterFlock() { diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index 79d20601a6..eb43e397bc 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -159,7 +159,7 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift) by QStandardPaths::GenericConfigLocation, e.g. \list - \li on Mac OS X: \c ~/Library/Preferences + \li on OS X and iOS: \c ~/Library/Preferences \li on Unix: \c ~/.config, \c /etc/xdg \li on Windows: \c %LOCALAPPDATA%, \c %ProgramData%, \l QCoreApplication::applicationDirPath(), diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index ebca7d57ff..a230427ee8 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -1916,7 +1916,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, Users normally expect an application to remember its settings (window sizes and positions, options, etc.) across sessions. This information is often stored in the system registry on Windows, - and in XML preferences files on Mac OS X. On Unix systems, in the + and in property list files on OS X and iOS. On Unix systems, in the absence of a standard, many applications (including the KDE applications) use INI text files. @@ -1961,8 +1961,8 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \snippet settings/settings.cpp 4 (Here, we also specify the organization's Internet domain. When - the Internet domain is set, it is used on Mac OS X instead of the - organization name, since Mac OS X applications conventionally use + the Internet domain is set, it is used on OS X and iOS instead of the + organization name, since OS X and iOS applications conventionally use Internet domains to identify themselves. If no domain is set, a fake domain is derived from the organization name. See the \l{Platform-Specific Notes} below for details.) @@ -2020,7 +2020,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, Setting keys can contain any Unicode characters. The Windows registry and INI files use case-insensitive keys, whereas the - Carbon Preferences API on Mac OS X uses case-sensitive keys. To + CFPreferences API on OS X and iOS uses case-sensitive keys. To avoid portability problems, follow these simple rules: \list 1 @@ -2223,7 +2223,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, in the application's home directory. If the file format is IniFormat, the following files are - used on Unix and Mac OS X: + used on Unix, OS X, and iOS: \list 1 \li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini}) @@ -2251,7 +2251,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, in the application's home directory. The paths for the \c .ini and \c .conf files can be changed using - setPath(). On Unix and Mac OS X, the user can override them by + setPath(). On Unix, OS X, and iOS the user can override them by setting the \c XDG_CONFIG_HOME environment variable; see setPath() for details. @@ -2268,7 +2268,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, You can then use the QSettings object to read and write settings in the file. - On Mac OS X, you can access XML-based \c .plist files by passing + On OS X and iOS, you can access property list \c .plist files by passing QSettings::NativeFormat as second argument. For example: \snippet code/src_corelib_io_qsettings.cpp 3 @@ -2322,13 +2322,13 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, limitations is to store the settings using the IniFormat instead of the NativeFormat. - \li On Mac OS X, allKeys() will return some extra keys for global + \li On OS X and iOS, allKeys() will return some extra keys for global settings that apply to all applications. These keys can be read using value() but cannot be changed, only shadowed. Calling setFallbacksEnabled(false) will hide these global settings. - \li On Mac OS X, the CFPreferences API used by QSettings expects + \li On OS X and iOS, the CFPreferences API used by QSettings expects Internet domain names rather than organization names. To provide a uniform API, QSettings derives a fake domain name from the organization name (unless the organization name @@ -2345,7 +2345,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \snippet code/src_corelib_io_qsettings.cpp 7 - \li On Mac OS X, permissions to access settings not belonging to the + \li On OS X, permissions to access settings not belonging to the current user (i.e. SystemScope) have changed with 10.7 (Lion). Prior to that version, users having admin rights could access these. For 10.7 and 10.8 (Mountain Lion), only root can. However, 10.9 (Mavericks) changes @@ -2385,7 +2385,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \value NativeFormat Store the settings using the most appropriate storage format for the platform. On Windows, this means the system registry; - on Mac OS X, this means the CFPreferences + on OS X and iOS, this means the CFPreferences API; on Unix, this means textual configuration files in INI format. \value IniFormat Store the settings in INI files. @@ -2548,7 +2548,7 @@ QSettings::QSettings(Format format, Scope scope, const QString &organization, If \a format is QSettings::NativeFormat, the meaning of \a fileName depends on the platform. On Unix, \a fileName is the - name of an INI file. On Mac OS X, \a fileName is the name of a + name of an INI file. On OS X and iOS, \a fileName is the name of a \c .plist file. On Windows, \a fileName is a path in the system registry. @@ -2601,7 +2601,7 @@ QSettings::QSettings(const QString &fileName, Format format, QObject *parent) called, the QSettings object will not be able to read or write any settings, and status() will return AccessError. - On Mac OS X, if both a name and an Internet domain are specified + On OS X and iOS, if both a name and an Internet domain are specified for the organization, the domain is preferred over the name. On other platforms, the name is preferred over the domain. @@ -3117,7 +3117,7 @@ bool QSettings::isWritable() const exists, the previous value is overwritten. Note that the Windows registry and INI files use case-insensitive - keys, whereas the Carbon Preferences API on Mac OS X uses + keys, whereas the CFPreferences API on OS X and iOS uses case-sensitive keys. To avoid portability problems, see the \l{Section and Key Syntax} rules. @@ -3156,7 +3156,7 @@ void QSettings::setValue(const QString &key, const QVariant &value) \snippet code/src_corelib_io_qsettings.cpp 25 Note that the Windows registry and INI files use case-insensitive - keys, whereas the Carbon Preferences API on Mac OS X uses + keys, whereas the CFPreferences API on OS X and iOS uses case-sensitive keys. To avoid portability problems, see the \l{Section and Key Syntax} rules. @@ -3191,7 +3191,7 @@ void QSettings::remove(const QString &key) relative to that group. Note that the Windows registry and INI files use case-insensitive - keys, whereas the Carbon Preferences API on Mac OS X uses + keys, whereas the CFPreferences API on OS X and iOS uses case-sensitive keys. To avoid portability problems, see the \l{Section and Key Syntax} rules. @@ -3253,7 +3253,7 @@ bool QSettings::event(QEvent *event) returned. Note that the Windows registry and INI files use case-insensitive - keys, whereas the Carbon Preferences API on Mac OS X uses + keys, whereas the CFPreferences API on OS X and iOS uses case-sensitive keys. To avoid portability problems, see the \l{Section and Key Syntax} rules. @@ -3356,18 +3356,18 @@ void QSettings::setUserIniPath(const QString &dir) \row \li SystemScope \li \c /etc/xdg \row \li{1,2} Qt for Embedded Linux \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/Settings \row \li SystemScope \li \c /etc/xdg - \row \li{1,2} Mac OS X \li{1,2} IniFormat \li UserScope \li \c $HOME/.config + \row \li{1,2} OS X and iOS \li{1,2} IniFormat \li UserScope \li \c $HOME/.config \row \li SystemScope \li \c /etc/xdg \endtable - The default UserScope paths on Unix and Mac OS X (\c + The default UserScope paths on Unix, OS X, and iOS (\c $HOME/.config or $HOME/Settings) can be overridden by the user by setting the \c XDG_CONFIG_HOME environment variable. The default SystemScope - paths on Unix and Mac OS X (\c /etc/xdg) can be overridden when + paths on Unix, OS X, and iOS (\c /etc/xdg) can be overridden when building the Qt library using the \c configure script's \c -sysconfdir flag (see QLibraryInfo for details). - Setting the NativeFormat paths on Windows and Mac OS X has no + Setting the NativeFormat paths on Windows, OS X, and iOS has no effect. \warning This function doesn't affect existing QSettings objects. diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index aea82fd48b..dcd6cad33d 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -663,7 +663,7 @@ QCoreApplication::QCoreApplication(QCoreApplicationPrivate &p) If you are doing graphical changes inside a loop that does not return to the event loop on asynchronous window systems like X11 - or double buffered window systems like Mac OS X, and you want to + or double buffered window systems like Quartz (OS X and iOS), and you want to visualize these changes immediately (e.g. Splash Screens), call this function. @@ -1975,7 +1975,7 @@ void QCoreApplicationPrivate::setApplicationFilePath(const QString &path) directory, and you run the \c{regexp} example, this function will return "C:/Qt/examples/tools/regexp". - On Mac OS X this will point to the directory actually containing the + On OS X and iOS this will point to the directory actually containing the executable, which may be inside of an application bundle (if the application is bundled). diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index c0094fb7f2..990b1089c7 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -167,7 +167,7 @@ QT_BEGIN_NAMESPACE \value NonClientAreaMouseButtonPress A mouse button press occurred outside the client area. \value NonClientAreaMouseButtonRelease A mouse button release occurred outside the client area. \value NonClientAreaMouseMove A mouse move occurred outside the client area. - \value MacSizeChange The user changed his widget sizes (Mac OS X only). + \value MacSizeChange The user changed his widget sizes (OS X only). \value MetaCall An asynchronous method invocation via QMetaObject::invokeMethod(). \value ModifiedChange Widgets modification state has been changed. \value MouseButtonDblClick Mouse press again (QMouseEvent). @@ -210,7 +210,7 @@ QT_BEGIN_NAMESPACE \omitvalue ThemeChange \value ThreadChange The object is moved to another thread. This is the last event sent to this object in the previous thread. See QObject::moveToThread(). \value Timer Regular timer events (QTimerEvent). - \value ToolBarChange The toolbar button is toggled on Mac OS X. + \value ToolBarChange The toolbar button is toggled on OS X. \value ToolTip A tooltip was requested (QHelpEvent). \value ToolTipChange The widget's tooltip has changed. \value TouchBegin Beginning of a sequence of touch-screen or track-pad events (QTouchEvent). diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index f2ceb7081c..b3abcd8b35 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1475,7 +1475,7 @@ void QObject::moveToThread(QThread *targetThread) currentData->thread, d->threadData->thread, targetData ? targetData->thread : Q_NULLPTR); #ifdef Q_OS_MAC - qWarning("On Mac OS X, you might be loading two sets of Qt binaries into the same process. " + qWarning("You might be loading two sets of Qt binaries into the same process. " "Check that all plugins are compiled against the right Qt binaries. Export " "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded."); #endif diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index c5103ebe59..b2c3834743 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -237,7 +237,7 @@ bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent) The MIME type database is provided by the freedesktop.org shared-mime-info project. If the MIME type database cannot be found on the system, as is the case - on most Windows and Mac OS X systems, Qt will use its own copy of it. + on most Windows, OS X, and iOS systems, Qt will use its own copy of it. Applications which want to define custom MIME types need to install an XML file into the locations searched for MIME definitions. diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 832ee250c7..bdb61339ad 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -594,7 +594,7 @@ bool QLibraryPrivate::loadPlugin() \row \li Unix/Linux \li \c .so \row \li AIX \li \c .a \row \li HP-UX \li \c .sl, \c .so (HP-UXi) - \row \li Mac OS X \li \c .dylib, \c .bundle, \c .so + \row \li OS X and iOS \li \c .dylib, \c .bundle, \c .so \endtable Trailing versioning numbers on Unix are ignored. @@ -831,7 +831,7 @@ QLibrary::QLibrary(QObject *parent) We recommend omitting the file's suffix in \a fileName, since QLibrary will automatically look for the file with the appropriate suffix in accordance with the platform, e.g. ".so" on Unix, - ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) + ".dylib" on OS X and iOS, and ".dll" on Windows. (See \l{fileName}.) */ QLibrary::QLibrary(const QString& fileName, QObject *parent) :QObject(parent), d(0), did_load(false) @@ -848,7 +848,7 @@ QLibrary::QLibrary(const QString& fileName, QObject *parent) We recommend omitting the file's suffix in \a fileName, since QLibrary will automatically look for the file with the appropriate suffix in accordance with the platform, e.g. ".so" on Unix, - ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) + ".dylib" on OS X and iOS, and ".dll" on Windows. (See \l{fileName}.) */ QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent) :QObject(parent), d(0), did_load(false) @@ -864,7 +864,7 @@ QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent) We recommend omitting the file's suffix in \a fileName, since QLibrary will automatically look for the file with the appropriate suffix in accordance with the platform, e.g. ".so" on Unix, - ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) + ".dylib" on OS X and iOS, and ".dll" on Windows. (See \l{fileName}.) */ QLibrary::QLibrary(const QString& fileName, const QString &version, QObject *parent) :QObject(parent), d(0), did_load(false) diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index f850394984..dc2a6d57b0 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -139,7 +139,7 @@ QPluginLoader::QPluginLoader(QObject *parent) To be loadable, the file's suffix must be a valid suffix for a loadable library in accordance with the platform, e.g. \c .so on - Unix, - \c .dylib on Mac OS X, and \c .dll on Windows. The suffix + Unix, - \c .dylib on OS X and iOS, and \c .dll on Windows. The suffix can be verified with QLibrary::isLibrary(). \sa setFileName() diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index e4338e10b4..d17403df7a 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -406,7 +406,7 @@ int QThread::idealThreadCount() Q_DECL_NOTHROW cores = (int)psd.psd_proc_cnt; } #elif defined(Q_OS_BSD4) - // FreeBSD, OpenBSD, NetBSD, BSD/OS, Mac OS X + // FreeBSD, OpenBSD, NetBSD, BSD/OS, OS X, iOS size_t len = sizeof(cores); int mib[2]; mib[0] = CTL_HW; diff --git a/src/corelib/tools/qelapsedtimer.cpp b/src/corelib/tools/qelapsedtimer.cpp index 52875bc9fe..fb6c9bd3a0 100644 --- a/src/corelib/tools/qelapsedtimer.cpp +++ b/src/corelib/tools/qelapsedtimer.cpp @@ -131,7 +131,7 @@ QT_BEGIN_NAMESPACE \value SystemTime The human-readable system time. This clock is not monotonic. \value MonotonicClock The system's monotonic clock, usually found in Unix systems. This clock is monotonic and does not overflow. \value TickCounter The system's tick counter, used on Windows systems. This clock may overflow. - \value MachAbsoluteTime The Mach kernel's absolute time (Mac OS X). This clock is monotonic and does not overflow. + \value MachAbsoluteTime The Mach kernel's absolute time (OS X and iOS). This clock is monotonic and does not overflow. \value PerformanceCounter The high-resolution performance counter provided by Windows. This clock is monotonic and does not overflow. \section2 SystemTime @@ -173,8 +173,8 @@ QT_BEGIN_NAMESPACE \section2 MachAbsoluteTime This clock type is based on the absolute time presented by Mach kernels, - such as that found on Mac OS X. This clock type is presented separately - from MonotonicClock since Mac OS X is also a Unix system and may support + such as that found on OS X. This clock type is presented separately + from MonotonicClock since OS X and iOS are also Unix systems and may support a POSIX monotonic clock with values differing from the Mach absolute time. diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 9921d5cfbb..189caf8bd7 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -5288,7 +5288,7 @@ int QString::compare_helper(const QChar *data1, int length1, QLatin1String s2, platform-dependent manner. Use this function to present sorted lists of strings to the user. - On Mac OS X since Qt 4.3, this function compares according the + On OS X and iOS this function compares according the "Order for sorted lists" setting in the International preferences panel. \sa compare(), QLocale @@ -7713,7 +7713,7 @@ QString QString::multiArg(int numArgs, const QString **args) const Constructs a new QString containing a copy of the \a string CFString. - \note this function is only available on Mac OS X and iOS. + \note this function is only available on OS X and iOS. */ /*! \fn CFStringRef QString::toCFString() const @@ -7722,7 +7722,7 @@ QString QString::multiArg(int numArgs, const QString **args) const Creates a CFString from a QString. The caller owns the CFString and is responsible for releasing it. - \note this function is only available on Mac OS X and iOS. + \note this function is only available on OS X and iOS. */ /*! \fn QString QString::fromNSString(const NSString *string) @@ -7730,7 +7730,7 @@ QString QString::multiArg(int numArgs, const QString **args) const Constructs a new QString containing a copy of the \a string NSString. - \note this function is only available on Mac OS X and iOS. + \note this function is only available on OS X and iOS. */ /*! \fn NSString QString::toNSString() const @@ -7738,7 +7738,7 @@ QString QString::multiArg(int numArgs, const QString **args) const Creates a NSString from a QString. The NSString is autoreleased. - \note this function is only available on Mac OS X and iOS. + \note this function is only available on OS X and iOS. */ /*! \fn bool QString::isSimpleText() const @@ -8915,7 +8915,7 @@ QStringRef QStringRef::appendTo(QString *string) const platform-dependent manner. Use this function to present sorted lists of strings to the user. - On Mac OS X, this function compares according the + On OS X and iOS, this function compares according the "Order for sorted lists" setting in the International prefereces panel. \sa compare(), QLocale diff --git a/src/corelib/tools/qtimezone.cpp b/src/corelib/tools/qtimezone.cpp index 8f3db74131..5685e92447 100644 --- a/src/corelib/tools/qtimezone.cpp +++ b/src/corelib/tools/qtimezone.cpp @@ -179,7 +179,7 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz); given moment then you should use a Qt::TimeSpec of Qt::LocalTime. The method systemTimeZoneId() returns the current system IANA time zone - ID which on OSX and Linux will always be correct. On Windows this ID is + ID which on Unix-like systems will always be correct. On Windows this ID is translated from the Windows system ID using an internal translation table and the user's selected country. As a consequence there is a small chance any Windows install may have IDs not known by Qt, in which case -- cgit v1.2.3 From 633b950bd49a958cc2391692c9dd753431c80a4d Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Fri, 16 Jan 2015 14:48:08 +0200 Subject: QSslSocket: try to send all data on close() Takes care about unencrypted data in the socket writeBuffer when close() flushes the output. Change-Id: I301f41ea709817e215ee4246a3951e3182d94fbd Reviewed-by: Richard J. Moore --- src/network/ssl/qsslsocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 39cd562bc4..c1fab94fce 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -764,7 +764,7 @@ void QSslSocket::close() qCDebug(lcSsl) << "QSslSocket::close()"; #endif Q_D(QSslSocket); - if (encryptedBytesToWrite()) + if (encryptedBytesToWrite() || !d->writeBuffer.isEmpty()) flush(); if (d->plainSocket) d->plainSocket->close(); -- cgit v1.2.3 From 1458d1b31d2df20e79db9e873d36986bc87074a2 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Fri, 20 Mar 2015 16:38:15 +0100 Subject: Use allConfigurations instead of onlineConfigurations in isOnline() We need it because otherwise code like QNetworkConfigurationManager ncm; qDebug() << "ONLINE" << ncm->isOnline(); may give the wrong value because the queued signals that have been just connected a few lines above may not have been processed yet Change-Id: I959db75ed17497ab91eeba2669ee2c8947244f00 Reviewed-by: Alex Blasche --- src/network/bearer/qnetworkconfigmanager_p.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp index ef7ab51462..6bbea1683c 100644 --- a/src/network/bearer/qnetworkconfigmanager_p.cpp +++ b/src/network/bearer/qnetworkconfigmanager_p.cpp @@ -276,7 +276,9 @@ bool QNetworkConfigurationManagerPrivate::isOnline() const { QMutexLocker locker(&mutex); - return !onlineConfigurations.isEmpty(); + // We need allConfigurations since onlineConfigurations is filled with queued connections + // and thus is not always (more importantly just after creation) up to date + return !allConfigurations(QNetworkConfiguration::Active).isEmpty(); } QNetworkConfigurationManager::Capabilities QNetworkConfigurationManagerPrivate::capabilities() const -- cgit v1.2.3 From c1a67e7dc3a6f8876efa32cdbabbfde1c5a37bc6 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Tue, 31 Mar 2015 17:43:44 +0200 Subject: Windows: Do not crash if SSL context is gone after root cert lookup On Windows, we perform an extra certificate lookup for root CAs that are not in Windows' (minimal) root store. This check can take up to 15 seconds. The SSL context can already be gone once we return. Hence we now check for a non-null SSL context on Windows before proceeding. Change-Id: I1951569d9b17da33fa604f7c9d8b33255acf200d Reviewed-by: Richard J. Moore --- src/network/ssl/qsslsocket_openssl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 0e1a3e53c9..b132aec038 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1281,7 +1281,7 @@ void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertifi if (plainSocket) plainSocket->resume(); paused = false; - if (checkSslErrors()) + if (checkSslErrors() && ssl) continueHandshake(); } -- cgit v1.2.3 From 20c651d8b8c18ed123b84162fe4531eb4f414509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Sun, 29 Mar 2015 16:02:53 +0100 Subject: Fix QNX and Blackberry -qtnamespace build Task-number: QTBUG-43569 Change-Id: I81a560d1508de4d808a807f1febdc17619cf4dda Reviewed-by: Rafael Roquetto --- src/corelib/kernel/qeventdispatcher_blackberry.cpp | 2 ++ src/corelib/kernel/qppsattribute.cpp | 4 ++++ src/corelib/kernel/qppsattribute_p.h | 5 +++-- src/corelib/kernel/qppsobject.cpp | 4 ++++ src/gui/kernel/qclipboard.cpp | 4 ++-- src/plugins/platforms/qnx/qqnxfilepicker.cpp | 4 ++++ src/plugins/platforms/qnx/qqnxfilepicker.h | 4 ++++ src/plugins/platforms/qnx/qqnxsystemsettings.h | 4 ++-- src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h | 2 ++ 9 files changed, 27 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qeventdispatcher_blackberry.cpp b/src/corelib/kernel/qeventdispatcher_blackberry.cpp index 047e3dff07..7a70f5cb58 100644 --- a/src/corelib/kernel/qeventdispatcher_blackberry.cpp +++ b/src/corelib/kernel/qeventdispatcher_blackberry.cpp @@ -49,6 +49,8 @@ #define qEventDispatcherDebug QT_NO_QDEBUG_MACRO() #endif +QT_BEGIN_NAMESPACE + class BpsChannelScopeSwitcher { public: diff --git a/src/corelib/kernel/qppsattribute.cpp b/src/corelib/kernel/qppsattribute.cpp index 09d8d1bb0c..b77ea0b643 100644 --- a/src/corelib/kernel/qppsattribute.cpp +++ b/src/corelib/kernel/qppsattribute.cpp @@ -37,6 +37,8 @@ #include #include +QT_BEGIN_NAMESPACE + /////////////////////////// // // QPpsAttributePrivate @@ -297,3 +299,5 @@ QDebug operator<<(QDebug dbg, const QPpsAttribute &attribute) return dbg; } + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qppsattribute_p.h b/src/corelib/kernel/qppsattribute_p.h index 209a8c3101..73beb7c96f 100644 --- a/src/corelib/kernel/qppsattribute_p.h +++ b/src/corelib/kernel/qppsattribute_p.h @@ -57,8 +57,6 @@ class QPpsAttribute; typedef QList QPpsAttributeList; typedef QMap QPpsAttributeMap; -Q_DECLARE_METATYPE(QPpsAttributeList) -Q_DECLARE_METATYPE(QPpsAttributeMap) class Q_CORE_EXPORT QPpsAttribute { @@ -128,4 +126,7 @@ Q_CORE_EXPORT QDebug operator<<(QDebug dbg, const QPpsAttribute &attribute); QT_END_NAMESPACE +Q_DECLARE_METATYPE(QPpsAttributeList) +Q_DECLARE_METATYPE(QPpsAttributeMap) + #endif // QPPSATTRIBUTE_P_H diff --git a/src/corelib/kernel/qppsobject.cpp b/src/corelib/kernel/qppsobject.cpp index 9a5ae3c7a4..612e756881 100644 --- a/src/corelib/kernel/qppsobject.cpp +++ b/src/corelib/kernel/qppsobject.cpp @@ -50,6 +50,8 @@ #include +QT_BEGIN_NAMESPACE + /////////////////////////////////////////////////////////////////////////////// static inline void safeAssign(bool *pointer, bool value) { @@ -954,3 +956,5 @@ int QPpsObject::sendMessage(const QString &path, const QByteArray &ppsData) return EOK; } + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qclipboard.cpp b/src/gui/kernel/qclipboard.cpp index 5be9f19b3e..ec7a98571d 100644 --- a/src/gui/kernel/qclipboard.cpp +++ b/src/gui/kernel/qclipboard.cpp @@ -584,6 +584,6 @@ void QClipboard::emitChanged(Mode mode) emit changed(mode); } -#endif // QT_NO_CLIPBOARD - QT_END_NAMESPACE + +#endif // QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/qnx/qqnxfilepicker.cpp b/src/plugins/platforms/qnx/qqnxfilepicker.cpp index 9362f9cd0b..4853dce9d9 100644 --- a/src/plugins/platforms/qnx/qqnxfilepicker.cpp +++ b/src/plugins/platforms/qnx/qqnxfilepicker.cpp @@ -55,6 +55,8 @@ #define qFilePickerDebug QT_NO_QDEBUG_MACRO #endif +QT_BEGIN_NAMESPACE + static const char s_filePickerTarget[] = "sys.filepicker.target"; QQnxFilePicker::QQnxFilePicker(QObject *parent) @@ -322,3 +324,5 @@ QString QQnxFilePicker::modeToString(QQnxFilePicker::Mode mode) const return QStringLiteral("Picker"); } + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxfilepicker.h b/src/plugins/platforms/qnx/qqnxfilepicker.h index 82df1ea32d..63832633d8 100644 --- a/src/plugins/platforms/qnx/qqnxfilepicker.h +++ b/src/plugins/platforms/qnx/qqnxfilepicker.h @@ -38,6 +38,8 @@ #include #include +QT_BEGIN_NAMESPACE + struct navigator_invoke_invocation_t; class QQnxFilePicker : public QObject, public QAbstractNativeEventFilter @@ -100,4 +102,6 @@ private: QString m_title; }; +QT_END_NAMESPACE + #endif // QQNXFILEPICKER_H diff --git a/src/plugins/platforms/qnx/qqnxsystemsettings.h b/src/plugins/platforms/qnx/qqnxsystemsettings.h index 3402243572..1f0e425f71 100644 --- a/src/plugins/platforms/qnx/qqnxsystemsettings.h +++ b/src/plugins/platforms/qnx/qqnxsystemsettings.h @@ -37,10 +37,10 @@ #include #include -class QPlatformFontDatabase; - QT_BEGIN_NAMESPACE +class QPlatformFontDatabase; + QHash qt_qnx_createRoleFonts(QPlatformFontDatabase *fontDatabase); QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h index faba3409d9..0ced2340b0 100644 --- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h @@ -86,4 +86,6 @@ private: static const size_t ms_bufferSize; }; +QT_END_NAMESPACE + #endif // VIRTUALKEYBOARDPPS_H -- cgit v1.2.3 From e7e580412e7375aee6dad8d1b60ae8a40d6c7207 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 7 Apr 2015 13:13:14 +0200 Subject: Windows: Fix -no-widgets build Change-Id: I0a79a61ffe8b6c6f66895dbeb988e653e11c9661 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/accessible/iaccessible2.cpp | 2 +- src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 7f60be0d50..465770176d 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index a115d7c477..a11aa74e8a 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -49,10 +49,6 @@ #include #include #include -#include -#include -#include -#include //#include #ifndef UiaRootObjectId -- cgit v1.2.3 From 5b5d25cc417a43c4733fc19644e11c6523fd6f72 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Wed, 8 Apr 2015 16:52:24 +0400 Subject: [QtFontFamily] Get rid of unused member Change-Id: I8c70995767bfb5fdbd6e9e9464029beeccf41f53 Reviewed-by: Friedemann Kleint Reviewed-by: Simon Hausmann --- src/gui/text/qfontdatabase.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 1a71042648..0f3cb21c70 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -356,7 +356,6 @@ struct QtFontFamily populated(false), fixedPitch(false), name(n), count(0), foundries(0) - , bogusWritingSystems(false) , askedForFallback(false) { memset(writingSystems, 0, sizeof(writingSystems)); @@ -375,7 +374,6 @@ struct QtFontFamily int count; QtFontFoundry **foundries; - bool bogusWritingSystems; QStringList fallbackFamilies; bool askedForFallback; unsigned char writingSystems[QFontDatabase::WritingSystemsCount]; -- cgit v1.2.3 From e63752e6bb886d83af0c22faa673ea4cf99729f0 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 17 Mar 2015 14:07:37 +0100 Subject: Remove table of mostly null pointers The patch moves the initialization of the format to format blend tables to runtime, so we only have to explicitly set the values that are not null. This removes most of the lines in qblendfunctions.cpp. Change-Id: Ie017f380ff11cfb764a631cfea7626786731b5fb Reviewed-by: Gunnar Sletta --- src/gui/kernel/qguiapplication.cpp | 3 + src/gui/painting/qblendfunctions.cpp | 2136 ++-------------------------------- 2 files changed, 73 insertions(+), 2066 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 9f73f019a3..47c20a71fc 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -185,6 +185,7 @@ extern void qRegisterGuiVariant(); #ifndef QT_NO_ANIMATION extern void qRegisterGuiGetInterpolator(); #endif +extern void qInitBlendFunctions(); extern void qInitDrawhelperAsm(); extern void qInitImageConversions(); @@ -1279,6 +1280,8 @@ void QGuiApplicationPrivate::init() if (platform_integration == 0) createPlatformIntegration(); + // Set up blend function tables. + qInitBlendFunctions(); // Set up which span functions should be used in raster engine... qInitDrawhelperAsm(); // and QImage conversion functions diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 478fe6564c..b3710411c9 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -432,10 +432,10 @@ static void qt_blend_argb32pm_on_a2rgb30pm(uchar *destPixels, int dbpl, } template -void qt_blend_rgb32_on_rgb30(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) +static void qt_blend_rgb32_on_rgb30(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) { #ifdef QT_DEBUG_DRAW fprintf(stdout, "qt_blend_rgb32_on_rgb30: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", @@ -496,10 +496,10 @@ static void qt_blend_a2rgb30pm_on_a2rgb30pm(uchar *destPixels, int dbpl, } -void qt_blend_rgb30_on_rgb30(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) +static void qt_blend_rgb30_on_rgb30(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) { #ifdef QT_DEBUG_DRAW fprintf(stdout, "qt_blend_rgb30_on_rgb30: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", @@ -740,2071 +740,75 @@ void qt_transform_image_argb32_on_argb32(uchar *destPixels, int dbpl, } } -SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGRs30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_scale_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_scale_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_scale_image_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_scale_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_scale_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_scale_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_scale_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - } -}; - +SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats]; +SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats]; +SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats]; -SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb16, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_blend_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_blend_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_blend_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, +void qInitBlendFunctions() +{ + qScaleFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_blend_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_blend_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_RGB30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_BGR30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_RGB30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_BGR30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_BGR30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - } -}; -SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_transform_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_transform_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_transform_image_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb16; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_transform_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_transform_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, + qBlendFunctions[QImage::Format_BGR30][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_BGR30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_RGB30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_BGR30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_BGR30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_RGB30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_BGR30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + + qTransformFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_transform_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_transform_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qTransformFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_transform_image_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, -}; +} QT_END_NAMESPACE -- cgit v1.2.3 From cd61b6c969dee74776ad7e9f3dcf1e1623b1059b Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 8 Apr 2015 10:33:36 +0200 Subject: Add a cast to glTexImage2D to keep QNX happy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The internalformat parameter seems to be GLenum (unsigned int) on QNX based on the error message in the linked bug report. The standard is GLint, though. To keep everyone happy, add a cast. Task-number: QTBUG-45346 Change-Id: I57fece7b381e0d02acc842a21b1edc5451ea0224 Reviewed-by: Sérgio Martins Reviewed-by: Rafael Roquetto --- src/gui/opengl/qopengltexturehelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gui/opengl/qopengltexturehelper.cpp b/src/gui/opengl/qopengltexturehelper.cpp index e1e3593f4f..442fa4c22c 100644 --- a/src/gui/opengl/qopengltexturehelper.cpp +++ b/src/gui/opengl/qopengltexturehelper.cpp @@ -171,7 +171,7 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) GetTexParameteriv = ::glGetTexParameteriv; GetTexParameterfv = ::glGetTexParameterfv; GetTexImage = 0; - TexImage2D = ::glTexImage2D; + TexImage2D = reinterpret_cast(::glTexImage2D); TexImage1D = 0; TexParameteriv = ::glTexParameteriv; TexParameteri = ::glTexParameteri; -- cgit v1.2.3 From db52d55fba61abf295de9f8430f60890cde58ee7 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 8 Apr 2015 09:21:25 +0200 Subject: Avoid leaking the QPlatformTextureList MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-45395 Change-Id: I8fbdc5136d7d15b9c131d6b91186a1bf2645e4d4 Reviewed-by: Jørgen Lind --- src/widgets/kernel/qwidgetbackingstore.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index f8b8ec5ea3..485cf82078 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -762,6 +762,7 @@ QWidgetBackingStore::~QWidgetBackingStore() resetWidget(dirtyRenderToTextureWidgets.at(c)); #ifndef QT_NO_OPENGL + delete widgetTextures; delete dirtyOnScreenWidgets; #endif dirtyOnScreenWidgets = 0; -- cgit v1.2.3 From 7c149dd86944b3669420832b2b14fac00327d4b7 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Sat, 28 Mar 2015 15:03:18 +0200 Subject: Prevent memory overgrowth while reading from a sequential device After flushing the internal buffer, QIODevice::readAll() attempts to read the device incrementally. On each iteration, the result buffer size is increased by a constant value independently from the number of read bytes. This lead to unreasonable growth of the buffer if these additional conditions were met: - readData() requests new data from the device on every call; - highly loaded device provides at least one byte on each request. Instead of constant resizing, keep the size of free block to avoid a possible memory exhaustion. Task-number: QTBUG-44286 Change-Id: I637e2d0e05bd900a1bb9517af2fe7d8038c75a35 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qiodevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 7a87a78c60..43ad8d9316 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -989,8 +989,8 @@ QByteArray QIODevice::readAll() // Size is unknown, read incrementally. qint64 readResult; do { - result.resize(result.size() + QIODEVICE_BUFFERSIZE); - readResult = read(result.data() + readBytes, result.size() - readBytes); + result.resize(readBytes + QIODEVICE_BUFFERSIZE); + readResult = read(result.data() + readBytes, QIODEVICE_BUFFERSIZE); if (readResult > 0 || readBytes == 0) readBytes += readResult; } while (readResult > 0); -- cgit v1.2.3 From bc00e6da8477a5fc0e547733effef9db944f3eab Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 9 Apr 2015 00:22:06 +0000 Subject: QIconvCodec: fix compilation when NO_BOM is defined. qiconvcodec.cpp:305:34: error: unused parameter 'cd' [-Werror,-Wunused-parameter] Change-Id: I27eaacb532114dd188c4ffff13d330b64b4feaa6 Reviewed-by: Lars Knoll --- src/corelib/codecs/qiconvcodec.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/corelib/codecs/qiconvcodec.cpp b/src/corelib/codecs/qiconvcodec.cpp index bf4e8f26f3..5a1ba51f65 100644 --- a/src/corelib/codecs/qiconvcodec.cpp +++ b/src/corelib/codecs/qiconvcodec.cpp @@ -323,6 +323,8 @@ static bool setByteOrder(iconv_t cd) if (iconv(cd, inBytesPtr, &inBytesLeft, &outBytes, &outBytesLeft) == (size_t) -1) { return false; } +#else + Q_UNUSED(cd); #endif // NO_BOM return true; -- cgit v1.2.3 From f0cee4568ec3bd58cbc33108a6e606c3294e0fb3 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 9 Apr 2015 08:58:32 +0200 Subject: Add a null pointer check for parent before derefencing it Change-Id: I5b411f50acc6719b36cdde9ae2dd766b29e9731c Reviewed-by: Friedemann Kleint --- src/printsupport/dialogs/qpagesetupdialog_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/printsupport/dialogs/qpagesetupdialog_win.cpp b/src/printsupport/dialogs/qpagesetupdialog_win.cpp index baa8f93454..84cdf8f976 100644 --- a/src/printsupport/dialogs/qpagesetupdialog_win.cpp +++ b/src/printsupport/dialogs/qpagesetupdialog_win.cpp @@ -94,7 +94,7 @@ int QPageSetupDialog::exec() parent = parent ? parent->window() : QApplication::activeWindow(); Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created)); - QWindow *parentWindow = parent->windowHandle(); + QWindow *parentWindow = parent ? parent->windowHandle() : 0; psd.hwndOwner = parentWindow ? (HWND)QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", parentWindow) : 0; psd.Flags = PSD_MARGINS; -- cgit v1.2.3 From d984b07221f55ccb8b531e6184a6fb361c324139 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 24 Mar 2015 08:40:21 +0100 Subject: Guard QWidget::setStyleSheet() against invocation from destructor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-45178 Change-Id: I3670d9cd9645155318b595d1324a3b3caf2352f6 Reviewed-by: Jørgen Lind --- src/widgets/kernel/qwidget.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 4f618e34a8..b2ea83c991 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -2608,6 +2608,8 @@ QString QWidget::styleSheet() const void QWidget::setStyleSheet(const QString& styleSheet) { Q_D(QWidget); + if (data->in_destructor) + return; d->createExtra(); QStyleSheetStyle *proxy = qobject_cast(d->extra->style); -- cgit v1.2.3 From 56d091a4ea0276a4af732bfc8c701f392e57b9a1 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 24 Mar 2015 09:31:28 +0100 Subject: QToolButton: Fix popup menu geometry in case of QGraphicsProxyWidget. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QDesktopWidget::availableGeometry(const QWidget *) returns the scene geometry when the widget is embedded into a QGraphicsProxyWidget. Work around by using the overload taking a point. Task-number: QTBUG-38559 Change-Id: Ie630bda57e14648255015587a04e29b0de96bab7 Reviewed-by: Arnaud Bienner Reviewed-by: Jørgen Lind --- src/widgets/widgets/qtoolbutton.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp index 1efe88acde..5a56c592a6 100644 --- a/src/widgets/widgets/qtoolbutton.cpp +++ b/src/widgets/widgets/qtoolbutton.cpp @@ -733,9 +733,9 @@ void QToolButtonPrivate::popupTimerDone() horizontal = false; #endif QPoint p; - QRect screen = QApplication::desktop()->availableGeometry(q); + const QRect rect = q->rect(); // Find screen via point in case of QGraphicsProxyWidget. + QRect screen = QApplication::desktop()->availableGeometry(q->mapToGlobal(rect.center())); QSize sh = ((QToolButton*)(QMenu*)actualMenu)->receivers(SIGNAL(aboutToShow()))? QSize() : actualMenu->sizeHint(); - QRect rect = q->rect(); if (horizontal) { if (q->isRightToLeft()) { if (q->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) { -- cgit v1.2.3 From 24b3d82efff7709073bb74e1420d16a8b7312997 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 30 Mar 2015 11:30:47 +0200 Subject: QStateMachine: move QState::finished() emision into method. By moving the code for QState::finished() emission into a virtual method which also receives the QFinalState that caused the emission, subclasses can hook in and do some extra processing. Change-Id: Id19947c09e196a0df4edb87d71b74b0600c78867 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/statemachine/qstatemachine.cpp | 26 ++++++++++++++++++-------- src/corelib/statemachine/qstatemachine_p.h | 2 ++ 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 760ac59bf4..375fe6c8e8 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -610,10 +610,9 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QListparentState(); if (parent) { if (parent != rootState()) { -#ifdef QSTATEMACHINE_DEBUG - qDebug() << q << ": emitting finished signal for" << parent; -#endif - QStatePrivate::get(parent)->emitFinished(); + QFinalState *finalState = qobject_cast(s); + Q_ASSERT(finalState); + emitStateFinished(parent, finalState); } QState *grandparent = parent->parentState(); if (grandparent && isParallel(grandparent)) { @@ -627,10 +626,9 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QListemitFinished(); + QFinalState *finalState = qobject_cast(s); + Q_ASSERT(finalState); + emitStateFinished(grandparent, finalState); } } } @@ -1619,6 +1617,18 @@ void QStateMachinePrivate::cancelAllDelayedEvents() delayedEvents.clear(); } +void QStateMachinePrivate::emitStateFinished(QState *forState, QFinalState *guiltyState) +{ + Q_UNUSED(guiltyState); + Q_ASSERT(guiltyState); + +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": emitting finished signal for" << forState; +#endif + + QStatePrivate::get(forState)->emitFinished(); +} + namespace _QStateMachine_Internal{ class GoToStateTransition : public QAbstractTransition diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index 3a93c47c5b..1c885d1a36 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -188,6 +188,8 @@ public: void processEvents(EventProcessingMode processingMode); void cancelAllDelayedEvents(); + virtual void emitStateFinished(QState *forState, QFinalState *guiltyState); + #ifndef QT_NO_PROPERTIES class RestorableId { QPointer guard; -- cgit v1.2.3 From 65d2b6b4df8d339177e640e5166d2a88088b8453 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 31 Mar 2015 14:43:53 +0200 Subject: Add missing event types in printXcbEvent And replace Xlib define GenericEvent with XCB define XCB_GE_GENERIC. Change-Id: Ie82cb7f58b18fc0d253e4b7fd65495608df0a7d9 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbconnection.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index f4c633e2d7..f0cd4c8484 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -83,6 +83,12 @@ Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input") Q_LOGGING_CATEGORY(lcQpaXInputDevices, "qt.qpa.input.devices") Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen") +// this event type was added in libxcb 1.10, +// but we support also older version +#ifndef XCB_GE_GENERIC +#define XCB_GE_GENERIC 35 +#endif + #ifdef XCB_USE_XLIB static const char * const xcbConnectionErrors[] = { "No error", /* Error 0 */ @@ -666,6 +672,7 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event) PRINT_XCB_EVENT(XCB_KEYMAP_NOTIFY); PRINT_XCB_EVENT(XCB_EXPOSE); PRINT_XCB_EVENT(XCB_GRAPHICS_EXPOSURE); + PRINT_XCB_EVENT(XCB_NO_EXPOSURE); PRINT_XCB_EVENT(XCB_VISIBILITY_NOTIFY); PRINT_XCB_EVENT(XCB_CREATE_NOTIFY); PRINT_XCB_EVENT(XCB_DESTROY_NOTIFY); @@ -685,6 +692,8 @@ void printXcbEvent(const char *message, xcb_generic_event_t *event) PRINT_XCB_EVENT(XCB_SELECTION_NOTIFY); PRINT_XCB_EVENT(XCB_COLORMAP_NOTIFY); PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE); + PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY); + PRINT_XCB_EVENT(XCB_GE_GENERIC); default: qDebug("QXcbConnection: %s: unknown event - response_type: %d - sequence: %d", message, int(event->response_type & ~0x80), int(event->sequence)); } @@ -1080,7 +1089,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent); break; #if defined(XCB_USE_XINPUT2) - case GenericEvent: + case XCB_GE_GENERIC: if (m_xi2Enabled) xi2HandleEvent(reinterpret_cast(event)); break; -- cgit v1.2.3 From 2314286883dd7d31db05115ced82d6916499d933 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 25 Mar 2015 11:36:29 +0100 Subject: evdevtouch: Add hotplug support Follow the exact same structure as evdevmouse and keyboard. We must do monitoring via device discovery just like we do for keyboards and mice. Otherwise the usage of touchscreens that connect via USB or can be turned on/off independently from the board becomes troublesome. Change-Id: I2de3b519e8d617b0612e5df486e481bbc09b9c8c Reviewed-by: Andy Nichols --- .../eglconvenience/qeglplatformintegration.cpp | 4 +- .../input/evdevtouch/evdevtouch.pri | 6 +- .../input/evdevtouch/qevdevtouch.cpp | 700 --------------------- .../input/evdevtouch/qevdevtouch_p.h | 98 --- .../input/evdevtouch/qevdevtouchhandler.cpp | 665 ++++++++++++++++++++ .../input/evdevtouch/qevdevtouchhandler_p.h | 99 +++ .../input/evdevtouch/qevdevtouchmanager.cpp | 122 ++++ .../input/evdevtouch/qevdevtouchmanager_p.h | 76 +++ src/plugins/generic/evdevtouch/main.cpp | 4 +- .../platforms/linuxfb/qlinuxfbintegration.cpp | 4 +- 10 files changed, 972 insertions(+), 806 deletions(-) delete mode 100644 src/platformsupport/input/evdevtouch/qevdevtouch.cpp delete mode 100644 src/platformsupport/input/evdevtouch/qevdevtouch_p.h create mode 100644 src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp create mode 100644 src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h create mode 100644 src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp create mode 100644 src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h (limited to 'src') diff --git a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp index 200ded760c..1868ff1665 100644 --- a/src/platformsupport/eglconvenience/qeglplatformintegration.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformintegration.cpp @@ -48,7 +48,7 @@ #if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) #include #include -#include +#include #endif #if !defined(QT_NO_TSLIB) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) @@ -359,7 +359,7 @@ void QEGLPlatformIntegration::createInputHandlers() new QTsLibMouseHandler(QLatin1String("TsLib"), QString() /* spec */); else #endif // QT_NO_TSLIB - new QEvdevTouchScreenHandlerThread(QString() /* spec */, this); + new QEvdevTouchManager(QLatin1String("EvdevTouch"), QString() /* spec */, this); #endif } diff --git a/src/platformsupport/input/evdevtouch/evdevtouch.pri b/src/platformsupport/input/evdevtouch/evdevtouch.pri index ffbb05d61d..c2edc13143 100644 --- a/src/platformsupport/input/evdevtouch/evdevtouch.pri +++ b/src/platformsupport/input/evdevtouch/evdevtouch.pri @@ -1,8 +1,10 @@ HEADERS += \ - $$PWD/qevdevtouch_p.h + $$PWD/qevdevtouchhandler_p.h \ + $$PWD/qevdevtouchmanager_p.h SOURCES += \ - $$PWD/qevdevtouch.cpp + $$PWD/qevdevtouchhandler.cpp \ + $$PWD/qevdevtouchmanager.cpp contains(QT_CONFIG, libudev) { LIBS_PRIVATE += $$QMAKE_LIBS_LIBUDEV diff --git a/src/platformsupport/input/evdevtouch/qevdevtouch.cpp b/src/platformsupport/input/evdevtouch/qevdevtouch.cpp deleted file mode 100644 index 5c28dfb082..0000000000 --- a/src/platformsupport/input/evdevtouch/qevdevtouch.cpp +++ /dev/null @@ -1,700 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qevdevtouch_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(QT_NO_MTDEV) -extern "C" { -#include -} -#endif - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(qLcEvdevTouch, "qt.qpa.input") - -/* android (and perhaps some other linux-derived stuff) don't define everything - * in linux/input.h, so we'll need to do that ourselves. - */ -#ifndef ABS_MT_TOUCH_MAJOR -#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ -#endif -#ifndef ABS_MT_POSITION_X -#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ -#endif -#ifndef ABS_MT_POSITION_Y -#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ -#endif -#ifndef ABS_MT_SLOT -#define ABS_MT_SLOT 0x2f -#endif -#ifndef ABS_CNT -#define ABS_CNT (ABS_MAX+1) -#endif -#ifndef ABS_MT_TRACKING_ID -#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ -#endif -#ifndef SYN_MT_REPORT -#define SYN_MT_REPORT 2 -#endif - -class QEvdevTouchScreenData -{ -public: - QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, const QStringList &args); - - void processInputEvent(input_event *data); - void assignIds(); - - QEvdevTouchScreenHandler *q; - int m_lastEventType; - QList m_touchPoints; - - struct Contact { - int trackingId; - int x; - int y; - int maj; - int pressure; - Qt::TouchPointState state; - QTouchEvent::TouchPoint::InfoFlags flags; - Contact() : trackingId(-1), - x(0), y(0), maj(-1), pressure(0), - state(Qt::TouchPointPressed), flags(0) { } - }; - QHash m_contacts; // The key is a tracking id for type A, slot number for type B. - QHash m_lastContacts; - Contact m_currentData; - int m_currentSlot; - - int findClosestContact(const QHash &contacts, int x, int y, int *dist); - void reportPoints(); - void registerDevice(); - void addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates); - - int hw_range_x_min; - int hw_range_x_max; - int hw_range_y_min; - int hw_range_y_max; - int hw_pressure_min; - int hw_pressure_max; - QString hw_name; - bool m_forceToActiveWindow; - QTouchDevice *m_device; - bool m_typeB; - QTransform m_rotate; - bool m_singleTouch; -}; - -QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, const QStringList &args) - : q(q_ptr), - m_lastEventType(-1), - m_currentSlot(0), - hw_range_x_min(0), hw_range_x_max(0), - hw_range_y_min(0), hw_range_y_max(0), - hw_pressure_min(0), hw_pressure_max(0), - m_device(0), m_typeB(false), m_singleTouch(false) -{ - m_forceToActiveWindow = args.contains(QLatin1String("force_window")); -} - -void QEvdevTouchScreenData::registerDevice() -{ - m_device = new QTouchDevice; - m_device->setName(hw_name); - m_device->setType(QTouchDevice::TouchScreen); - m_device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area); - if (hw_pressure_max > hw_pressure_min) - m_device->setCapabilities(m_device->capabilities() | QTouchDevice::Pressure); - - QWindowSystemInterface::registerTouchDevice(m_device); - - // No monitoring of added/removed devices is done here, so for now just - // increase the number of touch devices. - QInputDeviceManager *imgr = QGuiApplicationPrivate::inputDeviceManager(); - QInputDeviceManagerPrivate::get(imgr)->setDeviceCount(QInputDeviceManager::DeviceTypeTouch, - imgr->deviceCount(QInputDeviceManager::DeviceTypeTouch) + 1); -} - -#define LONG_BITS (sizeof(long) << 3) -#define NUM_LONGS(bits) (((bits) + LONG_BITS - 1) / LONG_BITS) - -#if defined(QT_NO_MTDEV) -static inline bool testBit(long bit, const long *array) -{ - return (array[bit / LONG_BITS] >> bit % LONG_BITS) & 1; -} -#endif - -QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &specification, QObject *parent) - : QObject(parent), m_notify(0), m_fd(-1), d(0) -#if !defined(QT_NO_MTDEV) - , m_mtdev(0) -#endif -{ - setObjectName(QLatin1String("Evdev Touch Handler")); - - if (qEnvironmentVariableIsSet("QT_QPA_EVDEV_DEBUG")) - const_cast(qLcEvdevTouch()).setEnabled(QtDebugMsg, true); - - // only the first device argument is used for now - QString spec = QString::fromLocal8Bit(qgetenv("QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS")); - - if (spec.isEmpty()) - spec = specification; - - QStringList args = spec.split(QLatin1Char(':')); - - QString dev; - int rotationAngle = 0; - bool invertx = false; - bool inverty = false; - for (int i = 0; i < args.count(); ++i) { - if (args.at(i).startsWith(QLatin1String("/dev/")) && dev.isEmpty()) { - dev = args.at(i); - } else if (args.at(i).startsWith(QLatin1String("rotate"))) { - QString rotateArg = args.at(i).section(QLatin1Char('='), 1, 1); - bool ok; - uint argValue = rotateArg.toUInt(&ok); - if (ok) { - switch (argValue) { - case 90: - case 180: - case 270: - rotationAngle = argValue; - default: - break; - } - } - } else if (args.at(i) == QLatin1String("invertx")) { - invertx = true; - } else if (args.at(i) == QLatin1String("inverty")) { - inverty = true; - } - } - - if (dev.isEmpty()) { - // try to let udev scan for already connected devices - QScopedPointer deviceDiscovery(QDeviceDiscovery::create(QDeviceDiscovery::Device_Touchpad | QDeviceDiscovery::Device_Touchscreen, this)); - if (deviceDiscovery) { - QStringList devices = deviceDiscovery->scanConnectedDevices(); - - // only the first device found is used for now - if (devices.size() > 0) - dev = devices[0]; - } - } - - if (dev.isEmpty()) { - qCDebug(qLcEvdevTouch, "evdevtouch: No touch devices found"); - return; - } - - qCDebug(qLcEvdevTouch, "evdevtouch: Using device %s", qPrintable(dev)); - - m_fd = QT_OPEN(dev.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); - - if (m_fd >= 0) { - m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); - connect(m_notify, SIGNAL(activated(int)), this, SLOT(readData())); - } else { - qErrnoWarning(errno, "evdevtouch: Cannot open input device %s", qPrintable(dev)); - return; - } - -#if !defined(QT_NO_MTDEV) - m_mtdev = static_cast(calloc(1, sizeof(mtdev))); - int mtdeverr = mtdev_open(m_mtdev, m_fd); - if (mtdeverr) { - qWarning("evdevtouch: mtdev_open failed: %d", mtdeverr); - QT_CLOSE(m_fd); - return; - } -#endif - - d = new QEvdevTouchScreenData(this, args); - -#if !defined(QT_NO_MTDEV) - const char *mtdevStr = "(mtdev)"; - d->m_typeB = true; -#else - const char *mtdevStr = ""; - long absbits[NUM_LONGS(ABS_CNT)]; - if (ioctl(m_fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits) >= 0) { - d->m_typeB = testBit(ABS_MT_SLOT, absbits); - d->m_singleTouch = !testBit(ABS_MT_POSITION_X, absbits); - } -#endif - - qCDebug(qLcEvdevTouch, "evdevtouch: Protocol type %c %s (%s)", d->m_typeB ? 'B' : 'A', - mtdevStr, d->m_singleTouch ? "single" : "multi"); - - input_absinfo absInfo; - memset(&absInfo, 0, sizeof(input_absinfo)); - bool has_x_range = false, has_y_range = false; - - if (ioctl(m_fd, EVIOCGABS((d->m_singleTouch ? ABS_X : ABS_MT_POSITION_X)), &absInfo) >= 0) { - qCDebug(qLcEvdevTouch, "evdevtouch: min X: %d max X: %d", absInfo.minimum, absInfo.maximum); - d->hw_range_x_min = absInfo.minimum; - d->hw_range_x_max = absInfo.maximum; - has_x_range = true; - } - - if (ioctl(m_fd, EVIOCGABS((d->m_singleTouch ? ABS_Y : ABS_MT_POSITION_Y)), &absInfo) >= 0) { - qCDebug(qLcEvdevTouch, "evdevtouch: min Y: %d max Y: %d", absInfo.minimum, absInfo.maximum); - d->hw_range_y_min = absInfo.minimum; - d->hw_range_y_max = absInfo.maximum; - has_y_range = true; - } - - if (!has_x_range || !has_y_range) - qWarning("evdevtouch: Invalid ABS limits, behavior unspecified"); - - if (ioctl(m_fd, EVIOCGABS(ABS_PRESSURE), &absInfo) >= 0) { - qCDebug(qLcEvdevTouch, "evdevtouch: min pressure: %d max pressure: %d", absInfo.minimum, absInfo.maximum); - if (absInfo.maximum > absInfo.minimum) { - d->hw_pressure_min = absInfo.minimum; - d->hw_pressure_max = absInfo.maximum; - } - } - - char name[1024]; - if (ioctl(m_fd, EVIOCGNAME(sizeof(name) - 1), name) >= 0) { - d->hw_name = QString::fromLocal8Bit(name); - qCDebug(qLcEvdevTouch, "evdevtouch: device name: %s", name); - } - - // Fix up the coordinate ranges for am335x in case the kernel driver does not have them fixed. - if (d->hw_name == QLatin1String("ti-tsc")) { - if (d->hw_range_x_min == 0 && d->hw_range_x_max == 4095) { - d->hw_range_x_min = 165; - d->hw_range_x_max = 4016; - } - if (d->hw_range_y_min == 0 && d->hw_range_y_max == 4095) { - d->hw_range_y_min = 220; - d->hw_range_y_max = 3907; - } - qCDebug(qLcEvdevTouch, "evdevtouch: found ti-tsc, overriding: min X: %d max X: %d min Y: %d max Y: %d", - d->hw_range_x_min, d->hw_range_x_max, d->hw_range_y_min, d->hw_range_y_max); - } - - bool grabSuccess = !ioctl(m_fd, EVIOCGRAB, (void *) 1); - if (grabSuccess) - ioctl(m_fd, EVIOCGRAB, (void *) 0); - else - qWarning("evdevtouch: The device is grabbed by another process. No events will be read."); - - if (rotationAngle) - d->m_rotate = QTransform::fromTranslate(0.5, 0.5).rotate(rotationAngle).translate(-0.5, -0.5); - - if (invertx) - d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(-1.0, 1.0).translate(-0.5, -0.5); - - if (inverty) - d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(1.0, -1.0).translate(-0.5, -0.5); - - d->registerDevice(); -} - -QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() -{ -#if !defined(QT_NO_MTDEV) - if (m_mtdev) { - mtdev_close(m_mtdev); - free(m_mtdev); - } -#endif - - if (m_fd >= 0) - QT_CLOSE(m_fd); - - delete d; -} - -void QEvdevTouchScreenHandler::readData() -{ - ::input_event buffer[32]; - int events = 0; - -#if !defined(QT_NO_MTDEV) - forever { - do { - events = mtdev_get(m_mtdev, m_fd, buffer, sizeof(buffer) / sizeof(::input_event)); - // keep trying mtdev_get if we get interrupted. note that we do not - // (and should not) handle EAGAIN; EAGAIN means that reading would - // block and we'll get back here later to try again anyway. - } while (events == -1 && errno == EINTR); - - // 0 events is EOF, -1 means error, handle both in the same place - if (events <= 0) - goto err; - - // process our shiny new events - for (int i = 0; i < events; ++i) - d->processInputEvent(&buffer[i]); - - // and try to get more - } -#else - int n = 0; - for (; ;) { - events = QT_READ(m_fd, reinterpret_cast(buffer) + n, sizeof(buffer) - n); - if (events <= 0) - goto err; - n += events; - if (n % sizeof(::input_event) == 0) - break; - } - - n /= sizeof(::input_event); - - for (int i = 0; i < n; ++i) - d->processInputEvent(&buffer[i]); -#endif - return; - -err: - if (!events) { - qWarning("evdevtouch: Got EOF from input device"); - return; - } else if (events < 0) { - if (errno != EINTR && errno != EAGAIN) { - qErrnoWarning(errno, "evdevtouch: Could not read from input device"); - if (errno == ENODEV) { // device got disconnected -> stop reading - delete m_notify; - m_notify = 0; - QT_CLOSE(m_fd); - m_fd = -1; - } - return; - } - } -} - -void QEvdevTouchScreenData::addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates) -{ - QWindowSystemInterface::TouchPoint tp; - tp.id = contact.trackingId; - tp.flags = contact.flags; - tp.state = contact.state; - *combinedStates |= tp.state; - - // Store the HW coordinates for now, will be updated later. - tp.area = QRectF(0, 0, contact.maj, contact.maj); - tp.area.moveCenter(QPoint(contact.x, contact.y)); - tp.pressure = contact.pressure; - - // Get a normalized position in range 0..1. - tp.normalPosition = QPointF((contact.x - hw_range_x_min) / qreal(hw_range_x_max - hw_range_x_min), - (contact.y - hw_range_y_min) / qreal(hw_range_y_max - hw_range_y_min)); - - if (!m_rotate.isIdentity()) - tp.normalPosition = m_rotate.map(tp.normalPosition); - - tp.rawPositions.append(QPointF(contact.x, contact.y)); - - m_touchPoints.append(tp); -} - -void QEvdevTouchScreenData::processInputEvent(input_event *data) -{ - if (data->type == EV_ABS) { - - if (data->code == ABS_MT_POSITION_X || (m_singleTouch && data->code == ABS_X)) { - m_currentData.x = qBound(hw_range_x_min, data->value, hw_range_x_max); - if (m_singleTouch) - m_contacts[m_currentSlot].x = m_currentData.x; - if (m_typeB) { - m_contacts[m_currentSlot].x = m_currentData.x; - if (m_contacts[m_currentSlot].state == Qt::TouchPointStationary) - m_contacts[m_currentSlot].state = Qt::TouchPointMoved; - } - } else if (data->code == ABS_MT_POSITION_Y || (m_singleTouch && data->code == ABS_Y)) { - m_currentData.y = qBound(hw_range_y_min, data->value, hw_range_y_max); - if (m_singleTouch) - m_contacts[m_currentSlot].y = m_currentData.y; - if (m_typeB) { - m_contacts[m_currentSlot].y = m_currentData.y; - if (m_contacts[m_currentSlot].state == Qt::TouchPointStationary) - m_contacts[m_currentSlot].state = Qt::TouchPointMoved; - } - } else if (data->code == ABS_MT_TRACKING_ID) { - m_currentData.trackingId = data->value; - if (m_typeB) { - if (m_currentData.trackingId == -1) { - m_contacts[m_currentSlot].state = Qt::TouchPointReleased; - } else { - m_contacts[m_currentSlot].state = Qt::TouchPointPressed; - m_contacts[m_currentSlot].trackingId = m_currentData.trackingId; - } - } - } else if (data->code == ABS_MT_TOUCH_MAJOR) { - m_currentData.maj = data->value; - if (data->value == 0) - m_currentData.state = Qt::TouchPointReleased; - if (m_typeB) - m_contacts[m_currentSlot].maj = m_currentData.maj; - } else if (data->code == ABS_PRESSURE) { - m_currentData.pressure = qBound(hw_pressure_min, data->value, hw_pressure_max); - if (m_typeB || m_singleTouch) - m_contacts[m_currentSlot].pressure = m_currentData.pressure; - } else if (data->code == ABS_MT_SLOT) { - m_currentSlot = data->value; - } - - } else if (data->type == EV_KEY && !m_typeB) { - if (data->code == BTN_TOUCH && data->value == 0) - m_contacts[m_currentSlot].state = Qt::TouchPointReleased; - } else if (data->type == EV_SYN && data->code == SYN_MT_REPORT && m_lastEventType != EV_SYN) { - - // If there is no tracking id, one will be generated later. - // Until that use a temporary key. - int key = m_currentData.trackingId; - if (key == -1) - key = m_contacts.count(); - - m_contacts.insert(key, m_currentData); - m_currentData = Contact(); - - } else if (data->type == EV_SYN && data->code == SYN_REPORT) { - - // Ensure valid IDs even when the driver does not report ABS_MT_TRACKING_ID. - if (!m_contacts.isEmpty() && m_contacts.constBegin().value().trackingId == -1) - assignIds(); - - m_touchPoints.clear(); - Qt::TouchPointStates combinedStates; - - QMutableHashIterator it(m_contacts); - while (it.hasNext()) { - it.next(); - Contact &contact(it.value()); - - if (!contact.state) - continue; - - int key = m_typeB ? it.key() : contact.trackingId; - if (!m_typeB && m_lastContacts.contains(key)) { - const Contact &prev(m_lastContacts.value(key)); - if (contact.state == Qt::TouchPointReleased) { - // Copy over the previous values for released points, just in case. - contact.x = prev.x; - contact.y = prev.y; - contact.maj = prev.maj; - } else { - contact.state = (prev.x == contact.x && prev.y == contact.y) - ? Qt::TouchPointStationary : Qt::TouchPointMoved; - } - } - - // Avoid reporting a contact in released state more than once. - if (!m_typeB && contact.state == Qt::TouchPointReleased - && !m_lastContacts.contains(key)) { - it.remove(); - continue; - } - - addTouchPoint(contact, &combinedStates); - } - - // Now look for contacts that have disappeared since the last sync. - it = m_lastContacts; - while (it.hasNext()) { - it.next(); - Contact &contact(it.value()); - int key = m_typeB ? it.key() : contact.trackingId; - if (!m_contacts.contains(key)) { - contact.state = Qt::TouchPointReleased; - addTouchPoint(contact, &combinedStates); - } - } - - // Remove contacts that have just been reported as released. - it = m_contacts; - while (it.hasNext()) { - it.next(); - Contact &contact(it.value()); - - if (!contact.state) - continue; - - if (contact.state == Qt::TouchPointReleased) { - if (m_typeB) - contact.state = static_cast(0); - else - it.remove(); - } else { - contact.state = Qt::TouchPointStationary; - } - } - - m_lastContacts = m_contacts; - if (!m_typeB && !m_singleTouch) - m_contacts.clear(); - - if (!m_touchPoints.isEmpty() && combinedStates != Qt::TouchPointStationary) - reportPoints(); - } - - m_lastEventType = data->type; -} - -int QEvdevTouchScreenData::findClosestContact(const QHash &contacts, int x, int y, int *dist) -{ - int minDist = -1, id = -1; - for (QHash::const_iterator it = contacts.constBegin(), ite = contacts.constEnd(); - it != ite; ++it) { - const Contact &contact(it.value()); - int dx = x - contact.x; - int dy = y - contact.y; - int dist = dx * dx + dy * dy; - if (minDist == -1 || dist < minDist) { - minDist = dist; - id = contact.trackingId; - } - } - if (dist) - *dist = minDist; - return id; -} - -void QEvdevTouchScreenData::assignIds() -{ - QHash candidates = m_lastContacts, pending = m_contacts, newContacts; - int maxId = -1; - QHash::iterator it, ite, bestMatch; - while (!pending.isEmpty() && !candidates.isEmpty()) { - int bestDist = -1, bestId = 0; - for (it = pending.begin(), ite = pending.end(); it != ite; ++it) { - int dist; - int id = findClosestContact(candidates, it->x, it->y, &dist); - if (id >= 0 && (bestDist == -1 || dist < bestDist)) { - bestDist = dist; - bestId = id; - bestMatch = it; - } - } - if (bestDist >= 0) { - bestMatch->trackingId = bestId; - newContacts.insert(bestId, *bestMatch); - candidates.remove(bestId); - pending.erase(bestMatch); - if (bestId > maxId) - maxId = bestId; - } - } - if (candidates.isEmpty()) { - for (it = pending.begin(), ite = pending.end(); it != ite; ++it) { - it->trackingId = ++maxId; - newContacts.insert(it->trackingId, *it); - } - } - m_contacts = newContacts; -} - -void QEvdevTouchScreenData::reportPoints() -{ - QRect winRect; - if (m_forceToActiveWindow) { - QWindow *win = QGuiApplication::focusWindow(); - if (!win) - return; - winRect = win->geometry(); - } else { - winRect = QGuiApplication::primaryScreen()->geometry(); - } - - const int hw_w = hw_range_x_max - hw_range_x_min; - const int hw_h = hw_range_y_max - hw_range_y_min; - - // Map the coordinates based on the normalized position. QPA expects 'area' - // to be in screen coordinates. - const int pointCount = m_touchPoints.count(); - for (int i = 0; i < pointCount; ++i) { - QWindowSystemInterface::TouchPoint &tp(m_touchPoints[i]); - - // Generate a screen position that is always inside the active window - // or the primary screen. Even though we report this as a QRectF, internally - // Qt uses QRect/QPoint so we need to bound the size to winRect.size() - QSize(1, 1) - const qreal wx = winRect.left() + tp.normalPosition.x() * (winRect.width() - 1); - const qreal wy = winRect.top() + tp.normalPosition.y() * (winRect.height() - 1); - const qreal sizeRatio = (winRect.width() + winRect.height()) / qreal(hw_w + hw_h); - if (tp.area.width() == -1) // touch major was not provided - tp.area = QRectF(0, 0, 8, 8); - else - tp.area = QRectF(0, 0, tp.area.width() * sizeRatio, tp.area.height() * sizeRatio); - tp.area.moveCenter(QPointF(wx, wy)); - - // Calculate normalized pressure. - if (!hw_pressure_min && !hw_pressure_max) - tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1; - else - tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min); - } - - QWindowSystemInterface::handleTouchEvent(0, m_device, m_touchPoints); -} - - -QEvdevTouchScreenHandlerThread::QEvdevTouchScreenHandlerThread(const QString &spec, QObject *parent) - : QThread(parent), m_spec(spec), m_handler(0) -{ - start(); -} - -QEvdevTouchScreenHandlerThread::~QEvdevTouchScreenHandlerThread() -{ - quit(); - wait(); -} - -void QEvdevTouchScreenHandlerThread::run() -{ - m_handler = new QEvdevTouchScreenHandler(m_spec); - exec(); - delete m_handler; - m_handler = 0; -} - - -QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouch_p.h b/src/platformsupport/input/evdevtouch/qevdevtouch_p.h deleted file mode 100644 index eca1bf465c..0000000000 --- a/src/platformsupport/input/evdevtouch/qevdevtouch_p.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEVDEVTOUCH_P_H -#define QEVDEVTOUCH_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include -#include - -#if !defined(QT_NO_MTDEV) -struct mtdev; -#endif - -QT_BEGIN_NAMESPACE - -class QSocketNotifier; -class QEvdevTouchScreenData; - -class QEvdevTouchScreenHandler : public QObject -{ - Q_OBJECT - -public: - explicit QEvdevTouchScreenHandler(const QString &specification = QString(), QObject *parent = 0); - ~QEvdevTouchScreenHandler(); - -private slots: - void readData(); - -private: - QSocketNotifier *m_notify; - int m_fd; - QEvdevTouchScreenData *d; -#if !defined(QT_NO_MTDEV) - mtdev *m_mtdev; -#endif -}; - -class QEvdevTouchScreenHandlerThread : public QThread -{ -public: - explicit QEvdevTouchScreenHandlerThread(const QString &spec, QObject *parent = 0); - ~QEvdevTouchScreenHandlerThread(); - void run() Q_DECL_OVERRIDE; - QEvdevTouchScreenHandler *handler() { return m_handler; } - -private: - QString m_spec; - QEvdevTouchScreenHandler *m_handler; -}; - -QT_END_NAMESPACE - -#endif // QEVDEVTOUCH_P_H diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp new file mode 100644 index 0000000000..885326e512 --- /dev/null +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -0,0 +1,665 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qevdevtouchhandler_p.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(QT_NO_MTDEV) +extern "C" { +#include +} +#endif + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(qLcEvdevTouch, "qt.qpa.input") + +/* android (and perhaps some other linux-derived stuff) don't define everything + * in linux/input.h, so we'll need to do that ourselves. + */ +#ifndef ABS_MT_TOUCH_MAJOR +#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ +#endif +#ifndef ABS_MT_POSITION_X +#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ +#endif +#ifndef ABS_MT_POSITION_Y +#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ +#endif +#ifndef ABS_MT_SLOT +#define ABS_MT_SLOT 0x2f +#endif +#ifndef ABS_CNT +#define ABS_CNT (ABS_MAX+1) +#endif +#ifndef ABS_MT_TRACKING_ID +#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ +#endif +#ifndef SYN_MT_REPORT +#define SYN_MT_REPORT 2 +#endif + +class QEvdevTouchScreenData +{ +public: + QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, const QStringList &args); + + void processInputEvent(input_event *data); + void assignIds(); + + QEvdevTouchScreenHandler *q; + int m_lastEventType; + QList m_touchPoints; + + struct Contact { + int trackingId; + int x; + int y; + int maj; + int pressure; + Qt::TouchPointState state; + QTouchEvent::TouchPoint::InfoFlags flags; + Contact() : trackingId(-1), + x(0), y(0), maj(-1), pressure(0), + state(Qt::TouchPointPressed), flags(0) { } + }; + QHash m_contacts; // The key is a tracking id for type A, slot number for type B. + QHash m_lastContacts; + Contact m_currentData; + int m_currentSlot; + + int findClosestContact(const QHash &contacts, int x, int y, int *dist); + void reportPoints(); + void registerDevice(); + void addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates); + + int hw_range_x_min; + int hw_range_x_max; + int hw_range_y_min; + int hw_range_y_max; + int hw_pressure_min; + int hw_pressure_max; + QString hw_name; + bool m_forceToActiveWindow; + QTouchDevice *m_device; + bool m_typeB; + QTransform m_rotate; + bool m_singleTouch; +}; + +QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, const QStringList &args) + : q(q_ptr), + m_lastEventType(-1), + m_currentSlot(0), + hw_range_x_min(0), hw_range_x_max(0), + hw_range_y_min(0), hw_range_y_max(0), + hw_pressure_min(0), hw_pressure_max(0), + m_device(0), m_typeB(false), m_singleTouch(false) +{ + m_forceToActiveWindow = args.contains(QLatin1String("force_window")); +} + +void QEvdevTouchScreenData::registerDevice() +{ + m_device = new QTouchDevice; + m_device->setName(hw_name); + m_device->setType(QTouchDevice::TouchScreen); + m_device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area); + if (hw_pressure_max > hw_pressure_min) + m_device->setCapabilities(m_device->capabilities() | QTouchDevice::Pressure); + + QWindowSystemInterface::registerTouchDevice(m_device); +} + +#define LONG_BITS (sizeof(long) << 3) +#define NUM_LONGS(bits) (((bits) + LONG_BITS - 1) / LONG_BITS) + +#if defined(QT_NO_MTDEV) +static inline bool testBit(long bit, const long *array) +{ + return (array[bit / LONG_BITS] >> bit % LONG_BITS) & 1; +} +#endif + +QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const QString &spec, QObject *parent) + : QObject(parent), m_notify(0), m_fd(-1), d(0) +#if !defined(QT_NO_MTDEV) + , m_mtdev(0) +#endif +{ + setObjectName(QLatin1String("Evdev Touch Handler")); + + const QStringList args = spec.split(QLatin1Char(':')); + int rotationAngle = 0; + bool invertx = false; + bool inverty = false; + for (int i = 0; i < args.count(); ++i) { + if (args.at(i).startsWith(QLatin1String("rotate"))) { + QString rotateArg = args.at(i).section(QLatin1Char('='), 1, 1); + bool ok; + uint argValue = rotateArg.toUInt(&ok); + if (ok) { + switch (argValue) { + case 90: + case 180: + case 270: + rotationAngle = argValue; + default: + break; + } + } + } else if (args.at(i) == QLatin1String("invertx")) { + invertx = true; + } else if (args.at(i) == QLatin1String("inverty")) { + inverty = true; + } + } + + qCDebug(qLcEvdevTouch, "evdevtouch: Using device %s", qPrintable(device)); + + m_fd = QT_OPEN(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); + + if (m_fd >= 0) { + m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); + connect(m_notify, SIGNAL(activated(int)), this, SLOT(readData())); + } else { + qErrnoWarning(errno, "evdevtouch: Cannot open input device %s", qPrintable(device)); + return; + } + +#if !defined(QT_NO_MTDEV) + m_mtdev = static_cast(calloc(1, sizeof(mtdev))); + int mtdeverr = mtdev_open(m_mtdev, m_fd); + if (mtdeverr) { + qWarning("evdevtouch: mtdev_open failed: %d", mtdeverr); + QT_CLOSE(m_fd); + return; + } +#endif + + d = new QEvdevTouchScreenData(this, args); + +#if !defined(QT_NO_MTDEV) + const char *mtdevStr = "(mtdev)"; + d->m_typeB = true; +#else + const char *mtdevStr = ""; + long absbits[NUM_LONGS(ABS_CNT)]; + if (ioctl(m_fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits) >= 0) { + d->m_typeB = testBit(ABS_MT_SLOT, absbits); + d->m_singleTouch = !testBit(ABS_MT_POSITION_X, absbits); + } +#endif + + qCDebug(qLcEvdevTouch, "evdevtouch: %s: Protocol type %c %s (%s)", qPrintable(device), + d->m_typeB ? 'B' : 'A', mtdevStr, d->m_singleTouch ? "single" : "multi"); + + input_absinfo absInfo; + memset(&absInfo, 0, sizeof(input_absinfo)); + bool has_x_range = false, has_y_range = false; + + if (ioctl(m_fd, EVIOCGABS((d->m_singleTouch ? ABS_X : ABS_MT_POSITION_X)), &absInfo) >= 0) { + qCDebug(qLcEvdevTouch, "evdevtouch: %s: min X: %d max X: %d", qPrintable(device), + absInfo.minimum, absInfo.maximum); + d->hw_range_x_min = absInfo.minimum; + d->hw_range_x_max = absInfo.maximum; + has_x_range = true; + } + + if (ioctl(m_fd, EVIOCGABS((d->m_singleTouch ? ABS_Y : ABS_MT_POSITION_Y)), &absInfo) >= 0) { + qCDebug(qLcEvdevTouch, "evdevtouch: %s: min Y: %d max Y: %d", qPrintable(device), + absInfo.minimum, absInfo.maximum); + d->hw_range_y_min = absInfo.minimum; + d->hw_range_y_max = absInfo.maximum; + has_y_range = true; + } + + if (!has_x_range || !has_y_range) + qWarning("evdevtouch: %s: Invalid ABS limits, behavior unspecified", qPrintable(device)); + + if (ioctl(m_fd, EVIOCGABS(ABS_PRESSURE), &absInfo) >= 0) { + qCDebug(qLcEvdevTouch, "evdevtouch: %s: min pressure: %d max pressure: %d", qPrintable(device), + absInfo.minimum, absInfo.maximum); + if (absInfo.maximum > absInfo.minimum) { + d->hw_pressure_min = absInfo.minimum; + d->hw_pressure_max = absInfo.maximum; + } + } + + char name[1024]; + if (ioctl(m_fd, EVIOCGNAME(sizeof(name) - 1), name) >= 0) { + d->hw_name = QString::fromLocal8Bit(name); + qCDebug(qLcEvdevTouch, "evdevtouch: %s: device name: %s", qPrintable(device), name); + } + + // Fix up the coordinate ranges for am335x in case the kernel driver does not have them fixed. + if (d->hw_name == QLatin1String("ti-tsc")) { + if (d->hw_range_x_min == 0 && d->hw_range_x_max == 4095) { + d->hw_range_x_min = 165; + d->hw_range_x_max = 4016; + } + if (d->hw_range_y_min == 0 && d->hw_range_y_max == 4095) { + d->hw_range_y_min = 220; + d->hw_range_y_max = 3907; + } + qCDebug(qLcEvdevTouch, "evdevtouch: found ti-tsc, overriding: min X: %d max X: %d min Y: %d max Y: %d", + d->hw_range_x_min, d->hw_range_x_max, d->hw_range_y_min, d->hw_range_y_max); + } + + bool grabSuccess = !ioctl(m_fd, EVIOCGRAB, (void *) 1); + if (grabSuccess) + ioctl(m_fd, EVIOCGRAB, (void *) 0); + else + qWarning("evdevtouch: The device is grabbed by another process. No events will be read."); + + if (rotationAngle) + d->m_rotate = QTransform::fromTranslate(0.5, 0.5).rotate(rotationAngle).translate(-0.5, -0.5); + + if (invertx) + d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(-1.0, 1.0).translate(-0.5, -0.5); + + if (inverty) + d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(1.0, -1.0).translate(-0.5, -0.5); + + d->registerDevice(); +} + +QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() +{ +#if !defined(QT_NO_MTDEV) + if (m_mtdev) { + mtdev_close(m_mtdev); + free(m_mtdev); + } +#endif + + if (m_fd >= 0) + QT_CLOSE(m_fd); + + delete d; +} + +void QEvdevTouchScreenHandler::readData() +{ + ::input_event buffer[32]; + int events = 0; + +#if !defined(QT_NO_MTDEV) + forever { + do { + events = mtdev_get(m_mtdev, m_fd, buffer, sizeof(buffer) / sizeof(::input_event)); + // keep trying mtdev_get if we get interrupted. note that we do not + // (and should not) handle EAGAIN; EAGAIN means that reading would + // block and we'll get back here later to try again anyway. + } while (events == -1 && errno == EINTR); + + // 0 events is EOF, -1 means error, handle both in the same place + if (events <= 0) + goto err; + + // process our shiny new events + for (int i = 0; i < events; ++i) + d->processInputEvent(&buffer[i]); + + // and try to get more + } +#else + int n = 0; + for (; ;) { + events = QT_READ(m_fd, reinterpret_cast(buffer) + n, sizeof(buffer) - n); + if (events <= 0) + goto err; + n += events; + if (n % sizeof(::input_event) == 0) + break; + } + + n /= sizeof(::input_event); + + for (int i = 0; i < n; ++i) + d->processInputEvent(&buffer[i]); +#endif + return; + +err: + if (!events) { + qWarning("evdevtouch: Got EOF from input device"); + return; + } else if (events < 0) { + if (errno != EINTR && errno != EAGAIN) { + qErrnoWarning(errno, "evdevtouch: Could not read from input device"); + if (errno == ENODEV) { // device got disconnected -> stop reading + delete m_notify; + m_notify = 0; + QT_CLOSE(m_fd); + m_fd = -1; + } + return; + } + } +} + +void QEvdevTouchScreenData::addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates) +{ + QWindowSystemInterface::TouchPoint tp; + tp.id = contact.trackingId; + tp.flags = contact.flags; + tp.state = contact.state; + *combinedStates |= tp.state; + + // Store the HW coordinates for now, will be updated later. + tp.area = QRectF(0, 0, contact.maj, contact.maj); + tp.area.moveCenter(QPoint(contact.x, contact.y)); + tp.pressure = contact.pressure; + + // Get a normalized position in range 0..1. + tp.normalPosition = QPointF((contact.x - hw_range_x_min) / qreal(hw_range_x_max - hw_range_x_min), + (contact.y - hw_range_y_min) / qreal(hw_range_y_max - hw_range_y_min)); + + if (!m_rotate.isIdentity()) + tp.normalPosition = m_rotate.map(tp.normalPosition); + + tp.rawPositions.append(QPointF(contact.x, contact.y)); + + m_touchPoints.append(tp); +} + +void QEvdevTouchScreenData::processInputEvent(input_event *data) +{ + if (data->type == EV_ABS) { + + if (data->code == ABS_MT_POSITION_X || (m_singleTouch && data->code == ABS_X)) { + m_currentData.x = qBound(hw_range_x_min, data->value, hw_range_x_max); + if (m_singleTouch) + m_contacts[m_currentSlot].x = m_currentData.x; + if (m_typeB) { + m_contacts[m_currentSlot].x = m_currentData.x; + if (m_contacts[m_currentSlot].state == Qt::TouchPointStationary) + m_contacts[m_currentSlot].state = Qt::TouchPointMoved; + } + } else if (data->code == ABS_MT_POSITION_Y || (m_singleTouch && data->code == ABS_Y)) { + m_currentData.y = qBound(hw_range_y_min, data->value, hw_range_y_max); + if (m_singleTouch) + m_contacts[m_currentSlot].y = m_currentData.y; + if (m_typeB) { + m_contacts[m_currentSlot].y = m_currentData.y; + if (m_contacts[m_currentSlot].state == Qt::TouchPointStationary) + m_contacts[m_currentSlot].state = Qt::TouchPointMoved; + } + } else if (data->code == ABS_MT_TRACKING_ID) { + m_currentData.trackingId = data->value; + if (m_typeB) { + if (m_currentData.trackingId == -1) { + m_contacts[m_currentSlot].state = Qt::TouchPointReleased; + } else { + m_contacts[m_currentSlot].state = Qt::TouchPointPressed; + m_contacts[m_currentSlot].trackingId = m_currentData.trackingId; + } + } + } else if (data->code == ABS_MT_TOUCH_MAJOR) { + m_currentData.maj = data->value; + if (data->value == 0) + m_currentData.state = Qt::TouchPointReleased; + if (m_typeB) + m_contacts[m_currentSlot].maj = m_currentData.maj; + } else if (data->code == ABS_PRESSURE) { + m_currentData.pressure = qBound(hw_pressure_min, data->value, hw_pressure_max); + if (m_typeB || m_singleTouch) + m_contacts[m_currentSlot].pressure = m_currentData.pressure; + } else if (data->code == ABS_MT_SLOT) { + m_currentSlot = data->value; + } + + } else if (data->type == EV_KEY && !m_typeB) { + if (data->code == BTN_TOUCH && data->value == 0) + m_contacts[m_currentSlot].state = Qt::TouchPointReleased; + } else if (data->type == EV_SYN && data->code == SYN_MT_REPORT && m_lastEventType != EV_SYN) { + + // If there is no tracking id, one will be generated later. + // Until that use a temporary key. + int key = m_currentData.trackingId; + if (key == -1) + key = m_contacts.count(); + + m_contacts.insert(key, m_currentData); + m_currentData = Contact(); + + } else if (data->type == EV_SYN && data->code == SYN_REPORT) { + + // Ensure valid IDs even when the driver does not report ABS_MT_TRACKING_ID. + if (!m_contacts.isEmpty() && m_contacts.constBegin().value().trackingId == -1) + assignIds(); + + m_touchPoints.clear(); + Qt::TouchPointStates combinedStates; + + QMutableHashIterator it(m_contacts); + while (it.hasNext()) { + it.next(); + Contact &contact(it.value()); + + if (!contact.state) + continue; + + int key = m_typeB ? it.key() : contact.trackingId; + if (!m_typeB && m_lastContacts.contains(key)) { + const Contact &prev(m_lastContacts.value(key)); + if (contact.state == Qt::TouchPointReleased) { + // Copy over the previous values for released points, just in case. + contact.x = prev.x; + contact.y = prev.y; + contact.maj = prev.maj; + } else { + contact.state = (prev.x == contact.x && prev.y == contact.y) + ? Qt::TouchPointStationary : Qt::TouchPointMoved; + } + } + + // Avoid reporting a contact in released state more than once. + if (!m_typeB && contact.state == Qt::TouchPointReleased + && !m_lastContacts.contains(key)) { + it.remove(); + continue; + } + + addTouchPoint(contact, &combinedStates); + } + + // Now look for contacts that have disappeared since the last sync. + it = m_lastContacts; + while (it.hasNext()) { + it.next(); + Contact &contact(it.value()); + int key = m_typeB ? it.key() : contact.trackingId; + if (!m_contacts.contains(key)) { + contact.state = Qt::TouchPointReleased; + addTouchPoint(contact, &combinedStates); + } + } + + // Remove contacts that have just been reported as released. + it = m_contacts; + while (it.hasNext()) { + it.next(); + Contact &contact(it.value()); + + if (!contact.state) + continue; + + if (contact.state == Qt::TouchPointReleased) { + if (m_typeB) + contact.state = static_cast(0); + else + it.remove(); + } else { + contact.state = Qt::TouchPointStationary; + } + } + + m_lastContacts = m_contacts; + if (!m_typeB && !m_singleTouch) + m_contacts.clear(); + + if (!m_touchPoints.isEmpty() && combinedStates != Qt::TouchPointStationary) + reportPoints(); + } + + m_lastEventType = data->type; +} + +int QEvdevTouchScreenData::findClosestContact(const QHash &contacts, int x, int y, int *dist) +{ + int minDist = -1, id = -1; + for (QHash::const_iterator it = contacts.constBegin(), ite = contacts.constEnd(); + it != ite; ++it) { + const Contact &contact(it.value()); + int dx = x - contact.x; + int dy = y - contact.y; + int dist = dx * dx + dy * dy; + if (minDist == -1 || dist < minDist) { + minDist = dist; + id = contact.trackingId; + } + } + if (dist) + *dist = minDist; + return id; +} + +void QEvdevTouchScreenData::assignIds() +{ + QHash candidates = m_lastContacts, pending = m_contacts, newContacts; + int maxId = -1; + QHash::iterator it, ite, bestMatch; + while (!pending.isEmpty() && !candidates.isEmpty()) { + int bestDist = -1, bestId = 0; + for (it = pending.begin(), ite = pending.end(); it != ite; ++it) { + int dist; + int id = findClosestContact(candidates, it->x, it->y, &dist); + if (id >= 0 && (bestDist == -1 || dist < bestDist)) { + bestDist = dist; + bestId = id; + bestMatch = it; + } + } + if (bestDist >= 0) { + bestMatch->trackingId = bestId; + newContacts.insert(bestId, *bestMatch); + candidates.remove(bestId); + pending.erase(bestMatch); + if (bestId > maxId) + maxId = bestId; + } + } + if (candidates.isEmpty()) { + for (it = pending.begin(), ite = pending.end(); it != ite; ++it) { + it->trackingId = ++maxId; + newContacts.insert(it->trackingId, *it); + } + } + m_contacts = newContacts; +} + +void QEvdevTouchScreenData::reportPoints() +{ + QRect winRect; + if (m_forceToActiveWindow) { + QWindow *win = QGuiApplication::focusWindow(); + if (!win) + return; + winRect = win->geometry(); + } else { + winRect = QGuiApplication::primaryScreen()->geometry(); + } + + const int hw_w = hw_range_x_max - hw_range_x_min; + const int hw_h = hw_range_y_max - hw_range_y_min; + + // Map the coordinates based on the normalized position. QPA expects 'area' + // to be in screen coordinates. + const int pointCount = m_touchPoints.count(); + for (int i = 0; i < pointCount; ++i) { + QWindowSystemInterface::TouchPoint &tp(m_touchPoints[i]); + + // Generate a screen position that is always inside the active window + // or the primary screen. Even though we report this as a QRectF, internally + // Qt uses QRect/QPoint so we need to bound the size to winRect.size() - QSize(1, 1) + const qreal wx = winRect.left() + tp.normalPosition.x() * (winRect.width() - 1); + const qreal wy = winRect.top() + tp.normalPosition.y() * (winRect.height() - 1); + const qreal sizeRatio = (winRect.width() + winRect.height()) / qreal(hw_w + hw_h); + if (tp.area.width() == -1) // touch major was not provided + tp.area = QRectF(0, 0, 8, 8); + else + tp.area = QRectF(0, 0, tp.area.width() * sizeRatio, tp.area.height() * sizeRatio); + tp.area.moveCenter(QPointF(wx, wy)); + + // Calculate normalized pressure. + if (!hw_pressure_min && !hw_pressure_max) + tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1; + else + tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min); + } + + QWindowSystemInterface::handleTouchEvent(0, m_device, m_touchPoints); +} + + +QEvdevTouchScreenHandlerThread::QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent) + : QThread(parent), m_device(device), m_spec(spec), m_handler(0) +{ + start(); +} + +QEvdevTouchScreenHandlerThread::~QEvdevTouchScreenHandlerThread() +{ + quit(); + wait(); +} + +void QEvdevTouchScreenHandlerThread::run() +{ + m_handler = new QEvdevTouchScreenHandler(m_device, m_spec); + exec(); + delete m_handler; + m_handler = 0; +} + + +QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h new file mode 100644 index 0000000000..a6d3a860f5 --- /dev/null +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVDEVTOUCHHANDLER_P_H +#define QEVDEVTOUCHHANDLER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +#if !defined(QT_NO_MTDEV) +struct mtdev; +#endif + +QT_BEGIN_NAMESPACE + +class QSocketNotifier; +class QEvdevTouchScreenData; + +class QEvdevTouchScreenHandler : public QObject +{ + Q_OBJECT + +public: + explicit QEvdevTouchScreenHandler(const QString &device, const QString &spec = QString(), QObject *parent = 0); + ~QEvdevTouchScreenHandler(); + +private slots: + void readData(); + +private: + QSocketNotifier *m_notify; + int m_fd; + QEvdevTouchScreenData *d; +#if !defined(QT_NO_MTDEV) + mtdev *m_mtdev; +#endif +}; + +class QEvdevTouchScreenHandlerThread : public QThread +{ +public: + explicit QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent = 0); + ~QEvdevTouchScreenHandlerThread(); + void run() Q_DECL_OVERRIDE; + QEvdevTouchScreenHandler *handler() { return m_handler; } + +private: + QString m_device; + QString m_spec; + QEvdevTouchScreenHandler *m_handler; +}; + +QT_END_NAMESPACE + +#endif // QEVDEVTOUCH_P_H diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp new file mode 100644 index 0000000000..98fc83700c --- /dev/null +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qevdevtouchmanager_p.h" +#include "qevdevtouchhandler_p.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(qLcEvdevTouch) + +QEvdevTouchManager::QEvdevTouchManager(const QString &key, const QString &specification, QObject *parent) + : QObject(parent) +{ + Q_UNUSED(key); + + if (qEnvironmentVariableIsSet("QT_QPA_EVDEV_DEBUG")) + const_cast(qLcEvdevTouch()).setEnabled(QtDebugMsg, true); + + QString spec = QString::fromLocal8Bit(qgetenv("QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS")); + + if (spec.isEmpty()) + spec = specification; + + QStringList args = spec.split(QLatin1Char(':')); + QStringList devices; + + foreach (const QString &arg, args) { + if (arg.startsWith(QLatin1String("/dev/"))) { + devices.append(arg); + args.removeAll(arg); + } + } + + // build new specification without /dev/ elements + m_spec = args.join(QLatin1Char(':')); + + foreach (const QString &device, devices) + addDevice(device); + + // when no devices specified, use device discovery to scan and monitor + if (devices.isEmpty()) { + qCDebug(qLcEvdevTouch) << "evdevtouch: Using device discovery"; + m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_Touchpad | QDeviceDiscovery::Device_Touchscreen, this); + if (m_deviceDiscovery) { + QStringList devices = m_deviceDiscovery->scanConnectedDevices(); + foreach (const QString &device, devices) + addDevice(device); + connect(m_deviceDiscovery, SIGNAL(deviceDetected(QString)), this, SLOT(addDevice(QString))); + connect(m_deviceDiscovery, SIGNAL(deviceRemoved(QString)), this, SLOT(removeDevice(QString))); + } + } +} + +QEvdevTouchManager::~QEvdevTouchManager() +{ + qDeleteAll(m_activeDevices); +} + +void QEvdevTouchManager::addDevice(const QString &deviceNode) +{ + qCDebug(qLcEvdevTouch) << "Adding device at" << deviceNode; + QEvdevTouchScreenHandlerThread *handler; + handler = new QEvdevTouchScreenHandlerThread(deviceNode, m_spec); + if (handler) { + m_activeDevices.insert(deviceNode, handler); + QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( + QInputDeviceManager::DeviceTypeTouch, m_activeDevices.count()); + } else { + qWarning("evdevtouch: Failed to open touch device %s", qPrintable(deviceNode)); + } +} + +void QEvdevTouchManager::removeDevice(const QString &deviceNode) +{ + if (m_activeDevices.contains(deviceNode)) { + qCDebug(qLcEvdevTouch) << "Removing device at" << deviceNode; + QEvdevTouchScreenHandlerThread *handler = m_activeDevices.value(deviceNode); + m_activeDevices.remove(deviceNode); + QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( + QInputDeviceManager::DeviceTypeTouch, m_activeDevices.count()); + delete handler; + } +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h new file mode 100644 index 0000000000..bf484fd88b --- /dev/null +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVDEVTOUCHMANAGER_P_H +#define QEVDEVTOUCHMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDeviceDiscovery; +class QEvdevTouchScreenHandlerThread; + +class QEvdevTouchManager : public QObject +{ + Q_OBJECT +public: + QEvdevTouchManager(const QString &key, const QString &spec, QObject *parent = 0); + ~QEvdevTouchManager(); + +private slots: + void addDevice(const QString &deviceNode); + void removeDevice(const QString &deviceNode); + +private: + QString m_spec; + QDeviceDiscovery *m_deviceDiscovery; + QHash m_activeDevices; +}; + +QT_END_NAMESPACE + +#endif // QEVDEVTOUCHMANAGER_P_H diff --git a/src/plugins/generic/evdevtouch/main.cpp b/src/plugins/generic/evdevtouch/main.cpp index d9aebfbe4c..ef6774b0a0 100644 --- a/src/plugins/generic/evdevtouch/main.cpp +++ b/src/plugins/generic/evdevtouch/main.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ #include -#include +#include QT_BEGIN_NAMESPACE @@ -55,7 +55,7 @@ QObject* QEvdevTouchScreenPlugin::create(const QString &key, const QString &spec) { if (!key.compare(QLatin1String("EvdevTouch"), Qt::CaseInsensitive)) - return new QEvdevTouchScreenHandlerThread(spec); + return new QEvdevTouchManager(key, spec); return 0; } diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index 2c61f68e83..ccf86dafb2 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -49,7 +49,7 @@ #if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) #include #include -#include +#include #endif #if !defined(QT_NO_TSLIB) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) @@ -139,7 +139,7 @@ void QLinuxFbIntegration::createInputHandlers() new QTsLibMouseHandler(QLatin1String("TsLib"), QString()); else #endif // QT_NO_TSLIB - new QEvdevTouchScreenHandlerThread(QString(), this); + new QEvdevTouchManager(QLatin1String("EvdevTouch"), QString() /* spec */, this); #endif } -- cgit v1.2.3 From f3e405cb3b40c585cb5a535aa0562bfca74d3474 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Wed, 18 Mar 2015 16:38:12 +0100 Subject: Fix logicalDotsPerInch when using devicePixelRatio Qt does not support having different fontMetrics for different screens Also add environment variable for overriding logicalDpi Change-Id: I0baf73026d97fec590597ee304ad9fa119d7a328 Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbscreen.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 383adf9734..6f1fc08167 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -310,19 +310,16 @@ QImage::Format QXcbScreen::format() const QDpi QXcbScreen::logicalDpi() const { - int dpr = int(devicePixelRatio()); - - if (m_forcedDpi > 0) - return QDpi(m_forcedDpi/dpr, m_forcedDpi/dpr); + static const int overrideDpi = qEnvironmentVariableIntValue("QT_FONT_DPI"); + if (overrideDpi) + return QDpi(overrideDpi, overrideDpi); - static const bool auto_dpr = qgetenv("QT_DEVICE_PIXEL_RATIO").toLower() == "auto"; - if (auto_dpr) { - return QDpi(Q_MM_PER_INCH * m_geometry.width() / m_sizeMillimeters.width(), - Q_MM_PER_INCH * m_geometry.height() / m_sizeMillimeters.height()); - } else { - return QDpi(Q_MM_PER_INCH * m_virtualSize.width() / m_virtualSizeMillimeters.width() / dpr, - Q_MM_PER_INCH * m_virtualSize.height() / m_virtualSizeMillimeters.height() / dpr); + if (m_forcedDpi > 0) { + int primaryDpr = int(connection()->screens().at(0)->devicePixelRatio()); + return QDpi(m_forcedDpi/primaryDpr, m_forcedDpi/primaryDpr); } + return QDpi(Q_MM_PER_INCH * m_virtualSize.width() / m_virtualSizeMillimeters.width(), + Q_MM_PER_INCH * m_virtualSize.height() / m_virtualSizeMillimeters.height()); } -- cgit v1.2.3 From f932a85bd91556f608d884a61600ea0cacedd33f Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 25 Feb 2015 09:52:15 +0100 Subject: Windows: Fix dialog close button showing despite ~Qt::WindowCloseButtonHint. Further restrict the condition under which the special window flags for QTBUG-2027 apply. Change-Id: I458c7c6bfb06820992b5a21820c0439fd2ce7d9d Task-number: QTBUG-2027 Reviewed-by: Joerg Bornemann --- src/plugins/platforms/windows/qwindowswindow.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 6afa4e6591..b19510073a 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -540,13 +540,9 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } if (flags & Qt::WindowSystemMenuHint) style |= WS_SYSMENU; - else if (dialog) { - // QTBUG-2027, dialogs without system menu. - style |= WS_SYSMENU; - if (!(flags & Qt::FramelessWindowHint)) { - style |= WS_BORDER; - exStyle |= WS_EX_DLGMODALFRAME; - } + else if (dialog && (flags & Qt::WindowCloseButtonHint) && !(flags & Qt::FramelessWindowHint)) { + style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu. + exStyle |= WS_EX_DLGMODALFRAME; } if (flags & Qt::WindowMinimizeButtonHint) style |= WS_MINIMIZEBOX; -- cgit v1.2.3 From 2af77ab826083d8a2a311bc7af2bc0f744beec25 Mon Sep 17 00:00:00 2001 From: Peng Wu Date: Wed, 8 Apr 2015 13:31:46 +0300 Subject: winrt: remove the dead WP8.0 code from input context Change-Id: I8db61b4db32052f64833767085f2ebc5f1cc5bcf Reviewed-by: Andrew Knight --- src/plugins/platforms/winrt/qwinrtinputcontext.cpp | 23 ---------------------- 1 file changed, 23 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index 299a80b1d7..63d4c01697 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -44,11 +44,6 @@ using namespace ABI::Windows::Foundation; using namespace ABI::Windows::UI::ViewManagement; using namespace ABI::Windows::UI::Core; -#if defined(Q_OS_WINPHONE) && _MSC_VER==1700 -#include -using namespace ABI::Windows::Phone::UI::Core; -#endif - typedef ITypedEventHandler InputPaneVisibilityHandler; QT_BEGIN_NAMESPACE @@ -140,7 +135,6 @@ void QWinRTInputContext::setKeyboardRect(const QRectF rect) #ifdef Q_OS_WINPHONE -#if _MSC_VER>1700 // Windows Phone 8.1+ static HRESULT getInputPane(ComPtr *inputPane2) { ComPtr factory; @@ -165,17 +159,9 @@ static HRESULT getInputPane(ComPtr *inputPane2) } return hr; } -#endif // _MSC_VER>1700 void QWinRTInputContext::showInputPanel() { -#if _MSC_VER<=1700 // Windows Phone 8.0 - ICoreWindowKeyboardInput *input; - if (SUCCEEDED(m_window->QueryInterface(IID_PPV_ARGS(&input)))) { - input->put_IsKeyboardInputEnabled(true); - input->Release(); - } -#else // _MSC_VER<=1700 ComPtr inputPane; HRESULT hr = getInputPane(&inputPane); if (FAILED(hr)) @@ -185,18 +171,10 @@ void QWinRTInputContext::showInputPanel() hr = inputPane->TryShow(&success); if (FAILED(hr)) qErrnoWarning(hr, "Failed to show input panel."); -#endif // _MSC_VER>1700 } void QWinRTInputContext::hideInputPanel() { -#if _MSC_VER<=1700 // Windows Phone 8.0 - ICoreWindowKeyboardInput *input; - if (SUCCEEDED(m_window->QueryInterface(IID_PPV_ARGS(&input)))) { - input->put_IsKeyboardInputEnabled(false); - input->Release(); - } -#else // _MSC_VER<=1700 ComPtr inputPane; HRESULT hr = getInputPane(&inputPane); if (FAILED(hr)) @@ -206,7 +184,6 @@ void QWinRTInputContext::hideInputPanel() hr = inputPane->TryHide(&success); if (FAILED(hr)) qErrnoWarning(hr, "Failed to hide input panel."); -#endif // _MSC_VER>1700 } #else // Q_OS_WINPHONE -- cgit v1.2.3 From 331ddacfca90c91c5b44484bf3c78e2aa5b85947 Mon Sep 17 00:00:00 2001 From: Peng Wu Date: Wed, 8 Apr 2015 11:30:39 +0300 Subject: winrt: set correct virtual keyboard size This is done by multiplying by the DIP scale factor. Task-number: QTBUG-44152 Change-Id: I587a66f1a2f7fa3a713c279f5d877e6acb844620 Reviewed-by: Andrew Knight --- src/plugins/platforms/winrt/qwinrtinputcontext.cpp | 41 +++++++++------------- src/plugins/platforms/winrt/qwinrtinputcontext.h | 8 +++-- src/plugins/platforms/winrt/qwinrtscreen.cpp | 10 ++++-- src/plugins/platforms/winrt/qwinrtscreen.h | 1 + 4 files changed, 31 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index 63d4c01697..f0de578db6 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include "qwinrtinputcontext.h" +#include "qwinrtscreen.h" #include #include @@ -61,8 +62,8 @@ QT_BEGIN_NAMESPACE Windows Phone, however, supports direct hiding/showing of the keyboard. */ -QWinRTInputContext::QWinRTInputContext(ICoreWindow *window) - : m_window(window) +QWinRTInputContext::QWinRTInputContext(QWinRTScreen *screen) + : m_screen(screen) { IInputPaneStatics *statics; if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_InputPane).Get(), @@ -81,9 +82,7 @@ QWinRTInputContext::QWinRTInputContext(ICoreWindow *window) inputPane->add_Hiding(Callback( this, &QWinRTInputContext::onHiding).Get(), &hideToken); - Rect rect; - inputPane->get_OccludedRect(&rect); - m_keyboardRect = QRectF(rect.X, rect.Y, rect.Width, rect.Height); + handleVisibilityChange(inputPane); m_isInputPanelVisible = !m_keyboardRect.isEmpty(); } else { qWarning(Q_FUNC_INFO ": failed to retrieve InputPane."); @@ -104,35 +103,29 @@ HRESULT QWinRTInputContext::onShowing(IInputPane *pane, IInputPaneVisibilityEven { m_isInputPanelVisible = true; emitInputPanelVisibleChanged(); - - Rect rect; - pane->get_OccludedRect(&rect); - setKeyboardRect(QRectF(rect.X, rect.Y, rect.Width, rect.Height)); - - return S_OK; + return handleVisibilityChange(pane); } HRESULT QWinRTInputContext::onHiding(IInputPane *pane, IInputPaneVisibilityEventArgs *) { m_isInputPanelVisible = false; emitInputPanelVisibleChanged(); + return handleVisibilityChange(pane); +} +HRESULT QWinRTInputContext::handleVisibilityChange(IInputPane *pane) +{ Rect rect; pane->get_OccludedRect(&rect); - setKeyboardRect(QRectF(rect.X, rect.Y, rect.Width, rect.Height)); - + const QRectF keyboardRect = QRectF(qRound(rect.X * m_screen->scaleFactor()), qRound(rect.Y * m_screen->scaleFactor()), + qRound(rect.Width * m_screen->scaleFactor()), qRound(rect.Height * m_screen->scaleFactor())); + if (m_keyboardRect != keyboardRect) { + m_keyboardRect = keyboardRect; + emitKeyboardRectChanged(); + } return S_OK; } -void QWinRTInputContext::setKeyboardRect(const QRectF rect) -{ - if (m_keyboardRect == rect) - return; - - m_keyboardRect = rect; - emitKeyboardRectChanged(); -} - #ifdef Q_OS_WINPHONE static HRESULT getInputPane(ComPtr *inputPane2) @@ -234,7 +227,7 @@ HRESULT QWinRTInputContext::GetPropertyValue(PROPERTYID idProp, VARIANT *retVal) break; case 30020: //UIA_NativeWindowHandlePropertyId retVal->vt = VT_PTR; - retVal->punkVal = m_window; + retVal->punkVal = m_screen->coreWindow(); break; } return S_OK; @@ -244,7 +237,7 @@ HRESULT QWinRTInputContext::get_HostRawElementProvider(IRawElementProviderSimple { // Return the window's element provider IInspectable *hostProvider; - HRESULT hr = m_window->get_AutomationHostProvider(&hostProvider); + HRESULT hr = m_screen->coreWindow()->get_AutomationHostProvider(&hostProvider); if (SUCCEEDED(hr)) { hr = hostProvider->QueryInterface(IID_PPV_ARGS(retVal)); hostProvider->Release(); diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.h b/src/plugins/platforms/winrt/qwinrtinputcontext.h index 6b1b66c0a3..761908a9cb 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.h +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.h @@ -58,6 +58,7 @@ namespace ABI { QT_BEGIN_NAMESPACE +class QWinRTScreen; class QWinRTInputContext : public QPlatformInputContext #ifndef Q_OS_WINPHONE , public Microsoft::WRL::RuntimeClass< @@ -66,7 +67,7 @@ class QWinRTInputContext : public QPlatformInputContext #endif // !Q_OS_WINPHONE { public: - explicit QWinRTInputContext(ABI::Windows::UI::Core::ICoreWindow *window); + explicit QWinRTInputContext(QWinRTScreen *); QRectF keyboardRect() const; @@ -101,9 +102,10 @@ private: ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs *); HRESULT onHiding(ABI::Windows::UI::ViewManagement::IInputPane *, ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs *); - void setKeyboardRect(const QRectF rect); - ABI::Windows::UI::Core::ICoreWindow *m_window; + HRESULT handleVisibilityChange(ABI::Windows::UI::ViewManagement::IInputPane *); + + QWinRTScreen *m_screen; QRectF m_keyboardRect; bool m_isInputPanelVisible; }; diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index d7888194c2..d53b4e6ab9 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -497,9 +497,9 @@ QWinRTScreen::QWinRTScreen() Q_ASSERT_SUCCEEDED(hr); #ifdef Q_OS_WINPHONE - d->inputContext.reset(new QWinRTInputContext(d->coreWindow.Get())); + d->inputContext.reset(new QWinRTInputContext(this)); #else - d->inputContext = Make(d->coreWindow.Get()); + d->inputContext = Make(this); #endif Rect rect; @@ -680,6 +680,12 @@ QDpi QWinRTScreen::logicalDpi() const return QDpi(d->logicalDpi, d->logicalDpi); } +qreal QWinRTScreen::scaleFactor() const +{ + Q_D(const QWinRTScreen); + return d->scaleFactor; +} + QWinRTInputContext *QWinRTScreen::inputContext() const { Q_D(const QWinRTScreen); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index 404c8ca04e..cbef9543a9 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -93,6 +93,7 @@ public: QSurfaceFormat surfaceFormat() const; QSizeF physicalSize() const Q_DECL_OVERRIDE; QDpi logicalDpi() const Q_DECL_OVERRIDE; + qreal scaleFactor() const; QWinRTInputContext *inputContext() const; QPlatformCursor *cursor() const; Qt::KeyboardModifiers keyboardModifiers() const; -- cgit v1.2.3 From a218a252c4200cfe7048de81a46f7e48349084d5 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 8 Apr 2015 17:04:36 +0300 Subject: Upgrade ANGLE to 2.1~99f075dade7c This aligns with Chromium branch 2356. This version brings more complete OpenGL ES 3 support as well as various bug fixes and performance improvements. The following changes were made to earlier patches: -0000-General-fixes-for-ANGLE-2.1 Removed. All changes are now handled elsewhere. +0001-ANGLE-Improve-Windows-Phone-support Consolidated remaining parts from 0009/0010. +0002-ANGLE-Fix-compilation-with-MinGW Remaining issues from patch 0016. +0003-ANGLE-Fix-compilation-with-MSVC2010 Remaining issues from patch 0015. +0004-ANGLE-Dynamically-load-D3D-compiler-from-list Renamed from patch 0008. +0005-ANGLE-Add-support-for-querying-platform-device Renamed from patch 0013. -0004-Make-it-possible-to-link-ANGLE-statically-for-single Removed. Fixed by adding defines to project files. -0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t Renamed to patch 0005. -0009-ANGLE-Support-WinRT Removed. Mostly fixed upstream; remaining parts in patch 0001. -0010-ANGLE-Enable-D3D11-for-feature-level-9-cards Removed. Mostly fixed upstream; remaining parts in patch 0001. -0012-ANGLE-fix-semantic-index-lookup Removed. Fixed upstream. -0013-ANGLE-Add-support-for-querying-platform-device Renamed to patch 0005. -0014-Let-ANGLE-use-multithreaded-devices-if-necessary Removed. No longer needed. -0015-ANGLE-Fix-angle-d3d11-on-MSVC2010 Moved remaining parts to patch 0003. -0016-ANGLE-Fix-compilation-with-MinGW-D3D11 Moved remaining parts to patch 0002. -0017-ANGLE-Fix-compilation-with-D3D9 Removed. Fixed upstream. -0018-ANGLE-Fix-releasing-textures-after-we-kill-D3D11 Removed. Fixed upstream. -0019-ANGLE-Fix-handling-of-shader-source-with-fixed-lengt Removed. Fixed upstream. -0020-ANGLE-Do-not-use-std-strlen Removed. Fixed upstream. -0020-ANGLE-Fix-compilation-with-MSVC2013-Update4 Removed. Fixed upstream. [ChangeLog][Third-party libraries] ANGLE was updated to Chromium branch 2356 (2.1~99f075dade7c). Change-Id: I32ccbfe95e10986bd94be7191dfd53445ea09158 Task-number: QTBUG-44815 Task-number: QTBUG-37660 Task-number: QTBUG-44694 Task-number: QTBUG-42443 Reviewed-by: Andrew Knight Reviewed-by: Friedemann Kleint --- src/3rdparty/angle/.gitignore | 15 +- src/3rdparty/angle/AUTHORS | 6 + src/3rdparty/angle/CONTRIBUTORS | 21 +- src/3rdparty/angle/include/EGL/egl.h | 9 +- src/3rdparty/angle/include/EGL/eglext.h | 24 +- src/3rdparty/angle/include/EGL/eglplatform.h | 17 +- src/3rdparty/angle/include/GLSLANG/ShaderLang.h | 30 +- src/3rdparty/angle/include/GLSLANG/ShaderVars.h | 9 +- src/3rdparty/angle/include/KHR/khrplatform.h | 2 +- src/3rdparty/angle/include/angle_gl.h | 6 +- src/3rdparty/angle/include/export.h | 28 + src/3rdparty/angle/include/platform/Platform.h | 112 + src/3rdparty/angle/src/commit.h | 12 - src/3rdparty/angle/src/common/MemoryBuffer.cpp | 80 + src/3rdparty/angle/src/common/MemoryBuffer.h | 38 + src/3rdparty/angle/src/common/NativeWindow.h | 82 - src/3rdparty/angle/src/common/Optional.h | 61 + src/3rdparty/angle/src/common/RefCountObject.cpp | 47 - src/3rdparty/angle/src/common/RefCountObject.h | 95 - src/3rdparty/angle/src/common/angleutils.cpp | 3 +- src/3rdparty/angle/src/common/angleutils.h | 35 +- src/3rdparty/angle/src/common/blocklayout.cpp | 251 - src/3rdparty/angle/src/common/blocklayout.h | 127 - src/3rdparty/angle/src/common/debug.cpp | 263 +- src/3rdparty/angle/src/common/debug.h | 82 +- src/3rdparty/angle/src/common/event_tracer.cpp | 38 + src/3rdparty/angle/src/common/event_tracer.h | 34 + src/3rdparty/angle/src/common/features.h | 35 - src/3rdparty/angle/src/common/mathutil.h | 61 +- src/3rdparty/angle/src/common/platform.h | 109 +- src/3rdparty/angle/src/common/tls.h | 4 +- src/3rdparty/angle/src/common/utilities.cpp | 40 +- src/3rdparty/angle/src/common/utilities.h | 18 +- src/3rdparty/angle/src/common/version.h | 13 +- .../angle/src/common/win32/NativeWindow.cpp | 66 - .../src/common/winrt/CoreWindowNativeWindow.cpp | 200 - .../src/common/winrt/CoreWindowNativeWindow.h | 39 - .../src/common/winrt/InspectableNativeWindow.cpp | 274 - .../src/common/winrt/InspectableNativeWindow.h | 91 - .../common/winrt/SwapChainPanelNativeWindow.cpp | 226 - .../src/common/winrt/SwapChainPanelNativeWindow.h | 79 - .../src/compiler/preprocessor/DiagnosticsBase.h | 7 +- .../compiler/preprocessor/DirectiveHandlerBase.h | 7 +- .../src/compiler/preprocessor/DirectiveParser.h | 6 +- .../src/compiler/preprocessor/ExpressionParser.h | 7 +- .../src/compiler/preprocessor/ExpressionParser.y | 4 +- .../angle/src/compiler/preprocessor/Input.h | 2 +- .../angle/src/compiler/preprocessor/Lexer.h | 2 +- .../angle/src/compiler/preprocessor/Macro.h | 1 + .../src/compiler/preprocessor/MacroExpander.h | 6 +- .../angle/src/compiler/preprocessor/Preprocessor.h | 2 +- .../src/compiler/preprocessor/SourceLocation.h | 7 +- .../angle/src/compiler/preprocessor/Token.h | 1 + .../angle/src/compiler/preprocessor/Tokenizer.h | 2 +- .../angle/src/compiler/preprocessor/Tokenizer.l | 4 +- .../angle/src/compiler/preprocessor/numeric_lex.h | 7 +- .../angle/src/compiler/translator/BaseTypes.h | 49 +- .../translator/BuiltInFunctionEmulator.cpp | 415 +- .../compiler/translator/BuiltInFunctionEmulator.h | 112 +- .../translator/BuiltInFunctionEmulatorGLSL.cpp | 37 + .../translator/BuiltInFunctionEmulatorGLSL.h | 19 + .../translator/BuiltInFunctionEmulatorHLSL.cpp | 410 + .../translator/BuiltInFunctionEmulatorHLSL.h | 16 + .../angle/src/compiler/translator/CodeGen.cpp | 22 +- .../angle/src/compiler/translator/Common.h | 6 +- .../angle/src/compiler/translator/Compiler.cpp | 107 +- .../angle/src/compiler/translator/Compiler.h | 29 +- .../angle/src/compiler/translator/ConstantUnion.h | 13 +- .../src/compiler/translator/DetectCallDepth.cpp | 6 +- .../src/compiler/translator/DetectCallDepth.h | 6 +- .../src/compiler/translator/DetectDiscontinuity.h | 6 +- .../angle/src/compiler/translator/Diagnostics.h | 9 +- .../src/compiler/translator/DirectiveHandler.cpp | 13 +- .../src/compiler/translator/DirectiveHandler.h | 13 +- .../src/compiler/translator/EmulatePrecision.cpp | 528 ++ .../src/compiler/translator/EmulatePrecision.h | 74 + .../src/compiler/translator/ExtensionBehavior.h | 6 +- .../src/compiler/translator/FlagStd140Structs.h | 6 +- .../angle/src/compiler/translator/ForLoopUnroll.h | 6 +- .../angle/src/compiler/translator/HashNames.h | 6 +- .../angle/src/compiler/translator/InfoSink.h | 6 +- .../angle/src/compiler/translator/Initialize.cpp | 703 +- .../angle/src/compiler/translator/Initialize.h | 12 +- .../angle/src/compiler/translator/InitializeDll.h | 6 +- .../src/compiler/translator/InitializeGlobals.h | 6 +- .../compiler/translator/InitializeParseContext.h | 6 +- .../src/compiler/translator/InitializeVariables.h | 6 +- .../angle/src/compiler/translator/IntermNode.cpp | 311 +- .../angle/src/compiler/translator/IntermNode.h | 287 +- .../src/compiler/translator/IntermTraverse.cpp | 54 + .../angle/src/compiler/translator/Intermediate.cpp | 114 +- .../angle/src/compiler/translator/Intermediate.h | 71 + .../angle/src/compiler/translator/LoopInfo.h | 6 +- src/3rdparty/angle/src/compiler/translator/MMap.h | 6 +- .../angle/src/compiler/translator/NodeSearch.h | 6 +- .../angle/src/compiler/translator/Operator.cpp | 195 + .../angle/src/compiler/translator/Operator.h | 226 + .../angle/src/compiler/translator/OutputESSL.cpp | 23 +- .../angle/src/compiler/translator/OutputESSL.h | 11 +- .../angle/src/compiler/translator/OutputGLSL.cpp | 52 +- .../angle/src/compiler/translator/OutputGLSL.h | 13 +- .../src/compiler/translator/OutputGLSLBase.cpp | 216 +- .../angle/src/compiler/translator/OutputGLSLBase.h | 18 +- .../angle/src/compiler/translator/OutputHLSL.cpp | 991 ++- .../angle/src/compiler/translator/OutputHLSL.h | 113 +- .../angle/src/compiler/translator/ParseContext.cpp | 626 +- .../angle/src/compiler/translator/ParseContext.h | 61 +- .../angle/src/compiler/translator/PoolAlloc.h | 6 +- .../angle/src/compiler/translator/Pragma.h | 13 +- .../src/compiler/translator/QualifierAlive.cpp | 2 +- .../angle/src/compiler/translator/QualifierAlive.h | 5 + .../compiler/translator/RegenerateStructNames.h | 6 +- .../translator/RemoveSwitchFallThrough.cpp | 157 + .../compiler/translator/RemoveSwitchFallThrough.h | 43 + .../angle/src/compiler/translator/RemoveTree.cpp | 29 - .../angle/src/compiler/translator/RemoveTree.h | 7 - .../angle/src/compiler/translator/RenameFunction.h | 6 +- .../src/compiler/translator/RewriteElseBlocks.h | 6 +- .../translator/ScalarizeVecAndMatConstructorArgs.h | 6 +- .../angle/src/compiler/translator/SearchSymbol.cpp | 1 - .../angle/src/compiler/translator/SearchSymbol.h | 6 +- .../angle/src/compiler/translator/ShaderLang.cpp | 16 + .../angle/src/compiler/translator/ShaderVars.cpp | 18 +- .../translator/SimplifyArrayAssignment.cpp | 38 + .../compiler/translator/SimplifyArrayAssignment.h | 25 + .../src/compiler/translator/StructureHLSL.cpp | 22 +- .../angle/src/compiler/translator/StructureHLSL.h | 14 +- .../angle/src/compiler/translator/SymbolTable.cpp | 218 +- .../angle/src/compiler/translator/SymbolTable.h | 70 +- .../src/compiler/translator/TranslatorESSL.cpp | 69 +- .../angle/src/compiler/translator/TranslatorESSL.h | 19 +- .../src/compiler/translator/TranslatorGLSL.cpp | 114 +- .../angle/src/compiler/translator/TranslatorGLSL.h | 12 +- .../src/compiler/translator/TranslatorHLSL.cpp | 16 +- .../angle/src/compiler/translator/TranslatorHLSL.h | 8 +- .../angle/src/compiler/translator/Types.cpp | 18 +- src/3rdparty/angle/src/compiler/translator/Types.h | 38 +- .../src/compiler/translator/UnfoldShortCircuit.cpp | 6 +- .../src/compiler/translator/UnfoldShortCircuit.h | 9 +- .../compiler/translator/UnfoldShortCircuitAST.cpp | 28 +- .../compiler/translator/UnfoldShortCircuitAST.h | 29 +- .../angle/src/compiler/translator/UniformHLSL.cpp | 17 +- .../angle/src/compiler/translator/UniformHLSL.h | 12 +- .../angle/src/compiler/translator/UtilsHLSL.cpp | 7 + .../angle/src/compiler/translator/UtilsHLSL.h | 6 +- .../compiler/translator/ValidateLimitations.cpp | 87 - .../src/compiler/translator/ValidateLimitations.h | 4 + .../src/compiler/translator/ValidateOutputs.h | 5 + .../src/compiler/translator/ValidateSwitch.cpp | 200 + .../angle/src/compiler/translator/ValidateSwitch.h | 52 + .../angle/src/compiler/translator/VariableInfo.cpp | 36 +- .../angle/src/compiler/translator/VariableInfo.h | 8 +- .../angle/src/compiler/translator/VariablePacker.h | 6 +- .../angle/src/compiler/translator/VersionGLSL.cpp | 19 +- .../angle/src/compiler/translator/VersionGLSL.h | 18 +- .../angle/src/compiler/translator/blocklayout.cpp | 123 + .../angle/src/compiler/translator/blocklayout.h | 94 + .../src/compiler/translator/blocklayoutHLSL.cpp | 165 + .../src/compiler/translator/blocklayoutHLSL.h | 62 + .../angle/src/compiler/translator/compilerdebug.h | 6 +- .../compiler/translator/depgraph/DependencyGraph.h | 8 +- .../translator/depgraph/DependencyGraphBuilder.h | 12 +- .../translator/depgraph/DependencyGraphOutput.h | 25 +- .../angle/src/compiler/translator/glslang.h | 4 + .../angle/src/compiler/translator/glslang.l | 19 +- .../angle/src/compiler/translator/glslang.y | 427 +- .../angle/src/compiler/translator/intermOut.cpp | 110 +- .../angle/src/compiler/translator/intermediate.h | 67 - .../angle/src/compiler/translator/length_limits.h | 6 +- .../timing/RestrictFragmentShaderTiming.h | 33 +- .../translator/timing/RestrictVertexShaderTiming.h | 6 +- .../angle/src/compiler/translator/util.cpp | 2 +- src/3rdparty/angle/src/compiler/translator/util.h | 10 +- src/3rdparty/angle/src/id/commit.h | 3 + src/3rdparty/angle/src/libANGLE/AttributeMap.cpp | 53 + src/3rdparty/angle/src/libANGLE/AttributeMap.h | 39 + src/3rdparty/angle/src/libANGLE/BinaryStream.h | 218 + src/3rdparty/angle/src/libANGLE/Buffer.cpp | 121 + src/3rdparty/angle/src/libANGLE/Buffer.h | 70 + src/3rdparty/angle/src/libANGLE/Caps.cpp | 527 ++ src/3rdparty/angle/src/libANGLE/Caps.h | 374 + src/3rdparty/angle/src/libANGLE/Compiler.cpp | 38 + src/3rdparty/angle/src/libANGLE/Compiler.h | 39 + src/3rdparty/angle/src/libANGLE/Config.cpp | 275 + src/3rdparty/angle/src/libANGLE/Config.h | 91 + src/3rdparty/angle/src/libANGLE/Constants.h | 44 + src/3rdparty/angle/src/libANGLE/Context.cpp | 1587 ++++ src/3rdparty/angle/src/libANGLE/Context.h | 277 + src/3rdparty/angle/src/libANGLE/Data.cpp | 51 + src/3rdparty/angle/src/libANGLE/Data.h | 38 + src/3rdparty/angle/src/libANGLE/Display.cpp | 675 ++ src/3rdparty/angle/src/libANGLE/Display.h | 124 + src/3rdparty/angle/src/libANGLE/Error.cpp | 86 + src/3rdparty/angle/src/libANGLE/Error.h | 83 + src/3rdparty/angle/src/libANGLE/Error.inl | 163 + src/3rdparty/angle/src/libANGLE/Fence.cpp | 117 + src/3rdparty/angle/src/libANGLE/Fence.h | 71 + .../angle/src/libANGLE/Float16ToFloat32.cpp | 2203 +++++ src/3rdparty/angle/src/libANGLE/Framebuffer.cpp | 658 ++ src/3rdparty/angle/src/libANGLE/Framebuffer.h | 144 + .../angle/src/libANGLE/FramebufferAttachment.cpp | 302 + .../angle/src/libANGLE/FramebufferAttachment.h | 154 + .../angle/src/libANGLE/HandleAllocator.cpp | 133 + src/3rdparty/angle/src/libANGLE/HandleAllocator.h | 63 + src/3rdparty/angle/src/libANGLE/ImageIndex.cpp | 170 + src/3rdparty/angle/src/libANGLE/ImageIndex.h | 79 + src/3rdparty/angle/src/libANGLE/Platform.cpp | 35 + src/3rdparty/angle/src/libANGLE/Program.cpp | 1617 ++++ src/3rdparty/angle/src/libANGLE/Program.h | 276 + src/3rdparty/angle/src/libANGLE/Query.cpp | 50 + src/3rdparty/angle/src/libANGLE/Query.h | 47 + src/3rdparty/angle/src/libANGLE/RefCountObject.cpp | 39 + src/3rdparty/angle/src/libANGLE/RefCountObject.h | 110 + src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp | 130 + src/3rdparty/angle/src/libANGLE/Renderbuffer.h | 69 + .../angle/src/libANGLE/ResourceManager.cpp | 456 ++ src/3rdparty/angle/src/libANGLE/ResourceManager.h | 114 + src/3rdparty/angle/src/libANGLE/Sampler.cpp | 43 + src/3rdparty/angle/src/libANGLE/Sampler.h | 60 + src/3rdparty/angle/src/libANGLE/Shader.cpp | 243 + src/3rdparty/angle/src/libANGLE/Shader.h | 118 + src/3rdparty/angle/src/libANGLE/State.cpp | 1470 ++++ src/3rdparty/angle/src/libANGLE/State.h | 335 + src/3rdparty/angle/src/libANGLE/Surface.cpp | 166 + src/3rdparty/angle/src/libANGLE/Surface.h | 98 + src/3rdparty/angle/src/libANGLE/Texture.cpp | 573 ++ src/3rdparty/angle/src/libANGLE/Texture.h | 156 + .../angle/src/libANGLE/TransformFeedback.cpp | 71 + .../angle/src/libANGLE/TransformFeedback.h | 50 + src/3rdparty/angle/src/libANGLE/Uniform.cpp | 107 + src/3rdparty/angle/src/libANGLE/Uniform.h | 77 + src/3rdparty/angle/src/libANGLE/VertexArray.cpp | 101 + src/3rdparty/angle/src/libANGLE/VertexArray.h | 66 + .../angle/src/libANGLE/VertexAttribute.cpp | 73 + src/3rdparty/angle/src/libANGLE/VertexAttribute.h | 122 + src/3rdparty/angle/src/libANGLE/angletypes.cpp | 246 + src/3rdparty/angle/src/libANGLE/angletypes.h | 323 + src/3rdparty/angle/src/libANGLE/features.h | 40 + src/3rdparty/angle/src/libANGLE/formatutils.cpp | 650 ++ src/3rdparty/angle/src/libANGLE/formatutils.h | 81 + .../angle/src/libANGLE/queryconversions.cpp | 147 + src/3rdparty/angle/src/libANGLE/queryconversions.h | 17 + .../angle/src/libANGLE/renderer/BufferImpl.h | 38 + .../angle/src/libANGLE/renderer/CompilerImpl.h | 30 + .../angle/src/libANGLE/renderer/DisplayImpl.cpp | 58 + .../angle/src/libANGLE/renderer/DisplayImpl.h | 99 + .../angle/src/libANGLE/renderer/FenceNVImpl.h | 34 + .../angle/src/libANGLE/renderer/FenceSyncImpl.h | 35 + .../angle/src/libANGLE/renderer/FramebufferImpl.h | 68 + src/3rdparty/angle/src/libANGLE/renderer/Image.h | 77 + .../angle/src/libANGLE/renderer/ImplFactory.h | 68 + .../src/libANGLE/renderer/IndexRangeCache.cpp | 114 + .../angle/src/libANGLE/renderer/IndexRangeCache.h | 53 + .../angle/src/libANGLE/renderer/ProgramImpl.cpp | 152 + .../angle/src/libANGLE/renderer/ProgramImpl.h | 137 + .../angle/src/libANGLE/renderer/QueryImpl.h | 40 + .../src/libANGLE/renderer/RenderbufferImpl.cpp | 21 + .../angle/src/libANGLE/renderer/RenderbufferImpl.h | 33 + .../angle/src/libANGLE/renderer/Renderer.cpp | 72 + .../angle/src/libANGLE/renderer/Renderer.h | 91 + .../angle/src/libANGLE/renderer/ShaderImpl.h | 57 + .../angle/src/libANGLE/renderer/SurfaceImpl.cpp | 22 + .../angle/src/libANGLE/renderer/SurfaceImpl.h | 48 + .../angle/src/libANGLE/renderer/TextureImpl.h | 72 + .../src/libANGLE/renderer/TransformFeedbackImpl.h | 31 + .../angle/src/libANGLE/renderer/VertexArrayImpl.h | 32 + .../angle/src/libANGLE/renderer/Workarounds.h | 74 + .../angle/src/libANGLE/renderer/d3d/BufferD3D.cpp | 80 + .../angle/src/libANGLE/renderer/d3d/BufferD3D.h | 56 + .../src/libANGLE/renderer/d3d/CompilerD3D.cpp | 128 + .../angle/src/libANGLE/renderer/d3d/CompilerD3D.h | 48 + .../angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp | 357 + .../angle/src/libANGLE/renderer/d3d/DisplayD3D.h | 61 + .../src/libANGLE/renderer/d3d/DynamicHLSL.cpp | 1265 +++ .../angle/src/libANGLE/renderer/d3d/DynamicHLSL.h | 99 + .../src/libANGLE/renderer/d3d/FramebufferD3D.cpp | 463 ++ .../src/libANGLE/renderer/d3d/FramebufferD3D.h | 111 + .../src/libANGLE/renderer/d3d/HLSLCompiler.cpp | 340 + .../angle/src/libANGLE/renderer/d3d/HLSLCompiler.h | 54 + .../angle/src/libANGLE/renderer/d3d/ImageD3D.cpp | 47 + .../angle/src/libANGLE/renderer/d3d/ImageD3D.h | 84 + .../src/libANGLE/renderer/d3d/IndexBuffer.cpp | 196 + .../angle/src/libANGLE/renderer/d3d/IndexBuffer.h | 101 + .../src/libANGLE/renderer/d3d/IndexDataManager.cpp | 267 + .../src/libANGLE/renderer/d3d/IndexDataManager.h | 70 + .../angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp | 2005 +++++ .../angle/src/libANGLE/renderer/d3d/ProgramD3D.h | 244 + .../src/libANGLE/renderer/d3d/RenderTargetD3D.cpp | 36 + .../src/libANGLE/renderer/d3d/RenderTargetD3D.h | 42 + .../src/libANGLE/renderer/d3d/RenderbufferD3D.cpp | 73 + .../src/libANGLE/renderer/d3d/RenderbufferD3D.h | 43 + .../src/libANGLE/renderer/d3d/RendererD3D.cpp | 628 ++ .../angle/src/libANGLE/renderer/d3d/RendererD3D.h | 241 + .../angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp | 388 + .../angle/src/libANGLE/renderer/d3d/ShaderD3D.h | 89 + .../libANGLE/renderer/d3d/ShaderExecutableD3D.cpp | 61 + .../libANGLE/renderer/d3d/ShaderExecutableD3D.h | 54 + .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 396 + .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.h | 92 + .../angle/src/libANGLE/renderer/d3d/SwapChainD3D.h | 63 + .../angle/src/libANGLE/renderer/d3d/TextureD3D.cpp | 2916 +++++++ .../angle/src/libANGLE/renderer/d3d/TextureD3D.h | 364 + .../src/libANGLE/renderer/d3d/TextureStorage.cpp | 39 + .../src/libANGLE/renderer/d3d/TextureStorage.h | 67 + .../libANGLE/renderer/d3d/TransformFeedbackD3D.cpp | 38 + .../libANGLE/renderer/d3d/TransformFeedbackD3D.h | 32 + .../src/libANGLE/renderer/d3d/VertexBuffer.cpp | 311 + .../angle/src/libANGLE/renderer/d3d/VertexBuffer.h | 143 + .../libANGLE/renderer/d3d/VertexDataManager.cpp | 396 + .../src/libANGLE/renderer/d3d/VertexDataManager.h | 95 + .../angle/src/libANGLE/renderer/d3d/copyimage.cpp | 22 + .../angle/src/libANGLE/renderer/d3d/copyimage.h | 35 + .../angle/src/libANGLE/renderer/d3d/copyimage.inl | 32 + .../src/libANGLE/renderer/d3d/d3d11/Blit11.cpp | 1059 +++ .../angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h | 121 + .../src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp | 1070 +++ .../src/libANGLE/renderer/d3d/d3d11/Buffer11.h | 103 + .../src/libANGLE/renderer/d3d/d3d11/Clear11.cpp | 614 ++ .../src/libANGLE/renderer/d3d/d3d11/Clear11.h | 86 + .../renderer/d3d/d3d11/DebugAnnotator11.cpp | 119 + .../libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h | 39 + .../src/libANGLE/renderer/d3d/d3d11/Fence11.cpp | 231 + .../src/libANGLE/renderer/d3d/d3d11/Fence11.h | 59 + .../libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp | 270 + .../libANGLE/renderer/d3d/d3d11/Framebuffer11.h | 45 + .../src/libANGLE/renderer/d3d/d3d11/Image11.cpp | 664 ++ .../src/libANGLE/renderer/d3d/d3d11/Image11.h | 84 + .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp | 162 + .../libANGLE/renderer/d3d/d3d11/IndexBuffer11.h | 51 + .../renderer/d3d/d3d11/InputLayoutCache.cpp | 430 + .../libANGLE/renderer/d3d/d3d11/InputLayoutCache.h | 103 + .../src/libANGLE/renderer/d3d/d3d11/NativeWindow.h | 80 + .../renderer/d3d/d3d11/PixelTransfer11.cpp | 302 + .../libANGLE/renderer/d3d/d3d11/PixelTransfer11.h | 89 + .../src/libANGLE/renderer/d3d/d3d11/Query11.cpp | 164 + .../src/libANGLE/renderer/d3d/d3d11/Query11.h | 42 + .../renderer/d3d/d3d11/RenderStateCache.cpp | 452 ++ .../libANGLE/renderer/d3d/d3d11/RenderStateCache.h | 111 + .../libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp | 394 + .../libANGLE/renderer/d3d/d3d11/RenderTarget11.h | 110 + .../src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp | 3585 +++++++++ .../src/libANGLE/renderer/d3d/d3d11/Renderer11.h | 400 + .../renderer/d3d/d3d11/ShaderExecutable11.cpp | 110 + .../renderer/d3d/d3d11/ShaderExecutable11.h | 59 + .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 711 ++ .../src/libANGLE/renderer/d3d/d3d11/SwapChain11.h | 87 + .../renderer/d3d/d3d11/TextureStorage11.cpp | 2676 +++++++ .../libANGLE/renderer/d3d/d3d11/TextureStorage11.h | 326 + .../src/libANGLE/renderer/d3d/d3d11/Trim11.cpp | 95 + .../angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h | 43 + .../libANGLE/renderer/d3d/d3d11/VertexArray11.h | 40 + .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp | 244 + .../libANGLE/renderer/d3d/d3d11/VertexBuffer11.h | 58 + .../src/libANGLE/renderer/d3d/d3d11/copyvertex.h | 40 + .../src/libANGLE/renderer/d3d/d3d11/copyvertex.inl | 377 + .../libANGLE/renderer/d3d/d3d11/formatutils11.cpp | 1328 +++ .../libANGLE/renderer/d3d/d3d11/formatutils11.h | 93 + .../renderer/d3d/d3d11/renderer11_utils.cpp | 1378 ++++ .../libANGLE/renderer/d3d/d3d11/renderer11_utils.h | 190 + .../d3d/d3d11/shaders/BufferToTexture11.hlsl | 77 + .../renderer/d3d/d3d11/shaders/Clear11.hlsl | 119 + .../d3d/d3d11/shaders/Passthrough2D11.hlsl | 111 + .../d3d/d3d11/shaders/Passthrough3D11.hlsl | 146 + .../renderer/d3d/d3d11/shaders/Swizzle11.hlsl | 99 + .../renderer/d3d/d3d11/win32/NativeWindow.cpp | 68 + .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 214 + .../d3d/d3d11/winrt/CoreWindowNativeWindow.h | 110 + .../d3d/d3d11/winrt/InspectableNativeWindow.cpp | 291 + .../d3d/d3d11/winrt/InspectableNativeWindow.h | 105 + .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp | 228 + .../d3d/d3d11/winrt/SwapChainPanelNativeWindow.h | 79 + .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp | 679 ++ .../angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h | 97 + .../src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp | 116 + .../angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h | 49 + .../libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp | 36 + .../libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h | 29 + .../src/libANGLE/renderer/d3d/d3d9/Fence9.cpp | 90 + .../angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h | 36 + .../libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp | 422 + .../src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h | 41 + .../src/libANGLE/renderer/d3d/d3d9/Image9.cpp | 788 ++ .../angle/src/libANGLE/renderer/d3d/d3d9/Image9.h | 73 + .../libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp | 173 + .../src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h | 51 + .../src/libANGLE/renderer/d3d/d3d9/Query9.cpp | 144 + .../angle/src/libANGLE/renderer/d3d/d3d9/Query9.h | 41 + .../libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp | 139 + .../src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h | 84 + .../src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp | 2933 +++++++ .../src/libANGLE/renderer/d3d/d3d9/Renderer9.h | 377 + .../src/libANGLE/renderer/d3d/d3d9/ShaderCache.h | 108 + .../renderer/d3d/d3d9/ShaderExecutable9.cpp | 53 + .../libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h | 37 + .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp | 425 + .../src/libANGLE/renderer/d3d/d3d9/SwapChain9.h | 63 + .../libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp | 472 ++ .../libANGLE/renderer/d3d/d3d9/TextureStorage9.h | 108 + .../src/libANGLE/renderer/d3d/d3d9/VertexArray9.h | 41 + .../libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp | 239 + .../src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h | 52 + .../renderer/d3d/d3d9/VertexDeclarationCache.cpp | 237 + .../renderer/d3d/d3d9/VertexDeclarationCache.h | 60 + .../libANGLE/renderer/d3d/d3d9/formatutils9.cpp | 602 ++ .../src/libANGLE/renderer/d3d/d3d9/formatutils9.h | 86 + .../libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp | 597 ++ .../libANGLE/renderer/d3d/d3d9/renderer9_utils.h | 86 + .../src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps | 33 + .../src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs | 43 + .../libANGLE/renderer/d3d/d3d9/vertexconversion.h | 197 + .../src/libANGLE/renderer/d3d/formatutilsD3D.cpp | 147 + .../src/libANGLE/renderer/d3d/formatutilsD3D.h | 50 + .../angle/src/libANGLE/renderer/d3d/generatemip.h | 28 + .../src/libANGLE/renderer/d3d/generatemip.inl | 266 + .../angle/src/libANGLE/renderer/d3d/imageformats.h | 2031 +++++ .../angle/src/libANGLE/renderer/d3d/loadimage.cpp | 662 ++ .../angle/src/libANGLE/renderer/d3d/loadimage.h | 193 + .../angle/src/libANGLE/renderer/d3d/loadimage.inl | 156 + .../src/libANGLE/renderer/d3d/loadimageSSE2.cpp | 125 + src/3rdparty/angle/src/libANGLE/validationEGL.cpp | 503 ++ src/3rdparty/angle/src/libANGLE/validationEGL.h | 49 + src/3rdparty/angle/src/libANGLE/validationES.cpp | 1882 +++++ src/3rdparty/angle/src/libANGLE/validationES.h | 94 + src/3rdparty/angle/src/libANGLE/validationES2.cpp | 882 ++ src/3rdparty/angle/src/libANGLE/validationES2.h | 34 + src/3rdparty/angle/src/libANGLE/validationES3.cpp | 1282 +++ src/3rdparty/angle/src/libANGLE/validationES3.h | 49 + src/3rdparty/angle/src/libEGL/AttributeMap.cpp | 40 - src/3rdparty/angle/src/libEGL/AttributeMap.h | 33 - src/3rdparty/angle/src/libEGL/Config.cpp | 353 - src/3rdparty/angle/src/libEGL/Config.h | 114 - src/3rdparty/angle/src/libEGL/Display.cpp | 648 -- src/3rdparty/angle/src/libEGL/Display.h | 104 - src/3rdparty/angle/src/libEGL/Error.cpp | 48 - src/3rdparty/angle/src/libEGL/Error.h | 39 - src/3rdparty/angle/src/libEGL/Surface.cpp | 505 -- src/3rdparty/angle/src/libEGL/Surface.h | 120 - src/3rdparty/angle/src/libEGL/libEGL.cpp | 1235 +-- src/3rdparty/angle/src/libEGL/libEGL.def | 12 + src/3rdparty/angle/src/libEGL/libEGL.rc | 103 - src/3rdparty/angle/src/libEGL/libEGL_mingw32.def | 12 + src/3rdparty/angle/src/libEGL/libEGLd.def | 12 + src/3rdparty/angle/src/libEGL/main.cpp | 203 - src/3rdparty/angle/src/libEGL/main.h | 45 - src/3rdparty/angle/src/libGLESv2/BinaryStream.h | 208 - src/3rdparty/angle/src/libGLESv2/Buffer.cpp | 128 - src/3rdparty/angle/src/libGLESv2/Buffer.h | 74 - src/3rdparty/angle/src/libGLESv2/Caps.cpp | 425 - src/3rdparty/angle/src/libGLESv2/Caps.h | 273 - src/3rdparty/angle/src/libGLESv2/Context.cpp | 1769 ---- src/3rdparty/angle/src/libGLESv2/Context.h | 291 - src/3rdparty/angle/src/libGLESv2/Data.cpp | 51 - src/3rdparty/angle/src/libGLESv2/Data.h | 38 - src/3rdparty/angle/src/libGLESv2/Error.cpp | 48 - src/3rdparty/angle/src/libGLESv2/Error.h | 39 - src/3rdparty/angle/src/libGLESv2/Fence.cpp | 116 - src/3rdparty/angle/src/libGLESv2/Fence.h | 75 - .../angle/src/libGLESv2/Float16ToFloat32.cpp | 2203 ----- .../angle/src/libGLESv2/Float16ToFloat32.py | 78 - src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp | 672 -- src/3rdparty/angle/src/libGLESv2/Framebuffer.h | 126 - .../angle/src/libGLESv2/FramebufferAttachment.cpp | 230 - .../angle/src/libGLESv2/FramebufferAttachment.h | 132 - .../angle/src/libGLESv2/HandleAllocator.cpp | 63 - src/3rdparty/angle/src/libGLESv2/HandleAllocator.h | 44 - src/3rdparty/angle/src/libGLESv2/ImageIndex.cpp | 148 - src/3rdparty/angle/src/libGLESv2/ImageIndex.h | 68 - src/3rdparty/angle/src/libGLESv2/Program.cpp | 668 -- src/3rdparty/angle/src/libGLESv2/Program.h | 151 - src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp | 1233 --- src/3rdparty/angle/src/libGLESv2/ProgramBinary.h | 237 - src/3rdparty/angle/src/libGLESv2/Query.cpp | 50 - src/3rdparty/angle/src/libGLESv2/Query.h | 48 - src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp | 119 - src/3rdparty/angle/src/libGLESv2/Renderbuffer.h | 71 - .../angle/src/libGLESv2/ResourceManager.cpp | 427 - src/3rdparty/angle/src/libGLESv2/ResourceManager.h | 115 - src/3rdparty/angle/src/libGLESv2/Sampler.cpp | 43 - src/3rdparty/angle/src/libGLESv2/Sampler.h | 60 - src/3rdparty/angle/src/libGLESv2/Shader.cpp | 219 - src/3rdparty/angle/src/libGLESv2/Shader.h | 118 - src/3rdparty/angle/src/libGLESv2/State.cpp | 1464 ---- src/3rdparty/angle/src/libGLESv2/State.h | 325 - src/3rdparty/angle/src/libGLESv2/Texture.cpp | 1012 --- src/3rdparty/angle/src/libGLESv2/Texture.h | 241 - .../angle/src/libGLESv2/TransformFeedback.cpp | 71 - .../angle/src/libGLESv2/TransformFeedback.h | 51 - src/3rdparty/angle/src/libGLESv2/Uniform.cpp | 105 - src/3rdparty/angle/src/libGLESv2/Uniform.h | 79 - src/3rdparty/angle/src/libGLESv2/VertexArray.cpp | 96 - src/3rdparty/angle/src/libGLESv2/VertexArray.h | 62 - .../angle/src/libGLESv2/VertexAttribute.cpp | 55 - src/3rdparty/angle/src/libGLESv2/VertexAttribute.h | 119 - src/3rdparty/angle/src/libGLESv2/angletypes.cpp | 210 - src/3rdparty/angle/src/libGLESv2/angletypes.h | 257 - src/3rdparty/angle/src/libGLESv2/constants.h | 44 - .../angle/src/libGLESv2/entry_points_egl.cpp | 1127 +++ .../angle/src/libGLESv2/entry_points_egl.h | 74 + .../angle/src/libGLESv2/entry_points_egl_ext.cpp | 271 + .../angle/src/libGLESv2/entry_points_egl_ext.h | 30 + .../angle/src/libGLESv2/entry_points_gles_2_0.cpp | 4318 ++++++++++ .../angle/src/libGLESv2/entry_points_gles_2_0.h | 163 + .../src/libGLESv2/entry_points_gles_2_0_ext.cpp | 1058 +++ .../src/libGLESv2/entry_points_gles_2_0_ext.h | 78 + .../angle/src/libGLESv2/entry_points_gles_3_0.cpp | 3394 ++++++++ .../angle/src/libGLESv2/entry_points_gles_3_0.h | 125 + .../src/libGLESv2/entry_points_gles_3_0_ext.cpp | 14 + .../src/libGLESv2/entry_points_gles_3_0_ext.h | 23 + src/3rdparty/angle/src/libGLESv2/formatutils.cpp | 629 -- src/3rdparty/angle/src/libGLESv2/formatutils.h | 106 - src/3rdparty/angle/src/libGLESv2/global_state.cpp | 235 + src/3rdparty/angle/src/libGLESv2/global_state.h | 49 + src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp | 8423 +------------------- src/3rdparty/angle/src/libGLESv2/libGLESv2.def | 12 +- src/3rdparty/angle/src/libGLESv2/libGLESv2.rc | 103 - .../angle/src/libGLESv2/libGLESv2_mingw32.def | 12 +- src/3rdparty/angle/src/libGLESv2/libGLESv2d.def | 12 +- .../angle/src/libGLESv2/libGLESv2d_mingw32.def | 12 +- src/3rdparty/angle/src/libGLESv2/main.cpp | 186 - src/3rdparty/angle/src/libGLESv2/main.h | 61 - .../angle/src/libGLESv2/queryconversions.cpp | 147 - .../angle/src/libGLESv2/queryconversions.h | 17 - .../angle/src/libGLESv2/renderer/BufferImpl.h | 35 - .../angle/src/libGLESv2/renderer/FenceImpl.h | 52 - .../angle/src/libGLESv2/renderer/Image.cpp | 46 - src/3rdparty/angle/src/libGLESv2/renderer/Image.h | 79 - .../src/libGLESv2/renderer/IndexRangeCache.cpp | 128 - .../angle/src/libGLESv2/renderer/IndexRangeCache.h | 64 - .../angle/src/libGLESv2/renderer/ProgramImpl.cpp | 146 - .../angle/src/libGLESv2/renderer/ProgramImpl.h | 127 - .../angle/src/libGLESv2/renderer/QueryImpl.h | 42 - .../angle/src/libGLESv2/renderer/RenderTarget.cpp | 36 - .../angle/src/libGLESv2/renderer/RenderTarget.h | 53 - .../src/libGLESv2/renderer/RenderbufferImpl.cpp | 21 - .../src/libGLESv2/renderer/RenderbufferImpl.h | 41 - .../angle/src/libGLESv2/renderer/Renderer.cpp | 172 - .../angle/src/libGLESv2/renderer/Renderer.h | 193 - .../src/libGLESv2/renderer/ShaderExecutable.h | 78 - .../angle/src/libGLESv2/renderer/ShaderImpl.h | 55 - .../angle/src/libGLESv2/renderer/SwapChain.h | 56 - .../angle/src/libGLESv2/renderer/TextureImpl.h | 64 - .../src/libGLESv2/renderer/TransformFeedbackImpl.h | 31 - .../angle/src/libGLESv2/renderer/VertexArrayImpl.h | 32 - .../angle/src/libGLESv2/renderer/Workarounds.h | 39 - .../angle/src/libGLESv2/renderer/copyimage.cpp | 22 - .../angle/src/libGLESv2/renderer/copyimage.h | 35 - .../angle/src/libGLESv2/renderer/copyimage.inl | 32 - .../angle/src/libGLESv2/renderer/copyvertex.h | 35 - .../angle/src/libGLESv2/renderer/copyvertex.inl | 288 - .../angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp | 88 - .../angle/src/libGLESv2/renderer/d3d/BufferD3D.h | 59 - .../src/libGLESv2/renderer/d3d/DynamicHLSL.cpp | 1148 --- .../angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h | 101 - .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 333 - .../src/libGLESv2/renderer/d3d/HLSLCompiler.h | 56 - .../angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp | 26 - .../angle/src/libGLESv2/renderer/d3d/ImageD3D.h | 50 - .../src/libGLESv2/renderer/d3d/IndexBuffer.cpp | 199 - .../angle/src/libGLESv2/renderer/d3d/IndexBuffer.h | 112 - .../libGLESv2/renderer/d3d/IndexDataManager.cpp | 271 - .../src/libGLESv2/renderer/d3d/IndexDataManager.h | 71 - .../src/libGLESv2/renderer/d3d/MemoryBuffer.cpp | 74 - .../src/libGLESv2/renderer/d3d/MemoryBuffer.h | 36 - .../src/libGLESv2/renderer/d3d/ProgramD3D.cpp | 1925 ----- .../angle/src/libGLESv2/renderer/d3d/ProgramD3D.h | 219 - .../src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp | 108 - .../src/libGLESv2/renderer/d3d/RenderbufferD3D.h | 51 - .../src/libGLESv2/renderer/d3d/RendererD3D.cpp | 801 -- .../angle/src/libGLESv2/renderer/d3d/RendererD3D.h | 197 - .../angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp | 481 -- .../angle/src/libGLESv2/renderer/d3d/ShaderD3D.h | 98 - .../src/libGLESv2/renderer/d3d/TextureD3D.cpp | 2813 ------- .../angle/src/libGLESv2/renderer/d3d/TextureD3D.h | 335 - .../src/libGLESv2/renderer/d3d/TextureStorage.cpp | 39 - .../src/libGLESv2/renderer/d3d/TextureStorage.h | 66 - .../renderer/d3d/TransformFeedbackD3D.cpp | 38 - .../libGLESv2/renderer/d3d/TransformFeedbackD3D.h | 32 - .../src/libGLESv2/renderer/d3d/VertexBuffer.cpp | 307 - .../src/libGLESv2/renderer/d3d/VertexBuffer.h | 144 - .../libGLESv2/renderer/d3d/VertexDataManager.cpp | 354 - .../src/libGLESv2/renderer/d3d/VertexDataManager.h | 96 - .../src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp | 1047 --- .../src/libGLESv2/renderer/d3d/d3d11/Blit11.h | 123 - .../src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp | 983 --- .../src/libGLESv2/renderer/d3d/d3d11/Buffer11.h | 105 - .../src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 556 -- .../src/libGLESv2/renderer/d3d/d3d11/Clear11.h | 87 - .../src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp | 232 - .../src/libGLESv2/renderer/d3d/d3d11/Fence11.h | 62 - .../src/libGLESv2/renderer/d3d/d3d11/Image11.cpp | 634 -- .../src/libGLESv2/renderer/d3d/d3d11/Image11.h | 87 - .../libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp | 162 - .../libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h | 53 - .../renderer/d3d/d3d11/InputLayoutCache.cpp | 255 - .../renderer/d3d/d3d11/InputLayoutCache.h | 101 - .../renderer/d3d/d3d11/PixelTransfer11.cpp | 304 - .../libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h | 88 - .../src/libGLESv2/renderer/d3d/d3d11/Query11.cpp | 157 - .../src/libGLESv2/renderer/d3d/d3d11/Query11.h | 44 - .../renderer/d3d/d3d11/RenderStateCache.cpp | 439 - .../renderer/d3d/d3d11/RenderStateCache.h | 113 - .../renderer/d3d/d3d11/RenderTarget11.cpp | 404 - .../libGLESv2/renderer/d3d/d3d11/RenderTarget11.h | 110 - .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 3422 -------- .../src/libGLESv2/renderer/d3d/d3d11/Renderer11.h | 362 - .../renderer/d3d/d3d11/ShaderExecutable11.cpp | 110 - .../renderer/d3d/d3d11/ShaderExecutable11.h | 61 - .../libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp | 675 -- .../src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h | 82 - .../renderer/d3d/d3d11/TextureStorage11.cpp | 2112 ----- .../renderer/d3d/d3d11/TextureStorage11.h | 298 - .../libGLESv2/renderer/d3d/d3d11/VertexArray11.h | 42 - .../renderer/d3d/d3d11/VertexBuffer11.cpp | 214 - .../libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h | 52 - .../libGLESv2/renderer/d3d/d3d11/formatutils11.cpp | 1075 --- .../libGLESv2/renderer/d3d/d3d11/formatutils11.h | 84 - .../renderer/d3d/d3d11/renderer11_utils.cpp | 1228 --- .../renderer/d3d/d3d11/renderer11_utils.h | 189 - .../d3d/d3d11/shaders/BufferToTexture11.hlsl | 76 - .../renderer/d3d/d3d11/shaders/Clear11.hlsl | 106 - .../d3d/d3d11/shaders/Passthrough2D11.hlsl | 111 - .../d3d/d3d11/shaders/Passthrough3D11.hlsl | 146 - .../renderer/d3d/d3d11/shaders/Swizzle11.hlsl | 99 - .../src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp | 679 -- .../angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h | 97 - .../src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp | 122 - .../src/libGLESv2/renderer/d3d/d3d9/Buffer9.h | 52 - .../src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp | 91 - .../angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h | 37 - .../src/libGLESv2/renderer/d3d/d3d9/Image9.cpp | 792 -- .../angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h | 77 - .../libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp | 173 - .../src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h | 53 - .../src/libGLESv2/renderer/d3d/d3d9/Query9.cpp | 144 - .../angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h | 43 - .../libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp | 148 - .../libGLESv2/renderer/d3d/d3d9/RenderTarget9.h | 89 - .../src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 3171 -------- .../src/libGLESv2/renderer/d3d/d3d9/Renderer9.h | 352 - .../src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h | 110 - .../renderer/d3d/d3d9/ShaderExecutable9.cpp | 53 - .../renderer/d3d/d3d9/ShaderExecutable9.h | 39 - .../src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp | 422 - .../src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h | 58 - .../renderer/d3d/d3d9/TextureStorage9.cpp | 472 -- .../libGLESv2/renderer/d3d/d3d9/TextureStorage9.h | 114 - .../src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h | 43 - .../libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp | 239 - .../libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h | 54 - .../renderer/d3d/d3d9/VertexDeclarationCache.cpp | 237 - .../renderer/d3d/d3d9/VertexDeclarationCache.h | 59 - .../libGLESv2/renderer/d3d/d3d9/formatutils9.cpp | 588 -- .../src/libGLESv2/renderer/d3d/d3d9/formatutils9.h | 74 - .../renderer/d3d/d3d9/renderer9_utils.cpp | 558 -- .../libGLESv2/renderer/d3d/d3d9/renderer9_utils.h | 86 - .../libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps | 33 - .../libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs | 43 - .../angle/src/libGLESv2/renderer/generatemip.h | 28 - .../angle/src/libGLESv2/renderer/generatemip.inl | 266 - .../angle/src/libGLESv2/renderer/imageformats.h | 2029 ----- .../angle/src/libGLESv2/renderer/loadimage.cpp | 661 -- .../angle/src/libGLESv2/renderer/loadimage.h | 193 - .../angle/src/libGLESv2/renderer/loadimage.inl | 156 - .../angle/src/libGLESv2/renderer/loadimageSSE2.cpp | 118 - .../src/libGLESv2/renderer/vertexconversion.h | 197 - src/3rdparty/angle/src/libGLESv2/validationES.cpp | 1954 ----- src/3rdparty/angle/src/libGLESv2/validationES.h | 92 - src/3rdparty/angle/src/libGLESv2/validationES2.cpp | 980 --- src/3rdparty/angle/src/libGLESv2/validationES2.h | 34 - src/3rdparty/angle/src/libGLESv2/validationES3.cpp | 1286 --- src/3rdparty/angle/src/libGLESv2/validationES3.h | 44 - .../src/third_party/compiler/ArrayBoundsClamper.h | 6 +- .../src/third_party/murmurhash/MurmurHash3.cpp | 2 + .../angle/src/third_party/murmurhash/MurmurHash3.h | 2 +- .../angle/src/third_party/systeminfo/SystemInfo.h | 6 +- .../src/third_party/trace_event/trace_event.h | 795 ++ .../patches/0000-General-fixes-for-ANGLE-2.1.patch | 477 -- .../0001-ANGLE-Improve-Windows-Phone-Support.patch | 439 + .../0002-ANGLE-Fix-compilation-with-MinGW.patch | 927 +++ ...03-ANGLE-Fix-compilation-on-MSVC2010-2012.patch | 363 + ...Dynamically-load-D3D-compiler-from-a-list.patch | 61 + ...sible-to-link-ANGLE-statically-for-single.patch | 109 - ...-Add-support-for-querying-platform-device.patch | 84 + ...ically-load-D3D-compiler-from-a-list-or-t.patch | 64 - src/angle/patches/0009-ANGLE-Support-WinRT.patch | 837 -- ...LE-Enable-D3D11-for-feature-level-9-cards.patch | 637 -- .../0012-ANGLE-fix-semantic-index-lookup.patch | 48 - ...-Add-support-for-querying-platform-device.patch | 100 - ...LE-use-multithreaded-devices-if-necessary.patch | 69 - .../0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch | 536 -- ...16-ANGLE-Fix-compilation-with-MinGW-D3D11.patch | 169 - .../0017-ANGLE-Fix-compilation-with-D3D9.patch | 62 - ...ix-releasing-textures-after-we-kill-D3D11.patch | 106 - ...andling-of-shader-source-with-fixed-lengt.patch | 37 - .../patches/0020-ANGLE-Do-not-use-std-strlen.patch | 30 - ...GLE-Fix-compilation-with-MSVC2013-Update4.patch | 43 - src/angle/src/common/common.pri | 18 +- .../src/compiler/preprocessor/preprocessor.pro | 2 +- src/angle/src/compiler/translator.pro | 39 +- src/angle/src/config.pri | 5 +- src/angle/src/libEGL/libEGL.pro | 35 +- src/angle/src/libGLESv2/libGLESv2.pro | 760 +- 702 files changed, 92349 insertions(+), 83060 deletions(-) mode change 100644 => 100755 src/3rdparty/angle/include/KHR/khrplatform.h create mode 100644 src/3rdparty/angle/include/export.h create mode 100644 src/3rdparty/angle/include/platform/Platform.h delete mode 100644 src/3rdparty/angle/src/commit.h create mode 100644 src/3rdparty/angle/src/common/MemoryBuffer.cpp create mode 100644 src/3rdparty/angle/src/common/MemoryBuffer.h delete mode 100644 src/3rdparty/angle/src/common/NativeWindow.h create mode 100644 src/3rdparty/angle/src/common/Optional.h delete mode 100644 src/3rdparty/angle/src/common/RefCountObject.cpp delete mode 100644 src/3rdparty/angle/src/common/RefCountObject.h delete mode 100644 src/3rdparty/angle/src/common/blocklayout.cpp delete mode 100644 src/3rdparty/angle/src/common/blocklayout.h create mode 100644 src/3rdparty/angle/src/common/event_tracer.cpp create mode 100644 src/3rdparty/angle/src/common/event_tracer.h delete mode 100644 src/3rdparty/angle/src/common/features.h delete mode 100644 src/3rdparty/angle/src/common/win32/NativeWindow.cpp delete mode 100644 src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp delete mode 100644 src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h delete mode 100644 src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp delete mode 100644 src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h delete mode 100644 src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp delete mode 100644 src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h create mode 100644 src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h create mode 100644 src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h create mode 100644 src/3rdparty/angle/src/compiler/translator/Intermediate.h create mode 100644 src/3rdparty/angle/src/compiler/translator/Operator.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/Operator.h create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp delete mode 100644 src/3rdparty/angle/src/compiler/translator/RemoveTree.h create mode 100644 src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h create mode 100644 src/3rdparty/angle/src/compiler/translator/blocklayout.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/blocklayout.h create mode 100644 src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp create mode 100644 src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h delete mode 100644 src/3rdparty/angle/src/compiler/translator/intermediate.h create mode 100644 src/3rdparty/angle/src/id/commit.h create mode 100644 src/3rdparty/angle/src/libANGLE/AttributeMap.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/AttributeMap.h create mode 100644 src/3rdparty/angle/src/libANGLE/BinaryStream.h create mode 100644 src/3rdparty/angle/src/libANGLE/Buffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Buffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/Caps.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Caps.h create mode 100644 src/3rdparty/angle/src/libANGLE/Compiler.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Compiler.h create mode 100644 src/3rdparty/angle/src/libANGLE/Config.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Config.h create mode 100644 src/3rdparty/angle/src/libANGLE/Constants.h create mode 100644 src/3rdparty/angle/src/libANGLE/Context.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Context.h create mode 100644 src/3rdparty/angle/src/libANGLE/Data.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Data.h create mode 100644 src/3rdparty/angle/src/libANGLE/Display.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Display.h create mode 100644 src/3rdparty/angle/src/libANGLE/Error.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Error.h create mode 100644 src/3rdparty/angle/src/libANGLE/Error.inl create mode 100644 src/3rdparty/angle/src/libANGLE/Fence.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Fence.h create mode 100644 src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Framebuffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Framebuffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h create mode 100644 src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/HandleAllocator.h create mode 100644 src/3rdparty/angle/src/libANGLE/ImageIndex.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ImageIndex.h create mode 100644 src/3rdparty/angle/src/libANGLE/Platform.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Program.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Program.h create mode 100644 src/3rdparty/angle/src/libANGLE/Query.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Query.h create mode 100644 src/3rdparty/angle/src/libANGLE/RefCountObject.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/RefCountObject.h create mode 100644 src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Renderbuffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/ResourceManager.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/ResourceManager.h create mode 100644 src/3rdparty/angle/src/libANGLE/Sampler.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Sampler.h create mode 100644 src/3rdparty/angle/src/libANGLE/Shader.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Shader.h create mode 100644 src/3rdparty/angle/src/libANGLE/State.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/State.h create mode 100644 src/3rdparty/angle/src/libANGLE/Surface.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Surface.h create mode 100644 src/3rdparty/angle/src/libANGLE/Texture.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Texture.h create mode 100644 src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/TransformFeedback.h create mode 100644 src/3rdparty/angle/src/libANGLE/Uniform.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/Uniform.h create mode 100644 src/3rdparty/angle/src/libANGLE/VertexArray.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/VertexArray.h create mode 100644 src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/VertexAttribute.h create mode 100644 src/3rdparty/angle/src/libANGLE/angletypes.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/angletypes.h create mode 100644 src/3rdparty/angle/src/libANGLE/features.h create mode 100644 src/3rdparty/angle/src/libANGLE/formatutils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/formatutils.h create mode 100644 src/3rdparty/angle/src/libANGLE/queryconversions.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/queryconversions.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Image.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Renderer.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl create mode 100644 src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationEGL.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationEGL.h create mode 100644 src/3rdparty/angle/src/libANGLE/validationES.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationES.h create mode 100644 src/3rdparty/angle/src/libANGLE/validationES2.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationES2.h create mode 100644 src/3rdparty/angle/src/libANGLE/validationES3.cpp create mode 100644 src/3rdparty/angle/src/libANGLE/validationES3.h delete mode 100644 src/3rdparty/angle/src/libEGL/AttributeMap.cpp delete mode 100644 src/3rdparty/angle/src/libEGL/AttributeMap.h delete mode 100644 src/3rdparty/angle/src/libEGL/Config.cpp delete mode 100644 src/3rdparty/angle/src/libEGL/Config.h delete mode 100644 src/3rdparty/angle/src/libEGL/Display.cpp delete mode 100644 src/3rdparty/angle/src/libEGL/Display.h delete mode 100644 src/3rdparty/angle/src/libEGL/Error.cpp delete mode 100644 src/3rdparty/angle/src/libEGL/Error.h delete mode 100644 src/3rdparty/angle/src/libEGL/Surface.cpp delete mode 100644 src/3rdparty/angle/src/libEGL/Surface.h delete mode 100644 src/3rdparty/angle/src/libEGL/libEGL.rc delete mode 100644 src/3rdparty/angle/src/libEGL/main.cpp delete mode 100644 src/3rdparty/angle/src/libEGL/main.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/BinaryStream.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Buffer.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Buffer.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Caps.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Caps.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Context.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Context.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Data.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Data.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Error.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Error.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Fence.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Fence.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py delete mode 100644 src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Framebuffer.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/HandleAllocator.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/ImageIndex.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/ImageIndex.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Program.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Program.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/ProgramBinary.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Query.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Query.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Renderbuffer.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/ResourceManager.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Sampler.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Sampler.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Shader.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Shader.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/State.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/State.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Texture.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Texture.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/TransformFeedback.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/TransformFeedback.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/Uniform.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/Uniform.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/VertexArray.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/VertexArray.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/VertexAttribute.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/VertexAttribute.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/angletypes.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/angletypes.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/constants.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_egl.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.h create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/formatutils.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/formatutils.h create mode 100644 src/3rdparty/angle/src/libGLESv2/global_state.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/global_state.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/libGLESv2.rc delete mode 100644 src/3rdparty/angle/src/libGLESv2/main.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/main.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/queryconversions.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/queryconversions.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/Image.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/QueryImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/ShaderImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/TransformFeedbackImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/VertexArrayImpl.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/Workarounds.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/copyimage.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/copyimage.inl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.inl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/generatemip.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/generatemip.inl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/imageformats.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/loadimage.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/loadimage.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/loadimage.inl delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/vertexconversion.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/validationES.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/validationES.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/validationES2.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/validationES2.h delete mode 100644 src/3rdparty/angle/src/libGLESv2/validationES3.cpp delete mode 100644 src/3rdparty/angle/src/libGLESv2/validationES3.h create mode 100644 src/3rdparty/angle/src/third_party/trace_event/trace_event.h delete mode 100644 src/angle/patches/0000-General-fixes-for-ANGLE-2.1.patch create mode 100644 src/angle/patches/0001-ANGLE-Improve-Windows-Phone-Support.patch create mode 100644 src/angle/patches/0002-ANGLE-Fix-compilation-with-MinGW.patch create mode 100644 src/angle/patches/0003-ANGLE-Fix-compilation-on-MSVC2010-2012.patch create mode 100644 src/angle/patches/0004-ANGLE-Dynamically-load-D3D-compiler-from-a-list.patch delete mode 100644 src/angle/patches/0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch create mode 100644 src/angle/patches/0005-ANGLE-Add-support-for-querying-platform-device.patch delete mode 100644 src/angle/patches/0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t.patch delete mode 100644 src/angle/patches/0009-ANGLE-Support-WinRT.patch delete mode 100644 src/angle/patches/0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch delete mode 100644 src/angle/patches/0012-ANGLE-fix-semantic-index-lookup.patch delete mode 100644 src/angle/patches/0013-ANGLE-Add-support-for-querying-platform-device.patch delete mode 100644 src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch delete mode 100644 src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch delete mode 100644 src/angle/patches/0016-ANGLE-Fix-compilation-with-MinGW-D3D11.patch delete mode 100644 src/angle/patches/0017-ANGLE-Fix-compilation-with-D3D9.patch delete mode 100644 src/angle/patches/0018-ANGLE-Fix-releasing-textures-after-we-kill-D3D11.patch delete mode 100644 src/angle/patches/0019-ANGLE-Fix-handling-of-shader-source-with-fixed-lengt.patch delete mode 100644 src/angle/patches/0020-ANGLE-Do-not-use-std-strlen.patch delete mode 100644 src/angle/patches/0020-ANGLE-Fix-compilation-with-MSVC2013-Update4.patch (limited to 'src') diff --git a/src/3rdparty/angle/.gitignore b/src/3rdparty/angle/.gitignore index cbb7e6a5af..17958a0fb5 100644 --- a/src/3rdparty/angle/.gitignore +++ b/src/3rdparty/angle/.gitignore @@ -6,19 +6,28 @@ build extensions samples tests -third_party src/ipch +util .svn # Files from ANGLE we don't want/need DEPS +*.chromium +*.isolate +*.md +*.gn *.gyp *.gypi *.sh *.bat *.patch *.py +*.rc +*_unittest.cpp codereview.settings +src/commit.h +src/libANGLE/renderer/gl +src/third_party/khronos/GL # Generated by flex/bison src/compiler/preprocessor/Tokenizer.cpp @@ -28,5 +37,5 @@ src/compiler/translator/glslang_tab.cpp src/compiler/translator/glslang_tab.h # Generated by FXC -src/libGLESv2/renderer/d3d/d3d9/shaders/compiled/*.h -src/libGLESv2/renderer/d3d/d3d11/shaders/compiled/*.h +src/libANGLE/renderer/d3d/d3d9/shaders/compiled/*.h +src/libANGLE/renderer/d3d/d3d11/shaders/compiled/*.h diff --git a/src/3rdparty/angle/AUTHORS b/src/3rdparty/angle/AUTHORS index be114bcf68..836bed8e8a 100644 --- a/src/3rdparty/angle/AUTHORS +++ b/src/3rdparty/angle/AUTHORS @@ -16,17 +16,22 @@ Autodesk, Inc. BlackBerry Limited Cable Television Laboratories, Inc. Cloud Party, Inc. +Imagination Technologies Ltd. Intel Corporation Mozilla Corporation Turbulenz Klarälvdalens Datakonsult AB +Microsoft Corporation Microsoft Open Technologies, Inc. NVIDIA Corporation +Opera Software ASA +The Qt Company Ltd. Jacek Caban Mark Callow Ginn Chen Tibor den Ouden +Régis Fénéon James Hauxwell Sam Hocevar Pierre Leveille @@ -35,3 +40,4 @@ Boying Lu Aitor Moreno Yuri O'Donnell Josh Soref +Maks Naumov diff --git a/src/3rdparty/angle/CONTRIBUTORS b/src/3rdparty/angle/CONTRIBUTORS index 6b27416e38..5252141973 100644 --- a/src/3rdparty/angle/CONTRIBUTORS +++ b/src/3rdparty/angle/CONTRIBUTORS @@ -1,4 +1,4 @@ -# This is the official list of people who can contribute +# 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 @@ -40,6 +40,7 @@ Google Inc. thestig@chromium.org Justin Schuh Scott Graham + Corentin Wallez Adobe Systems Inc. Alexandru Chiculita @@ -55,6 +56,9 @@ Cloud Party, Inc. The Qt Company Ltd. Andrew Knight +Imagination Technologies Ltd. + Gregoire Payen de La Garanderie + Intel Corporation Jin Yang Andy Chen @@ -80,10 +84,21 @@ Mark Banner (standard8mbp) David Kilzer Jacek Caban Tibor den Ouden +Régis Fénéon + +Microsoft Corporation + Cooper Partin + Austin Kinross + Minmin Gong Microsoft Open Technologies, Inc. -Cooper Partin -Austin Kinross + Cooper Partin + Austin Kinross NVIDIA Corporation Olli Etuaho + Arun Patole + Qingqing Deng + +Opera Software ASA + Daniel Bratell diff --git a/src/3rdparty/angle/include/EGL/egl.h b/src/3rdparty/angle/include/EGL/egl.h index 12590a0e20..5a27291213 100644 --- a/src/3rdparty/angle/include/EGL/egl.h +++ b/src/3rdparty/angle/include/EGL/egl.h @@ -33,12 +33,12 @@ extern "C" { ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** -** Khronos $Revision: 27018 $ on $Date: 2014-06-10 08:06:12 -0700 (Tue, 10 Jun 2014) $ +** Khronos $Revision: 29318 $ on $Date: 2015-01-02 03:16:10 -0800 (Fri, 02 Jan 2015) $ */ #include -/* Generated on date 20140610 */ +/* Generated on date 20150102 */ /* Generated C header for: * API: egl @@ -240,6 +240,7 @@ EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void); typedef void *EGLSync; typedef intptr_t EGLAttrib; typedef khronos_utime_nanoseconds_t EGLTime; +typedef void *EGLImage; #define EGL_CONTEXT_MAJOR_VERSION 0x3098 #define EGL_CONTEXT_MINOR_VERSION 0x30FB #define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD @@ -281,10 +282,14 @@ typedef khronos_utime_nanoseconds_t EGLTime; #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6 #define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7 #define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8 +#define EGL_IMAGE_PRESERVED 0x30D2 +#define EGL_NO_IMAGE ((EGLImage)0) EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list); EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync); EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value); +EGLAPI EGLImage EGLAPIENTRY eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImage (EGLDisplay dpy, EGLImage image); EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list); EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list); EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list); diff --git a/src/3rdparty/angle/include/EGL/eglext.h b/src/3rdparty/angle/include/EGL/eglext.h index 0cc5eec293..a44afecb3f 100644 --- a/src/3rdparty/angle/include/EGL/eglext.h +++ b/src/3rdparty/angle/include/EGL/eglext.h @@ -440,24 +440,28 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSu #ifndef EGL_ANGLE_platform_angle #define EGL_ANGLE_platform_angle 1 -#define EGL_PLATFORM_ANGLE_ANGLE 0x3201 -#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202 -#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3203 -#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3204 -#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3205 +#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205 +#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206 #endif /* EGL_ANGLE_platform_angle */ #ifndef EGL_ANGLE_platform_angle_d3d #define EGL_ANGLE_platform_angle_d3d 1 -#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3206 -#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207 -#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208 +#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209 +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE 0x320B +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE 0x320C +#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F #endif /* EGL_ANGLE_platform_angle_d3d */ #ifndef EGL_ANGLE_platform_angle_opengl #define EGL_ANGLE_platform_angle_opengl 1 -#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x3209 -#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320A +#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D +#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E #endif /* EGL_ANGLE_platform_angle_opengl */ #ifndef EGL_ARM_pixmap_multisample_discard diff --git a/src/3rdparty/angle/include/EGL/eglplatform.h b/src/3rdparty/angle/include/EGL/eglplatform.h index 2eb3674a0b..519df3e750 100644 --- a/src/3rdparty/angle/include/EGL/eglplatform.h +++ b/src/3rdparty/angle/include/EGL/eglplatform.h @@ -73,15 +73,14 @@ #endif #include +typedef HDC EGLNativeDisplayType; typedef HBITMAP EGLNativePixmapType; -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) /* Windows Store */ +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) /* Windows Desktop */ +typedef HWND EGLNativeWindowType; +#else /* Windows Store */ #include -typedef IInspectable* EGLNativeDisplayType; typedef IInspectable* EGLNativeWindowType; -#else -typedef HDC EGLNativeDisplayType; -typedef HWND EGLNativeWindowType; #endif #elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ @@ -110,6 +109,14 @@ typedef Display *EGLNativeDisplayType; typedef Pixmap EGLNativePixmapType; typedef Window EGLNativeWindowType; +#elif defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) ) + +// TODO(jmadill): native implementation for OSX + +typedef void *EGLNativeDisplayType; +typedef void *EGLNativePixmapType; +typedef void *EGLNativeWindowType; + #else #error "Platform not recognized" #endif diff --git a/src/3rdparty/angle/include/GLSLANG/ShaderLang.h b/src/3rdparty/angle/include/GLSLANG/ShaderLang.h index 647fed6a02..126205af2c 100644 --- a/src/3rdparty/angle/include/GLSLANG/ShaderLang.h +++ b/src/3rdparty/angle/include/GLSLANG/ShaderLang.h @@ -3,8 +3,8 @@ // 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_ +#ifndef GLSLANG_SHADERLANG_H_ +#define GLSLANG_SHADERLANG_H_ #if defined(COMPONENT_BUILD) && !defined(ANGLE_TRANSLATOR_STATIC) #if defined(_WIN32) || defined(_WIN64) @@ -48,7 +48,7 @@ typedef unsigned int GLenum; // Version number for shader translation API. // It is incremented every time the API changes. -#define ANGLE_SH_VERSION 132 +#define ANGLE_SH_VERSION 134 typedef enum { SH_GLES2_SPEC = 0x8B40, @@ -81,11 +81,16 @@ typedef enum { } ShShaderSpec; typedef enum { - SH_ESSL_OUTPUT = 0x8B45, - SH_GLSL_OUTPUT = 0x8B46, - SH_HLSL_OUTPUT = 0x8B47, - SH_HLSL9_OUTPUT = 0x8B47, - SH_HLSL11_OUTPUT = 0x8B48 + SH_ESSL_OUTPUT = 0x8B45, + // SH_GLSL_OUTPUT is deprecated. This is to not break the build. + SH_GLSL_OUTPUT = 0x8B46, + SH_GLSL_COMPATIBILITY_OUTPUT = 0x8B46, + SH_GLSL_CORE_OUTPUT = 0x8B47, + + // HLSL output only supported in some configurations. + SH_HLSL_OUTPUT = 0x8B48, + SH_HLSL9_OUTPUT = 0x8B48, + SH_HLSL11_OUTPUT = 0x8B49 } ShShaderOutput; // Compile options. @@ -223,6 +228,10 @@ typedef struct int EXT_draw_buffers; int EXT_frag_depth; int EXT_shader_texture_lod; + int WEBGL_debug_shader_precision; + int EXT_shader_framebuffer_fetch; + int NV_shader_framebuffer_fetch; + int ARM_shader_framebuffer_fetch; // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate @@ -290,7 +299,8 @@ COMPILER_EXPORT const std::string &ShGetBuiltInResourcesString(const ShHandle ha // 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, -// SH_HLSL9_OUTPUT or SH_HLSL11_OUTPUT. +// SH_HLSL9_OUTPUT or SH_HLSL11_OUTPUT. Note: HLSL output is only +// supported in some configurations. // resources: Specifies the built-in resources. COMPILER_EXPORT ShHandle ShConstructCompiler( sh::GLenum type, @@ -408,4 +418,4 @@ COMPILER_EXPORT bool ShGetUniformRegister(const ShHandle handle, const std::string &uniformName, unsigned int *indexOut); -#endif // _COMPILER_INTERFACE_INCLUDED_ +#endif // GLSLANG_SHADERLANG_H_ diff --git a/src/3rdparty/angle/include/GLSLANG/ShaderVars.h b/src/3rdparty/angle/include/GLSLANG/ShaderVars.h index da21c3e76e..4128c343f8 100644 --- a/src/3rdparty/angle/include/GLSLANG/ShaderVars.h +++ b/src/3rdparty/angle/include/GLSLANG/ShaderVars.h @@ -7,8 +7,8 @@ // Types to represent GL variables (varyings, uniforms, etc) // -#ifndef _COMPILER_INTERFACE_VARIABLES_ -#define _COMPILER_INTERFACE_VARIABLES_ +#ifndef GLSLANG_SHADERVARS_H_ +#define GLSLANG_SHADERVARS_H_ #include #include @@ -28,6 +28,9 @@ enum InterpolationType INTERPOLATION_FLAT }; +// Validate link & SSO consistency of interpolation qualifiers +COMPILER_EXPORT bool InterpolationTypesMatch(InterpolationType a, InterpolationType b); + // Uniform block layout qualifier, see section 4.3.8.3 of the ESSL 3.00.4 spec enum BlockLayoutType { @@ -182,4 +185,4 @@ struct COMPILER_EXPORT InterfaceBlock } -#endif // _COMPILER_INTERFACE_VARIABLES_ +#endif // GLSLANG_SHADERVARS_H_ diff --git a/src/3rdparty/angle/include/KHR/khrplatform.h b/src/3rdparty/angle/include/KHR/khrplatform.h old mode 100644 new mode 100755 index 1ac2d3f324..c9e6f17d34 --- a/src/3rdparty/angle/include/KHR/khrplatform.h +++ b/src/3rdparty/angle/include/KHR/khrplatform.h @@ -97,7 +97,7 @@ *------------------------------------------------------------------------- * This precedes the return type of the function in the function prototype. */ -#if defined(_WIN32) && !defined(__SCITECH_SNAP__) && !defined(QT_OPENGL_ES_2_ANGLE_STATIC) +#if defined(_WIN32) && !defined(__SCITECH_SNAP__) # define KHRONOS_APICALL __declspec(dllimport) #elif defined (__SYMBIAN32__) # define KHRONOS_APICALL IMPORT_C diff --git a/src/3rdparty/angle/include/angle_gl.h b/src/3rdparty/angle/include/angle_gl.h index d093f75ee2..e7ecdbd2f0 100644 --- a/src/3rdparty/angle/include/angle_gl.h +++ b/src/3rdparty/angle/include/angle_gl.h @@ -7,8 +7,8 @@ // Includes all necessary GL headers and definitions for ANGLE. // -#ifndef ANGLE_GL_H_ -#define ANGLE_GL_H_ +#ifndef ANGLEGL_H_ +#define ANGLEGL_H_ #include "GLES2/gl2.h" #include "GLES2/gl2ext.h" @@ -20,4 +20,4 @@ #define GL_SAMPLER_2D_RECT_ARB 0x8B63 #endif -#endif // ANGLE_GL_H_ +#endif // ANGLEGL_H_ diff --git a/src/3rdparty/angle/include/export.h b/src/3rdparty/angle/include/export.h new file mode 100644 index 0000000000..cdf6245d6d --- /dev/null +++ b/src/3rdparty/angle/include/export.h @@ -0,0 +1,28 @@ +// +// Copyright(c) 2014 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. +// + +// export.h : Defines ANGLE_EXPORT, a macro for exporting functions from the DLL + +#ifndef LIBGLESV2_EXPORT_H_ +#define LIBGLESV2_EXPORT_H_ + +#if defined(_WIN32) +# if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) +# define ANGLE_EXPORT __declspec(dllexport) +# else +# define ANGLE_EXPORT __declspec(dllimport) +# endif +#elif defined(__GNUC__) +# if defined(LIBGLESV2_IMPLEMENTATION) || defined(LIBANGLE_IMPLEMENTATION) +# define ANGLE_EXPORT __attribute__((visibility ("default"))) +# else +# define ANGLE_EXPORT +# endif +#else +# define ANGLE_EXPORT +#endif + +#endif // LIBGLESV2_EXPORT_H_ diff --git a/src/3rdparty/angle/include/platform/Platform.h b/src/3rdparty/angle/include/platform/Platform.h new file mode 100644 index 0000000000..d915d5c0fd --- /dev/null +++ b/src/3rdparty/angle/include/platform/Platform.h @@ -0,0 +1,112 @@ +// +// Copyright (c) 2015 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. + +// Platform.h: The public interface ANGLE exposes to the API layer, for +// doing platform-specific tasks like gathering data, or for tracing. + +#ifndef ANGLE_PLATFORM_H +#define ANGLE_PLATFORM_H + +#include + +#include "../export.h" + +namespace angle +{ + +class Platform +{ + public: + + // Tracing -------- + + typedef uint64_t TraceEventHandle; + + // Add a trace event to the platform tracing system. Depending on the actual + // enabled state, this event may be recorded or dropped. + // - phase specifies the type of event: + // - BEGIN ('B'): Marks the beginning of a scoped event. + // - END ('E'): Marks the end of a scoped event. + // - COMPLETE ('X'): Marks the beginning of a scoped event, but doesn't + // need a matching END event. Instead, at the end of the scope, + // updateTraceEventDuration() must be called with the TraceEventHandle + // returned from addTraceEvent(). + // - INSTANT ('I'): Standalone, instantaneous event. + // - START ('S'): Marks the beginning of an asynchronous event (the end + // event can occur in a different scope or thread). The id parameter is + // used to match START/FINISH pairs. + // - FINISH ('F'): Marks the end of an asynchronous event. + // - COUNTER ('C'): Used to trace integer quantities that change over + // time. The argument values are expected to be of type int. + // - METADATA ('M'): Reserved for internal use. + // - categoryEnabled is the pointer returned by getTraceCategoryEnabledFlag. + // - name is the name of the event. Also used to match BEGIN/END and + // START/FINISH pairs. + // - id optionally allows events of the same name to be distinguished from + // each other. For example, to trace the consutruction and destruction of + // objects, specify the pointer as the id parameter. + // - numArgs specifies the number of elements in argNames, argTypes, and + // argValues. + // - argNames is the array of argument names. Use long-lived literal strings + // or specify the COPY flag. + // - argTypes is the array of argument types: + // - BOOL (1): bool + // - UINT (2): unsigned long long + // - INT (3): long long + // - DOUBLE (4): double + // - POINTER (5): void* + // - STRING (6): char* (long-lived null-terminated char* string) + // - COPY_STRING (7): char* (temporary null-terminated char* string) + // - CONVERTABLE (8): WebConvertableToTraceFormat + // - argValues is the array of argument values. Each value is the unsigned + // long long member of a union of all supported types. + // - flags can be 0 or one or more of the following, ORed together: + // - COPY (0x1): treat all strings (name, argNames and argValues of type + // string) as temporary so that they will be copied by addTraceEvent. + // - HAS_ID (0x2): use the id argument to uniquely identify the event for + // matching with other events of the same name. + // - MANGLE_ID (0x4): specify this flag if the id parameter is the value + // of a pointer. + virtual TraceEventHandle addTraceEvent(char phase, + const unsigned char *categoryEnabledFlag, + const char *name, + unsigned long long id, + double timestamp, + int numArgs, + const char **argNames, + const unsigned char *argTypes, + const unsigned long long *argValues, + unsigned char flags) + { + return 0; + } + + // Set the duration field of a COMPLETE trace event. + virtual void updateTraceEventDuration(const unsigned char* categoryEnabledFlag, const char* name, TraceEventHandle) { } + + // Callbacks for reporting histogram data. + // CustomCounts histogram has exponential bucket sizes, so that min=1, max=1000000, bucketCount=50 would do. + virtual void histogramCustomCounts(const char* name, int sample, int min, int max, int bucketCount) { } + // Enumeration histogram buckets are linear, boundaryValue should be larger than any possible sample value. + virtual void histogramEnumeration(const char* name, int sample, int boundaryValue) { } + // Unlike enumeration histograms, sparse histograms only allocate memory for non-empty buckets. + virtual void histogramSparse(const char* name, int sample) { } + + protected: + virtual ~Platform() { } +}; + +} + +typedef void(*ANGLEPlatformInitializeFunc)(angle::Platform*); +ANGLE_EXPORT void ANGLEPlatformInitialize(angle::Platform*); + +typedef void (*ANGLEPlatformShutdownFunc)(); +ANGLE_EXPORT void ANGLEPlatformShutdown(); + +typedef angle::Platform *(*ANGLEPlatformCurrentFunc)(); +ANGLE_EXPORT angle::Platform *ANGLEPlatformCurrent(); + +#endif // ANGLE_PLATFORM_H diff --git a/src/3rdparty/angle/src/commit.h b/src/3rdparty/angle/src/commit.h deleted file mode 100644 index 08fc893c25..0000000000 --- a/src/3rdparty/angle/src/commit.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Copyright (c) 2014 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. -// -// commit.h: -// This is a default commit hash header, when git is not available. -// - -#define ANGLE_COMMIT_HASH "30d6c255d238" -#define ANGLE_COMMIT_HASH_SIZE 12 -#define ANGLE_COMMIT_DATE "2014-11-13 17:37:03 +0000" diff --git a/src/3rdparty/angle/src/common/MemoryBuffer.cpp b/src/3rdparty/angle/src/common/MemoryBuffer.cpp new file mode 100644 index 0000000000..e7a3fb4a2b --- /dev/null +++ b/src/3rdparty/angle/src/common/MemoryBuffer.cpp @@ -0,0 +1,80 @@ +// +// Copyright (c) 2014 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 "common/MemoryBuffer.h" + +#include +#include + +#include "common/debug.h" + +namespace rx +{ + +MemoryBuffer::MemoryBuffer() + : mSize(0), + mData(NULL) +{ +} + +MemoryBuffer::~MemoryBuffer() +{ + free(mData); + mData = NULL; +} + +bool MemoryBuffer::resize(size_t size) +{ + if (size == 0) + { + free(mData); + mData = NULL; + mSize = 0; + return true; + } + + if (size == mSize) + { + return true; + } + + // Only reallocate if the size has changed. + uint8_t *newMemory = reinterpret_cast(malloc(sizeof(uint8_t) * size)); + if (newMemory == NULL) + { + return false; + } + + if (mData) + { + // Copy the intersection of the old data and the new data + std::copy(mData, mData + std::min(mSize, size), newMemory); + free(mData); + } + + mData = newMemory; + mSize = size; + + return true; +} + +size_t MemoryBuffer::size() const +{ + return mSize; +} + +const uint8_t *MemoryBuffer::data() const +{ + return mData; +} + +uint8_t *MemoryBuffer::data() +{ + ASSERT(mData); + return mData; +} + +} diff --git a/src/3rdparty/angle/src/common/MemoryBuffer.h b/src/3rdparty/angle/src/common/MemoryBuffer.h new file mode 100644 index 0000000000..ec621cbca7 --- /dev/null +++ b/src/3rdparty/angle/src/common/MemoryBuffer.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 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_MEMORYBUFFER_H_ +#define COMMON_MEMORYBUFFER_H_ + +#include "common/angleutils.h" + +#include +#include + +namespace rx +{ + +class MemoryBuffer : angle::NonCopyable +{ + public: + MemoryBuffer(); + ~MemoryBuffer(); + + bool resize(size_t size); + size_t size() const; + bool empty() const { return mSize == 0; } + + const uint8_t *data() const; + uint8_t *data(); + + private: + size_t mSize; + uint8_t *mData; +}; + +} + +#endif // COMMON_MEMORYBUFFER_H_ diff --git a/src/3rdparty/angle/src/common/NativeWindow.h b/src/3rdparty/angle/src/common/NativeWindow.h deleted file mode 100644 index c4a0e42bcc..0000000000 --- a/src/3rdparty/angle/src/common/NativeWindow.h +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// NativeWindow.h: Defines NativeWindow, a class for managing and -// performing operations on an EGLNativeWindowType. -// It is used for HWND (Desktop Windows) and IInspectable objects -//(Windows Store Applications). - -#ifndef COMMON_NATIVEWINDOW_H_ -#define COMMON_NATIVEWINDOW_H_ - -#include -#include "common/debug.h" -#include "common/platform.h" - -// DXGISwapChain and DXGIFactory are typedef'd to specific required -// types. The HWND NativeWindow implementation requires IDXGISwapChain -// and IDXGIFactory and the Windows Store NativeWindow -// implementation requires IDXGISwapChain1 and IDXGIFactory2. -#if defined(ANGLE_ENABLE_WINDOWS_STORE) -typedef IDXGISwapChain1 DXGISwapChain; -typedef IDXGIFactory2 DXGIFactory; - -#include -#include -#include -#include - -namespace rx -{ -class InspectableNativeWindow; -} - -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; - -#else -typedef IDXGISwapChain DXGISwapChain; -typedef IDXGIFactory DXGIFactory; -#endif - -namespace rx -{ - -class NativeWindow -{ -public: - explicit NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display); - - bool initialize(); - bool getClientRect(LPRECT rect); - bool isIconic(); - -# if defined(ANGLE_ENABLE_D3D11) - typedef ID3D11Device Device; -#else - typedef IDirect3DDevice9 Device; -#endif - HRESULT createSwapChain(Device* device, DXGIFactory* factory, - DXGI_FORMAT format, UINT width, UINT height, - DXGISwapChain** swapChain); - - inline EGLNativeWindowType getNativeWindow() const { return mWindow; } - inline EGLNativeDisplayType getNativeDisplay() const { return mDisplay; } - - private: - EGLNativeWindowType mWindow; - EGLNativeDisplayType mDisplay; - -#if defined(ANGLE_ENABLE_WINDOWS_STORE) - std::shared_ptr mImpl; -#endif - -}; - -bool IsValidEGLNativeWindowType(EGLNativeWindowType window); -} - -#endif // COMMON_NATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/common/Optional.h b/src/3rdparty/angle/src/common/Optional.h new file mode 100644 index 0000000000..9665b7ddf6 --- /dev/null +++ b/src/3rdparty/angle/src/common/Optional.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2015 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. +// +// Optional.h: +// Represents a type that may be invalid, similar to std::optional. +// + +#ifndef COMMON_OPTIONAL_H_ +#define COMMON_OPTIONAL_H_ + +template +struct Optional +{ + Optional() + : mValid(false), + mValue(T()) + {} + + explicit Optional(const T &valueIn) + : mValid(true), + mValue(valueIn) + {} + + Optional(const Optional &other) + : mValid(other.mValid), + mValue(other.mValue) + {} + + Optional &operator=(const Optional &other) + { + this->mValid = other.mValid; + this->mValue = other.mValue; + return *this; + } + + static Optional None() + { + return Optional(); + } + + bool valid() const { return mValid; } + const T &value() const { return mValue; } + + bool operator==(const Optional &other) const + { + return ((mValid == other.mValid) && (!mValid || (mValue == other.mValue))); + } + + bool operator!=(const Optional &other) const + { + return !(*this == other); + } + + private: + bool mValid; + T mValue; +}; + +#endif // COMMON_OPTIONAL_H_ diff --git a/src/3rdparty/angle/src/common/RefCountObject.cpp b/src/3rdparty/angle/src/common/RefCountObject.cpp deleted file mode 100644 index c1ef90cdcc..0000000000 --- a/src/3rdparty/angle/src/common/RefCountObject.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// -// 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 deleted file mode 100644 index 6eeaee1928..0000000000 --- a/src/3rdparty/angle/src/common/RefCountObject.h +++ /dev/null @@ -1,95 +0,0 @@ -// -// 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 "common/debug.h" - -#include "angle_gl.h" - -#include - -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(); } -}; - -template -class OffsetBindingPointer : public RefCountObjectBindingPointer -{ - public: - OffsetBindingPointer() : mOffset(0), mSize(0) { } - - void set(ObjectType *newObject) - { - RefCountObjectBindingPointer::set(newObject); - mOffset = 0; - mSize = 0; - } - - void set(ObjectType *newObject, GLintptr offset, GLsizeiptr size) - { - RefCountObjectBindingPointer::set(newObject); - mOffset = offset; - mSize = size; - } - - GLintptr getOffset() const { return mOffset; } - GLsizeiptr getSize() const { return mSize; } - - ObjectType *get() const { return static_cast(RefCountObjectBindingPointer::get()); } - ObjectType *operator->() const { return get(); } - - private: - GLintptr mOffset; - GLsizeiptr mSize; -}; - -#endif // COMMON_REFCOUNTOBJECT_H_ diff --git a/src/3rdparty/angle/src/common/angleutils.cpp b/src/3rdparty/angle/src/common/angleutils.cpp index c1367c460a..af5eb6c447 100644 --- a/src/3rdparty/angle/src/common/angleutils.cpp +++ b/src/3rdparty/angle/src/common/angleutils.cpp @@ -5,7 +5,8 @@ // #include "common/angleutils.h" -#include "debug.h" +#include "common/debug.h" + #include #include diff --git a/src/3rdparty/angle/src/common/angleutils.h b/src/3rdparty/angle/src/common/angleutils.h index b343ece5bc..4cf84a3182 100644 --- a/src/3rdparty/angle/src/common/angleutils.h +++ b/src/3rdparty/angle/src/common/angleutils.h @@ -11,19 +11,31 @@ #include "common/platform.h" -#include -#include +#include +#include +#include #include #include #include -#include #include -// 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&) +// A helper class to disallow copy and assignment operators +namespace angle +{ + +class NonCopyable +{ +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) + public: + NonCopyable() = default; + ~NonCopyable() = default; + protected: + NonCopyable(const NonCopyable&) = delete; + void operator=(const NonCopyable&) = delete; +#endif +}; + +} template inline size_t ArraySize(T(&)[N]) @@ -150,13 +162,12 @@ std::string FormatString(const char *fmt, ...); #define snprintf _snprintf #endif -#define VENDOR_ID_AMD 0x1002 -#define VENDOR_ID_INTEL 0x8086 -#define VENDOR_ID_NVIDIA 0x10DE - #define GL_BGRA4_ANGLEX 0x6ABC #define GL_BGR5_A1_ANGLEX 0x6ABD #define GL_INT_64_ANGLEX 0x6ABE #define GL_STRUCT_ANGLEX 0x6ABF +// Hidden enum for the NULL D3D device type. +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE 0x6AC0 + #endif // COMMON_ANGLEUTILS_H_ diff --git a/src/3rdparty/angle/src/common/blocklayout.cpp b/src/3rdparty/angle/src/common/blocklayout.cpp deleted file mode 100644 index e3b2d43566..0000000000 --- a/src/3rdparty/angle/src/common/blocklayout.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// -// blocklayout.cpp: -// Implementation for block layout classes and methods. -// - -#include "common/blocklayout.h" -#include "common/mathutil.h" -#include "common/utilities.h" - -namespace sh -{ - -BlockLayoutEncoder::BlockLayoutEncoder() - : mCurrentOffset(0) -{ -} - -BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix) -{ - int arrayStride; - int matrixStride; - - getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride); - - const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix); - - advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride); - - return memberInfo; -} - -void BlockLayoutEncoder::nextRegister() -{ - mCurrentOffset = rx::roundUp(mCurrentOffset, ComponentsPerRegister); -} - -Std140BlockEncoder::Std140BlockEncoder() -{ -} - -void Std140BlockEncoder::enterAggregateType() -{ - nextRegister(); -} - -void Std140BlockEncoder::exitAggregateType() -{ - nextRegister(); -} - -void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) -{ - // We assume we are only dealing with 4 byte components (no doubles or half-words currently) - ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); - - size_t baseAlignment = 0; - int matrixStride = 0; - int arrayStride = 0; - - if (gl::IsMatrixType(type)) - { - baseAlignment = ComponentsPerRegister; - matrixStride = ComponentsPerRegister; - - if (arraySize > 0) - { - const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); - arrayStride = ComponentsPerRegister * numRegisters; - } - } - else if (arraySize > 0) - { - baseAlignment = ComponentsPerRegister; - arrayStride = ComponentsPerRegister; - } - else - { - const int numComponents = gl::VariableComponentCount(type); - baseAlignment = (numComponents == 3 ? 4u : static_cast(numComponents)); - } - - mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment); - - *matrixStrideOut = matrixStride; - *arrayStrideOut = arrayStride; -} - -void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) -{ - if (arraySize > 0) - { - mCurrentOffset += arrayStride * arraySize; - } - else if (gl::IsMatrixType(type)) - { - ASSERT(matrixStride == ComponentsPerRegister); - const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); - mCurrentOffset += ComponentsPerRegister * numRegisters; - } - else - { - mCurrentOffset += gl::VariableComponentCount(type); - } -} - -HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy) - : mEncoderStrategy(strategy) -{ -} - -void HLSLBlockEncoder::enterAggregateType() -{ - nextRegister(); -} - -void HLSLBlockEncoder::exitAggregateType() -{ -} - -void HLSLBlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) -{ - // We assume we are only dealing with 4 byte components (no doubles or half-words currently) - ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); - - int matrixStride = 0; - int arrayStride = 0; - - // if variables are not to be packed, or we're about to - // pack a matrix or array, skip to the start of the next - // register - if (!isPacked() || - gl::IsMatrixType(type) || - arraySize > 0) - { - nextRegister(); - } - - if (gl::IsMatrixType(type)) - { - matrixStride = ComponentsPerRegister; - - if (arraySize > 0) - { - const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); - arrayStride = ComponentsPerRegister * numRegisters; - } - } - else if (arraySize > 0) - { - arrayStride = ComponentsPerRegister; - } - else if (isPacked()) - { - int numComponents = gl::VariableComponentCount(type); - if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister) - { - nextRegister(); - } - } - - *matrixStrideOut = matrixStride; - *arrayStrideOut = arrayStride; -} - -void HLSLBlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) -{ - if (arraySize > 0) - { - mCurrentOffset += arrayStride * (arraySize - 1); - } - - if (gl::IsMatrixType(type)) - { - ASSERT(matrixStride == ComponentsPerRegister); - const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); - const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix); - mCurrentOffset += ComponentsPerRegister * (numRegisters - 1); - mCurrentOffset += numComponents; - } - else if (isPacked()) - { - mCurrentOffset += gl::VariableComponentCount(type); - } - else - { - mCurrentOffset += ComponentsPerRegister; - } -} - -void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters) -{ - mCurrentOffset += (numRegisters * ComponentsPerRegister); -} - -HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShShaderOutput outputType) -{ - switch (outputType) - { - case SH_HLSL9_OUTPUT: return ENCODE_LOOSE; - case SH_HLSL11_OUTPUT: return ENCODE_PACKED; - default: UNREACHABLE(); return ENCODE_PACKED; - } -} - -template -void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder) -{ - if (variable.isStruct()) - { - for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++) - { - encoder->enterAggregateType(); - - for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++) - { - HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder); - } - - encoder->exitAggregateType(); - } - } - else - { - // We operate only on varyings and uniforms, which do not have matrix layout qualifiers - encoder->encodeType(variable.type, variable.arraySize, false); - } -} - -unsigned int HLSLVariableRegisterCount(const Varying &variable) -{ - HLSLBlockEncoder encoder(HLSLBlockEncoder::ENCODE_PACKED); - HLSLVariableRegisterCount(variable, &encoder); - - const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); - return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / registerBytes); -} - -unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType) -{ - HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType)); - HLSLVariableRegisterCount(variable, &encoder); - - const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); - return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / registerBytes); -} - -} diff --git a/src/3rdparty/angle/src/common/blocklayout.h b/src/3rdparty/angle/src/common/blocklayout.h deleted file mode 100644 index d46ac6e547..0000000000 --- a/src/3rdparty/angle/src/common/blocklayout.h +++ /dev/null @@ -1,127 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// -// blocklayout.h: -// Methods and classes related to uniform layout and packing in GLSL and HLSL. -// - -#ifndef COMMON_BLOCKLAYOUT_H_ -#define COMMON_BLOCKLAYOUT_H_ - -#include -#include - -#include "angle_gl.h" -#include - -namespace sh -{ -struct ShaderVariable; -struct InterfaceBlockField; -struct Uniform; -struct Varying; -struct InterfaceBlock; - -struct BlockMemberInfo -{ - BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) - : offset(offset), - arrayStride(arrayStride), - matrixStride(matrixStride), - isRowMajorMatrix(isRowMajorMatrix) - {} - - static BlockMemberInfo getDefaultBlockInfo() - { - return BlockMemberInfo(-1, -1, -1, false); - } - - int offset; - int arrayStride; - int matrixStride; - bool isRowMajorMatrix; -}; - -class BlockLayoutEncoder -{ - public: - BlockLayoutEncoder(); - - BlockMemberInfo encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix); - - size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; } - size_t getCurrentRegister() const { return mCurrentOffset / ComponentsPerRegister; } - size_t getCurrentElement() const { return mCurrentOffset % ComponentsPerRegister; } - - virtual void enterAggregateType() = 0; - virtual void exitAggregateType() = 0; - - static const size_t BytesPerComponent = 4u; - static const unsigned int ComponentsPerRegister = 4u; - - protected: - size_t mCurrentOffset; - - void nextRegister(); - - virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; - virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; -}; - -// Block layout according to the std140 block layout -// See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification - -class Std140BlockEncoder : public BlockLayoutEncoder -{ - public: - Std140BlockEncoder(); - - virtual void enterAggregateType(); - virtual void exitAggregateType(); - - protected: - virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut); - virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride); -}; - -// Block layout packed according to the D3D9 or default D3D10+ register packing rules -// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx -// The strategy should be ENCODE_LOOSE for D3D9 constant blocks, and ENCODE_PACKED -// for everything else (D3D10+ constant blocks and all attributes/varyings). - -class HLSLBlockEncoder : public BlockLayoutEncoder -{ - public: - enum HLSLBlockEncoderStrategy - { - ENCODE_PACKED, - ENCODE_LOOSE - }; - - HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy); - - virtual void enterAggregateType(); - virtual void exitAggregateType(); - void skipRegisters(unsigned int numRegisters); - - bool isPacked() const { return mEncoderStrategy == ENCODE_PACKED; } - - static HLSLBlockEncoderStrategy GetStrategyFor(ShShaderOutput outputType); - - protected: - virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut); - virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride); - - HLSLBlockEncoderStrategy mEncoderStrategy; -}; - -// This method returns the number of used registers for a ShaderVariable. It is dependent on the HLSLBlockEncoder -// class to count the number of used registers in a struct (which are individually packed according to the same rules). -unsigned int HLSLVariableRegisterCount(const Varying &variable); -unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType); - -} - -#endif // COMMON_BLOCKLAYOUT_H_ diff --git a/src/3rdparty/angle/src/common/debug.cpp b/src/3rdparty/angle/src/common/debug.cpp index 5f55ff1e39..2fc0a2984a 100644 --- a/src/3rdparty/angle/src/common/debug.cpp +++ b/src/3rdparty/angle/src/common/debug.cpp @@ -17,172 +17,9 @@ namespace gl { -#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) -// Wraps the D3D9/D3D11 debug annotation functions. -class DebugAnnotationWrapper -{ - public: - DebugAnnotationWrapper() { }; - virtual ~DebugAnnotationWrapper() { }; - virtual void beginEvent(const std::wstring &eventName) = 0; - virtual void endEvent() = 0; - virtual void setMarker(const std::wstring &markerName) = 0; - virtual bool getStatus() = 0; -}; -#if defined(ANGLE_ENABLE_D3D9) -class D3D9DebugAnnotationWrapper : public DebugAnnotationWrapper +namespace { - public: - void beginEvent(const std::wstring &eventName) - { - D3DPERF_BeginEvent(0, eventName.c_str()); - } - - void endEvent() - { - D3DPERF_EndEvent(); - } - - void setMarker(const std::wstring &markerName) - { - D3DPERF_SetMarker(0, markerName.c_str()); - } - - bool getStatus() - { - return !!D3DPERF_GetStatus(); - } -}; -#endif // ANGLE_ENABLE_D3D9 - -#if defined(ANGLE_ENABLE_D3D11) -class D3D11DebugAnnotationWrapper : public DebugAnnotationWrapper -{ - public: - - D3D11DebugAnnotationWrapper() - : mInitialized(false), - mD3d11Module(NULL), - mUserDefinedAnnotation(NULL) - { - // D3D11 devices can't be created during DllMain. - // We defer device creation until the object is actually used. - } - - ~D3D11DebugAnnotationWrapper() - { - if (mInitialized) - { - SafeRelease(mUserDefinedAnnotation); - FreeLibrary(mD3d11Module); - } - } - - virtual void beginEvent(const std::wstring &eventName) - { - initializeDevice(); - - mUserDefinedAnnotation->BeginEvent(eventName.c_str()); - } - - virtual void endEvent() - { - initializeDevice(); - - mUserDefinedAnnotation->EndEvent(); - } - - virtual void setMarker(const std::wstring &markerName) - { - initializeDevice(); - - mUserDefinedAnnotation->SetMarker(markerName.c_str()); - } - - virtual bool getStatus() - { - // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013. - -#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE) - // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture. - // This should only be called in DEBUG mode. - // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks. - IDXGraphicsAnalysis* graphicsAnalysis; - DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis)); - bool underCapture = (graphicsAnalysis != NULL); - SafeRelease(graphicsAnalysis); - return underCapture; -#endif - - // Otherwise, we have to return true here. - return true; - } - - protected: - - void initializeDevice() - { - if (!mInitialized) - { -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); - ASSERT(mD3d11Module); - - PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); - ASSERT(D3D11CreateDevice != NULL); -#endif // !ANGLE_ENABLE_WINDOWS_STORE - - ID3D11Device* device = NULL; - ID3D11DeviceContext* context = NULL; - - HRESULT hr = E_FAIL; - - // Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device. - hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context); - ASSERT(SUCCEEDED(hr)); - - hr = context->QueryInterface(__uuidof(mUserDefinedAnnotation), reinterpret_cast(&mUserDefinedAnnotation)); - ASSERT(SUCCEEDED(hr) && mUserDefinedAnnotation != NULL); - - SafeRelease(device); - SafeRelease(context); - - mInitialized = true; - } - } - - bool mInitialized; - HMODULE mD3d11Module; - ID3DUserDefinedAnnotation* mUserDefinedAnnotation; -}; -#endif // ANGLE_ENABLE_D3D11 - -static DebugAnnotationWrapper* g_DebugAnnotationWrapper = NULL; - -void InitializeDebugAnnotations() -{ -#if defined(ANGLE_ENABLE_D3D9) - g_DebugAnnotationWrapper = new D3D9DebugAnnotationWrapper(); -#elif defined(ANGLE_ENABLE_D3D11) - // If the project uses D3D9 then we can use the D3D9 debug annotations, even with the D3D11 renderer. - // However, if D3D9 is unavailable (e.g. in Windows Store), then we use D3D11 debug annotations. - // The D3D11 debug annotations are methods on ID3DUserDefinedAnnotation, which is implemented by the DeviceContext. - // This doesn't have to be the same DeviceContext that the renderer uses, though. - g_DebugAnnotationWrapper = new D3D11DebugAnnotationWrapper(); -#endif -} - -void UninitializeDebugAnnotations() -{ - if (g_DebugAnnotationWrapper != NULL) - { - SafeDelete(g_DebugAnnotationWrapper); - } -} - -#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS - enum DebugTraceOutputType { DebugTraceOutputTypeNone, @@ -190,29 +27,44 @@ enum DebugTraceOutputType DebugTraceOutputTypeBeginEvent }; -static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const char *format, va_list vararg) -{ -#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) - static std::vector buffer(512); +DebugAnnotator *g_debugAnnotator = nullptr; - if (perfActive()) +void output(bool traceInDebugOnly, MessageType messageType, DebugTraceOutputType outputType, + const char *format, va_list vararg) +{ + if (DebugAnnotationsActive()) { + static std::vector buffer(512); size_t len = FormatStringIntoVector(format, vararg, buffer); std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len); + ASSERT(g_debugAnnotator != nullptr); switch (outputType) { - case DebugTraceOutputTypeNone: - break; - case DebugTraceOutputTypeBeginEvent: - g_DebugAnnotationWrapper->beginEvent(formattedWideMessage); - break; - case DebugTraceOutputTypeSetMarker: - g_DebugAnnotationWrapper->setMarker(formattedWideMessage); - break; + case DebugTraceOutputTypeNone: + break; + case DebugTraceOutputTypeBeginEvent: + g_debugAnnotator->beginEvent(formattedWideMessage); + break; + case DebugTraceOutputTypeSetMarker: + g_debugAnnotator->setMarker(formattedWideMessage); + break; } } -#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS + + std::string formattedMessage; + UNUSED_TRACE_VARIABLE(formattedMessage); + +#if !defined(NDEBUG) && defined(_MSC_VER) + if (messageType == MESSAGE_ERR) + { + if (formattedMessage.empty()) + { + formattedMessage = FormatString(format, vararg); + } + OutputDebugStringA(formattedMessage.c_str()); + } +#endif #if defined(ANGLE_ENABLE_DEBUG_TRACE) #if defined(NDEBUG) @@ -221,7 +73,10 @@ static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const return; } #endif // NDEBUG - std::string formattedMessage = FormatString(format, vararg); + if (formattedMessage.empty()) + { + formattedMessage = FormatString(format, vararg); + } static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app); if (file) @@ -237,53 +92,57 @@ static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const #endif // ANGLE_ENABLE_DEBUG_TRACE } -void trace(bool traceInDebugOnly, const char *format, ...) +} // namespace + +bool DebugAnnotationsActive() { - va_list vararg; - va_start(vararg, format); #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) - output(traceInDebugOnly, DebugTraceOutputTypeSetMarker, format, vararg); + return g_debugAnnotator != nullptr && g_debugAnnotator->getStatus(); #else - output(traceInDebugOnly, DebugTraceOutputTypeNone, format, vararg); + return false; #endif - va_end(vararg); } -bool perfActive() +void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator) { -#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) - static bool active = g_DebugAnnotationWrapper->getStatus(); - return active; -#else - return false; -#endif + UninitializeDebugAnnotations(); + g_debugAnnotator = debugAnnotator; +} + +void UninitializeDebugAnnotations() +{ + // Pointer is not managed. + g_debugAnnotator = nullptr; +} + +void trace(bool traceInDebugOnly, MessageType messageType, const char *format, ...) +{ + va_list vararg; + va_start(vararg, format); + output(traceInDebugOnly, messageType, DebugTraceOutputTypeSetMarker, format, vararg); + va_end(vararg); } ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...) { #if !defined(ANGLE_ENABLE_DEBUG_TRACE) - if (!perfActive()) + if (!DebugAnnotationsActive()) { return; } #endif // !ANGLE_ENABLE_DEBUG_TRACE va_list vararg; va_start(vararg, format); -#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) - output(true, DebugTraceOutputTypeBeginEvent, format, vararg); -#else - output(true, DebugTraceOutputTypeNone, format, vararg); -#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS + output(true, MESSAGE_EVENT, DebugTraceOutputTypeBeginEvent, format, vararg); va_end(vararg); } ScopedPerfEventHelper::~ScopedPerfEventHelper() { -#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) - if (perfActive()) + if (DebugAnnotationsActive()) { - g_DebugAnnotationWrapper->endEvent(); + g_debugAnnotator->endEvent(); } -#endif } + } diff --git a/src/3rdparty/angle/src/common/debug.h b/src/3rdparty/angle/src/common/debug.h index c177f51314..c4f118ebae 100644 --- a/src/3rdparty/angle/src/common/debug.h +++ b/src/3rdparty/angle/src/common/debug.h @@ -9,8 +9,9 @@ #ifndef COMMON_DEBUG_H_ #define COMMON_DEBUG_H_ -#include #include +#include +#include #include "common/angleutils.h" @@ -20,50 +21,71 @@ namespace gl { - // Outputs text to the debugging log, or the debugging window - void trace(bool traceInDebugOnly, const char *format, ...); - // Returns whether D3DPERF is active. - bool perfActive(); +enum MessageType +{ + MESSAGE_TRACE, + MESSAGE_FIXME, + MESSAGE_ERR, + MESSAGE_EVENT, +}; - // Pairs a D3D begin event with an end event. - class ScopedPerfEventHelper - { - public: - ScopedPerfEventHelper(const char* format, ...); - ~ScopedPerfEventHelper(); +// Outputs text to the debugging log, or the debugging window +void trace(bool traceInDebugOnly, MessageType messageType, const char *format, ...); - private: - DISALLOW_COPY_AND_ASSIGN(ScopedPerfEventHelper); - }; +// Pairs a D3D begin event with an end event. +class ScopedPerfEventHelper : angle::NonCopyable +{ + public: + ScopedPerfEventHelper(const char* format, ...); + ~ScopedPerfEventHelper(); +}; + +// Wraps the D3D9/D3D11 debug annotation functions. +class DebugAnnotator : angle::NonCopyable +{ + public: + DebugAnnotator() { }; + virtual ~DebugAnnotator() { }; + virtual void beginEvent(const std::wstring &eventName) = 0; + virtual void endEvent() = 0; + virtual void setMarker(const std::wstring &markerName) = 0; + virtual bool getStatus() = 0; +}; + +void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator); +void UninitializeDebugAnnotations(); +bool DebugAnnotationsActive(); - void InitializeDebugAnnotations(); - void UninitializeDebugAnnotations(); } -// A macro to output a trace of a function call and its arguments to the debugging log #if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) -#define TRACE(message, ...) gl::trace(true, "trace: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#define ANGLE_TRACE_ENABLED +#endif + +// A macro to output a trace of a function call and its arguments to the debugging log +#if defined(ANGLE_TRACE_ENABLED) +#define TRACE(message, ...) gl::trace(true, gl::MESSAGE_TRACE, "trace: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) #else #define TRACE(message, ...) (void(0)) #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_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) -#define FIXME(message, ...) gl::trace(false, "fixme: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#if defined(ANGLE_TRACE_ENABLED) +#define FIXME(message, ...) gl::trace(false, gl::MESSAGE_FIXME, "fixme: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) #else #define FIXME(message, ...) (void(0)) #endif // A macro to output a function call and its arguments to the debugging log, in case of error. -#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) -#define ERR(message, ...) gl::trace(false, "err: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#if defined(ANGLE_TRACE_ENABLED) +#define ERR(message, ...) gl::trace(false, gl::MESSAGE_ERR, "err: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) #else #define ERR(message, ...) (void(0)) #endif // A macro to log a performance event around a scope. -#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) +#if defined(ANGLE_TRACE_ENABLED) #if defined(_MSC_VER) #define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__("%s" message "\n", __FUNCTION__, __VA_ARGS__); #else @@ -73,6 +95,10 @@ namespace gl #define EVENT(message, ...) (void(0)) #endif +#if defined(ANGLE_TRACE_ENABLED) +#undef ANGLE_TRACE_ENABLED +#endif + // A macro asserting a condition and outputting failures to the debug log #if !defined(NDEBUG) #define ASSERT(expression) do { \ @@ -130,14 +156,4 @@ namespace gl #define HAS_DYNAMIC_TYPE(type, obj) true #endif -// A macro functioning as a compile-time assert to validate constant conditions -#if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__GNUC__) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3)) -#define META_ASSERT_MSG(condition, msg) static_assert(condition, msg) -#else -#define META_ASSERT_CONCAT(a, b) a ## b -#define META_ASSERT_CONCAT2(a, b) META_ASSERT_CONCAT(a, b) -#define META_ASSERT_MSG(condition, msg) typedef int META_ASSERT_CONCAT2(COMPILE_TIME_ASSERT_, __LINE__)[static_cast(condition)?1:-1] -#endif -#define META_ASSERT(condition) META_ASSERT_MSG(condition, "compile time assertion failed.") - #endif // COMMON_DEBUG_H_ diff --git a/src/3rdparty/angle/src/common/event_tracer.cpp b/src/3rdparty/angle/src/common/event_tracer.cpp new file mode 100644 index 0000000000..eb0c98c9e5 --- /dev/null +++ b/src/3rdparty/angle/src/common/event_tracer.cpp @@ -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. + +#include "common/event_tracer.h" + +namespace gl +{ + +GetCategoryEnabledFlagFunc g_getCategoryEnabledFlag; +AddTraceEventFunc g_addTraceEvent; + +} // namespace gl + +namespace gl +{ + +const unsigned char* TraceGetTraceCategoryEnabledFlag(const char* name) +{ + if (g_getCategoryEnabledFlag) + { + return g_getCategoryEnabledFlag(name); + } + static unsigned char disabled = 0; + return &disabled; +} + +void TraceAddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, unsigned long long id, + int numArgs, const char** argNames, const unsigned char* argTypes, + const unsigned long long* argValues, unsigned char flags) +{ + if (g_addTraceEvent) + { + g_addTraceEvent(phase, categoryGroupEnabled, name, id, numArgs, argNames, argTypes, argValues, flags); + } +} + +} // namespace gl diff --git a/src/3rdparty/angle/src/common/event_tracer.h b/src/3rdparty/angle/src/common/event_tracer.h new file mode 100644 index 0000000000..dbe4c1bef9 --- /dev/null +++ b/src/3rdparty/angle/src/common/event_tracer.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 COMMON_EVENT_TRACER_H_ +#define COMMON_EVENT_TRACER_H_ + +#include "common/platform.h" + +extern "C" { + +typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name); +typedef void (*AddTraceEventFunc)(char phase, const unsigned char* categoryGroupEnabled, const char* name, + unsigned long long id, int numArgs, const char** argNames, + const unsigned char* argTypes, const unsigned long long* argValues, + unsigned char flags); + +} + +namespace gl +{ + +extern GetCategoryEnabledFlagFunc g_getCategoryEnabledFlag; +extern AddTraceEventFunc g_addTraceEvent; + +const unsigned char* TraceGetTraceCategoryEnabledFlag(const char* name); + +void TraceAddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, unsigned long long id, + int numArgs, const char** argNames, const unsigned char* argTypes, + const unsigned long long* argValues, unsigned char flags); + +} + +#endif // COMMON_EVENT_TRACER_H_ diff --git a/src/3rdparty/angle/src/common/features.h b/src/3rdparty/angle/src/common/features.h deleted file mode 100644 index b49a0ee852..0000000000 --- a/src/3rdparty/angle/src/common/features.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -#define ANGLE_DISABLED 0 -#define ANGLE_ENABLED 1 - -// Feature defaults - -// Direct3D9EX -// 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_D3D9EX=0" in your project file. -#if !defined(ANGLE_D3D9EX) -#define ANGLE_D3D9EX ANGLE_ENABLED -#endif - -// Vsync -// ENABLED allows Vsync to be configured at runtime -// DISABLED disallows Vsync -#if !defined(ANGLE_VSYNC) -#define ANGLE_VSYNC ANGLE_ENABLED -#endif - -// Program binary loading -#if !defined(ANGLE_PROGRAM_BINARY_LOAD) -#define ANGLE_PROGRAM_BINARY_LOAD ANGLE_ENABLED -#endif - -// Shader debug info -#if !defined(ANGLE_SHADER_DEBUG_INFO) -#define ANGLE_SHADER_DEBUG_INFO ANGLE_DISABLED -#endif diff --git a/src/3rdparty/angle/src/common/mathutil.h b/src/3rdparty/angle/src/common/mathutil.h index a1717892fd..1015bd2312 100644 --- a/src/3rdparty/angle/src/common/mathutil.h +++ b/src/3rdparty/angle/src/common/mathutil.h @@ -6,8 +6,8 @@ // mathutil.h: Math and bit manipulation functions. -#ifndef LIBGLESV2_MATHUTIL_H_ -#define LIBGLESV2_MATHUTIL_H_ +#ifndef COMMON_MATHUTIL_H_ +#define COMMON_MATHUTIL_H_ #include "common/debug.h" #include "common/platform.h" @@ -15,6 +15,7 @@ #include #include #include +#include namespace gl { @@ -118,6 +119,9 @@ inline bool supportsSSE2() return supports; } +#if defined(__GNUC__) + supports = __builtin_cpu_supports("sse2"); +#else int info[4]; __cpuid(info, 0); @@ -127,6 +131,7 @@ inline bool supportsSSE2() supports = (info[3] >> 26) & 1; } +#endif checked = true; @@ -353,7 +358,7 @@ inline float float11ToFloat32(unsigned short fp11) } else // The value is zero { - exponent = -112; + exponent = static_cast(-112); } return bitCast(((exponent + 112) << 23) | (mantissa << 17)); @@ -392,7 +397,7 @@ inline float float10ToFloat32(unsigned short fp11) } else // The value is zero { - exponent = -112; + exponent = static_cast(-112); } return bitCast(((exponent + 112) << 23) | (mantissa << 18)); @@ -402,7 +407,7 @@ inline float float10ToFloat32(unsigned short fp11) template inline float normalizedToFloat(T input) { - META_ASSERT(std::numeric_limits::is_integer); + static_assert(std::numeric_limits::is_integer, "T must be an integer."); const float inverseMax = 1.0f / std::numeric_limits::max(); return input * inverseMax; @@ -411,8 +416,8 @@ inline float normalizedToFloat(T input) template inline float normalizedToFloat(T input) { - META_ASSERT(std::numeric_limits::is_integer); - META_ASSERT(inputBitCount < (sizeof(T) * 8)); + static_assert(std::numeric_limits::is_integer, "T must be an integer."); + static_assert(inputBitCount < (sizeof(T) * 8), "T must have more bits than inputBitCount."); const float inverseMax = 1.0f / ((1 << inputBitCount) - 1); return input * inverseMax; @@ -427,14 +432,15 @@ inline T floatToNormalized(float input) template inline T floatToNormalized(float input) { - META_ASSERT(outputBitCount < (sizeof(T) * 8)); + static_assert(outputBitCount < (sizeof(T) * 8), "T must have more bits than outputBitCount."); return ((1 << outputBitCount) - 1) * input + 0.5f; } template inline T getShiftedData(T input) { - META_ASSERT(inputBitCount + inputBitStart <= (sizeof(T) * 8)); + static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8), + "T must have at least as many bits as inputBitCount + inputBitStart."); const T mask = (1 << inputBitCount) - 1; return (input >> inputBitStart) & mask; } @@ -442,7 +448,8 @@ inline T getShiftedData(T input) template inline T shiftData(T input) { - META_ASSERT(inputBitCount + inputBitStart <= (sizeof(T) * 8)); + static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8), + "T must have at least as many bits as inputBitCount + inputBitStart."); const T mask = (1 << inputBitCount) - 1; return (input & mask) << inputBitStart; } @@ -503,6 +510,7 @@ inline unsigned int averageFloat10(unsigned int a, unsigned int b) namespace rx { +// Represents intervals of the type [a, b) template struct Range { @@ -513,6 +521,18 @@ struct Range T end; T length() const { return end - start; } + + bool intersects(Range other) + { + if (start <= other.start) + { + return other.start < end; + } + else + { + return start < other.end; + } + } }; typedef Range RangeI; @@ -533,14 +553,14 @@ inline unsigned int UnsignedCeilDivide(unsigned int value, unsigned int divisor) template inline bool IsUnsignedAdditionSafe(T lhs, T rhs) { - META_ASSERT(!std::numeric_limits::is_signed); + static_assert(!std::numeric_limits::is_signed, "T must be unsigned."); return (rhs <= std::numeric_limits::max() - lhs); } template inline bool IsUnsignedMultiplicationSafe(T lhs, T rhs) { - META_ASSERT(!std::numeric_limits::is_signed); + static_assert(!std::numeric_limits::is_signed, "T must be unsigned."); return (lhs == T(0) || rhs == T(0) || (rhs <= std::numeric_limits::max() / lhs)); } @@ -550,6 +570,21 @@ inline bool IsIntegerCastSafe(BigIntT bigValue) return (static_cast(static_cast(bigValue)) == bigValue); } +#if defined(_MSC_VER) + +#define ANGLE_ROTL(x,y) _rotl(x,y) + +#else + +inline uint32_t RotL(uint32_t x, int8_t r) +{ + return (x << r) | (x >> (32 - r)); +} + +#define ANGLE_ROTL(x,y) RotL(x,y) + +#endif // namespace rx + } -#endif // LIBGLESV2_MATHUTIL_H_ +#endif // COMMON_MATHUTIL_H_ diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h index 5bf97f9184..3a2aa91bed 100644 --- a/src/3rdparty/angle/src/common/platform.h +++ b/src/3rdparty/angle/src/common/platform.h @@ -14,12 +14,12 @@ #elif defined(__APPLE__) # define ANGLE_PLATFORM_APPLE 1 # define ANGLE_PLATFORM_POSIX 1 -#elif defined(__linux__) -# define ANGLE_PLATFORM_LINUX 1 -# define ANGLE_PLATFORM_POSIX 1 #elif defined(ANDROID) # define ANGLE_PLATFORM_ANDROID 1 # define ANGLE_PLATFORM_POSIX 1 +#elif defined(__linux__) || defined(EMSCRIPTEN) +# define ANGLE_PLATFORM_LINUX 1 +# define ANGLE_PLATFORM_POSIX 1 #elif defined(__FreeBSD__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) || \ @@ -34,9 +34,6 @@ #endif #ifdef ANGLE_PLATFORM_WINDOWS -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) -# define ANGLE_ENABLE_WINDOWS_STORE 1 -# endif # ifndef STRICT # define STRICT 1 # endif @@ -50,24 +47,32 @@ # include # include +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) +# define ANGLE_ENABLE_WINDOWS_STORE 1 +# endif + # if defined(ANGLE_ENABLE_D3D9) # include -# include -# if !defined(COMPILER_IMPLEMENTATION) +# if !defined(ANGLE_TRANSLATOR_IMPLEMENTATION) # include # endif # endif # if defined(ANGLE_ENABLE_D3D11) # include -# include # include # include -# if defined(_MSC_VER) && (_MSC_VER >= 1700) +# if defined(__MINGW32__) && !defined(__d3d11sdklayers_h__) +# define ANGLE_MINGW32_COMPAT +# endif +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# define ANGLE_ENABLE_D3D11_1 +# endif +# if defined(ANGLE_ENABLE_D3D11_1) # include # include # endif -# if !defined(COMPILER_IMPLEMENTATION) +# if !defined(ANGLE_TRANSLATOR_IMPLEMENTATION) # include # endif # endif @@ -75,88 +80,24 @@ # if defined(ANGLE_ENABLE_WINDOWS_STORE) # include # if defined(_DEBUG) -# if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) +# if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP # include # endif # include # endif # endif -# if defined(__MINGW32__) // Missing defines on MinGW -typedef enum D3D11_MAP_FLAG -{ - D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000L -} D3D11_MAP_FLAG; -typedef struct D3D11_QUERY_DATA_SO_STATISTICS -{ - UINT64 NumPrimitivesWritten; - UINT64 PrimitivesStorageNeeded; -} D3D11_QUERY_DATA_SO_STATISTICS; -typedef HRESULT (WINAPI *PFN_D3D11_CREATE_DEVICE)( - IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL *, - UINT FeatureLevels, UINT, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **); -#define D3D11_MESSAGE_CATEGORY UINT -#define D3D11_MESSAGE_SEVERITY UINT -#define D3D11_MESSAGE_ID UINT -struct D3D11_MESSAGE; -typedef struct D3D11_INFO_QUEUE_FILTER_DESC -{ - UINT NumCategories; - D3D11_MESSAGE_CATEGORY *pCategoryList; - UINT NumSeverities; - D3D11_MESSAGE_SEVERITY *pSeverityList; - UINT NumIDs; - D3D11_MESSAGE_ID *pIDList; -} D3D11_INFO_QUEUE_FILTER_DESC; -typedef struct D3D11_INFO_QUEUE_FILTER -{ - D3D11_INFO_QUEUE_FILTER_DESC AllowList; - D3D11_INFO_QUEUE_FILTER_DESC DenyList; -} D3D11_INFO_QUEUE_FILTER; -static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 }; -MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown -{ -public: - virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0; - virtual void __stdcall ClearStoredMessages() = 0; - virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0; - virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0; - virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0; - virtual UINT64 __stdcall GetNumStoredMessages() = 0; - virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0; - virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0; - virtual UINT64 __stdcall GetMessageCountLimit() = 0; - virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; - virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; - virtual void __stdcall ClearStorageFilter() = 0; - virtual HRESULT __stdcall PushEmptyStorageFilter() = 0; - virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0; - virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0; - virtual void __stdcall PopStorageFilter() = 0; - virtual UINT __stdcall GetStorageFilterStackSize() = 0; - virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; - virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; - virtual void __stdcall ClearRetrievalFilter() = 0; - virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0; - virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0; - virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0; - virtual void __stdcall PopRetrievalFilter() = 0; - virtual UINT __stdcall GetRetrievalFilterStackSize() = 0; - virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0; - virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0; - virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0; - virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0; - virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0; - virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0; - virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0; - virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0; - virtual void __stdcall SetMuteDebugOutput(BOOL) = 0; - virtual BOOL __stdcall GetMuteDebugOutput() = 0; -}; -#endif // __MINGW32__ +# if defined(_MSC_VER) && (_MSC_VER <= 1600) +# define final +# define override +# endif # undef near # undef far #endif +#if !defined(_M_ARM) && !defined(ANGLE_PLATFORM_ANDROID) +# define ANGLE_USE_SSE +#endif + #endif // COMMON_PLATFORM_H_ diff --git a/src/3rdparty/angle/src/common/tls.h b/src/3rdparty/angle/src/common/tls.h index 8a06e92d1a..ca9e07ab70 100644 --- a/src/3rdparty/angle/src/common/tls.h +++ b/src/3rdparty/angle/src/common/tls.h @@ -15,7 +15,9 @@ // TLS does not exist for Windows Store and needs to be emulated # ifdef ANGLE_ENABLE_WINDOWS_STORE -# define TLS_OUT_OF_INDEXES -1 +# ifndef TLS_OUT_OF_INDEXES +# define TLS_OUT_OF_INDEXES static_cast(0xFFFFFFFF) +# endif # ifndef CREATE_SUSPENDED # define CREATE_SUSPENDED 0x00000004 # endif diff --git a/src/3rdparty/angle/src/common/utilities.cpp b/src/3rdparty/angle/src/common/utilities.cpp index 0eae42cac2..501e9c2564 100644 --- a/src/3rdparty/angle/src/common/utilities.cpp +++ b/src/3rdparty/angle/src/common/utilities.cpp @@ -254,7 +254,7 @@ int VariableColumnCount(GLenum type) return 0; } -bool IsSampler(GLenum type) +bool IsSamplerType(GLenum type) { switch (type) { @@ -343,9 +343,27 @@ int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsig return -1; } -bool IsCubemapTextureTarget(GLenum target) +static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1, "Unexpected GL cube map enum value."); +static_assert(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2, "Unexpected GL cube map enum value."); +static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3, "Unexpected GL cube map enum value."); +static_assert(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4, "Unexpected GL cube map enum value."); +static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5, "Unexpected GL cube map enum value."); + +bool IsCubeMapTextureTarget(GLenum target) +{ + return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget); +} + +size_t CubeMapTextureTargetToLayerIndex(GLenum target) { - return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); + ASSERT(IsCubeMapTextureTarget(target)); + return target - static_cast(FirstCubeMapTextureTarget); +} + +GLenum LayerIndexToCubeMapTextureTarget(size_t index) +{ + ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget)); + return FirstCubeMapTextureTarget + static_cast(index); } bool IsTriangleMode(GLenum drawMode) @@ -486,10 +504,15 @@ void writeFile(const char* path, const void* content, size_t size) } #endif // !ANGLE_ENABLE_WINDOWS_STORE -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && _MSC_FULL_VER < 180031101 +#if defined (ANGLE_PLATFORM_WINDOWS) -void Sleep(unsigned long dwMilliseconds) +// Causes the thread to relinquish the remainder of its time slice to any +// other thread that is ready to run.If there are no other threads ready +// to run, the function returns immediately, and the thread continues execution. +void ScheduleYield() { +#if defined(ANGLE_ENABLE_WINDOWS_STORE) + // This implementation of Sleep exists because it is not available prior to Update 4. static HANDLE singletonEvent = nullptr; HANDLE sleepEvent = singletonEvent; if (!sleepEvent) @@ -510,7 +533,10 @@ void Sleep(unsigned long dwMilliseconds) } // Emulate sleep by waiting with timeout on an event that is never signalled. - WaitForSingleObjectEx(sleepEvent, dwMilliseconds, false); + WaitForSingleObjectEx(sleepEvent, 0, false); +#else + Sleep(0); +#endif } -#endif // ANGLE_ENABLE_WINDOWS_STORE +#endif diff --git a/src/3rdparty/angle/src/common/utilities.h b/src/3rdparty/angle/src/common/utilities.h index 7583d3e160..9f7f5e03c0 100644 --- a/src/3rdparty/angle/src/common/utilities.h +++ b/src/3rdparty/angle/src/common/utilities.h @@ -6,8 +6,8 @@ // utilities.h: Conversion functions and other utility routines. -#ifndef LIBGLESV2_UTILITIES_H -#define LIBGLESV2_UTILITIES_H +#ifndef COMMON_UTILITIES_H_ +#define COMMON_UTILITIES_H_ #include "angle_gl.h" #include @@ -24,7 +24,7 @@ size_t VariableExternalSize(GLenum type); GLenum VariableBoolVectorType(GLenum type); int VariableRowCount(GLenum type); int VariableColumnCount(GLenum type); -bool IsSampler(GLenum type); +bool IsSamplerType(GLenum type); bool IsMatrixType(GLenum type); GLenum TransposeMatrixType(GLenum type); int VariableRegisterCount(GLenum type); @@ -34,7 +34,11 @@ int VariableSortOrder(GLenum type); int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize); -bool IsCubemapTextureTarget(GLenum target); +static const GLenum FirstCubeMapTextureTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X; +static const GLenum LastCubeMapTextureTarget = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; +bool IsCubeMapTextureTarget(GLenum target); +size_t CubeMapTextureTargetToLayerIndex(GLenum target); +GLenum LayerIndexToCubeMapTextureTarget(size_t index); bool IsTriangleMode(GLenum drawMode); @@ -51,8 +55,8 @@ std::string getTempPath(); void writeFile(const char* path, const void* data, size_t size); #endif -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && _MSC_FULL_VER < 180031101 -void Sleep(_In_ unsigned long dwMilliseconds); +#if defined (ANGLE_PLATFORM_WINDOWS) +void ScheduleYield(); #endif -#endif // LIBGLESV2_UTILITIES_H +#endif // COMMON_UTILITIES_H_ diff --git a/src/3rdparty/angle/src/common/version.h b/src/3rdparty/angle/src/common/version.h index f01e0242cb..758c78d44a 100644 --- a/src/3rdparty/angle/src/common/version.h +++ b/src/3rdparty/angle/src/common/version.h @@ -1,4 +1,13 @@ -#include "../commit.h" +// +// Copyright (c) 2014 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_VERSION_H_ +#define COMMON_VERSION_H_ + +#include "id/commit.h" #define ANGLE_MAJOR_VERSION 2 #define ANGLE_MINOR_VERSION 1 @@ -10,3 +19,5 @@ ANGLE_MACRO_STRINGIFY(ANGLE_MAJOR_VERSION) "." \ ANGLE_MACRO_STRINGIFY(ANGLE_MINOR_VERSION) "." \ ANGLE_COMMIT_HASH + +#endif // COMMON_VERSION_H_ diff --git a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp deleted file mode 100644 index 46082a2e28..0000000000 --- a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// NativeWindow.cpp: Handler for managing HWND native window types. - -#include "common/NativeWindow.h" -#include "common/debug.h" - -namespace rx -{ -bool IsValidEGLNativeWindowType(EGLNativeWindowType window) -{ - return (IsWindow(window) == TRUE); -} - -NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) : mWindow(window), mDisplay(display) -{ -} - -bool NativeWindow::initialize() -{ - return true; -} - -bool NativeWindow::getClientRect(LPRECT rect) -{ - return GetClientRect(mWindow, rect) == TRUE; -} - -bool NativeWindow::isIconic() -{ - return IsIconic(mWindow) == TRUE; -} - -HRESULT NativeWindow::createSwapChain(NativeWindow::Device* device, DXGIFactory* factory, - DXGI_FORMAT format, unsigned int width, unsigned int height, - DXGISwapChain** swapChain) -{ - if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) - { - return E_INVALIDARG; - } - - DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; - swapChainDesc.BufferCount = 1; - swapChainDesc.BufferDesc.Format = format; - swapChainDesc.BufferDesc.Width = width; - swapChainDesc.BufferDesc.Height = height; - swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; - swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; - swapChainDesc.Flags = 0; - swapChainDesc.OutputWindow = mWindow; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.Windowed = TRUE; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - - return factory->CreateSwapChain(device, &swapChainDesc, swapChain); -} -} diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp deleted file mode 100644 index 9b65c15625..0000000000 --- a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types. - -#include -#include "common/winrt/CoreWindowNativeWindow.h" -using namespace ABI::Windows::Foundation::Collections; - -namespace rx -{ - -typedef ITypedEventHandler SizeChangedHandler; - -CoreWindowNativeWindow::~CoreWindowNativeWindow() -{ - unregisterForSizeChangeEvents(); -} - -bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) -{ - ComPtr props = propertySet; - ComPtr win = window; - ComPtr displayInformation = display; - SIZE swapChainSize = {}; - bool swapChainSizeSpecified = false; - HRESULT result = S_OK; - - // IPropertySet is an optional parameter and can be null. - // If one is specified, cache as an IMap and read the properties - // used for initial host initialization. - if (propertySet) - { - result = props.As(&mPropertyMap); - if (SUCCEEDED(result)) - { - // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet - // was prevalidated to contain the EGLNativeWindowType before being passed to - // this host. - result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); - } - } - - if (SUCCEEDED(result)) - { - result = win.As(&mCoreWindow); - } - - if (SUCCEEDED(result)) - { - result = displayInformation.As(&mDisplayInformation); - } - - if (SUCCEEDED(result)) - { -#if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - ComPtr displayInformation2; - result = mDisplayInformation.As(&displayInformation2); - ASSERT(SUCCEEDED(result)); - - result = displayInformation2->get_RawPixelsPerViewPixel(&mScaleFactor); - ASSERT(SUCCEEDED(result)); -#else - ABI::Windows::Graphics::Display::ResolutionScale resolutionScale; - result = mDisplayInformation->get_ResolutionScale(&resolutionScale); - ASSERT(SUCCEEDED(result)); - - mScaleFactor = DOUBLE(resolutionScale) / 100.0; -#endif - } - - if (SUCCEEDED(result)) - { - // If a swapchain size is specfied, then the automatic resize - // behaviors implemented by the host should be disabled. The swapchain - // will be still be scaled when being rendered to fit the bounds - // of the host. - // Scaling of the swapchain output occurs automatically because if - // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain. - if (swapChainSizeSpecified) - { - mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; - mSupportsSwapChainResize = false; - } - else - { - ABI::Windows::Foundation::Rect rect; - HRESULT result = mCoreWindow->get_Bounds(&rect); - if (SUCCEEDED(result)) - { - LONG width = std::floor(rect.Width * mScaleFactor + 0.5); - LONG height = std::floor(rect.Height * mScaleFactor + 0.5); - mClientRect = { 0, 0, width, height }; - } - } - } - - if (SUCCEEDED(result)) - { - mNewClientRect = mClientRect; - mClientRectChanged = false; - return registerForSizeChangeEvents(); - } - - return false; -} - -bool CoreWindowNativeWindow::registerForSizeChangeEvents() -{ - HRESULT result = mCoreWindow->add_SizeChanged(Callback(this, &CoreWindowNativeWindow::onSizeChanged).Get(), - &mSizeChangedEventToken); - - if (SUCCEEDED(result)) - { - return true; - } - - return false; -} - -void CoreWindowNativeWindow::unregisterForSizeChangeEvents() -{ - if (mCoreWindow) - { - (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken); - } - mSizeChangedEventToken.value = 0; -} - -HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) -{ - if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) - { - return E_INVALIDARG; - } - - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; - swapChainDesc.Width = width; - swapChainDesc.Height = height; - swapChainDesc.Format = format; - swapChainDesc.Stereo = FALSE; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; - swapChainDesc.BufferCount = 2; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - - *swapChain = nullptr; - - ComPtr newSwapChain; - HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); - if (SUCCEEDED(result)) - { - -#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // This block is disabled for Qt applications, as the resize events are expected - // Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On - // other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed - // (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations. - if (newSwapChain->ResizeBuffers(swapChainDesc.BufferCount, swapChainDesc.Width, swapChainDesc.Height, swapChainDesc.Format, DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) == DXGI_ERROR_UNSUPPORTED) - { - mSupportsSwapChainResize = false; - } -#endif // (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - - result = newSwapChain.CopyTo(swapChain); - } - - if (SUCCEEDED(result)) - { - // If automatic swapchain resize behaviors have been disabled, then - // unregister for the resize change events. - if (mSupportsSwapChainResize == false) - { - unregisterForSizeChangeEvents(); - } - } - - return result; -} - -// Basically, this shouldn't be used on Phone -HRESULT CoreWindowNativeWindow::onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *e) -{ - ABI::Windows::Foundation::Size size; - if (SUCCEEDED(e->get_Size(&size))) - { - SIZE windowSizeInPixels = { - std::floor(size.Width * mScaleFactor + 0.5), - std::floor(size.Height * mScaleFactor + 0.5) - }; - setNewClientSize(windowSizeInPixels); - } - - return S_OK; -} -} diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h deleted file mode 100644 index 1c5512417d..0000000000 --- a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// CoreWindowNativeWindow.h: NativeWindow for managing ICoreWindow native window types. - -#ifndef COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_ -#define COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_ - -#include "common/winrt/InspectableNativeWindow.h" -#include -#include - -namespace rx -{ - -class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this -{ - public: - ~CoreWindowNativeWindow(); - - bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet); - bool registerForSizeChangeEvents(); - void unregisterForSizeChangeEvents(); - HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); - - private: - HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); - - ComPtr mCoreWindow; - ComPtr mDisplayInformation; - ComPtr> mPropertyMap; -}; - -} - -#endif // COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp deleted file mode 100644 index 0589f6dce5..0000000000 --- a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// InspectableNativeWindow.cpp: NativeWindow base class for managing IInspectable native window types. - -#include "common/winrt/CoreWindowNativeWindow.h" -#include "common/winrt/SwapChainPanelNativeWindow.h" - -namespace rx -{ -NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) - : mWindow(window), mDisplay(display) -{ -} - -bool NativeWindow::initialize() -{ - // If the native window type is a IPropertySet, extract the - // EGLNativeWindowType (IInspectable) and initialize the - // proper host with this IPropertySet. - ComPtr propertySet; - ComPtr eglNativeWindow; - if (IsEGLConfiguredPropertySet(mWindow, &propertySet, &eglNativeWindow)) - { - // A property set was found and the EGLNativeWindowType was - // retrieved. The mWindow member of the host to must be updated - // to use the EGLNativeWindowType specified in the property set. - // mWindow is treated as a raw pointer not an AddRef'd interface, so - // the old mWindow does not need a Release() before this assignment. - mWindow = eglNativeWindow.Get(); - } - - ComPtr coreWindow; - ComPtr swapChainPanel; - if (IsCoreWindow(mWindow, &coreWindow)) - { - mImpl = std::make_shared(); - if (mImpl) - { - return mImpl->initialize(mWindow, mDisplay, propertySet.Get()); - } - } - else if (IsSwapChainPanel(mWindow, &swapChainPanel)) - { - mImpl = std::make_shared(); - if (mImpl) - { - return mImpl->initialize(mWindow, mDisplay, propertySet.Get()); - } - } - else - { - ERR("Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include ICoreWindow, ISwapChainPanel and IPropertySet"); - } - - return false; -} - -bool NativeWindow::getClientRect(RECT *rect) -{ - if (mImpl) - { - return mImpl->getClientRect(rect); - } - - return false; -} - -bool NativeWindow::isIconic() -{ - return false; -} - -HRESULT NativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) -{ - if (mImpl) - { - return mImpl->createSwapChain(device, factory, format, width, height, swapChain); - } - - return E_UNEXPECTED; -} - -bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow) -{ - if (!window) - { - return false; - } - - ComPtr win = window; - ComPtr coreWin; - if (SUCCEEDED(win.As(&coreWin))) - { - if (coreWindow != nullptr) - { - *coreWindow = coreWin.Detach(); - } - return true; - } - - return false; -} - -bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel) -{ - if (!window) - { - return false; - } - - ComPtr win = window; - ComPtr panel; - if (SUCCEEDED(win.As(&panel))) - { - if (swapChainPanel != nullptr) - { - *swapChainPanel = panel.Detach(); - } - return true; - } - - return false; -} - -bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet, IInspectable **eglNativeWindow) -{ - if (!window) - { - return false; - } - - ComPtr props = window; - ComPtr propSet; - ComPtr nativeWindow; - ComPtr> propMap; - boolean hasEglNativeWindowPropertyKey = false; - - HRESULT result = props.As(&propSet); - if (SUCCEEDED(result)) - { - result = propSet.As(&propMap); - } - - // Look for the presence of the EGLNativeWindowType in the property set - if (SUCCEEDED(result)) - { - result = propMap->HasKey(HStringReference(EGLNativeWindowTypeProperty).Get(), &hasEglNativeWindowPropertyKey); - } - - // If the IPropertySet does not contain the required EglNativeWindowType key, the property set is - // considered invalid. - if (SUCCEEDED(result) && !hasEglNativeWindowPropertyKey) - { - ERR("Could not find EGLNativeWindowTypeProperty in IPropertySet. Valid EGLNativeWindowTypeProperty values include ICoreWindow"); - return false; - } - - // The EglNativeWindowType property exists, so retreive the IInspectable that represents the EGLNativeWindowType - if (SUCCEEDED(result) && hasEglNativeWindowPropertyKey) - { - result = propMap->Lookup(HStringReference(EGLNativeWindowTypeProperty).Get(), &nativeWindow); - } - - if (SUCCEEDED(result)) - { - if (propertySet != nullptr) - { - result = propSet.CopyTo(propertySet); - } - } - - if (SUCCEEDED(result)) - { - if (eglNativeWindow != nullptr) - { - result = nativeWindow.CopyTo(eglNativeWindow); - } - } - - if (SUCCEEDED(result)) - { - return true; - } - - return false; -} - -// A Valid EGLNativeWindowType IInspectable can only be: -// -// ICoreWindow -// IPropertySet -// -// Anything else will be rejected as an invalid IInspectable. -bool IsValidEGLNativeWindowType(EGLNativeWindowType window) -{ - return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window); -} - -// Attempts to read an optional SIZE property value that is assumed to be in the form of -// an ABI::Windows::Foundation::Size. This function validates the Size value before returning -// it to the caller. -// -// Possible return values are: -// S_OK, valueExists == true - optional SIZE value was successfully retrieved and validated -// S_OK, valueExists == false - optional SIZE value was not found -// E_INVALIDARG, valueExists = false - optional SIZE value was malformed in the property set. -// * Incorrect property type ( must be PropertyType_Size) -// * Invalid property value (width/height must be > 0) -// Additional errors may be returned from IMap or IPropertyValue -// -HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists) -{ - if (!propertyMap || !propertyName || !value || !valueExists) - { - return false; - } - - // Assume that the value does not exist - *valueExists = false; - *value = { 0, 0 }; - - ComPtr propertyValue; - ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty; - Size sizeValue = { 0, 0 }; - boolean hasKey = false; - - HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), &hasKey); - if (SUCCEEDED(result) && !hasKey) - { - // Value does not exist, so return S_OK and set the exists parameter to false to indicate - // that a the optional property does not exist. - *valueExists = false; - return S_OK; - } - - if (SUCCEEDED(result)) - { - result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue); - } - - if (SUCCEEDED(result)) - { - result = propertyValue->get_Type(&propertyType); - } - - // Check if the expected Size property is of PropertyType_Size type. - if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size) - { - if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0)) - { - // A valid property value exists - *value = { static_cast(sizeValue.Width), static_cast(sizeValue.Height) }; - *valueExists = true; - result = S_OK; - } - else - { - // An invalid Size property was detected. Width/Height values must > 0 - result = E_INVALIDARG; - } - } - else - { - // An invalid property type was detected. Size property must be of PropertyType_Size - result = E_INVALIDARG; - } - - return result; -} -} diff --git a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h deleted file mode 100644 index 402941a788..0000000000 --- a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// InspectableNativeWindow.h: Host specific implementation interface for -// managing IInspectable native window types. - -#ifndef COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_ -#define COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_ - -#include "common/platform.h" -#include "common/NativeWindow.h" -#include "angle_windowsstore.h" - -#include -#include - -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Foundation::Collections; - -namespace rx -{ -class InspectableNativeWindow -{ - public: - InspectableNativeWindow() : - mSupportsSwapChainResize(true), - mRequiresSwapChainScaling(false), - mClientRectChanged(false), - mClientRect({0,0,0,0}), - mNewClientRect({0,0,0,0}), - mScaleFactor(1.0) - { - mSizeChangedEventToken.value = 0; - } - virtual ~InspectableNativeWindow(){} - - virtual bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) = 0; - virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0; - virtual bool registerForSizeChangeEvents() = 0; - virtual void unregisterForSizeChangeEvents() = 0; - virtual HRESULT scaleSwapChain(const SIZE& newSize) { return S_OK; } - - bool getClientRect(RECT *rect) - { - if (mClientRectChanged && mSupportsSwapChainResize) - { - mClientRect = mNewClientRect; - mClientRectChanged = false; - } - - *rect = mClientRect; - - return true; - } - - void setNewClientSize(const SIZE &newSize) - { - if (mSupportsSwapChainResize && !mRequiresSwapChainScaling) - { - mNewClientRect = { 0, 0, newSize.cx, newSize.cy }; - mClientRectChanged = true; - } - - if (mRequiresSwapChainScaling) - { - scaleSwapChain(newSize); - } - } - -protected: - bool mSupportsSwapChainResize; - bool mRequiresSwapChainScaling; - RECT mClientRect; - RECT mNewClientRect; - bool mClientRectChanged; - DOUBLE mScaleFactor; - - EventRegistrationToken mSizeChangedEventToken; -}; - -bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow = nullptr); -bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel = nullptr); -bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr); -HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists); -} -#endif // COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp deleted file mode 100644 index 268dfbd8f0..0000000000 --- a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// SwapChainPanelNativeWindow.cpp: NativeWindow for managing ISwapChainPanel native window types. - -#include "common/winrt/SwapChainPanelNativeWindow.h" -#include -#include -using namespace ABI::Windows::Foundation::Collections; - -namespace rx -{ -SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow() -{ - unregisterForSizeChangeEvents(); -} - -bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) -{ - ComPtr props = propertySet; - ComPtr win = window; - SIZE swapChainSize = {}; - bool swapChainSizeSpecified = false; - HRESULT result = S_OK; - - // IPropertySet is an optional parameter and can be null. - // If one is specified, cache as an IMap and read the properties - // used for initial host initialization. - if (propertySet) - { - result = props.As(&mPropertyMap); - if (SUCCEEDED(result)) - { - // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet - // was prevalidated to contain the EGLNativeWindowType before being passed to - // this host. - result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); - } - } - - if (SUCCEEDED(result)) - { - result = win.As(&mSwapChainPanel); - } - - if (SUCCEEDED(result)) - { - // If a swapchain size is specfied, then the automatic resize - // behaviors implemented by the host should be disabled. The swapchain - // will be still be scaled when being rendered to fit the bounds - // of the host. - // Scaling of the swapchain output needs to be handled by the - // host for swapchain panels even though the scaling mode setting - // DXGI_SCALING_STRETCH is configured on the swapchain. - if (swapChainSizeSpecified) - { - mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; - - // Enable host swapchain scaling - mRequiresSwapChainScaling = true; - } - else - { - result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect); - } - } - - if (SUCCEEDED(result)) - { - mNewClientRect = mClientRect; - mClientRectChanged = false; - return registerForSizeChangeEvents(); - } - - return false; -} - -bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() -{ - ComPtr sizeChangedHandler; - ComPtr frameworkElement; - HRESULT result = Microsoft::WRL::MakeAndInitialize(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); - - if (SUCCEEDED(result)) - { - result = mSwapChainPanel.As(&frameworkElement); - } - - if (SUCCEEDED(result)) - { - result = frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); - } - - if (SUCCEEDED(result)) - { - return true; - } - - return false; -} - -void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() -{ - ComPtr frameworkElement; - if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) - { - (void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken); - } - - mSizeChangedEventToken.value = 0; -} - -HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) -{ - if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) - { - return E_INVALIDARG; - } - - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; - swapChainDesc.Width = width; - swapChainDesc.Height = height; - swapChainDesc.Format = format; - swapChainDesc.Stereo = FALSE; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; - swapChainDesc.BufferCount = 2; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - - *swapChain = nullptr; - - ComPtr newSwapChain; - ComPtr swapChainPanelNative; - RECT currentPanelSize = {}; - - HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); - - if (SUCCEEDED(result)) - { - result = mSwapChainPanel.As(&swapChainPanelNative); - } - - if (SUCCEEDED(result)) - { - result = swapChainPanelNative->SetSwapChain(newSwapChain.Get()); - } - - if (SUCCEEDED(result)) - { - // The swapchain panel host requires an instance of the swapchain set on the SwapChainPanel - // to perform the runtime-scale behavior. This swapchain is cached here because there are - // no methods for retreiving the currently configured on from ISwapChainPanelNative. - mSwapChain = newSwapChain; - result = newSwapChain.CopyTo(swapChain); - } - - // If the host is responsible for scaling the output of the swapchain, then - // scale it now before returning an instance to the caller. This is done by - // first reading the current size of the swapchain panel, then scaling - if (SUCCEEDED(result) && mRequiresSwapChainScaling) - { - result = GetSwapChainPanelSize(mSwapChainPanel, ¤tPanelSize); - } - - // Scale the swapchain to fit inside the contents of the panel. - if (SUCCEEDED(result) && mRequiresSwapChainScaling) - { - SIZE currentSize = { currentPanelSize.right, currentPanelSize.bottom }; - result = scaleSwapChain(currentSize); - } - - if (SUCCEEDED(result)) - { - // If automatic swapchain resize behaviors have been disabled, then - // unregister for the resize change events. - if (mSupportsSwapChainResize == false) - { - unregisterForSizeChangeEvents(); - } - } - - return result; -} - -HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) -{ - ABI::Windows::Foundation::Size renderScale = { (float)newSize.cx/(float)mClientRect.right, (float)newSize.cy/(float)mClientRect.bottom }; - // Setup a scale matrix for the swap chain - DXGI_MATRIX_3X2_F scaleMatrix = {}; - scaleMatrix._11 = renderScale.Width; - scaleMatrix._22 = renderScale.Height; - - ComPtr swapChain2; - HRESULT result = mSwapChain.As(&swapChain2); - if (SUCCEEDED(result)) - { - result = swapChain2->SetMatrixTransform(&scaleMatrix); - } - - return result; -} - -HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize) -{ - ComPtr uiElement; - ABI::Windows::Foundation::Size renderSize = { 0, 0 }; - HRESULT result = swapChainPanel.As(&uiElement); - if (SUCCEEDED(result)) - { - result = uiElement->get_RenderSize(&renderSize); - } - - if (SUCCEEDED(result)) - { - *windowSize = { 0, 0, lround(renderSize.Width), lround(renderSize.Height) }; - } - - return result; -} -} diff --git a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h deleted file mode 100644 index 5bbf274e64..0000000000 --- a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// SwapChainPanelNativeWindow.h: NativeWindow for managing ISwapChainPanel native window types. - -#ifndef COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ -#define COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ - -#include "common/winrt/InspectableNativeWindow.h" - -namespace rx -{ -class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this -{ - public: - ~SwapChainPanelNativeWindow(); - - bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet); - bool registerForSizeChangeEvents(); - void unregisterForSizeChangeEvents(); - HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); - HRESULT scaleSwapChain(const SIZE &newSize); - - private: - ComPtr mSwapChainPanel; - ComPtr> mPropertyMap; - ComPtr mSwapChain; -}; - -[uuid(8ACBD974-8187-4508-AD80-AEC77F93CF36)] -class SwapChainPanelSizeChangedHandler : - public Microsoft::WRL::RuntimeClass, ABI::Windows::UI::Xaml::ISizeChangedEventHandler> -{ - public: - SwapChainPanelSizeChangedHandler() { } - HRESULT RuntimeClassInitialize(std::shared_ptr host) - { - if (!host) - { - return E_INVALIDARG; - } - - mHost = host; - return S_OK; - } - - // ISizeChangedEventHandler - IFACEMETHOD(Invoke)(IInspectable *sender, ABI::Windows::UI::Xaml::ISizeChangedEventArgs *sizeChangedEventArgs) - { - std::shared_ptr host = mHost.lock(); - if (host) - { - // The size of the ISwapChainPanel control is returned in DIPs. - // We are keeping these in dips because the swapchain created for composition - // also uses dip units. This keeps dimensions, viewports, etc in the same unit. - // XAML Clients of the ISwapChainPanel are required to use dips to define their - // layout sizes as well. - ABI::Windows::Foundation::Size newSize; - HRESULT result = sizeChangedEventArgs->get_NewSize(&newSize); - if (SUCCEEDED(result)) - { - SIZE windowSize = { lround(newSize.Width), lround(newSize.Height) }; - host->setNewClientSize(windowSize); - } - } - - return S_OK; - } - - private: - std::weak_ptr mHost; -}; - -HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize); -} -#endif // COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h index a7587ed657..5922d03857 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DiagnosticsBase.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ -#define COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ +#ifndef COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_ +#define COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_ #include @@ -84,4 +84,5 @@ class Diagnostics }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_DIAGNOSTICS_H_ + +#endif // COMPILER_PREPROCESSOR_DIAGNOSTICSBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h index eec0d5e5f0..cf67895764 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ -#define COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ +#ifndef COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ #include @@ -41,4 +41,5 @@ class DirectiveHandler }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_DIRECTIVE_HANDLER_H_ + +#endif // COMPILER_PREPROCESSOR_DIRECTIVEHANDLERBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h index 335091781c..e1acdbb8d0 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ -#define COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ +#ifndef COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ +#define COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ #include "Lexer.h" #include "Macro.h" @@ -78,5 +78,5 @@ class DirectiveParser : public Lexer }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_DIRECTIVE_PARSER_H_ +#endif // COMPILER_PREPROCESSOR_DIRECTIVEPARSER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h index f040cb01fa..4b80ba7261 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ -#define COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ +#ifndef COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ +#define COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ #include "pp_utils.h" @@ -31,4 +31,5 @@ class ExpressionParser }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_EXPRESSION_PARSER_H_ + +#endif // COMPILER_PREPROCESSOR_EXPRESSIONPARSER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y index 662a31b650..8caf36bfc8 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y +++ b/src/3rdparty/angle/src/compiler/preprocessor/ExpressionParser.y @@ -28,7 +28,7 @@ WHICH GENERATES THE GLSL ES preprocessor expression parser. #pragma GCC diagnostic ignored "-Wuninitialized" #endif #elif defined(_MSC_VER) -#pragma warning(disable: 4065 4701) +#pragma warning(disable: 4065 4701 4702) #endif #include "ExpressionParser.h" @@ -69,7 +69,7 @@ struct Context %} %pure-parser -%name-prefix="pp" +%name-prefix "pp" %parse-param {Context *context} %lex-param {Context *context} diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Input.h b/src/3rdparty/angle/src/compiler/preprocessor/Input.h index 2ac4f0c170..e951cb4d5f 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Input.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Input.h @@ -58,5 +58,5 @@ class Input }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_INPUT_H_ +#endif // COMPILER_PREPROCESSOR_INPUT_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h index d42d3db7e0..990dc5e21d 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Lexer.h @@ -21,5 +21,5 @@ class Lexer }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_LEXER_H_ +#endif // COMPILER_PREPROCESSOR_LEXER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h index b77e7bc15c..7662a9c5a2 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Macro.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Macro.h @@ -46,4 +46,5 @@ struct Macro typedef std::map MacroSet; } // namespace pp + #endif // COMPILER_PREPROCESSOR_MACRO_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h index d4fd091786..5a0c7751a8 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ -#define COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ +#ifndef COMPILER_PREPROCESSOR_MACROEXPANDER_H_ +#define COMPILER_PREPROCESSOR_MACROEXPANDER_H_ #include #include @@ -85,5 +85,5 @@ class MacroExpander : public Lexer }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_MACRO_EXPANDER_H_ +#endif // COMPILER_PREPROCESSOR_MACROEXPANDER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h index 0a55f1c9c1..fe25daa123 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Preprocessor.h @@ -50,5 +50,5 @@ class Preprocessor }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_ +#endif // COMPILER_PREPROCESSOR_PREPROCESSOR_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h index d4c1a5e178..af8a8d5d19 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/SourceLocation.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ -#define COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ +#ifndef COMPILER_PREPROCESSOR_SOURCELOCATION_H_ +#define COMPILER_PREPROCESSOR_SOURCELOCATION_H_ namespace pp { @@ -43,4 +43,5 @@ inline bool operator!=(const SourceLocation &lhs, const SourceLocation &rhs) } } // namespace pp -#endif // COMPILER_PREPROCESSOR_SOURCE_LOCATION_H_ + +#endif // COMPILER_PREPROCESSOR_SOURCELOCATION_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Token.h b/src/3rdparty/angle/src/compiler/preprocessor/Token.h index 8832e279c7..347c47e307 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Token.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Token.h @@ -116,4 +116,5 @@ inline bool operator!=(const Token &lhs, const Token &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/Tokenizer.h b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h index 07ad93da05..78eb86dd3b 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.h @@ -55,5 +55,5 @@ class Tokenizer : public Lexer }; } // namespace pp -#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_ +#endif // COMPILER_PREPROCESSOR_TOKENIZER_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l index 2a77b905a4..89cb5c8596 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l +++ b/src/3rdparty/angle/src/compiler/preprocessor/Tokenizer.l @@ -267,7 +267,9 @@ FRACTIONAL_CONSTANT ({DIGIT}*"."{DIGIT}+)|({DIGIT}+".") namespace pp { -Tokenizer::Tokenizer(Diagnostics *diagnostics) : mHandle(0) +Tokenizer::Tokenizer(Diagnostics *diagnostics) + : mHandle(0), + mMaxTokenSize(256) { mContext.diagnostics = diagnostics; } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h index 8a24540696..58c51b0961 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/numeric_lex.h @@ -6,8 +6,8 @@ // numeric_lex.h: Functions to extract numeric values from string. -#ifndef COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ -#define COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ +#ifndef COMPILER_PREPROCESSOR_NUMERICLEX_H_ +#define COMPILER_PREPROCESSOR_NUMERICLEX_H_ #include @@ -58,4 +58,5 @@ bool numeric_lex_float(const std::string &str, FloatType *value) } } // namespace pp. -#endif // COMPILER_PREPROCESSOR_NUMERIC_LEX_H_ + +#endif // COMPILER_PREPROCESSOR_NUMERICLEX_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h index 324b0669f4..ee1428b2d3 100644 --- a/src/3rdparty/angle/src/compiler/translator/BaseTypes.h +++ b/src/3rdparty/angle/src/compiler/translator/BaseTypes.h @@ -4,10 +4,10 @@ // found in the LICENSE file. // -#ifndef _BASICTYPES_INCLUDED_ -#define _BASICTYPES_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_BASETYPES_H_ +#define COMPILER_TRANSLATOR_BASETYPES_H_ -#include +#include "compiler/translator/compilerdebug.h" // // Precision qualifiers @@ -42,7 +42,15 @@ enum TBasicType EbtInt, EbtUInt, EbtBool, - EbtGVec4, // non type: represents vec4, ivec4 and uvec4 + EbtGVec4, // non type: represents vec4, ivec4, and uvec4 + EbtGenType, // non type: represents float, vec2, vec3, and vec4 + EbtGenIType, // non type: represents int, ivec2, ivec3, and ivec4 + EbtGenUType, // non type: represents uint, uvec2, uvec3, and uvec4 + EbtGenBType, // non type: represents bool, bvec2, bvec3, and bvec4 + EbtVec, // non type: represents vec2, vec3, and vec4 + EbtIVec, // non type: represents ivec2, ivec3, and ivec4 + EbtUVec, // non type: represents uvec2, uvec3, and uvec4 + EbtBVec, // non type: represents bvec2, bvec3, and bvec4 EbtGuardSamplerBegin, // non type: see implementation of IsSampler() EbtSampler2D, EbtSampler3D, @@ -62,10 +70,10 @@ enum TBasicType EbtSamplerCubeShadow, EbtSampler2DArrayShadow, EbtGuardSamplerEnd, // non type: see implementation of IsSampler() - EbtGSampler2D, // non type: represents sampler2D, isampler2D and usampler2D - EbtGSampler3D, // non type: represents sampler3D, isampler3D and usampler3D - EbtGSamplerCube, // non type: represents samplerCube, isamplerCube and usamplerCube - EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray and usampler2DArray + EbtGSampler2D, // non type: represents sampler2D, isampler2D, and usampler2D + EbtGSampler3D, // non type: represents sampler3D, isampler3D, and usampler3D + EbtGSamplerCube, // non type: represents samplerCube, isamplerCube, and usamplerCube + EbtGSampler2DArray, // non type: represents sampler2DArray, isampler2DArray, and usampler2DArray EbtStruct, EbtInterfaceBlock, EbtAddress, // should be deprecated?? @@ -258,6 +266,11 @@ inline bool IsShadowSampler(TBasicType type) return false; } +inline bool IsInteger(TBasicType type) +{ + return type == EbtInt || type == EbtUInt; +} + inline bool SupportsPrecision(TBasicType type) { return type == EbtFloat || type == EbtInt || type == EbtUInt || IsSampler(type); @@ -293,6 +306,9 @@ enum TQualifier EvqInOut, EvqConstReadOnly, + // built-ins read by vertex shader + EvqInstanceID, + // built-ins written by vertex shader EvqPosition, EvqPointSize, @@ -307,6 +323,10 @@ enum TQualifier EvqFragData, EvqFragDepth, + // built-ins written by the shader_framebuffer_fetch extension(s) + EvqLastFragColor, + EvqLastFragData, + // GLSL ES 3.0 vertex output and fragment input EvqSmooth, // Incomplete qualifier, smooth is the default EvqFlat, // Incomplete qualifier @@ -383,6 +403,7 @@ inline const char* getQualifierString(TQualifier q) case EvqIn: return "in"; break; case EvqOut: return "out"; break; case EvqInOut: return "inout"; break; + case EvqInstanceID: return "InstanceID"; break; case EvqPosition: return "Position"; break; case EvqPointSize: return "PointSize"; break; case EvqFragCoord: return "FragCoord"; break; @@ -396,7 +417,9 @@ inline const char* getQualifierString(TQualifier q) case EvqSmoothIn: return "smooth in"; break; case EvqCentroidIn: return "centroid in"; break; case EvqFlatIn: return "flat in"; break; - default: return "unknown qualifier"; + case EvqLastFragColor: return "LastFragColor"; break; + case EvqLastFragData: return "LastFragData"; break; + default: UNREACHABLE(); return "unknown qualifier"; } } @@ -407,7 +430,7 @@ inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq) case EmpUnspecified: return "mp_unspecified"; case EmpRowMajor: return "row_major"; case EmpColumnMajor: return "column_major"; - default: return "unknown matrix packing"; + default: UNREACHABLE(); return "unknown matrix packing"; } } @@ -419,7 +442,7 @@ inline const char* getBlockStorageString(TLayoutBlockStorage bsq) case EbsShared: return "shared"; case EbsPacked: return "packed"; case EbsStd140: return "std140"; - default: return "unknown block storage"; + default: UNREACHABLE(); return "unknown block storage"; } } @@ -433,8 +456,8 @@ inline const char* getInterpolationString(TQualifier q) case EvqSmoothIn: return "smooth"; break; case EvqCentroidIn: return "centroid"; break; case EvqFlatIn: return "flat"; break; - default: return "unknown interpolation"; + default: UNREACHABLE(); return "unknown interpolation"; } } -#endif // _BASICTYPES_INCLUDED_ +#endif // COMPILER_TRANSLATOR_BASETYPES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp index 0e8239cc1e..51461207c5 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.cpp @@ -8,193 +8,9 @@ #include "compiler/translator/BuiltInFunctionEmulator.h" #include "compiler/translator/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: +class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser +{ + public: BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator& emulator) : mEmulator(emulator) { @@ -238,148 +54,119 @@ public: case EOpFaceForward: case EOpReflect: case EOpRefract: + case EOpOuterProduct: 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) + bool needToEmulate = false; + // Right now we only handle built-in functions with two or three parameters. + if (sequence.size() == 2) + { + TIntermTyped* param1 = sequence[0]->getAsTyped(); + TIntermTyped* param2 = sequence[1]->getAsTyped(); + if (!param1 || !param2) + return true; + needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), param1->getType(), param2->getType()); + } + else if (sequence.size() == 3) + { + TIntermTyped* param1 = sequence[0]->getAsTyped(); + TIntermTyped* param2 = sequence[1]->getAsTyped(); + TIntermTyped* param3 = sequence[2]->getAsTyped(); + if (!param1 || !param2 || !param3) + return true; + needToEmulate = mEmulator.SetFunctionCalled( + node->getOp(), param1->getType(), param2->getType(), param3->getType()); + } + else + { return true; - bool needToEmulate = mEmulator.SetFunctionCalled( - node->getOp(), param1->getType(), param2->getType()); + } + if (needToEmulate) node->setUseEmulatedFunction(); } return true; } -private: + private: BuiltInFunctionEmulator& mEmulator; }; -} // anonymous namepsace +BuiltInFunctionEmulator::BuiltInFunctionEmulator() +{} -BuiltInFunctionEmulator::BuiltInFunctionEmulator(sh::GLenum shaderType) +void BuiltInFunctionEmulator::addEmulatedFunction( + TOperator op, const TType& param, + const char* emulatedFunctionDefinition) { - if (shaderType == GL_FRAGMENT_SHADER) { - mFunctionMask = kFunctionEmulationFragmentMask; - mFunctionSource = kFunctionEmulationFragmentSource; - } else { - mFunctionMask = kFunctionEmulationVertexMask; - mFunctionSource = kFunctionEmulationVertexSource; - } + mEmulatedFunctions[FunctionId(op, param)] = + std::string(emulatedFunctionDefinition); } -bool BuiltInFunctionEmulator::SetFunctionCalled( - TOperator op, const TType& param) +void BuiltInFunctionEmulator::addEmulatedFunction( + TOperator op, const TType& param1, const TType& param2, + const char* emulatedFunctionDefinition) { - TBuiltInFunction function = IdentifyFunction(op, param); - return SetFunctionCalled(function); + mEmulatedFunctions[FunctionId(op, param1, param2)] = + std::string(emulatedFunctionDefinition); } -bool BuiltInFunctionEmulator::SetFunctionCalled( - TOperator op, const TType& param1, const TType& param2) +void BuiltInFunctionEmulator::addEmulatedFunction( + TOperator op, const TType& param1, const TType& param2, const TType& param3, + const char* emulatedFunctionDefinition) { - TBuiltInFunction function = IdentifyFunction(op, param1, param2); - return SetFunctionCalled(function); + mEmulatedFunctions[FunctionId(op, param1, param2, param3)] = + std::string(emulatedFunctionDefinition); } -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; +bool BuiltInFunctionEmulator::IsOutputEmpty() const +{ + return (mFunctions.size() == 0); } -void BuiltInFunctionEmulator::OutputEmulatedFunctionDefinition( - TInfoSinkBase& out, bool withPrecision) const +void BuiltInFunctionEmulator::OutputEmulatedFunctions( + TInfoSinkBase& out) 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 << mEmulatedFunctions.find(mFunctions[i])->second << "\n\n"; } - out << "// END: Generated code for built-in function emulation\n\n"; } -BuiltInFunctionEmulator::TBuiltInFunction -BuiltInFunctionEmulator::IdentifyFunction( +bool BuiltInFunctionEmulator::SetFunctionCalled( TOperator op, const TType& param) { - if (param.getNominalSize() > 4 || param.getSecondarySize() > 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); + return SetFunctionCalled(FunctionId(op, param)); } -BuiltInFunctionEmulator::TBuiltInFunction -BuiltInFunctionEmulator::IdentifyFunction( +bool BuiltInFunctionEmulator::SetFunctionCalled( 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.getNominalSize() != param2.getNominalSize() || - param1.getSecondarySize() != param2.getSecondarySize() || - param1.getNominalSize() > 4 || param1.getSecondarySize() > 4) - return TFunctionUnknown; + return SetFunctionCalled(FunctionId(op, param1, param2)); +} + +bool BuiltInFunctionEmulator::SetFunctionCalled( + TOperator op, const TType& param1, const TType& param2, const TType& param3) +{ + return SetFunctionCalled(FunctionId(op, param1, param2, param3)); +} - 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; +bool BuiltInFunctionEmulator::SetFunctionCalled( + const FunctionId& functionId) { + if (mEmulatedFunctions.find(functionId) != mEmulatedFunctions.end()) + { + for (size_t i = 0; i < mFunctions.size(); ++i) { + if (mFunctions[i] == functionId) + return true; + } + mFunctions.push_back(functionId); + return true; } - if (function == TFunctionUnknown) - return TFunctionUnknown; - if (param1.isVector()) - function += param1.getNominalSize() - 1; - return static_cast(function); + return false; } void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( @@ -387,6 +174,9 @@ void BuiltInFunctionEmulator::MarkBuiltInFunctionsForEmulation( { ASSERT(root); + if (mEmulatedFunctions.empty()) + return; + BuiltInFunctionEmulationMarker marker(*this); root->traverse(&marker); } @@ -404,3 +194,52 @@ TString BuiltInFunctionEmulator::GetEmulatedFunctionName( return "webgl_" + name.substr(0, name.length() - 1) + "_emu("; } +BuiltInFunctionEmulator::FunctionId::FunctionId + (TOperator op, const TType& param) + : mOp(op), + mParam1(param), + mParam2(EbtVoid), + mParam3(EbtVoid) +{ +} + +BuiltInFunctionEmulator::FunctionId::FunctionId + (TOperator op, const TType& param1, const TType& param2) + : mOp(op), + mParam1(param1), + mParam2(param2), + mParam3(EbtVoid) +{ +} + +BuiltInFunctionEmulator::FunctionId::FunctionId + (TOperator op, const TType& param1, const TType& param2, const TType& param3) + : mOp(op), + mParam1(param1), + mParam2(param2), + mParam3(param3) +{ +} + +bool BuiltInFunctionEmulator::FunctionId::operator== + (const BuiltInFunctionEmulator::FunctionId& other) const +{ + return (mOp == other.mOp && + mParam1 == other.mParam1 && + mParam2 == other.mParam2 && + mParam3 == other.mParam3); +} + +bool BuiltInFunctionEmulator::FunctionId::operator< + (const BuiltInFunctionEmulator::FunctionId& other) const +{ + if (mOp != other.mOp) + return mOp < other.mOp; + if (mParam1 != other.mParam1) + return mParam1 < other.mParam1; + if (mParam2 != other.mParam2) + return mParam2 < other.mParam2; + if (mParam3 != other.mParam3) + return mParam3 < other.mParam3; + return false; // all fields are equal +} diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h index c6bf77c386..df556985e1 100644 --- a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulator.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ -#define COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ +#ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" @@ -13,23 +13,13 @@ // // 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. +// It can be used to work around driver bugs or implement functions that are +// not natively implemented on a specific platform. // -class BuiltInFunctionEmulator { -public: - BuiltInFunctionEmulator(sh::GLenum 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; +class BuiltInFunctionEmulator +{ + public: + BuiltInFunctionEmulator(); void MarkBuiltInFunctionsForEmulation(TIntermNode* root); @@ -38,54 +28,52 @@ public: // "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 - }; + bool IsOutputEmpty() const; + + // Output function emulation definition. This should be before any other + // shader source. + void OutputEmulatedFunctions(TInfoSinkBase& out) const; + + // Add functions that need to be emulated. + void addEmulatedFunction(TOperator op, const TType& param, const char* emulatedFunctionDefinition); + void addEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const char* emulatedFunctionDefinition); + void addEmulatedFunction(TOperator op, const TType& param1, const TType& param2, const TType& param3, const char* emulatedFunctionDefinition); - TBuiltInFunction IdentifyFunction(TOperator op, const TType& param); - TBuiltInFunction IdentifyFunction( + private: + class BuiltInFunctionEmulationMarker; + + // Records that a function is called by the shader and might need to be + // emulated. If the function is not in mEmulatedFunctions, this becomes a + // 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); + bool SetFunctionCalled( + TOperator op, const TType& param1, const TType& param2, const TType& param3); + + class FunctionId { + public: + FunctionId(TOperator op, const TType& param); + FunctionId(TOperator op, const TType& param1, const TType& param2); + FunctionId(TOperator op, const TType& param1, const TType& param2, const TType& param3); + + bool operator==(const FunctionId& other) const; + bool operator<(const FunctionId& other) const; + private: + TOperator mOp; + TType mParam1; + TType mParam2; + TType mParam3; + }; - bool SetFunctionCalled(TBuiltInFunction function); + bool SetFunctionCalled(const FunctionId& functionId); - std::vector mFunctions; + // Map from function id to emulated function definition + std::map mEmulatedFunctions; - const bool* mFunctionMask; // a boolean flag for each function. - const char** mFunctionSource; + // Called function ids + std::vector mFunctions; }; -#endif // COMPILIER_BUILT_IN_FUNCTION_EMULATOR_H_ +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp new file mode 100644 index 0000000000..9de99831ad --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp @@ -0,0 +1,37 @@ +// +// 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 "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" +#include "compiler/translator/SymbolTable.h" + +void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType) +{ + // 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. + + TType float1(EbtFloat); + TType float2(EbtFloat, 2); + TType float3(EbtFloat, 3); + TType float4(EbtFloat, 4); + + if (shaderType == GL_FRAGMENT_SHADER) + { + emu->addEmulatedFunction(EOpCos, float1, "webgl_emu_precision float webgl_cos_emu(webgl_emu_precision float a) { return cos(a); }"); + emu->addEmulatedFunction(EOpCos, float2, "webgl_emu_precision vec2 webgl_cos_emu(webgl_emu_precision vec2 a) { return cos(a); }"); + emu->addEmulatedFunction(EOpCos, float3, "webgl_emu_precision vec3 webgl_cos_emu(webgl_emu_precision vec3 a) { return cos(a); }"); + emu->addEmulatedFunction(EOpCos, float4, "webgl_emu_precision vec4 webgl_cos_emu(webgl_emu_precision vec4 a) { return cos(a); }"); + } + emu->addEmulatedFunction(EOpDistance, float1, float1, "#define webgl_distance_emu(x, y) ((x) >= (y) ? (x) - (y) : (y) - (x))"); + emu->addEmulatedFunction(EOpDot, float1, float1, "#define webgl_dot_emu(x, y) ((x) * (y))"); + emu->addEmulatedFunction(EOpLength, float1, "#define webgl_length_emu(x) ((x) >= 0.0 ? (x) : -(x))"); + emu->addEmulatedFunction(EOpNormalize, float1, "#define webgl_normalize_emu(x) ((x) == 0.0 ? 0.0 : ((x) > 0.0 ? 1.0 : -1.0))"); + emu->addEmulatedFunction(EOpReflect, float1, float1, "#define webgl_reflect_emu(I, N) ((I) - 2.0 * (N) * (I) * (N))"); +} diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h new file mode 100644 index 0000000000..5707a4b35a --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h @@ -0,0 +1,19 @@ +// +// 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_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ + +#include "GLSLANG/ShaderLang.h" + +class BuiltInFunctionEmulator; + +// +// This is only a workaround for OpenGL driver bugs, and isn't needed in general. +// +void InitBuiltInFunctionEmulatorForGLSL(BuiltInFunctionEmulator *emu, sh::GLenum shaderType); + +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp new file mode 100644 index 0000000000..7123a0d5c0 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp @@ -0,0 +1,410 @@ +// +// Copyright (c) 2014 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 "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" +#include "compiler/translator/SymbolTable.h" + +void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu) +{ + TType float1(EbtFloat); + TType float2(EbtFloat, 2); + TType float3(EbtFloat, 3); + TType float4(EbtFloat, 4); + + emu->addEmulatedFunction(EOpMod, float1, float1, + "float webgl_mod_emu(float x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float2, float2, + "float2 webgl_mod_emu(float2 x, float2 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float2, float1, + "float2 webgl_mod_emu(float2 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float3, float3, + "float3 webgl_mod_emu(float3 x, float3 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float3, float1, + "float3 webgl_mod_emu(float3 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float4, float4, + "float4 webgl_mod_emu(float4 x, float4 y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + emu->addEmulatedFunction(EOpMod, float4, float1, + "float4 webgl_mod_emu(float4 x, float y)\n" + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"); + + emu->addEmulatedFunction(EOpFaceForward, float1, float1, float1, + "float webgl_faceforward_emu(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"); + emu->addEmulatedFunction(EOpFaceForward, float2, float2, float2, + "float2 webgl_faceforward_emu(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"); + emu->addEmulatedFunction(EOpFaceForward, float3, float3, float3, + "float3 webgl_faceforward_emu(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"); + emu->addEmulatedFunction(EOpFaceForward, float4, float4, float4, + "float4 webgl_faceforward_emu(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"); + + emu->addEmulatedFunction(EOpAtan, float1, float1, + "float webgl_atan_emu(float y, float x)\n" + "{\n" + " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN + " return atan2(y, x);\n" + "}\n"); + emu->addEmulatedFunction(EOpAtan, float2, float2, + "float2 webgl_atan_emu(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"); + emu->addEmulatedFunction(EOpAtan, float3, float3, + "float3 webgl_atan_emu(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"); + emu->addEmulatedFunction(EOpAtan, float4, float4, + "float4 webgl_atan_emu(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"); + + emu->addEmulatedFunction(EOpAsinh, float1, + "float webgl_asinh_emu(in float x) {\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAsinh, float2, + "float2 webgl_asinh_emu(in float2 x) {\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAsinh, float3, + "float3 webgl_asinh_emu(in float3 x) {\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAsinh, float4, + "float4 webgl_asinh_emu(in float4 x) {\n" + " return log(x + sqrt(pow(x, 2.0) + 1.0));\n" + "}\n"); + + emu->addEmulatedFunction(EOpAcosh, float1, + "float webgl_acosh_emu(in float x) {\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAcosh, float2, + "float2 webgl_acosh_emu(in float2 x) {\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAcosh, float3, + "float3 webgl_acosh_emu(in float3 x) {\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"); + emu->addEmulatedFunction(EOpAcosh, float4, + "float4 webgl_acosh_emu(in float4 x) {\n" + " return log(x + sqrt(x + 1.0) * sqrt(x - 1.0));\n" + "}\n"); + + emu->addEmulatedFunction(EOpAtanh, float1, + "float webgl_atanh_emu(in float x) {\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"); + emu->addEmulatedFunction(EOpAtanh, float2, + "float2 webgl_atanh_emu(in float2 x) {\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"); + emu->addEmulatedFunction(EOpAtanh, float3, + "float3 webgl_atanh_emu(in float3 x) {\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"); + emu->addEmulatedFunction(EOpAtanh, float4, + "float4 webgl_atanh_emu(in float4 x) {\n" + " return 0.5 * log((1.0 + x) / (1.0 - x));\n" + "}\n"); + + emu->addEmulatedFunction(EOpRoundEven, float1, + "float webgl_roundEven_emu(in float x) {\n" + " return (frac(x) == 0.5 && trunc(x) % 2.0 == 0.0) ? trunc(x) : round(x);\n" + "}\n"); + emu->addEmulatedFunction(EOpRoundEven, float2, + "float2 webgl_roundEven_emu(in float2 x) {\n" + " float2 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " return v;\n" + "}\n"); + emu->addEmulatedFunction(EOpRoundEven, float3, + "float3 webgl_roundEven_emu(in float3 x) {\n" + " float3 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" + " return v;\n" + "}\n"); + emu->addEmulatedFunction(EOpRoundEven, float4, + "float4 webgl_roundEven_emu(in float4 x) {\n" + " float4 v;\n" + " v[0] = (frac(x[0]) == 0.5 && trunc(x[0]) % 2.0 == 0.0) ? trunc(x[0]) : round(x[0]);\n" + " v[1] = (frac(x[1]) == 0.5 && trunc(x[1]) % 2.0 == 0.0) ? trunc(x[1]) : round(x[1]);\n" + " v[2] = (frac(x[2]) == 0.5 && trunc(x[2]) % 2.0 == 0.0) ? trunc(x[2]) : round(x[2]);\n" + " v[3] = (frac(x[3]) == 0.5 && trunc(x[3]) % 2.0 == 0.0) ? trunc(x[3]) : round(x[3]);\n" + " return v;\n" + "}\n"); + + emu->addEmulatedFunction(EOpPackSnorm2x16, float2, + "int webgl_toSnorm(in float x) {\n" + " return int(round(clamp(x, -1.0, 1.0) * 32767.0));\n" + "}\n" + "\n" + "uint webgl_packSnorm2x16_emu(in float2 v) {\n" + " int x = webgl_toSnorm(v.x);\n" + " int y = webgl_toSnorm(v.y);\n" + " return (asuint(y) << 16) | (asuint(x) & 0xffffu);\n" + "}\n"); + emu->addEmulatedFunction(EOpPackUnorm2x16, float2, + "uint webgl_toUnorm(in float x) {\n" + " return uint(round(clamp(x, 0.0, 1.0) * 65535.0));\n" + "}\n" + "\n" + "uint webgl_packUnorm2x16_emu(in float2 v) {\n" + " uint x = webgl_toUnorm(v.x);\n" + " uint y = webgl_toUnorm(v.y);\n" + " return (y << 16) | x;\n" + "}\n"); + emu->addEmulatedFunction(EOpPackHalf2x16, float2, + "uint webgl_packHalf2x16_emu(in float2 v) {\n" + " uint x = f32tof16(v.x);\n" + " uint y = f32tof16(v.y);\n" + " return (y << 16) | x;\n" + "}\n"); + + TType uint1(EbtUInt); + + emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1, + "float webgl_fromSnorm(in uint x) {\n" + " int xi = asint(x & 0x7fffu) - asint(x & 0x8000u);\n" + " return clamp(float(xi) / 32767.0, -1.0, 1.0);\n" + "}\n" + "\n" + "float2 webgl_unpackSnorm2x16_emu(in uint u) {\n" + " uint y = (u >> 16);\n" + " uint x = u;\n" + " return float2(webgl_fromSnorm(x), webgl_fromSnorm(y));\n" + "}\n"); + emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1, + "float webgl_fromUnorm(in uint x) {\n" + " return float(x) / 65535.0;\n" + "}\n" + "\n" + "float2 webgl_unpackUnorm2x16_emu(in uint u) {\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xffffu;\n" + " return float2(webgl_fromUnorm(x), webgl_fromUnorm(y));\n" + "}\n"); + emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1, + "float2 webgl_unpackHalf2x16_emu(in uint u) {\n" + " uint y = (u >> 16);\n" + " uint x = u & 0xffffu;\n" + " return float2(f16tof32(x), f16tof32(y));\n" + "}\n"); + + // The matrix resulting from outer product needs to be transposed + // (matrices are stored as transposed to simplify element access in HLSL). + // So the function should return transpose(c * r) where c is a column vector + // and r is a row vector. This can be simplified by using the following + // formula: + // transpose(c * r) = transpose(r) * transpose(c) + // transpose(r) and transpose(c) are in a sense free, since to get the + // transpose of r, we simply can build a column matrix out of the original + // vector instead of a row matrix. + emu->addEmulatedFunction(EOpOuterProduct, float2, float2, + "float2x2 webgl_outerProduct_emu(in float2 c, in float2 r) {\n" + " return mul(float2x1(r), float1x2(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float3, float3, + "float3x3 webgl_outerProduct_emu(in float3 c, in float3 r) {\n" + " return mul(float3x1(r), float1x3(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float4, float4, + "float4x4 webgl_outerProduct_emu(in float4 c, in float4 r) {\n" + " return mul(float4x1(r), float1x4(c));\n" + "}\n"); + + emu->addEmulatedFunction(EOpOuterProduct, float3, float2, + "float2x3 webgl_outerProduct_emu(in float3 c, in float2 r) {\n" + " return mul(float2x1(r), float1x3(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float2, float3, + "float3x2 webgl_outerProduct_emu(in float2 c, in float3 r) {\n" + " return mul(float3x1(r), float1x2(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float4, float2, + "float2x4 webgl_outerProduct_emu(in float4 c, in float2 r) {\n" + " return mul(float2x1(r), float1x4(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float2, float4, + "float4x2 webgl_outerProduct_emu(in float2 c, in float4 r) {\n" + " return mul(float4x1(r), float1x2(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float4, float3, + "float3x4 webgl_outerProduct_emu(in float4 c, in float3 r) {\n" + " return mul(float3x1(r), float1x4(c));\n" + "}\n"); + emu->addEmulatedFunction(EOpOuterProduct, float3, float4, + "float4x3 webgl_outerProduct_emu(in float3 c, in float4 r) {\n" + " return mul(float4x1(r), float1x3(c));\n" + "}\n"); + + TType mat2(EbtFloat, 2, 2); + TType mat3(EbtFloat, 3, 3); + TType mat4(EbtFloat, 4, 4); + + // Remember here that the parameter matrix is actually the transpose + // of the matrix that we're trying to invert, and the resulting matrix + // should also be the transpose of the inverse. + + // When accessing the parameter matrix with m[a][b] it can be thought of so + // that a is the column and b is the row of the matrix that we're inverting. + + // We calculate the inverse as the adjugate matrix divided by the + // determinant of the matrix being inverted. However, as the result needs + // to be transposed, we actually use of the transpose of the adjugate matrix + // which happens to be the cofactor matrix. That's stored in "cof". + + // We don't need to care about divide-by-zero since results are undefined + // for singular or poorly-conditioned matrices. + + emu->addEmulatedFunction(EOpInverse, mat2, + "float2x2 webgl_inverse_emu(in float2x2 m) {\n" + " float2x2 cof = { m[1][1], -m[0][1], -m[1][0], m[0][0] };\n" + " return cof / determinant(transpose(m));\n" + "}\n"); + + // cofAB is the cofactor for column A and row B. + + emu->addEmulatedFunction(EOpInverse, mat3, + "float3x3 webgl_inverse_emu(in float3x3 m) {\n" + " float cof00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n" + " float cof01 = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n" + " float cof02 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n" + " float cof10 = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n" + " float cof11 = m[0][0] * m[2][2] - m[2][0] * m[0][2];\n" + " float cof12 = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n" + " float cof20 = m[0][1] * m[1][2] - m[1][1] * m[0][2];\n" + " float cof21 = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n" + " float cof22 = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n" + " float3x3 cof = { cof00, cof10, cof20, cof01, cof11, cof21, cof02, cof12, cof22 };\n" + " return cof / determinant(transpose(m));\n" + "}\n"); + + emu->addEmulatedFunction(EOpInverse, mat4, + "float4x4 webgl_inverse_emu(in float4x4 m) {\n" + " float cof00 = m[1][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3]" + " - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] - m[3][1] * m[2][2] * m[1][3];\n" + " float cof01 = -(m[1][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[1][3] + m[3][0] * m[1][2] * m[2][3]" + " - m[1][0] * m[3][2] * m[2][3] - m[2][0] * m[1][2] * m[3][3] - m[3][0] * m[2][2] * m[1][3]);\n" + " float cof02 = m[1][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[1][3] + m[3][0] * m[1][1] * m[2][3]" + " - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] - m[3][0] * m[2][1] * m[1][3];\n" + " float cof03 = -(m[1][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[1][2] + m[3][0] * m[1][1] * m[2][2]" + " - m[1][0] * m[3][1] * m[2][2] - m[2][0] * m[1][1] * m[3][2] - m[3][0] * m[2][1] * m[1][2]);\n" + " float cof10 = -(m[0][1] * m[2][2] * m[3][3] + m[2][1] * m[3][2] * m[0][3] + m[3][1] * m[0][2] * m[2][3]" + " - m[0][1] * m[3][2] * m[2][3] - m[2][1] * m[0][2] * m[3][3] - m[3][1] * m[2][2] * m[0][3]);\n" + " float cof11 = m[0][0] * m[2][2] * m[3][3] + m[2][0] * m[3][2] * m[0][3] + m[3][0] * m[0][2] * m[2][3]" + " - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] - m[3][0] * m[2][2] * m[0][3];\n" + " float cof12 = -(m[0][0] * m[2][1] * m[3][3] + m[2][0] * m[3][1] * m[0][3] + m[3][0] * m[0][1] * m[2][3]" + " - m[0][0] * m[3][1] * m[2][3] - m[2][0] * m[0][1] * m[3][3] - m[3][0] * m[2][1] * m[0][3]);\n" + " float cof13 = m[0][0] * m[2][1] * m[3][2] + m[2][0] * m[3][1] * m[0][2] + m[3][0] * m[0][1] * m[2][2]" + " - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] - m[3][0] * m[2][1] * m[0][2];\n" + " float cof20 = m[0][1] * m[1][2] * m[3][3] + m[1][1] * m[3][2] * m[0][3] + m[3][1] * m[0][2] * m[1][3]" + " - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] - m[3][1] * m[1][2] * m[0][3];\n" + " float cof21 = -(m[0][0] * m[1][2] * m[3][3] + m[1][0] * m[3][2] * m[0][3] + m[3][0] * m[0][2] * m[1][3]" + " - m[0][0] * m[3][2] * m[1][3] - m[1][0] * m[0][2] * m[3][3] - m[3][0] * m[1][2] * m[0][3]);\n" + " float cof22 = m[0][0] * m[1][1] * m[3][3] + m[1][0] * m[3][1] * m[0][3] + m[3][0] * m[0][1] * m[1][3]" + " - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] - m[3][0] * m[1][1] * m[0][3];\n" + " float cof23 = -(m[0][0] * m[1][1] * m[3][2] + m[1][0] * m[3][1] * m[0][2] + m[3][0] * m[0][1] * m[1][2]" + " - m[0][0] * m[3][1] * m[1][2] - m[1][0] * m[0][1] * m[3][2] - m[3][0] * m[1][1] * m[0][2]);\n" + " float cof30 = -(m[0][1] * m[1][2] * m[2][3] + m[1][1] * m[2][2] * m[0][3] + m[2][1] * m[0][2] * m[1][3]" + " - m[0][1] * m[2][2] * m[1][3] - m[1][1] * m[0][2] * m[2][3] - m[2][1] * m[1][2] * m[0][3]);\n" + " float cof31 = m[0][0] * m[1][2] * m[2][3] + m[1][0] * m[2][2] * m[0][3] + m[2][0] * m[0][2] * m[1][3]" + " - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] - m[2][0] * m[1][2] * m[0][3];\n" + " float cof32 = -(m[0][0] * m[1][1] * m[2][3] + m[1][0] * m[2][1] * m[0][3] + m[2][0] * m[0][1] * m[1][3]" + " - m[0][0] * m[2][1] * m[1][3] - m[1][0] * m[0][1] * m[2][3] - m[2][0] * m[1][1] * m[0][3]);\n" + " float cof33 = m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * m[0][1] * m[1][2]" + " - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] - m[2][0] * m[1][1] * m[0][2];\n" + " float4x4 cof = { cof00, cof10, cof20, cof30, cof01, cof11, cof21, cof31," + " cof02, cof12, cof22, cof32, cof03, cof13, cof23, cof33 };\n" + " return cof / determinant(transpose(m));\n" + "}\n"); +} diff --git a/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h new file mode 100644 index 0000000000..4c45a93dc4 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h @@ -0,0 +1,16 @@ +// +// Copyright (c) 2014 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_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ +#define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ + +#include "GLSLANG/ShaderLang.h" + +class BuiltInFunctionEmulator; + +void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu); + +#endif // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATORHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp index 71056f4297..5e3eb1cc05 100644 --- a/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp +++ b/src/3rdparty/angle/src/compiler/translator/CodeGen.cpp @@ -6,7 +6,9 @@ #include "compiler/translator/TranslatorESSL.h" #include "compiler/translator/TranslatorGLSL.h" +#ifdef ANGLE_ENABLE_HLSL #include "compiler/translator/TranslatorHLSL.h" +#endif // ANGLE_ENABLE_HLSL // // This function must be provided to create the actual @@ -17,14 +19,22 @@ TCompiler* ConstructCompiler( sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) { switch (output) { - case SH_ESSL_OUTPUT: + case SH_ESSL_OUTPUT: return new TranslatorESSL(type, spec); - case SH_GLSL_OUTPUT: - return new TranslatorGLSL(type, spec); - case SH_HLSL9_OUTPUT: - case SH_HLSL11_OUTPUT: + case SH_GLSL_CORE_OUTPUT: + case SH_GLSL_COMPATIBILITY_OUTPUT: + return new TranslatorGLSL(type, spec, output); + case SH_HLSL9_OUTPUT: + case SH_HLSL11_OUTPUT: +#ifdef ANGLE_ENABLE_HLSL return new TranslatorHLSL(type, spec, output); - default: +#else + // This compiler is not supported in this + // configuration. Return NULL per the ShConstructCompiler API. + return NULL; +#endif // ANGLE_ENABLE_HLSL + default: + // Unknown format. Return NULL per the ShConstructCompiler API. return NULL; } } diff --git a/src/3rdparty/angle/src/compiler/translator/Common.h b/src/3rdparty/angle/src/compiler/translator/Common.h index 1e4503e340..ac1aef0f4c 100644 --- a/src/3rdparty/angle/src/compiler/translator/Common.h +++ b/src/3rdparty/angle/src/compiler/translator/Common.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _COMMON_INCLUDED_ -#define _COMMON_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_COMMON_H_ +#define COMPILER_TRANSLATOR_COMMON_H_ #include #include @@ -89,4 +89,4 @@ inline TString str(T i) return buffer; } -#endif // _COMMON_INCLUDED_ +#endif // COMPILER_TRANSLATOR_COMMON_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp index 5c62a64d10..534861ca70 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp @@ -4,7 +4,6 @@ // found in the LICENSE file. // -#include "compiler/translator/BuiltInFunctionEmulator.h" #include "compiler/translator/Compiler.h" #include "compiler/translator/DetectCallDepth.h" #include "compiler/translator/ForLoopUnroll.h" @@ -126,7 +125,8 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) maxCallStackDepth(0), fragmentPrecisionHigh(false), clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), - builtInFunctionEmulator(type) + builtInFunctionEmulator(), + mSourcePath(NULL) { } @@ -159,33 +159,41 @@ bool TCompiler::Init(const ShBuiltInResources& resources) return true; } -bool TCompiler::compile(const char* const shaderStrings[], - size_t numStrings, - int compileOptions) +TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[], + size_t numStrings, int compileOptions) +{ + return compileTreeImpl(shaderStrings, numStrings, compileOptions); +} + +TIntermNode *TCompiler::compileTreeImpl(const char* const shaderStrings[], + size_t numStrings, int compileOptions) { - TScopedPoolAllocator scopedAlloc(&allocator); clearResults(); - if (numStrings == 0) - return true; + ASSERT(numStrings > 0); + ASSERT(GetGlobalPoolAllocator()); + + // Reset the extension behavior for each compilation unit. + ResetExtensionBehavior(extensionBehavior); // 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; size_t firstSource = 0; if (compileOptions & SH_SOURCE_PATH) { - sourcePath = shaderStrings[0]; + mSourcePath = shaderStrings[0]; ++firstSource; } + bool debugShaderPrecision = getResources().WEBGL_debug_shader_precision == 1; TIntermediate intermediate(infoSink); TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec, compileOptions, true, - sourcePath, infoSink); + infoSink, debugShaderPrecision); + parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; SetGlobalParseContext(&parseContext); @@ -206,6 +214,8 @@ bool TCompiler::compile(const char* const shaderStrings[], success = false; } + TIntermNode *root = NULL; + if (success) { mPragma = parseContext.pragma(); @@ -214,7 +224,7 @@ bool TCompiler::compile(const char* const shaderStrings[], symbolTable.setGlobalInvariant(); } - TIntermNode* root = parseContext.treeRoot; + root = parseContext.treeRoot; success = intermediate.postProcess(root); // Disallow expressions deemed too complex. @@ -255,8 +265,11 @@ bool TCompiler::compile(const char* const shaderStrings[], } // Built-in function emulation needs to happen after validateLimitations pass. - if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) + if (success) + { + initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions); builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); + } // Clamping uniform array bounds needs to happen after validateLimitations pass. if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) @@ -301,18 +314,37 @@ bool TCompiler::compile(const char* const shaderStrings[], RegenerateStructNames gen(symbolTable, shaderVersion); root->traverse(&gen); } - - if (success && (compileOptions & SH_INTERMEDIATE_TREE)) - intermediate.outputTree(root); - - if (success && (compileOptions & SH_OBJECT_CODE)) - translate(root); } - // Cleanup memory. - intermediate.remove(parseContext.treeRoot); SetGlobalParseContext(NULL); - return success; + if (success) + return root; + + return NULL; +} + +bool TCompiler::compile(const char* const shaderStrings[], + size_t numStrings, int compileOptions) +{ + if (numStrings == 0) + return true; + + TScopedPoolAllocator scopedAlloc(&allocator); + TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions); + + if (root) + { + if (compileOptions & SH_INTERMEDIATE_TREE) + TIntermediate::outputTree(root, infoSink.info); + + if (compileOptions & SH_OBJECT_CODE) + translate(root, compileOptions); + + // The IntermNode tree doesn't need to be deleted here, since the + // memory will be freed in a big chunk by the PoolAllocator. + return true; + } + return false; } bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) @@ -390,11 +422,15 @@ void TCompiler::setResourceString() << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth << ":EXT_frag_depth:" << compileResources.EXT_frag_depth << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod + << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch + << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch + << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset - << ":NV_draw_buffers:" << compileResources.NV_draw_buffers; + << ":NV_draw_buffers:" << compileResources.NV_draw_buffers + << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision; builtInResourcesString = strstream.str(); } @@ -416,27 +452,29 @@ void TCompiler::clearResults() builtInFunctionEmulator.Cleanup(); nameMap.clear(); + + mSourcePath = NULL; } -bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth) +bool TCompiler::detectCallDepth(TIntermNode* inputRoot, TInfoSink& inputInfoSink, bool limitCallStackDepth) { - DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth); - root->traverse(&detect); + DetectCallDepth detect(inputInfoSink, limitCallStackDepth, maxCallStackDepth); + inputRoot->traverse(&detect); switch (detect.detectCallDepth()) { case DetectCallDepth::kErrorNone: return true; case DetectCallDepth::kErrorMissingMain: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Missing main()"; + inputInfoSink.info.prefix(EPrefixError); + inputInfoSink.info << "Missing main()"; return false; case DetectCallDepth::kErrorRecursion: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Function recursion detected"; + inputInfoSink.info.prefix(EPrefixError); + inputInfoSink.info << "Function recursion detected"; return false; case DetectCallDepth::kErrorMaxDepthExceeded: - infoSink.info.prefix(EPrefixError); - infoSink.info << "Function call stack too deep"; + inputInfoSink.info.prefix(EPrefixError); + inputInfoSink.info << "Function call stack too deep"; return false; default: UNREACHABLE(); @@ -594,6 +632,11 @@ const TExtensionBehavior& TCompiler::getExtensionBehavior() const return extensionBehavior; } +const char *TCompiler::getSourcePath() const +{ + return mSourcePath; +} + const ShBuiltInResources& TCompiler::getResources() const { return compileResources; diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.h b/src/3rdparty/angle/src/compiler/translator/Compiler.h index b6c9d13ed0..bcdb0d4c9d 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.h +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _SHHANDLE_INCLUDED_ -#define _SHHANDLE_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_COMPILER_H_ +#define COMPILER_TRANSLATOR_COMPILER_H_ // // Machine independent part of the compiler private objects @@ -25,7 +25,9 @@ class TCompiler; class TDependencyGraph; +#ifdef ANGLE_ENABLE_HLSL class TranslatorHLSL; +#endif // ANGLE_ENABLE_HLSL // // Helper function to identify specs that are based on the WebGL spec, @@ -41,7 +43,9 @@ public: TShHandleBase(); virtual ~TShHandleBase(); virtual TCompiler* getAsCompiler() { return 0; } +#ifdef ANGLE_ENABLE_HLSL virtual TranslatorHLSL* getAsTranslatorHLSL() { return 0; } +#endif // ANGLE_ENABLE_HLSL protected: // Memory allocator. Allocates and tracks memory required by the compiler. @@ -61,9 +65,15 @@ class TCompiler : public TShHandleBase virtual TCompiler* getAsCompiler() { return this; } bool Init(const ShBuiltInResources& resources); + + // compileTreeForTesting should be used only when tests require access to + // the AST. Users of this function need to manually manage the global pool + // allocator. Returns NULL whenever there are compilation errors. + TIntermNode *compileTreeForTesting(const char* const shaderStrings[], + size_t numStrings, int compileOptions); + bool compile(const char* const shaderStrings[], - size_t numStrings, - int compileOptions); + size_t numStrings, int compileOptions); // Get results of the last compilation. int getShaderVersion() const { return shaderVersion; } @@ -104,8 +114,10 @@ class TCompiler : public TShHandleBase bool validateLimitations(TIntermNode* root); // Collect info for all attribs, uniforms, varyings. void collectVariables(TIntermNode* root); + // Add emulated functions to the built-in function emulator. + virtual void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) {}; // Translate to object code. - virtual void translate(TIntermNode* root) = 0; + virtual void translate(TIntermNode *root, int compileOptions) = 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(); @@ -130,6 +142,7 @@ class TCompiler : public TShHandleBase bool limitExpressionComplexity(TIntermNode* root); // Get built-in extensions with default behavior. const TExtensionBehavior& getExtensionBehavior() const; + const char *getSourcePath() const; const TPragma& getPragma() const { return mPragma; } void writePragma(); @@ -145,6 +158,9 @@ class TCompiler : public TShHandleBase std::vector interfaceBlocks; private: + TIntermNode *compileTreeImpl(const char* const shaderStrings[], + size_t numStrings, int compileOptions); + sh::GLenum shaderType; ShShaderSpec shaderSpec; ShShaderOutput outputType; @@ -170,6 +186,7 @@ class TCompiler : public TShHandleBase // Results of compilation. int shaderVersion; TInfoSink infoSink; // Output sink. + const char *mSourcePath; // Path of source file or NULL // name hashing. ShHashFunction64 hashFunction; @@ -191,4 +208,4 @@ TCompiler* ConstructCompiler( sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); void DeleteCompiler(TCompiler*); -#endif // _SHHANDLE_INCLUDED_ +#endif // COMPILER_TRANSLATOR_COMPILER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h index 5e86c64805..31ff2ccfa7 100644 --- a/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h +++ b/src/3rdparty/angle/src/compiler/translator/ConstantUnion.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _CONSTANT_UNION_INCLUDED_ -#define _CONSTANT_UNION_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_CONSTANTUNION_H_ +#define COMPILER_TRANSLATOR_CONSTANTUNION_H_ #include @@ -254,7 +254,10 @@ public: ConstantUnion operator<<(const ConstantUnion& constant) const { ConstantUnion returnValue; - assert(type == constant.type); + // The signedness of the second parameter might be different, but we + // don't care, since the result is undefined if the second parameter is + // negative, and aliasing should not be a problem with unions. + assert(constant.type == EbtInt || constant.type == EbtUInt); switch (type) { case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; case EbtUInt: returnValue.setUConst(uConst << constant.uConst); break; @@ -267,7 +270,7 @@ public: ConstantUnion operator&(const ConstantUnion& constant) const { ConstantUnion returnValue; - assert(type == constant.type); + assert(constant.type == EbtInt || constant.type == EbtUInt); switch (type) { case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; case EbtUInt: returnValue.setUConst(uConst & constant.uConst); break; @@ -340,4 +343,4 @@ private: TBasicType type; }; -#endif // _CONSTANT_UNION_INCLUDED_ +#endif // COMPILER_TRANSLATOR_CONSTANTUNION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp index bfc1d5852f..0dc5d22709 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp +++ b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.cpp @@ -33,7 +33,7 @@ int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDe ASSERT(visit == PreVisit); ASSERT(detectCallDepth); - int maxDepth = depth; + int retMaxDepth = depth; visit = InVisit; for (size_t i = 0; i < callees.size(); ++i) { switch (callees[i]->visit) { @@ -52,7 +52,7 @@ int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDe detectCallDepth->getInfoSink().info << "<-" << callees[i]->getName(); return callDepth; } - maxDepth = std::max(callDepth, maxDepth); + retMaxDepth = std::max(callDepth, retMaxDepth); break; } default: @@ -61,7 +61,7 @@ int DetectCallDepth::FunctionNode::detectCallDepth(DetectCallDepth* detectCallDe } } visit = PostVisit; - return maxDepth; + return retMaxDepth; } void DetectCallDepth::FunctionNode::reset() diff --git a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h index 86810650dc..8dd1391e67 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h +++ b/src/3rdparty/angle/src/compiler/translator/DetectCallDepth.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_DETECT_RECURSION_H_ -#define COMPILER_DETECT_RECURSION_H_ +#ifndef COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ +#define COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ #include #include "compiler/translator/IntermNode.h" @@ -75,4 +75,4 @@ private: void operator=(const DetectCallDepth&); }; -#endif // COMPILER_DETECT_RECURSION_H_ +#endif // COMPILER_TRANSLATOR_DETECTCALLDEPTH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h index 67e37be398..623be13533 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h +++ b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h @@ -8,8 +8,8 @@ // gradients of functions with discontinuities. // -#ifndef COMPILER_DETECTDISCONTINUITY_H_ -#define COMPILER_DETECTDISCONTINUITY_H_ +#ifndef COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ +#define COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ #include "compiler/translator/IntermNode.h" @@ -68,4 +68,4 @@ bool containsGradientOperation(TIntermNode *node); } -#endif // COMPILER_DETECTDISCONTINUITY_H_ +#endif // COMPILER_TRANSLATOR_DETECTDISCONTINUITY_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h index 664da7803b..078bc97772 100644 --- a/src/3rdparty/angle/src/compiler/translator/Diagnostics.h +++ b/src/3rdparty/angle/src/compiler/translator/Diagnostics.h @@ -4,14 +4,15 @@ // found in the LICENSE file. // -#ifndef COMPILER_DIAGNOSTICS_H_ -#define COMPILER_DIAGNOSTICS_H_ +#ifndef COMPILER_TRANSLATOR_DIAGNOSTICS_H_ +#define COMPILER_TRANSLATOR_DIAGNOSTICS_H_ +#include "common/angleutils.h" #include "compiler/preprocessor/DiagnosticsBase.h" class TInfoSink; -class TDiagnostics : public pp::Diagnostics +class TDiagnostics : public pp::Diagnostics, angle::NonCopyable { public: TDiagnostics(TInfoSink& infoSink); @@ -41,4 +42,4 @@ class TDiagnostics : public pp::Diagnostics int mNumWarnings; }; -#endif // COMPILER_DIAGNOSTICS_H_ +#endif // COMPILER_TRANSLATOR_DIAGNOSTICS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp index f67a03aa93..936c00a56c 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp @@ -27,10 +27,12 @@ static TBehavior getBehavior(const std::string& str) TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior, TDiagnostics& diagnostics, - int& shaderVersion) + int& shaderVersion, + bool debugShaderPrecisionSupported) : mExtensionBehavior(extBehavior), mDiagnostics(diagnostics), - mShaderVersion(shaderVersion) + mShaderVersion(shaderVersion), + mDebugShaderPrecisionSupported(debugShaderPrecisionSupported) { } @@ -65,6 +67,7 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, { const char kOptimize[] = "optimize"; const char kDebug[] = "debug"; + const char kDebugShaderPrecision[] = "webgl_debug_shader_precision"; const char kOn[] = "on"; const char kOff[] = "off"; @@ -81,6 +84,12 @@ void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, else if (value == kOff) mPragma.debug = false; else invalidValue = true; } + else if (name == kDebugShaderPrecision && mDebugShaderPrecisionSupported) + { + if (value == kOn) mPragma.debugShaderPrecision = true; + else if (value == kOff) mPragma.debugShaderPrecision = false; + else invalidValue = true; + } else { mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name); diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h index 0433c3bf89..2a81ee5707 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h @@ -4,21 +4,23 @@ // found in the LICENSE file. // -#ifndef COMPILER_DIRECTIVE_HANDLER_H_ -#define COMPILER_DIRECTIVE_HANDLER_H_ +#ifndef COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ +#define COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ +#include "common/angleutils.h" #include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/Pragma.h" #include "compiler/preprocessor/DirectiveHandlerBase.h" class TDiagnostics; -class TDirectiveHandler : public pp::DirectiveHandler +class TDirectiveHandler : public pp::DirectiveHandler, angle::NonCopyable { public: TDirectiveHandler(TExtensionBehavior& extBehavior, TDiagnostics& diagnostics, - int& shaderVersion); + int& shaderVersion, + bool debugShaderPrecisionSupported); virtual ~TDirectiveHandler(); const TPragma& pragma() const { return mPragma; } @@ -44,6 +46,7 @@ class TDirectiveHandler : public pp::DirectiveHandler TExtensionBehavior& mExtensionBehavior; TDiagnostics& mDiagnostics; int& mShaderVersion; + bool mDebugShaderPrecisionSupported; }; -#endif // COMPILER_DIRECTIVE_HANDLER_H_ +#endif // COMPILER_TRANSLATOR_DIRECTIVEHANDLER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp new file mode 100644 index 0000000000..697e042954 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.cpp @@ -0,0 +1,528 @@ +// +// Copyright (c) 2002-2014 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/translator/EmulatePrecision.h" + +namespace +{ + +static void writeVectorPrecisionEmulationHelpers( + TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size) +{ + std::stringstream vecTypeStrStr; + if (outputLanguage == SH_ESSL_OUTPUT) + vecTypeStrStr << "highp "; + vecTypeStrStr << "vec" << size; + std::string vecType = vecTypeStrStr.str(); + + sink << + vecType << " angle_frm(in " << vecType << " v) {\n" + " v = clamp(v, -65504.0, 65504.0);\n" + " " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n" + " bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n" + " v = v * exp2(-exponent);\n" + " v = sign(v) * floor(abs(v));\n" + " return v * exp2(exponent) * vec" << size << "(isNonZero);\n" + "}\n"; + + sink << + vecType << " angle_frl(in " << vecType << " v) {\n" + " v = clamp(v, -2.0, 2.0);\n" + " v = v * 256.0;\n" + " v = sign(v) * floor(abs(v));\n" + " return v * 0.00390625;\n" + "}\n"; +} + +static void writeMatrixPrecisionEmulationHelper( + TInfoSinkBase& sink, ShShaderOutput outputLanguage, unsigned int size, const char *functionName) +{ + std::stringstream matTypeStrStr; + if (outputLanguage == SH_ESSL_OUTPUT) + matTypeStrStr << "highp "; + matTypeStrStr << "mat" << size; + std::string matType = matTypeStrStr.str(); + + sink << matType << " " << functionName << "(in " << matType << " m) {\n" + " " << matType << " rounded;\n"; + + for (unsigned int i = 0; i < size; ++i) + { + sink << " rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n"; + } + + sink << " return rounded;\n" + "}\n"; +} + +static void writeCommonPrecisionEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage) +{ + // Write the angle_frm functions that round floating point numbers to + // half precision, and angle_frl functions that round them to minimum lowp + // precision. + + // Unoptimized version of angle_frm for single floats: + // + // int webgl_maxNormalExponent(in int exponentBits) { + // int possibleExponents = int(exp2(float(exponentBits))); + // int exponentBias = possibleExponents / 2 - 1; + // int allExponentBitsOne = possibleExponents - 1; + // return (allExponentBitsOne - 1) - exponentBias; + // } + // + // float angle_frm(in float x) { + // int mantissaBits = 10; + // int exponentBits = 5; + // float possibleMantissas = exp2(float(mantissaBits)); + // float mantissaMax = 2.0 - 1.0 / possibleMantissas; + // int maxNE = webgl_maxNormalExponent(exponentBits); + // float max = exp2(float(maxNE)) * mantissaMax; + // if (x > max) { + // return max; + // } + // if (x < -max) { + // return -max; + // } + // float exponent = floor(log2(abs(x))); + // if (abs(x) == 0.0 || exponent < -float(maxNE)) { + // return 0.0 * sign(x) + // } + // x = x * exp2(-(exponent - float(mantissaBits))); + // x = sign(x) * floor(abs(x)); + // return x * exp2(exponent - float(mantissaBits)); + // } + + // All numbers with a magnitude less than 2^-15 are subnormal, and are + // flushed to zero. + + // Note the constant numbers below: + // a) 65504 is the maximum possible mantissa (1.1111111111 in binary) times + // 2^15, the maximum normal exponent. + // b) 10.0 is the number of mantissa bits. + // c) -25.0 is the minimum normal half-float exponent -15.0 minus the number + // of mantissa bits. + // d) + 1e-30 is to make sure the argument of log2() won't be zero. It can + // only affect the result of log2 on x where abs(x) < 1e-22. Since these + // numbers will be flushed to zero either way (2^-15 is the smallest + // normal positive number), this does not introduce any error. + + std::string floatType = "float"; + if (outputLanguage == SH_ESSL_OUTPUT) + floatType = "highp float"; + + sink << + floatType << " angle_frm(in " << floatType << " x) {\n" + " x = clamp(x, -65504.0, 65504.0);\n" + " " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n" + " bool isNonZero = (exponent >= -25.0);\n" + " x = x * exp2(-exponent);\n" + " x = sign(x) * floor(abs(x));\n" + " return x * exp2(exponent) * float(isNonZero);\n" + "}\n"; + + sink << + floatType << " angle_frl(in " << floatType << " x) {\n" + " x = clamp(x, -2.0, 2.0);\n" + " x = x * 256.0;\n" + " x = sign(x) * floor(abs(x));\n" + " return x * 0.00390625;\n" + "}\n"; + + writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 2); + writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 3); + writeVectorPrecisionEmulationHelpers(sink, outputLanguage, 4); + for (unsigned int size = 2; size <= 4; ++size) + { + writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frm"); + writeMatrixPrecisionEmulationHelper(sink, outputLanguage, size, "angle_frl"); + } +} + +static void writeCompoundAssignmentPrecisionEmulation( + TInfoSinkBase& sink, ShShaderOutput outputLanguage, + const char *lType, const char *rType, const char *opStr, const char *opNameStr) +{ + std::string lTypeStr = lType; + std::string rTypeStr = rType; + if (outputLanguage == SH_ESSL_OUTPUT) + { + std::stringstream lTypeStrStr; + lTypeStrStr << "highp " << lType; + lTypeStr = lTypeStrStr.str(); + std::stringstream rTypeStrStr; + rTypeStrStr << "highp " << rType; + rTypeStr = rTypeStrStr.str(); + } + + // Note that y should be passed through angle_frm at the function call site, + // but x can't be passed through angle_frm there since it is an inout parameter. + // So only pass x and the result through angle_frm here. + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frm(angle_frm(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; + sink << + lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n" + " x = angle_frl(angle_frm(x) " << opStr << " y);\n" + " return x;\n" + "}\n"; +} + +const char *getFloatTypeStr(const TType& type) +{ + switch (type.getNominalSize()) + { + case 1: + return "float"; + case 2: + return type.getSecondarySize() > 1 ? "mat2" : "vec2"; + case 3: + return type.getSecondarySize() > 1 ? "mat3" : "vec3"; + case 4: + return type.getSecondarySize() > 1 ? "mat4" : "vec4"; + default: + UNREACHABLE(); + return NULL; + } +} + +bool canRoundFloat(const TType &type) +{ + return type.getBasicType() == EbtFloat && !type.isNonSquareMatrix() && !type.isArray() && + (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium); +} + +TIntermAggregate *createInternalFunctionCallNode(TString name, TIntermNode *child) +{ + TIntermAggregate *callNode = new TIntermAggregate(); + callNode->setOp(EOpInternalFunctionCall); + callNode->setName(name); + callNode->getSequence()->push_back(child); + return callNode; +} + +TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild) +{ + TString roundFunctionName; + if (roundedChild->getPrecision() == EbpMedium) + roundFunctionName = "angle_frm"; + else + roundFunctionName = "angle_frl"; + return createInternalFunctionCallNode(roundFunctionName, roundedChild); +} + +TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left, TIntermTyped *right, const char *opNameStr) +{ + std::stringstream strstr; + if (left->getPrecision() == EbpMedium) + strstr << "angle_compound_" << opNameStr << "_frm"; + else + strstr << "angle_compound_" << opNameStr << "_frl"; + TString functionName = strstr.str().c_str(); + TIntermAggregate *callNode = createInternalFunctionCallNode(functionName, left); + callNode->getSequence()->push_back(right); + return callNode; +} + +bool parentUsesResult(TIntermNode* parent, TIntermNode* node) +{ + if (!parent) + { + return false; + } + + TIntermAggregate *aggParent = parent->getAsAggregate(); + // If the parent's op is EOpSequence, the result is not assigned anywhere, + // so rounding it is not needed. In particular, this can avoid a lot of + // unnecessary rounding of unused return values of assignment. + if (aggParent && aggParent->getOp() == EOpSequence) + { + return false; + } + if (aggParent && aggParent->getOp() == EOpComma && (aggParent->getSequence()->back() != node)) + { + return false; + } + return true; +} + +} // namespace anonymous + +EmulatePrecision::EmulatePrecision() + : TIntermTraverser(true, true, true), + mDeclaringVariables(false), + mInLValue(false), + mInFunctionCallOutParameter(false) +{} + +void EmulatePrecision::visitSymbol(TIntermSymbol *node) +{ + if (canRoundFloat(node->getType()) && + !mDeclaringVariables && !mInLValue && !mInFunctionCallOutParameter) + { + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + } +} + + +bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node) +{ + bool visitChildren = true; + + if (node->isAssignment()) + { + if (visit == PreVisit) + mInLValue = true; + else if (visit == InVisit) + mInLValue = false; + } + + TOperator op = node->getOp(); + + // RHS of initialize is not being declared. + if (op == EOpInitialize && visit == InVisit) + mDeclaringVariables = false; + + if ((op == EOpIndexDirectStruct || op == EOpVectorSwizzle) && visit == InVisit) + visitChildren = false; + + if (visit != PreVisit) + return visitChildren; + + const TType& type = node->getType(); + bool roundFloat = canRoundFloat(type); + + if (roundFloat) { + switch (op) { + // Math operators that can result in a float may need to apply rounding to the return + // value. Note that in the case of assignment, the rounding is applied to its return + // value here, not the value being assigned. + case EOpAssign: + case EOpAdd: + case EOpSub: + case EOpMul: + case EOpDiv: + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: + case EOpMatrixTimesMatrix: + { + TIntermNode *parent = getParentNode(); + if (!parentUsesResult(parent, node)) + { + break; + } + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + break; + } + + // Compound assignment cases need to replace the operator with a function call. + case EOpAddAssign: + { + mEmulateCompoundAdd.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "add"); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); + break; + } + case EOpSubAssign: + { + mEmulateCompoundSub.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "sub"); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); + break; + } + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + { + mEmulateCompoundMul.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "mul"); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); + break; + } + case EOpDivAssign: + { + mEmulateCompoundDiv.insert(TypePair(getFloatTypeStr(type), getFloatTypeStr(node->getRight()->getType()))); + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(node->getLeft(), node->getRight(), "div"); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, false)); + break; + } + default: + // The rest of the binary operations should not need precision emulation. + break; + } + } + return visitChildren; +} + +bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node) +{ + bool visitChildren = true; + switch (node->getOp()) + { + case EOpSequence: + case EOpConstructStruct: + // No special handling + break; + case EOpFunction: + if (visit == PreVisit) + { + const TIntermSequence &sequence = *(node->getSequence()); + TIntermSequence::const_iterator seqIter = sequence.begin(); + TIntermAggregate *params = (*seqIter)->getAsAggregate(); + ASSERT(params != NULL); + ASSERT(params->getOp() == EOpParameters); + mFunctionMap[node->getName()] = params->getSequence(); + } + break; + case EOpPrototype: + if (visit == PreVisit) + mFunctionMap[node->getName()] = node->getSequence(); + visitChildren = false; + break; + case EOpParameters: + visitChildren = false; + break; + case EOpInvariantDeclaration: + visitChildren = false; + break; + case EOpDeclaration: + // Variable declaration. + if (visit == PreVisit) + { + mDeclaringVariables = true; + } + else if (visit == InVisit) + { + mDeclaringVariables = true; + } + else + { + mDeclaringVariables = false; + } + break; + case EOpFunctionCall: + { + // Function call. + bool inFunctionMap = (mFunctionMap.find(node->getName()) != mFunctionMap.end()); + if (visit == PreVisit) + { + // User-defined function return values are not rounded, this relies on that + // calculations producing the value were rounded. + TIntermNode *parent = getParentNode(); + if (canRoundFloat(node->getType()) && !inFunctionMap && parentUsesResult(parent, node)) + { + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + } + + if (inFunctionMap) + { + mSeqIterStack.push_back(mFunctionMap[node->getName()]->begin()); + if (mSeqIterStack.back() != mFunctionMap[node->getName()]->end()) + { + TQualifier qualifier = (*mSeqIterStack.back())->getAsTyped()->getQualifier(); + mInFunctionCallOutParameter = (qualifier == EvqOut || qualifier == EvqInOut); + } + } + else + { + // The function is not user-defined - it is likely built-in texture function. + // Assume that those do not have out parameters. + mInFunctionCallOutParameter = false; + } + } + else if (visit == InVisit) + { + if (inFunctionMap) + { + ++mSeqIterStack.back(); + TQualifier qualifier = (*mSeqIterStack.back())->getAsTyped()->getQualifier(); + mInFunctionCallOutParameter = (qualifier == EvqOut || qualifier == EvqInOut); + } + } + else + { + if (inFunctionMap) + { + mSeqIterStack.pop_back(); + mInFunctionCallOutParameter = false; + } + } + break; + } + default: + TIntermNode *parent = getParentNode(); + if (canRoundFloat(node->getType()) && visit == PreVisit && parentUsesResult(parent, node)) + { + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + } + break; + } + return visitChildren; +} + +bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node) +{ + switch (node->getOp()) + { + case EOpNegative: + case EOpVectorLogicalNot: + case EOpLogicalNot: + break; + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (visit == PreVisit) + mInLValue = true; + else if (visit == PostVisit) + mInLValue = false; + break; + default: + if (canRoundFloat(node->getType()) && visit == PreVisit) + { + TIntermNode *parent = getParentNode(); + TIntermNode *replacement = createRoundingFunctionCallNode(node); + mReplacements.push_back(NodeUpdateEntry(parent, node, replacement, true)); + } + break; + } + + return true; +} + +void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage) +{ + // Other languages not yet supported + ASSERT(outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT || + outputLanguage == SH_GLSL_CORE_OUTPUT || + outputLanguage == SH_ESSL_OUTPUT); + writeCommonPrecisionEmulationHelpers(sink, outputLanguage); + + EmulationSet::const_iterator it; + for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++) + writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "+", "add"); + for (it = mEmulateCompoundSub.begin(); it != mEmulateCompoundSub.end(); it++) + writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "-", "sub"); + for (it = mEmulateCompoundDiv.begin(); it != mEmulateCompoundDiv.end(); it++) + writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "/", "div"); + for (it = mEmulateCompoundMul.begin(); it != mEmulateCompoundMul.end(); it++) + writeCompoundAssignmentPrecisionEmulation(sink, outputLanguage, it->lType, it->rType, "*", "mul"); +} + diff --git a/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h new file mode 100644 index 0000000000..f1f560aa85 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/EmulatePrecision.h @@ -0,0 +1,74 @@ +// +// Copyright (c) 2002-2014 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_TRANSLATOR_EMULATE_PRECISION_H_ +#define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_ + +#include "common/angleutils.h" +#include "compiler/translator/InfoSink.h" +#include "compiler/translator/IntermNode.h" +#include "GLSLANG/ShaderLang.h" + +// This class gathers all compound assignments from the AST and can then write +// the functions required for their precision emulation. This way there is no +// need to write a huge number of variations of the emulated compound assignment +// to every translated shader with emulation enabled. + +class EmulatePrecision : public TIntermTraverser +{ + public: + EmulatePrecision(); + + virtual void visitSymbol(TIntermSymbol *node); + virtual bool visitBinary(Visit visit, TIntermBinary *node); + virtual bool visitUnary(Visit visit, TIntermUnary *node); + virtual bool visitAggregate(Visit visit, TIntermAggregate *node); + + void writeEmulationHelpers(TInfoSinkBase& sink, ShShaderOutput outputLanguage); + + private: + struct TypePair + { + TypePair(const char *l, const char *r) + : lType(l), rType(r) { } + + const char *lType; + const char *rType; + }; + + struct TypePairComparator + { + bool operator() (const TypePair& l, const TypePair& r) const + { + if (l.lType == r.lType) + return l.rType < r.rType; + return l.lType < r.lType; + } + }; + + typedef std::set EmulationSet; + EmulationSet mEmulateCompoundAdd; + EmulationSet mEmulateCompoundSub; + EmulationSet mEmulateCompoundMul; + EmulationSet mEmulateCompoundDiv; + + // Stack of function call parameter iterators + std::vector mSeqIterStack; + + bool mDeclaringVariables; + bool mInLValue; + bool mInFunctionCallOutParameter; + + struct TStringComparator + { + bool operator() (const TString& a, const TString& b) const { return a.compare(b) < 0; } + }; + + // Map from function names to their parameter sequences + std::map mFunctionMap; +}; + +#endif // COMPILER_TRANSLATOR_EMULATE_PRECISION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h index 5c1595fb21..cf4d7fba31 100644 --- a/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h +++ b/src/3rdparty/angle/src/compiler/translator/ExtensionBehavior.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _EXTENSION_BEHAVIOR_INCLUDED_ -#define _EXTENSION_BEHAVIOR_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ +#define COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ #include #include @@ -34,4 +34,4 @@ inline const char* getBehaviorString(TBehavior b) // Mapping between extension name and behavior. typedef std::map TExtensionBehavior; -#endif // _EXTENSION_TABLE_INCLUDED_ +#endif // COMPILER_TRANSLATOR_EXTENSIONBEHAVIOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h index c93a6f808e..07b9a72c5c 100644 --- a/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h +++ b/src/3rdparty/angle/src/compiler/translator/FlagStd140Structs.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_FLAGSTD140STRUCTS_H_ -#define COMPILER_FLAGSTD140STRUCTS_H_ +#ifndef COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ +#define COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ #include "compiler/translator/IntermNode.h" @@ -34,4 +34,4 @@ std::vector FlagStd140ValueStructs(TIntermNode *node); } -#endif // COMPILER_FLAGSTD140STRUCTS_H_ +#endif // COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h index a820d2a20d..c8787d55a0 100644 --- a/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h +++ b/src/3rdparty/angle/src/compiler/translator/ForLoopUnroll.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_FORLOOPUNROLL_H_ -#define COMPILER_FORLOOPUNROLL_H_ +#ifndef COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ +#define COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ #include "compiler/translator/LoopInfo.h" @@ -47,4 +47,4 @@ class ForLoopUnrollMarker : public TIntermTraverser bool mVisitSamplerArrayIndexNodeInsideLoop; }; -#endif +#endif // COMPILER_TRANSLATOR_FORLOOPUNROLL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/HashNames.h b/src/3rdparty/angle/src/compiler/translator/HashNames.h index 26546a3e7b..09c959f9da 100644 --- a/src/3rdparty/angle/src/compiler/translator/HashNames.h +++ b/src/3rdparty/angle/src/compiler/translator/HashNames.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_HASH_NAMES_H_ -#define COMPILER_HASH_NAMES_H_ +#ifndef COMPILER_TRANSLATOR_HASHNAMES_H_ +#define COMPILER_TRANSLATOR_HASHNAMES_H_ #include @@ -15,4 +15,4 @@ typedef std::map NameMap; -#endif // COMPILER_HASH_NAMES_H_ +#endif // COMPILER_TRANSLATOR_HASHNAMES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InfoSink.h b/src/3rdparty/angle/src/compiler/translator/InfoSink.h index 698a8b454b..f47fafa8ee 100644 --- a/src/3rdparty/angle/src/compiler/translator/InfoSink.h +++ b/src/3rdparty/angle/src/compiler/translator/InfoSink.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _INFOSINK_INCLUDED_ -#define _INFOSINK_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_INFOSINK_H_ +#define COMPILER_TRANSLATOR_INFOSINK_H_ #include #include @@ -113,4 +113,4 @@ public: TInfoSinkBase obj; }; -#endif // _INFOSINK_INCLUDED_ +#endif // COMPILER_TRANSLATOR_INFOSINK_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp index 10b21e6d28..9e11405758 100644 --- a/src/3rdparty/angle/src/compiler/translator/Initialize.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Initialize.cpp @@ -21,307 +21,208 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR TType *float2 = new TType(EbtFloat, 2); TType *float3 = new TType(EbtFloat, 3); TType *float4 = new TType(EbtFloat, 4); - TType *int1 = new TType(EbtInt); TType *int2 = new TType(EbtInt, 2); TType *int3 = new TType(EbtInt, 3); - TType *int4 = new TType(EbtInt, 4); + TType *uint1 = new TType(EbtUInt); + TType *bool1 = new TType(EbtBool); + TType *genType = new TType(EbtGenType); + TType *genIType = new TType(EbtGenIType); + TType *genUType = new TType(EbtGenUType); + TType *genBType = new TType(EbtGenBType); // // Angle and Trigonometric Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "radians", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "radians", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "radians", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "radians", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "degrees", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "degrees", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "degrees", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "degrees", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sin", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sin", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sin", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sin", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "cos", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "cos", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "cos", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "cos", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "tan", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "tan", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "tan", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "tan", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "asin", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "asin", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "asin", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "asin", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "acos", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "acos", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "acos", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "acos", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "atan", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "atan", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "atan", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "atan", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "atan", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "atan", float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpRadians, genType, "radians", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDegrees, genType, "degrees", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSin, genType, "sin", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCos, genType, "cos", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpTan, genType, "tan", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAsin, genType, "asin", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAcos, genType, "acos", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAtan, genType, "atan", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAtan, genType, "atan", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSinh, genType, "sinh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpCosh, genType, "cosh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTanh, genType, "tanh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAsinh, genType, "asinh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAcosh, genType, "acosh", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAtanh, genType, "atanh", genType); // // Exponential Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "pow", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "pow", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "pow", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "pow", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "exp", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "exp", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "exp", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "exp", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "log", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "log", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "log", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "log", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "exp2", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "exp2", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "exp2", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "exp2", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "log2", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "log2", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "log2", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "log2", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sqrt", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sqrt", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sqrt", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sqrt", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "inversesqrt", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "inversesqrt", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "inversesqrt", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "inversesqrt", float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpPow, genType, "pow", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpExp, genType, "exp", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLog, genType, "log", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpExp2, genType, "exp2", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLog2, genType, "log2", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSqrt, genType, "sqrt", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpInverseSqrt, genType, "inversesqrt", genType); // // Common Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "abs", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "abs", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "abs", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "abs", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "sign", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "sign", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "sign", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "sign", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "floor", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "floor", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "floor", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "floor", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "ceil", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "ceil", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "ceil", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "ceil", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "fract", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "fract", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "fract", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "fract", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "mod", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mod", float2, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mod", float3, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mod", float4, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mod", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mod", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mod", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "min", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "min", float2, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "min", float3, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "min", float4, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "min", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "min", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "min", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "max", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "max", float2, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "max", float3, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "max", float4, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "max", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "max", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "max", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "clamp", float1, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "clamp", float2, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "clamp", float3, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "clamp", float4, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "clamp", float2, float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "clamp", float3, float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "clamp", float4, float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "mix", float1, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mix", float2, float2, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mix", float3, float3, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mix", float4, float4, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "mix", float2, float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "mix", float3, float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "mix", float4, float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "step", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "step", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "step", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "step", float4, float4); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "step", float1, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "step", float1, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "step", float1, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "smoothstep", float1, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "smoothstep", float2, float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float3, float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float4, float4, float4); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "smoothstep", float1, float1, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "smoothstep", float1, float1, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "smoothstep", float1, float1, float4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAbs, genType, "abs", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpAbs, genIType, "abs", genIType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSign, genType, "sign", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpSign, genIType, "sign", genIType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFloor, genType, "floor", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTrunc, genType, "trunc", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRound, genType, "round", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpRoundEven, genType, "roundEven", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCeil, genType, "ceil", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFract, genType, "fract", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMod, genType, "mod", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMin, genType, "min", genType, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMin, genType, "min", genType, genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genIType, "min", genIType, genIType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genIType, "min", genIType, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genUType, "min", genUType, genUType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMin, genUType, "min", genUType, uint1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMax, genType, "max", genType, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMax, genType, "max", genType, genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genIType, "max", genIType, genIType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genIType, "max", genIType, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genUType, "max", genUType, genUType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMax, genUType, "max", genUType, uint1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpClamp, genType, "clamp", genType, float1, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpClamp, genType, "clamp", genType, genType, genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genIType, "clamp", genIType, int1, int1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genIType, "clamp", genIType, genIType, genIType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, uint1, uint1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpClamp, genUType, "clamp", genUType, genUType, genUType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMix, genType, "mix", genType, genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpStep, genType, "step", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpStep, genType, "step", float1, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSmoothStep, genType, "smoothstep", genType, genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpSmoothStep, genType, "smoothstep", float1, float1, genType); + + TType *outFloat1 = new TType(EbtFloat); + TType *outFloat2 = new TType(EbtFloat, 2); + TType *outFloat3 = new TType(EbtFloat, 3); + TType *outFloat4 = new TType(EbtFloat, 4); + outFloat1->setQualifier(EvqOut); + outFloat2->setQualifier(EvqOut); + outFloat3->setQualifier(EvqOut); + outFloat4->setQualifier(EvqOut); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float1, "modf", float1, outFloat1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float2, "modf", float2, outFloat2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float3, "modf", float3, outFloat3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpModf, float4, "modf", float4, outFloat4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIsNan, genBType, "isnan", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIsInf, genBType, "isinf", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFloatBitsToInt, genIType, "floatBitsToInt", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFloatBitsToUint, genUType, "floatBitsToUint", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpIntBitsToFloat, genType, "intBitsToFloat", genIType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUintBitsToFloat, genType, "uintBitsToFloat", genUType); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackSnorm2x16, uint1, "packSnorm2x16", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackUnorm2x16, uint1, "packUnorm2x16", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpPackHalf2x16, uint1, "packHalf2x16", float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackSnorm2x16, float2, "unpackSnorm2x16", uint1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackUnorm2x16, float2, "unpackUnorm2x16", uint1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpUnpackHalf2x16, float2, "unpackHalf2x16", uint1); // // Geometric Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "length", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "distance", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "dot", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "cross", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "normalize", float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "normalize", float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "normalize", float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "normalize", float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "faceforward", float1, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "faceforward", float2, float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "faceforward", float3, float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "faceforward", float4, float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "reflect", float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "reflect", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "reflect", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "reflect", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, float1, "refract", float1, float1, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float2, "refract", float2, float2, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float3, "refract", float3, float3, float1); - symbolTable.insertBuiltIn(COMMON_BUILTINS, float4, "refract", float4, float4, float1); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLength, float1, "length", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDistance, float1, "distance", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpDot, float1, "dot", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpCross, float3, "cross", float3, float3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpNormalize, genType, "normalize", genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpFaceForward, genType, "faceforward", genType, genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpReflect, genType, "reflect", genType, genType); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpRefract, genType, "refract", genType, genType, float1); TType *mat2 = new TType(EbtFloat, 2, 2); TType *mat3 = new TType(EbtFloat, 3, 3); TType *mat4 = new TType(EbtFloat, 4, 4); + TType *mat2x3 = new TType(EbtFloat, 2, 3); + TType *mat3x2 = new TType(EbtFloat, 3, 2); + TType *mat2x4 = new TType(EbtFloat, 2, 4); + TType *mat4x2 = new TType(EbtFloat, 4, 2); + TType *mat3x4 = new TType(EbtFloat, 3, 4); + TType *mat4x3 = new TType(EbtFloat, 4, 3); // // Matrix Functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, mat2, "matrixCompMult", mat2, mat2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, mat3, "matrixCompMult", mat3, mat3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, mat4, "matrixCompMult", mat4, mat4); - - TType *bool1 = new TType(EbtBool); - TType *bool2 = new TType(EbtBool, 2); - TType *bool3 = new TType(EbtBool, 3); - TType *bool4 = new TType(EbtBool, 4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat2, "matrixCompMult", mat2, mat2); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat3, "matrixCompMult", mat3, mat3); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpMul, mat4, "matrixCompMult", mat4, mat4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat2x3, "matrixCompMult", mat2x3, mat2x3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat3x2, "matrixCompMult", mat3x2, mat3x2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat2x4, "matrixCompMult", mat2x4, mat2x4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat4x2, "matrixCompMult", mat4x2, mat4x2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat3x4, "matrixCompMult", mat3x4, mat3x4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpMul, mat4x3, "matrixCompMult", mat4x3, mat4x3); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2, "outerProduct", float2, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3, "outerProduct", float3, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4, "outerProduct", float4, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2x3, "outerProduct", float3, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3x2, "outerProduct", float2, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat2x4, "outerProduct", float4, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4x2, "outerProduct", float2, float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat3x4, "outerProduct", float4, float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpOuterProduct, mat4x3, "outerProduct", float3, float4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2, "transpose", mat2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3, "transpose", mat3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4, "transpose", mat4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2x3, "transpose", mat3x2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3x2, "transpose", mat2x3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat2x4, "transpose", mat4x2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4x2, "transpose", mat2x4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat3x4, "transpose", mat4x3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpTranspose, mat4x3, "transpose", mat3x4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDeterminant, float1, "determinant", mat4); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat2, "inverse", mat2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat3, "inverse", mat3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpInverse, mat4, "inverse", mat4); + + TType *vec = new TType(EbtVec); + TType *ivec = new TType(EbtIVec); + TType *uvec = new TType(EbtUVec); + TType *bvec = new TType(EbtBVec); // // Vector relational functions. // - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThan", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThan", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThan", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThan", int4, int4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThanEqual", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "lessThanEqual", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "lessThanEqual", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "lessThanEqual", int4, int4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThan", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThan", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThan", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThan", int4, int4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThanEqual", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "greaterThanEqual", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "greaterThanEqual", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "greaterThanEqual", int4, int4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", int4, int4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "equal", bool2, bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "equal", bool3, bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "equal", bool4, bool4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", float2, float2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", float3, float3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", float4, float4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", int2, int2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", int3, int3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", int4, int4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "notEqual", bool2, bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "notEqual", bool3, bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "notEqual", bool4, bool4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "any", bool4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool1, "all", bool4); - - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool2, "not", bool2); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool3, "not", bool3); - symbolTable.insertBuiltIn(COMMON_BUILTINS, bool4, "not", bool4); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThan, bvec, "lessThan", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThan, bvec, "lessThan", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpLessThan, bvec, "lessThan", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpLessThanEqual, bvec, "lessThanEqual", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThan, bvec, "greaterThan", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThan, bvec, "greaterThan", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpGreaterThan, bvec, "greaterThan", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpGreaterThanEqual, bvec, "greaterThanEqual", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpVectorEqual, bvec, "equal", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorEqual, bvec, "equal", bvec, bvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", vec, vec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", ivec, ivec); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", uvec, uvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorNotEqual, bvec, "notEqual", bvec, bvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAny, bool1, "any", bvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpAll, bool1, "all", bvec); + symbolTable.insertBuiltIn(COMMON_BUILTINS, EOpVectorLogicalNot, bvec, "not", bvec); TType *sampler2D = new TType(EbtSampler2D); TType *samplerCube = new TType(EbtSamplerCube); @@ -357,10 +258,10 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR /* The *Grad* variants are new to both vertex and fragment shaders; the fragment * shader specific pieces are added separately below. */ - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DGradEXT", sampler2D, float2, float2, float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeGradEXT", samplerCube, float3, float3, float3); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DGradEXT", sampler2D, float2, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeGradEXT", samplerCube, float3, float3, float3); } if (type == GL_FRAGMENT_SHADER) @@ -372,32 +273,21 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR if (resources.OES_standard_derivatives) { - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "dFdx", float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "dFdx", float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "dFdx", float3); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "dFdx", float4); - - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "dFdy", float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "dFdy", float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "dFdy", float3); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "dFdy", float4); - - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float1, "fwidth", float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float2, "fwidth", float2); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float3, "fwidth", float3); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "fwidth", float4); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdx, "GL_OES_standard_derivatives", genType, "dFdx", genType); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpDFdy, "GL_OES_standard_derivatives", genType, "dFdy", genType); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, EOpFwidth, "GL_OES_standard_derivatives", genType, "fwidth", genType); } if (resources.EXT_shader_texture_lod) { - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLodEXT", sampler2D, float2, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float3, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLodEXT", sampler2D, float4, float1); - symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "textureCubeLodEXT", samplerCube, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DLodEXT", sampler2D, float2, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float3, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "texture2DProjLodEXT", sampler2D, float4, float1); + symbolTable.insertBuiltIn(ESSL1_BUILTINS, "GL_EXT_shader_texture_lod", float4, "textureCubeLodEXT", samplerCube, float3, float1); } } - if(type == GL_VERTEX_SHADER) + if (type == GL_VERTEX_SHADER) { symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DLod", sampler2D, float2, float1); symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProjLod", sampler2D, float3, float1); @@ -463,22 +353,11 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCubeShadow, int1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArrayShadow, int1); - if(type == GL_FRAGMENT_SHADER) + if (type == GL_FRAGMENT_SHADER) { - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdx", float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "dFdx", float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "dFdx", float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "dFdx", float4); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "dFdy", float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "dFdy", float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "dFdy", float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "dFdy", float4); - - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "fwidth", float1); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float2, "fwidth", float2); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float3, "fwidth", float3); - symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "fwidth", float4); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdx, genType, "dFdx", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdy, genType, "dFdy", genType); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpFwidth, genType, "fwidth", genType); } symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2); @@ -486,7 +365,7 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureOffset", sampler2DShadow, float3, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2DArray, float3, int2); - if(type == GL_FRAGMENT_SHADER) + if (type == GL_FRAGMENT_SHADER) { symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler2D, float2, int2, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureOffset", gsampler3D, float3, int3, float1); @@ -499,7 +378,7 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler3D, float4, int3); symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjOffset", sampler2DShadow, float4, int2); - if(type == GL_FRAGMENT_SHADER) + if (type == GL_FRAGMENT_SHADER) { symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float3, int2, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProjOffset", gsampler2D, float4, int2, float1); @@ -600,146 +479,84 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, TSymbolTable &symbolTable) { // - // First, insert some special built-in variables that are not in + // Insert some special built-in variables that are not in // the built-in header files. // - switch(type) { - case GL_FRAGMENT_SHADER: - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2))); + switch (type) + { + case GL_FRAGMENT_SHADER: + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FragCoord"), + TType(EbtFloat, EbpMedium, EvqFragCoord, 4))); + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_FrontFacing"), + TType(EbtBool, EbpUndefined, EvqFrontFacing, 1))); + symbolTable.insert(COMMON_BUILTINS, 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(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4))); - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4))); - if (resources.EXT_frag_depth) { - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragDepthEXT"), TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); - symbolTable.relateToExtension(ESSL1_BUILTINS, "gl_FragDepthEXT", "GL_EXT_frag_depth"); - } - } else { - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_MixColor"), TType(EbtFloat, EbpMedium, EvqGlobal, 4))); - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_ColorMatrix"), TType(EbtFloat, EbpMedium, EvqGlobal, 4, 4))); - } - - break; - - case GL_VERTEX_SHADER: - symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4))); - symbolTable.insert(COMMON_BUILTINS, 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(COMMON_BUILTINS, "matrixCompMult", EOpMul); - - symbolTable.relateToOperator(COMMON_BUILTINS, "equal", EOpVectorEqual); - symbolTable.relateToOperator(COMMON_BUILTINS, "notEqual", EOpVectorNotEqual); - symbolTable.relateToOperator(COMMON_BUILTINS, "lessThan", EOpLessThan); - symbolTable.relateToOperator(COMMON_BUILTINS, "greaterThan", EOpGreaterThan); - symbolTable.relateToOperator(COMMON_BUILTINS, "lessThanEqual", EOpLessThanEqual); - symbolTable.relateToOperator(COMMON_BUILTINS, "greaterThanEqual", EOpGreaterThanEqual); - - symbolTable.relateToOperator(COMMON_BUILTINS, "radians", EOpRadians); - symbolTable.relateToOperator(COMMON_BUILTINS, "degrees", EOpDegrees); - symbolTable.relateToOperator(COMMON_BUILTINS, "sin", EOpSin); - symbolTable.relateToOperator(COMMON_BUILTINS, "cos", EOpCos); - symbolTable.relateToOperator(COMMON_BUILTINS, "tan", EOpTan); - symbolTable.relateToOperator(COMMON_BUILTINS, "asin", EOpAsin); - symbolTable.relateToOperator(COMMON_BUILTINS, "acos", EOpAcos); - symbolTable.relateToOperator(COMMON_BUILTINS, "atan", EOpAtan); - - symbolTable.relateToOperator(COMMON_BUILTINS, "pow", EOpPow); - symbolTable.relateToOperator(COMMON_BUILTINS, "exp2", EOpExp2); - symbolTable.relateToOperator(COMMON_BUILTINS, "log", EOpLog); - symbolTable.relateToOperator(COMMON_BUILTINS, "exp", EOpExp); - symbolTable.relateToOperator(COMMON_BUILTINS, "log2", EOpLog2); - symbolTable.relateToOperator(COMMON_BUILTINS, "sqrt", EOpSqrt); - symbolTable.relateToOperator(COMMON_BUILTINS, "inversesqrt", EOpInverseSqrt); - - symbolTable.relateToOperator(COMMON_BUILTINS, "abs", EOpAbs); - symbolTable.relateToOperator(COMMON_BUILTINS, "sign", EOpSign); - symbolTable.relateToOperator(COMMON_BUILTINS, "floor", EOpFloor); - symbolTable.relateToOperator(COMMON_BUILTINS, "ceil", EOpCeil); - symbolTable.relateToOperator(COMMON_BUILTINS, "fract", EOpFract); - symbolTable.relateToOperator(COMMON_BUILTINS, "mod", EOpMod); - symbolTable.relateToOperator(COMMON_BUILTINS, "min", EOpMin); - symbolTable.relateToOperator(COMMON_BUILTINS, "max", EOpMax); - symbolTable.relateToOperator(COMMON_BUILTINS, "clamp", EOpClamp); - symbolTable.relateToOperator(COMMON_BUILTINS, "mix", EOpMix); - symbolTable.relateToOperator(COMMON_BUILTINS, "step", EOpStep); - symbolTable.relateToOperator(COMMON_BUILTINS, "smoothstep", EOpSmoothStep); - - symbolTable.relateToOperator(COMMON_BUILTINS, "length", EOpLength); - symbolTable.relateToOperator(COMMON_BUILTINS, "distance", EOpDistance); - symbolTable.relateToOperator(COMMON_BUILTINS, "dot", EOpDot); - symbolTable.relateToOperator(COMMON_BUILTINS, "cross", EOpCross); - symbolTable.relateToOperator(COMMON_BUILTINS, "normalize", EOpNormalize); - symbolTable.relateToOperator(COMMON_BUILTINS, "faceforward", EOpFaceForward); - symbolTable.relateToOperator(COMMON_BUILTINS, "reflect", EOpReflect); - symbolTable.relateToOperator(COMMON_BUILTINS, "refract", EOpRefract); - - symbolTable.relateToOperator(COMMON_BUILTINS, "any", EOpAny); - symbolTable.relateToOperator(COMMON_BUILTINS, "all", EOpAll); - symbolTable.relateToOperator(COMMON_BUILTINS, "not", EOpVectorLogicalNot); - - // Map language-specific operators. - switch(type) { - case GL_VERTEX_SHADER: - break; - case GL_FRAGMENT_SHADER: - if (resources.OES_standard_derivatives) + if (spec != SH_CSS_SHADERS_SPEC) { - symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdx", EOpDFdx); - symbolTable.relateToOperator(ESSL1_BUILTINS, "dFdy", EOpDFdy); - symbolTable.relateToOperator(ESSL1_BUILTINS, "fwidth", EOpFwidth); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragColor"), + TType(EbtFloat, EbpMedium, EvqFragColor, 4))); + TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true); + fragData.setArraySize(resources.MaxDrawBuffers); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData)); + + if (resources.EXT_frag_depth) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_frag_depth", new TVariable(NewPoolTString("gl_FragDepthEXT"), + TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); + } - symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdx", "GL_OES_standard_derivatives"); - symbolTable.relateToExtension(ESSL1_BUILTINS, "dFdy", "GL_OES_standard_derivatives"); - symbolTable.relateToExtension(ESSL1_BUILTINS, "fwidth", "GL_OES_standard_derivatives"); + if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch) + { + TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true); + lastFragData.setArraySize(resources.MaxDrawBuffers); + + if (resources.EXT_shader_framebuffer_fetch) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); + } + else if (resources.NV_shader_framebuffer_fetch) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragColor"), + TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); + symbolTable.insert(ESSL1_BUILTINS, "GL_NV_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragData"), lastFragData)); + } + } + else if (resources.ARM_shader_framebuffer_fetch) + { + symbolTable.insert(ESSL1_BUILTINS, "GL_ARM_shader_framebuffer_fetch", + new TVariable(NewPoolTString("gl_LastFragColorARM"), + TType(EbtFloat, EbpMedium, EvqLastFragColor, 4))); + } } - if (resources.EXT_shader_texture_lod) + else { - symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DLodEXT", "GL_EXT_shader_texture_lod"); - symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjLodEXT", "GL_EXT_shader_texture_lod"); - symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeLodEXT", "GL_EXT_shader_texture_lod"); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_MixColor"), + TType(EbtFloat, EbpMedium, EvqGlobal, 4))); + symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("css_ColorMatrix"), + TType(EbtFloat, EbpMedium, EvqGlobal, 4, 4))); } - break; - default: break; - } - symbolTable.relateToOperator(ESSL3_BUILTINS, "dFdx", EOpDFdx); - symbolTable.relateToOperator(ESSL3_BUILTINS, "dFdy", EOpDFdy); - symbolTable.relateToOperator(ESSL3_BUILTINS, "fwidth", EOpFwidth); - - if (resources.EXT_shader_texture_lod) - { - symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DGradEXT", "GL_EXT_shader_texture_lod"); - symbolTable.relateToExtension(ESSL1_BUILTINS, "texture2DProjGradEXT", "GL_EXT_shader_texture_lod"); - symbolTable.relateToExtension(ESSL1_BUILTINS, "textureCubeGradEXT", "GL_EXT_shader_texture_lod"); - } + break; - // Finally add resource-specific variables. - switch(type) { - case GL_FRAGMENT_SHADER: - if (spec != SH_CSS_SHADERS_SPEC) { - // Set up gl_FragData. The array size. - TType fragData(EbtFloat, EbpMedium, EvqFragData, 4, 1, true); - fragData.setArraySize(resources.MaxDrawBuffers); - symbolTable.insert(ESSL1_BUILTINS, new TVariable(NewPoolTString("gl_FragData"), fragData)); - } + case GL_VERTEX_SHADER: + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_Position"), + TType(EbtFloat, EbpHigh, EvqPosition, 4))); + symbolTable.insert(COMMON_BUILTINS, new TVariable(NewPoolTString("gl_PointSize"), + TType(EbtFloat, EbpMedium, EvqPointSize, 1))); + symbolTable.insert(ESSL3_BUILTINS, new TVariable(NewPoolTString("gl_InstanceID"), + TType(EbtInt, EbpHigh, EvqInstanceID, 1))); break; - default: break; + + default: + assert(false && "Language not supported"); } } @@ -758,4 +575,20 @@ void InitExtensionBehavior(const ShBuiltInResources& resources, extBehavior["GL_EXT_frag_depth"] = EBhUndefined; if (resources.EXT_shader_texture_lod) extBehavior["GL_EXT_shader_texture_lod"] = EBhUndefined; + if (resources.EXT_shader_framebuffer_fetch) + extBehavior["GL_EXT_shader_framebuffer_fetch"] = EBhUndefined; + if (resources.NV_shader_framebuffer_fetch) + extBehavior["GL_NV_shader_framebuffer_fetch"] = EBhUndefined; + if (resources.ARM_shader_framebuffer_fetch) + extBehavior["GL_ARM_shader_framebuffer_fetch"] = EBhUndefined; +} + +void ResetExtensionBehavior(TExtensionBehavior &extBehavior) +{ + for (auto ext_iter = extBehavior.begin(); + ext_iter != extBehavior.end(); + ++ext_iter) + { + ext_iter->second = EBhUndefined; + } } diff --git a/src/3rdparty/angle/src/compiler/translator/Initialize.h b/src/3rdparty/angle/src/compiler/translator/Initialize.h index cc1862c90e..c43ce3417a 100644 --- a/src/3rdparty/angle/src/compiler/translator/Initialize.h +++ b/src/3rdparty/angle/src/compiler/translator/Initialize.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _INITIALIZE_INCLUDED_ -#define _INITIALIZE_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_INITIALIZE_H_ +#define COMPILER_TRANSLATOR_INITIALIZE_H_ #include "compiler/translator/Common.h" #include "compiler/translator/Compiler.h" @@ -20,4 +20,10 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, void InitExtensionBehavior(const ShBuiltInResources& resources, TExtensionBehavior& extensionBehavior); -#endif // _INITIALIZE_INCLUDED_ +// Resets the behavior of the extensions listed in |extensionBehavior| to the +// undefined state. These extensions will only be those initially supported in +// the ShBuiltInResources object for this compiler instance. All other +// extensions will remain unsupported. +void ResetExtensionBehavior(TExtensionBehavior &extensionBehavior); + +#endif // COMPILER_TRANSLATOR_INITIALIZE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeDll.h b/src/3rdparty/angle/src/compiler/translator/InitializeDll.h index 43070cc3ff..4c400760f6 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeDll.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeDll.h @@ -3,11 +3,11 @@ // 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 +#ifndef COMPILER_TRANSLATOR_INITIALIZEDLL_H_ +#define COMPILER_TRANSLATOR_INITIALIZEDLL_H_ bool InitProcess(); void DetachProcess(); -#endif // __INITIALIZEDLL_H +#endif // COMPILER_TRANSLATOR_INITIALIZEDLL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h b/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h index 0715941424..8c65cb28da 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeGlobals.h @@ -4,10 +4,10 @@ // found in the LICENSE file. // -#ifndef __INITIALIZE_GLOBALS_INCLUDED_ -#define __INITIALIZE_GLOBALS_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ +#define COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ bool InitializePoolIndex(); void FreePoolIndex(); -#endif // __INITIALIZE_GLOBALS_INCLUDED_ +#endif // COMPILER_TRANSLATOR_INITIALIZEGLOBALS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h index bffbab87d0..fa9b885e80 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeParseContext.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_ -#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ +#define COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ bool InitializeParseContextIndex(); void FreeParseContextIndex(); @@ -14,4 +14,4 @@ struct TParseContext; extern void SetGlobalParseContext(TParseContext* context); extern TParseContext* GetGlobalParseContext(); -#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#endif // COMPILER_TRANSLATOR_INITIALIZEPARSECONTEXT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h index 59c3ea0a39..4a81266498 100644 --- a/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h +++ b/src/3rdparty/angle/src/compiler/translator/InitializeVariables.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_INITIALIZE_VARIABLES_H_ -#define COMPILER_INITIALIZE_VARIABLES_H_ +#ifndef COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ +#define COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ #include "compiler/translator/IntermNode.h" @@ -47,4 +47,4 @@ class InitializeVariables : public TIntermTraverser bool mCodeInserted; }; -#endif // COMPILER_INITIALIZE_VARIABLES_H_ +#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp index aa0f31d170..266e3c8e3d 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp @@ -157,26 +157,6 @@ bool TIntermLoop::replaceChildNode( return false; } -void TIntermLoop::enqueueChildren(std::queue *nodeQueue) const -{ - if (mInit) - { - nodeQueue->push(mInit); - } - if (mCond) - { - nodeQueue->push(mCond); - } - if (mExpr) - { - nodeQueue->push(mExpr); - } - if (mBody) - { - nodeQueue->push(mBody); - } -} - bool TIntermBranch::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { @@ -184,14 +164,6 @@ bool TIntermBranch::replaceChildNode( return false; } -void TIntermBranch::enqueueChildren(std::queue *nodeQueue) const -{ - if (mExpression) - { - nodeQueue->push(mExpression); - } -} - bool TIntermBinary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { @@ -200,18 +172,6 @@ bool TIntermBinary::replaceChildNode( return false; } -void TIntermBinary::enqueueChildren(std::queue *nodeQueue) const -{ - if (mLeft) - { - nodeQueue->push(mLeft); - } - if (mRight) - { - nodeQueue->push(mRight); - } -} - bool TIntermUnary::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { @@ -219,14 +179,6 @@ bool TIntermUnary::replaceChildNode( return false; } -void TIntermUnary::enqueueChildren(std::queue *nodeQueue) const -{ - if (mOperand) - { - nodeQueue->push(mOperand); - } -} - bool TIntermAggregate::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { @@ -237,14 +189,6 @@ bool TIntermAggregate::replaceChildNode( return false; } -void TIntermAggregate::enqueueChildren(std::queue *nodeQueue) const -{ - for (size_t childIndex = 0; childIndex < mSequence.size(); childIndex++) - { - nodeQueue->push(mSequence[childIndex]); - } -} - void TIntermAggregate::setPrecisionFromChildren() { if (getBasicType() == EbtBool) @@ -300,20 +244,19 @@ bool TIntermSelection::replaceChildNode( return false; } -void TIntermSelection::enqueueChildren(std::queue *nodeQueue) const +bool TIntermSwitch::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) { - if (mCondition) - { - nodeQueue->push(mCondition); - } - if (mTrueBlock) - { - nodeQueue->push(mTrueBlock); - } - if (mFalseBlock) - { - nodeQueue->push(mFalseBlock); - } + REPLACE_IF_IS(mInit, TIntermTyped, original, replacement); + REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement); + return false; +} + +bool TIntermCase::replaceChildNode( + TIntermNode *original, TIntermNode *replacement) +{ + REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement); + return false; } // @@ -336,6 +279,12 @@ bool TIntermOperator::isAssignment() const case EOpMatrixTimesScalarAssign: case EOpMatrixTimesMatrixAssign: case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: return true; default: return false; @@ -379,65 +328,55 @@ bool TIntermOperator::isConstructor() const // 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 &) +void TIntermUnary::promote(const TType *funcReturnType) { switch (mOp) { - case EOpLogicalNot: - if (mOperand->getBasicType() != EbtBool) - return false; + case EOpFloatBitsToInt: + case EOpFloatBitsToUint: + case EOpIntBitsToFloat: + case EOpUintBitsToFloat: + case EOpPackSnorm2x16: + case EOpPackUnorm2x16: + case EOpPackHalf2x16: + case EOpUnpackSnorm2x16: + case EOpUnpackUnorm2x16: + mType.setPrecision(EbpHigh); break; - case EOpNegative: - case EOpPositive: - case EOpPostIncrement: - case EOpPostDecrement: - case EOpPreIncrement: - case EOpPreDecrement: - if (mOperand->getBasicType() == EbtBool) - return false; + case EOpUnpackHalf2x16: + mType.setPrecision(EbpMedium); break; - - // operators for built-ins are already type checked against their prototype - case EOpAny: - case EOpAll: - case EOpVectorLogicalNot: - return true; - default: - if (mOperand->getBasicType() != EbtFloat) - return false; + setType(mOperand->getType()); } - setType(mOperand->getType()); - mType.setQualifier(EvqTemporary); + if (funcReturnType != nullptr) + { + if (funcReturnType->getBasicType() == EbtBool) + { + // Bool types should not have precision. + setType(*funcReturnType); + } + else + { + // Precision of the node has been set based on the operand. + setTypePreservePrecision(*funcReturnType); + } + } - return true; + mType.setQualifier(EvqTemporary); } // // 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. +// For lots of operations it should already be established that the operand +// combination is valid, but returns false if operator can't work on operands. // bool TIntermBinary::promote(TInfoSink &infoSink) { - // This function only handles scalars, vectors, and matrices. - if (mLeft->isArray() || mRight->isArray()) - { - infoSink.info.message(EPrefixInternalError, getLine(), - "Invalid operation for arrays"); - return false; - } - - // GLSL ES 2.0 does not support implicit type casting. - // So the basic type should always match. - if (mLeft->getBasicType() != mRight->getBasicType()) - { - return false; - } + ASSERT(mLeft->isArray() == mRight->isArray()); // // Base assumption: just make the type the same as the left @@ -483,12 +422,9 @@ bool TIntermBinary::promote(TInfoSink &infoSink) // And and Or operate on conditionals // case EOpLogicalAnd: + case EOpLogicalXor: case EOpLogicalOr: - // Both operands must be of type bool. - if (mLeft->getBasicType() != EbtBool || mRight->getBasicType() != EbtBool) - { - return false; - } + ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool); setType(TType(EbtBool, EbpUndefined)); break; @@ -625,12 +561,28 @@ bool TIntermBinary::promote(TInfoSink &infoSink) case EOpAssign: case EOpInitialize: + // No more additional checks are needed. + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); + break; case EOpAdd: case EOpSub: case EOpDiv: + case EOpIMod: + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: case EOpAddAssign: case EOpSubAssign: case EOpDivAssign: + case EOpIModAssign: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: if ((mLeft->isMatrix() && mRight->isVector()) || (mLeft->isVector() && mRight->isMatrix())) { @@ -641,13 +593,19 @@ bool TIntermBinary::promote(TInfoSink &infoSink) if (mLeft->getNominalSize() != mRight->getNominalSize() || mLeft->getSecondarySize() != mRight->getSecondarySize()) { - // If the nominal size of operands do not match: - // One of them must be scalar. + // If the nominal sizes of operands do not match: + // One of them must be a scalar. if (!mLeft->isScalar() && !mRight->isScalar()) return false; - // Operator cannot be of type pure assignment. - if (mOp == EOpAssign || mOp == EOpInitialize) + // In the case of compound assignment other than multiply-assign, + // the right side needs to be a scalar. Otherwise a vector/matrix + // would be assigned to a scalar. A scalar can't be shifted by a + // vector either. + if (!mRight->isScalar() && + (isAssignment() || + mOp == EOpBitShiftLeft || + mOp == EOpBitShiftRight)) return false; } @@ -656,6 +614,11 @@ bool TIntermBinary::promote(TInfoSink &infoSink) mLeft->getSecondarySize(), mRight->getSecondarySize()); setType(TType(basicType, higherPrecision, EvqTemporary, nominalSize, secondarySize)); + if (mLeft->isArray()) + { + ASSERT(mLeft->getArraySize() == mRight->getArraySize()); + mType.setArraySize(mLeft->getArraySize()); + } } break; @@ -665,11 +628,8 @@ bool TIntermBinary::promote(TInfoSink &infoSink) case EOpGreaterThan: case EOpLessThanEqual: case EOpGreaterThanEqual: - if ((mLeft->getNominalSize() != mRight->getNominalSize()) || - (mLeft->getSecondarySize() != mRight->getSecondarySize())) - { - return false; - } + ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) && + (mLeft->getSecondarySize() == mRight->getSecondarySize())); setType(TType(EbtBool, EbpUndefined)); break; @@ -793,6 +753,7 @@ TIntermTyped *TIntermConstantUnion::fold( break; case EOpDiv: + case EOpIMod: { tempConstArray = new ConstantUnion[objectSize]; for (size_t i = 0; i < objectSize; i++) @@ -810,6 +771,7 @@ TIntermTyped *TIntermConstantUnion::fold( } else { + ASSERT(op == EOpDiv); tempConstArray[i].setFConst( unionArray[i].getFConst() / rightUnionArray[i].getFConst()); @@ -826,9 +788,19 @@ TIntermTyped *TIntermConstantUnion::fold( } else { - tempConstArray[i].setIConst( - unionArray[i].getIConst() / - rightUnionArray[i].getIConst()); + if (op == EOpDiv) + { + tempConstArray[i].setIConst( + unionArray[i].getIConst() / + rightUnionArray[i].getIConst()); + } + else + { + ASSERT(op == EOpIMod); + tempConstArray[i].setIConst( + unionArray[i].getIConst() % + rightUnionArray[i].getIConst()); + } } break; @@ -842,9 +814,19 @@ TIntermTyped *TIntermConstantUnion::fold( } else { - tempConstArray[i].setUConst( - unionArray[i].getUConst() / - rightUnionArray[i].getUConst()); + if (op == EOpDiv) + { + tempConstArray[i].setUConst( + unionArray[i].getUConst() / + rightUnionArray[i].getUConst()); + } + else + { + ASSERT(op == EOpIMod); + tempConstArray[i].setUConst( + unionArray[i].getUConst() % + rightUnionArray[i].getUConst()); + } } break; @@ -968,6 +950,32 @@ TIntermTyped *TIntermConstantUnion::fold( } break; + case EOpBitwiseAnd: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] & rightUnionArray[i]; + break; + case EOpBitwiseXor: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] ^ rightUnionArray[i]; + break; + case EOpBitwiseOr: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] | rightUnionArray[i]; + break; + case EOpBitShiftLeft: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] << rightUnionArray[i]; + break; + case EOpBitShiftRight: + tempConstArray = new ConstantUnion[objectSize]; + for (size_t i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] >> rightUnionArray[i]; + break; + case EOpLessThan: ASSERT(objectSize == 1); tempConstArray = new ConstantUnion[1]; @@ -1160,6 +1168,23 @@ TIntermTyped *TIntermConstantUnion::fold( } break; + case EOpBitwiseNot: + switch (getType().getBasicType()) + { + case EbtInt: + tempConstArray[i].setIConst(~unionArray[i].getIConst()); + break; + case EbtUInt: + tempConstArray[i].setUConst(~unionArray[i].getUConst()); + break; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Unary operation not folded into constant"); + return NULL; + } + break; + default: return NULL; } @@ -1181,3 +1206,29 @@ TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunctio TString hashedName = stream.str(); return hashedName; } + +void TIntermTraverser::updateTree() +{ + for (size_t ii = 0; ii < mReplacements.size(); ++ii) + { + const NodeUpdateEntry& entry = mReplacements[ii]; + ASSERT(entry.parent); + bool replaced = entry.parent->replaceChildNode( + entry.original, entry.replacement); + ASSERT(replaced); + + if (!entry.originalBecomesChildOfReplacement) + { + // In AST traversing, a parent is visited before its children. + // After we replace a node, if an immediate child is to + // be replaced, we need to make sure we don't update the replaced + // node; instead, we update the replacement node. + for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj) + { + NodeUpdateEntry& entry2 = mReplacements[jj]; + if (entry2.parent == entry.original) + entry2.parent = entry.replacement; + } + } + } +} diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.h b/src/3rdparty/angle/src/compiler/translator/IntermNode.h index 32c70f4671..9f732cbb00 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermNode.h +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.h @@ -13,182 +13,19 @@ // each node can have it's own type of list of children. // -#ifndef COMPILER_TRANSLATOR_INTERMEDIATE_H_ -#define COMPILER_TRANSLATOR_INTERMEDIATE_H_ +#ifndef COMPILER_TRANSLATOR_INTERMNODE_H_ +#define COMPILER_TRANSLATOR_INTERMNODE_H_ #include "GLSLANG/ShaderLang.h" #include #include +#include "common/angleutils.h" #include "compiler/translator/Common.h" #include "compiler/translator/Types.h" #include "compiler/translator/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, - EOpInvariantDeclaration, // Specialized declarations for attributing invariance - EOpPrototype, - - // - // Unary operators - // - - EOpNegative, - EOpPositive, - EOpLogicalNot, - EOpVectorLogicalNot, - - EOpPostIncrement, - EOpPostDecrement, - EOpPreIncrement, - EOpPreDecrement, - - // - // 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, - EOpIndexDirectInterfaceBlock, - - 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, - EOpConstructUInt, - EOpConstructBool, - EOpConstructFloat, - EOpConstructVec2, - EOpConstructVec3, - EOpConstructVec4, - EOpConstructBVec2, - EOpConstructBVec3, - EOpConstructBVec4, - EOpConstructIVec2, - EOpConstructIVec3, - EOpConstructIVec4, - EOpConstructUVec2, - EOpConstructUVec3, - EOpConstructUVec4, - EOpConstructMat2, - EOpConstructMat3, - EOpConstructMat4, - EOpConstructStruct, - - // - // moves - // - - EOpAssign, - EOpInitialize, - EOpAddAssign, - EOpSubAssign, - EOpMulAssign, - EOpVectorTimesMatrixAssign, - EOpVectorTimesScalarAssign, - EOpMatrixTimesScalarAssign, - EOpMatrixTimesMatrixAssign, - EOpDivAssign -}; +#include "compiler/translator/Operator.h" class TIntermTraverser; class TIntermAggregate; @@ -196,10 +33,13 @@ class TIntermBinary; class TIntermUnary; class TIntermConstantUnion; class TIntermSelection; +class TIntermSwitch; +class TIntermCase; class TIntermTyped; class TIntermSymbol; class TIntermLoop; class TInfoSink; +class TInfoSinkBase; class TIntermRaw; // @@ -228,6 +68,8 @@ class TIntermNode virtual TIntermBinary *getAsBinaryNode() { return 0; } virtual TIntermUnary *getAsUnaryNode() { return 0; } virtual TIntermSelection *getAsSelectionNode() { return 0; } + virtual TIntermSwitch *getAsSwitchNode() { return 0; } + virtual TIntermCase *getAsCaseNode() { return 0; } virtual TIntermSymbol *getAsSymbolNode() { return 0; } virtual TIntermLoop *getAsLoopNode() { return 0; } virtual TIntermRaw *getAsRawNode() { return 0; } @@ -237,10 +79,6 @@ class TIntermNode virtual bool replaceChildNode( TIntermNode *original, TIntermNode *replacement) = 0; - // For traversing a tree in no particular order, but using - // heap memory. - virtual void enqueueChildren(std::queue *nodeQueue) const = 0; - protected: TSourceLoc mLine; }; @@ -331,8 +169,6 @@ class TIntermLoop : public TIntermNode void setUnrollFlag(bool flag) { mUnrollFlag = flag; } bool getUnrollFlag() const { return mUnrollFlag; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TLoopType mType; TIntermNode *mInit; // for-loop initialization @@ -360,8 +196,6 @@ class TIntermBranch : public TIntermNode TOperator getFlowOp() { return mFlowOp; } TIntermTyped* getExpression() { return mExpression; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TOperator mFlowOp; TIntermTyped *mExpression; // non-zero except for "return exp;" statements @@ -394,8 +228,6 @@ class TIntermSymbol : public TIntermTyped virtual TIntermSymbol *getAsSymbolNode() { return this; } virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } - virtual void enqueueChildren(std::queue *nodeQueue) const {} - protected: int mId; TString mSymbol; @@ -419,7 +251,6 @@ class TIntermRaw : public TIntermTyped virtual TIntermRaw *getAsRawNode() { return this; } virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; } - virtual void enqueueChildren(std::queue *nodeQueue) const {} protected: TString mRawText; @@ -459,8 +290,6 @@ class TIntermConstantUnion : public TIntermTyped TIntermTyped *fold(TOperator, TIntermTyped *, TInfoSink &); - virtual void enqueueChildren(std::queue *nodeQueue) const {} - protected: ConstantUnion *mUnionArrayPointer; }; @@ -519,8 +348,6 @@ class TIntermBinary : public TIntermOperator void setAddIndexClamp() { mAddIndexClamp = true; } bool getAddIndexClamp() { return mAddIndexClamp; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TIntermTyped* mLeft; TIntermTyped* mRight; @@ -556,13 +383,11 @@ class TIntermUnary : public TIntermOperator void setOperand(TIntermTyped *operand) { mOperand = operand; } TIntermTyped *getOperand() { return mOperand; } - bool promote(TInfoSink &); + void promote(const TType *funcReturnType); void setUseEmulatedFunction() { mUseEmulatedFunction = true; } bool getUseEmulatedFunction() { return mUseEmulatedFunction; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TIntermTyped *mOperand; @@ -613,8 +438,6 @@ class TIntermAggregate : public TIntermOperator void setUseEmulatedFunction() { mUseEmulatedFunction = true; } bool getUseEmulatedFunction() { return mUseEmulatedFunction; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - void setPrecisionFromChildren(); void setBuiltInFunctionPrecision(); @@ -634,7 +457,7 @@ class TIntermAggregate : public TIntermOperator }; // -// For if tests. Simplified since there is no switch statement. +// For if tests. // class TIntermSelection : public TIntermTyped { @@ -664,14 +487,64 @@ class TIntermSelection : public TIntermTyped TIntermNode *getFalseBlock() const { return mFalseBlock; } TIntermSelection *getAsSelectionNode() { return this; } - virtual void enqueueChildren(std::queue *nodeQueue) const; - protected: TIntermTyped *mCondition; TIntermNode *mTrueBlock; TIntermNode *mFalseBlock; }; +// +// Switch statement. +// +class TIntermSwitch : public TIntermNode +{ + public: + TIntermSwitch(TIntermTyped *init, TIntermAggregate *statementList) + : TIntermNode(), + mInit(init), + mStatementList(statementList) + { + } + + void traverse(TIntermTraverser *it) override; + bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement) override; + + TIntermSwitch *getAsSwitchNode() override { return this; } + + TIntermAggregate *getStatementList() { return mStatementList; } + void setStatementList(TIntermAggregate *statementList) { mStatementList = statementList; } + + protected: + TIntermTyped *mInit; + TIntermAggregate *mStatementList; +}; + +// +// Case label. +// +class TIntermCase : public TIntermNode +{ + public: + TIntermCase(TIntermTyped *condition) + : TIntermNode(), + mCondition(condition) + { + } + + void traverse(TIntermTraverser *it) override; + bool replaceChildNode( + TIntermNode *original, TIntermNode *replacement) override; + + TIntermCase *getAsCaseNode() override { return this; } + + bool hasCondition() const { return mCondition != nullptr; } + TIntermTyped *getCondition() const { return mCondition; } + + protected: + TIntermTyped *mCondition; +}; + enum Visit { PreVisit, @@ -687,7 +560,7 @@ enum Visit // 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 +class TIntermTraverser : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); @@ -708,6 +581,8 @@ class TIntermTraverser virtual bool visitBinary(Visit, TIntermBinary *) { return true; } virtual bool visitUnary(Visit, TIntermUnary *) { return true; } virtual bool visitSelection(Visit, TIntermSelection *) { return true; } + virtual bool visitSwitch(Visit, TIntermSwitch *) { return true; } + virtual bool visitCase(Visit, TIntermCase *) { return true; } virtual bool visitAggregate(Visit, TIntermAggregate *) { return true; } virtual bool visitLoop(Visit, TIntermLoop *) { return true; } virtual bool visitBranch(Visit, TIntermBranch *) { return true; } @@ -741,12 +616,38 @@ class TIntermTraverser const bool postVisit; const bool rightToLeft; + // If traversers need to replace nodes, they can add the replacements in + // mReplacements during traversal and the user of the traverser should call + // this function after traversal to perform them. + void updateTree(); + protected: int mDepth; int mMaxDepth; // All the nodes from root to the current node's parent during traversing. TVector mPath; + + struct NodeUpdateEntry + { + NodeUpdateEntry(TIntermNode *_parent, + TIntermNode *_original, + TIntermNode *_replacement, + bool _originalBecomesChildOfReplacement) + : parent(_parent), + original(_original), + replacement(_replacement), + originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement) {} + + TIntermNode *parent; + TIntermNode *original; + TIntermNode *replacement; + bool originalBecomesChildOfReplacement; + }; + + // During traversing, save all the changes that need to happen into + // mReplacements, then do them by calling updateTree(). + std::vector mReplacements; }; // @@ -768,10 +669,10 @@ class TMaxDepthTraverser : public TIntermTraverser virtual bool visitLoop(Visit, TIntermLoop *) { return depthCheck(); } virtual bool visitBranch(Visit, TIntermBranch *) { return depthCheck(); } -protected: + protected: bool depthCheck() const { return mMaxDepth < mDepthLimit; } int mDepthLimit; }; -#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ +#endif // COMPILER_TRANSLATOR_INTERMNODE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp index 72b2033fb3..7a7efb71f5 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp +++ b/src/3rdparty/angle/src/compiler/translator/IntermTraverse.cpp @@ -193,6 +193,60 @@ void TIntermSelection::traverse(TIntermTraverser *it) it->visitSelection(PostVisit, this); } +// +// Traverse a switch node. Same comments in binary node apply here. +// +void TIntermSwitch::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitSwitch(PreVisit, this); + + if (visit) + { + it->incrementDepth(this); + if (it->rightToLeft) + { + if (mStatementList) + mStatementList->traverse(it); + if (it->inVisit) + visit = it->visitSwitch(InVisit, this); + if (visit) + mInit->traverse(it); + } + else + { + mInit->traverse(it); + if (it->inVisit) + visit = it->visitSwitch(InVisit, this); + if (visit && mStatementList) + mStatementList->traverse(it); + } + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitSwitch(PostVisit, this); +} + +// +// Traverse a switch node. Same comments in binary node apply here. +// +void TIntermCase::traverse(TIntermTraverser *it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitCase(PreVisit, this); + + if (visit && mCondition) + mCondition->traverse(it); + + if (visit && it->postVisit) + it->visitCase(PostVisit, this); +} + // // Traverse a loop node. Same comments in binary node apply here. // diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp index e558683c55..320056f8ce 100644 --- a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp @@ -13,7 +13,6 @@ #include #include "compiler/translator/Intermediate.h" -#include "compiler/translator/RemoveTree.h" #include "compiler/translator/SymbolTable.h" //////////////////////////////////////////////////////////////////////////// @@ -46,47 +45,6 @@ TIntermSymbol *TIntermediate::addSymbol( TIntermTyped *TIntermediate::addBinaryMath( TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &line) { - switch (op) - { - case EOpEqual: - case EOpNotEqual: - if (left->isArray()) - return NULL; - break; - case EOpLessThan: - case EOpGreaterThan: - case EOpLessThanEqual: - case EOpGreaterThanEqual: - if (left->isMatrix() || left->isArray() || left->isVector() || - left->getBasicType() == EbtStruct) - { - return NULL; - } - break; - case EOpLogicalOr: - case EOpLogicalXor: - case EOpLogicalAnd: - if (left->getBasicType() != EbtBool || - left->isMatrix() || left->isArray() || left->isVector()) - { - return NULL; - } - break; - case EOpAdd: - case EOpSub: - case EOpDiv: - case EOpMul: - if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) - return NULL; - default: - break; - } - - if (left->getBasicType() != right->getBasicType()) - { - return NULL; - } - // // Need a new node holding things together then. Make // one and promote it to the right type. @@ -169,45 +127,8 @@ TIntermTyped *TIntermediate::addIndex( // Returns the added node. // TIntermTyped *TIntermediate::addUnaryMath( - TOperator op, TIntermNode *childNode, const TSourceLoc &line) + TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType) { - TIntermUnary *node; - TIntermTyped *child = childNode->getAsTyped(); - - if (child == NULL) - { - mInfoSink.info.message(EPrefixInternalError, line, - "Bad type in AddUnaryMath"); - return NULL; - } - - switch (op) - { - case EOpLogicalNot: - if (child->getType().getBasicType() != EbtBool || - child->getType().isMatrix() || - child->getType().isArray() || - child->getType().isVector()) - { - return NULL; - } - break; - - case EOpPostIncrement: - case EOpPreIncrement: - case EOpPostDecrement: - case EOpPreDecrement: - case EOpNegative: - case EOpPositive: - if (child->getType().getBasicType() == EbtStruct || - child->getType().isArray()) - { - return NULL; - } - default: - break; - } - TIntermConstantUnion *childTempConstant = 0; if (child->getAsConstantUnion()) childTempConstant = child->getAsConstantUnion(); @@ -215,12 +136,10 @@ TIntermTyped *TIntermediate::addUnaryMath( // // Make a new node for the operator. // - node = new TIntermUnary(op); + TIntermUnary *node = new TIntermUnary(op); node->setLine(line); node->setOperand(child); - - if (!node->promote(mInfoSink)) - return 0; + node->promote(funcReturnType); if (childTempConstant) { @@ -423,6 +342,24 @@ TIntermTyped *TIntermediate::addSelection( return node; } +TIntermSwitch *TIntermediate::addSwitch( + TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line) +{ + TIntermSwitch *node = new TIntermSwitch(init, statementList); + node->setLine(line); + + return node; +} + +TIntermCase *TIntermediate::addCase( + TIntermTyped *condition, const TSourceLoc &line) +{ + TIntermCase *node = new TIntermCase(condition); + node->setLine(line); + + return node; +} + // // Constant terminal nodes. Has a union that contains bool, float or int constants // @@ -510,12 +447,3 @@ bool TIntermediate::postProcess(TIntermNode *root) return true; } - -// -// This deletes the tree. -// -void TIntermediate::remove(TIntermNode *root) -{ - if (root) - RemoveAllTreeNodes(root); -} diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.h b/src/3rdparty/angle/src/compiler/translator/Intermediate.h new file mode 100644 index 0000000000..ec73e22834 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.h @@ -0,0 +1,71 @@ +// +// Copyright (c) 2002-2014 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_TRANSLATOR_INTERMEDIATE_H_ +#define COMPILER_TRANSLATOR_INTERMEDIATE_H_ + +#include "compiler/translator/IntermNode.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(); + TIntermediate(TInfoSink &i) + : mInfoSink(i) { } + + TIntermSymbol *addSymbol( + int id, const TString &, const TType &, const TSourceLoc &); + TIntermTyped *addBinaryMath( + TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); + TIntermTyped *addAssign( + TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); + TIntermTyped *addIndex( + TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &); + TIntermTyped *addUnaryMath( + TOperator op, TIntermTyped *child, const TSourceLoc &line, const TType *funcReturnType); + TIntermAggregate *growAggregate( + TIntermNode *left, TIntermNode *right, const TSourceLoc &); + TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &); + TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &); + TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &); + TIntermTyped *addSelection( + TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &); + TIntermSwitch *addSwitch( + TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &line); + TIntermCase *addCase( + TIntermTyped *condition, const TSourceLoc &line); + TIntermTyped *addComma( + TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); + TIntermConstantUnion *addConstantUnion(ConstantUnion *, const TType &, const TSourceLoc &); + // TODO(zmo): Get rid of default value. + bool parseConstTree(const TSourceLoc &, TIntermNode *, ConstantUnion *, + TOperator, TType, bool singleConstantParam = false); + TIntermNode *addLoop(TLoopType, TIntermNode *, TIntermTyped *, TIntermTyped *, + TIntermNode *, const TSourceLoc &); + TIntermBranch *addBranch(TOperator, const TSourceLoc &); + TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &); + TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &); + bool postProcess(TIntermNode *); + + static void outputTree(TIntermNode *, TInfoSinkBase &); + + private: + void operator=(TIntermediate &); // prevent assignments + + TInfoSink & mInfoSink; +}; + +#endif // COMPILER_TRANSLATOR_INTERMEDIATE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/LoopInfo.h b/src/3rdparty/angle/src/compiler/translator/LoopInfo.h index 5f72a6e944..ec73fd0fa5 100644 --- a/src/3rdparty/angle/src/compiler/translator/LoopInfo.h +++ b/src/3rdparty/angle/src/compiler/translator/LoopInfo.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATOR_LOOP_INFO_H_ -#define COMPILER_TRANSLATOR_LOOP_INFO_H_ +#ifndef COMPILER_TRANSLATOR_LOOPINFO_H_ +#define COMPILER_TRANSLATOR_LOOPINFO_H_ #include "compiler/translator/IntermNode.h" @@ -76,5 +76,5 @@ class TLoopStack : public TVector void pop(); }; -#endif // COMPILER_TRANSLATOR_LOOP_INDEX_H_ +#endif // COMPILER_TRANSLATOR_LOOPINFO_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/MMap.h b/src/3rdparty/angle/src/compiler/translator/MMap.h index a308671514..fca843992b 100644 --- a/src/3rdparty/angle/src/compiler/translator/MMap.h +++ b/src/3rdparty/angle/src/compiler/translator/MMap.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _MMAP_INCLUDED_ -#define _MMAP_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_MMAP_H_ +#define COMPILER_TRANSLATOR_MMAP_H_ // // Encapsulate memory mapped files @@ -53,4 +53,4 @@ private: char* fBuff; // the actual data; }; -#endif // _MMAP_INCLUDED_ +#endif // COMPILER_TRANSLATOR_MMAP_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/NodeSearch.h b/src/3rdparty/angle/src/compiler/translator/NodeSearch.h index 60070c9d33..8ffed614c3 100644 --- a/src/3rdparty/angle/src/compiler/translator/NodeSearch.h +++ b/src/3rdparty/angle/src/compiler/translator/NodeSearch.h @@ -6,8 +6,8 @@ // NodeSearch.h: Utilities for searching translator node graphs // -#ifndef TRANSLATOR_NODESEARCH_H_ -#define TRANSLATOR_NODESEARCH_H_ +#ifndef COMPILER_TRANSLATOR_NODESEARCH_H_ +#define COMPILER_TRANSLATOR_NODESEARCH_H_ #include "compiler/translator/IntermNode.h" @@ -77,4 +77,4 @@ class FindSideEffectRewriting : public NodeSearchTraverser"; + case EOpLessThanEqual: return "<="; + case EOpGreaterThanEqual: return ">="; + case EOpComma: return ","; + + // Fall-through. + case EOpVectorTimesScalar: + case EOpVectorTimesMatrix: + case EOpMatrixTimesVector: + case EOpMatrixTimesScalar: return "*"; + + case EOpLogicalOr: return "||"; + case EOpLogicalXor: return "^^"; + case EOpLogicalAnd: return "&&"; + + case EOpBitShiftLeft: return "<<"; + case EOpBitShiftRight: return ">>"; + + case EOpBitwiseAnd: return "&"; + case EOpBitwiseXor: return "^"; + case EOpBitwiseOr: return "|"; + + // Fall-through. + case EOpIndexDirect: + case EOpIndexIndirect: return "[]"; + + case EOpIndexDirectStruct: + case EOpIndexDirectInterfaceBlock: return "."; + + case EOpVectorSwizzle: return "."; + + 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 EOpSinh: return "sinh"; + case EOpCosh: return "cosh"; + case EOpTanh: return "tanh"; + case EOpAsinh: return "asinh"; + case EOpAcosh: return "acosh"; + case EOpAtanh: return "atanh"; + + case EOpPow: return "pow"; + 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 EOpTrunc: return "trunc"; + case EOpRound: return "round"; + case EOpRoundEven: return "roundEven"; + case EOpCeil: return "ceil"; + case EOpFract: return "fract"; + case EOpMod: return "mod"; + case EOpModf: return "modf"; + case EOpMin: return "min"; + case EOpMax: return "max"; + case EOpClamp: return "clamp"; + case EOpMix: return "mix"; + case EOpStep: return "step"; + case EOpSmoothStep: return "smoothstep"; + case EOpIsNan: return "isnan"; + case EOpIsInf: return "isinf"; + + case EOpFloatBitsToInt: return "floatBitsToInt"; + case EOpFloatBitsToUint: return "floatBitsToUint"; + case EOpIntBitsToFloat: return "intBitsToFloat"; + case EOpUintBitsToFloat: return "uintBitsToFloat"; + + case EOpPackSnorm2x16: return "packSnorm2x16"; + case EOpPackUnorm2x16: return "packUnorm2x16"; + case EOpPackHalf2x16: return "packHalf2x16"; + case EOpUnpackSnorm2x16: return "unpackSnorm2x16"; + case EOpUnpackUnorm2x16: return "unpackUnorm2x16"; + case EOpUnpackHalf2x16: return "unpackHalf2x16"; + + case EOpLength: return "length"; + case EOpDistance: return "distance"; + case EOpDot: return "dot"; + case EOpCross: return "cross"; + case EOpNormalize: return "normalize"; + case EOpFaceForward: return "faceforward"; + case EOpReflect: return "reflect"; + case EOpRefract: return "refract"; + + case EOpDFdx: return "dFdx"; + case EOpDFdy: return "dFdy"; + case EOpFwidth: return "fwidth"; + + case EOpMatrixTimesMatrix: return "*"; + + case EOpOuterProduct: return "outerProduct"; + case EOpTranspose: return "transpose"; + case EOpDeterminant: return "determinant"; + case EOpInverse: return "inverse"; + + case EOpAny: return "any"; + case EOpAll: return "all"; + + case EOpKill: return "kill"; + case EOpReturn: return "return"; + case EOpBreak: return "break"; + case EOpContinue: return "continue"; + + case EOpConstructInt: return "int"; + case EOpConstructUInt: return "uint"; + case EOpConstructBool: return "bool"; + case EOpConstructFloat: return "float"; + case EOpConstructVec2: return "vec2"; + case EOpConstructVec3: return "vec3"; + case EOpConstructVec4: return "vec4"; + case EOpConstructBVec2: return "bvec2"; + case EOpConstructBVec3: return "bvec3"; + case EOpConstructBVec4: return "bvec4"; + case EOpConstructIVec2: return "ivec2"; + case EOpConstructIVec3: return "ivec3"; + case EOpConstructIVec4: return "ivec4"; + case EOpConstructUVec2: return "uvec2"; + case EOpConstructUVec3: return "uvec3"; + case EOpConstructUVec4: return "uvec4"; + case EOpConstructMat2: return "mat2"; + case EOpConstructMat3: return "mat3"; + case EOpConstructMat4: return "mat4"; + // Note: EOpConstructStruct can't be handled here + + case EOpAssign: return "="; + case EOpInitialize: return "="; + case EOpAddAssign: return "+="; + case EOpSubAssign: return "-="; + + // Fall-through. + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: return "*="; + + case EOpDivAssign: return "/="; + case EOpIModAssign: return "%="; + case EOpBitShiftLeftAssign: return "<<="; + case EOpBitShiftRightAssign: return ">>="; + case EOpBitwiseAndAssign: return "&="; + case EOpBitwiseXorAssign: return "^="; + case EOpBitwiseOrAssign: return "|="; + + default: break; + } + return ""; +} + diff --git a/src/3rdparty/angle/src/compiler/translator/Operator.h b/src/3rdparty/angle/src/compiler/translator/Operator.h new file mode 100644 index 0000000000..8290f952fc --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/Operator.h @@ -0,0 +1,226 @@ +// +// Copyright (c) 2002-2015 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_TRANSLATOR_OPERATOR_H_ +#define COMPILER_TRANSLATOR_OPERATOR_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, + EOpInternalFunctionCall, // Call to an internal helper function + EOpFunction, // For function definition + EOpParameters, // an aggregate listing the parameters to a function + + EOpDeclaration, + EOpInvariantDeclaration, // Specialized declarations for attributing invariance + EOpPrototype, + + // + // Unary operators + // + + EOpNegative, + EOpPositive, + EOpLogicalNot, + EOpVectorLogicalNot, + EOpBitwiseNot, + + EOpPostIncrement, + EOpPostDecrement, + EOpPreIncrement, + EOpPreDecrement, + + // + // binary operations + // + + EOpAdd, + EOpSub, + EOpMul, + EOpDiv, + EOpIMod, + EOpEqual, + EOpNotEqual, + EOpVectorEqual, + EOpVectorNotEqual, + EOpLessThan, + EOpGreaterThan, + EOpLessThanEqual, + EOpGreaterThanEqual, + EOpComma, + + EOpVectorTimesScalar, + EOpVectorTimesMatrix, + EOpMatrixTimesVector, + EOpMatrixTimesScalar, + + EOpLogicalOr, + EOpLogicalXor, + EOpLogicalAnd, + + EOpBitShiftLeft, + EOpBitShiftRight, + + EOpBitwiseAnd, + EOpBitwiseXor, + EOpBitwiseOr, + + EOpIndexDirect, + EOpIndexIndirect, + EOpIndexDirectStruct, + EOpIndexDirectInterfaceBlock, + + EOpVectorSwizzle, + + // + // Built-in functions potentially mapped to operators + // + + EOpRadians, + EOpDegrees, + EOpSin, + EOpCos, + EOpTan, + EOpAsin, + EOpAcos, + EOpAtan, + + EOpSinh, + EOpCosh, + EOpTanh, + EOpAsinh, + EOpAcosh, + EOpAtanh, + + EOpPow, + EOpExp, + EOpLog, + EOpExp2, + EOpLog2, + EOpSqrt, + EOpInverseSqrt, + + EOpAbs, + EOpSign, + EOpFloor, + EOpTrunc, + EOpRound, + EOpRoundEven, + EOpCeil, + EOpFract, + EOpMod, + EOpModf, + EOpMin, + EOpMax, + EOpClamp, + EOpMix, + EOpStep, + EOpSmoothStep, + EOpIsNan, + EOpIsInf, + + EOpFloatBitsToInt, + EOpFloatBitsToUint, + EOpIntBitsToFloat, + EOpUintBitsToFloat, + + EOpPackSnorm2x16, + EOpPackUnorm2x16, + EOpPackHalf2x16, + EOpUnpackSnorm2x16, + EOpUnpackUnorm2x16, + EOpUnpackHalf2x16, + + 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, + + EOpOuterProduct, + EOpTranspose, + EOpDeterminant, + EOpInverse, + + EOpAny, + EOpAll, + + // + // Branch + // + + EOpKill, // Fragment only + EOpReturn, + EOpBreak, + EOpContinue, + + // + // Constructors + // + + EOpConstructInt, + EOpConstructUInt, + EOpConstructBool, + EOpConstructFloat, + EOpConstructVec2, + EOpConstructVec3, + EOpConstructVec4, + EOpConstructBVec2, + EOpConstructBVec3, + EOpConstructBVec4, + EOpConstructIVec2, + EOpConstructIVec3, + EOpConstructIVec4, + EOpConstructUVec2, + EOpConstructUVec3, + EOpConstructUVec4, + EOpConstructMat2, + EOpConstructMat3, + EOpConstructMat4, + EOpConstructStruct, + + // + // moves + // + + EOpAssign, + EOpInitialize, + EOpAddAssign, + EOpSubAssign, + + EOpMulAssign, + EOpVectorTimesMatrixAssign, + EOpVectorTimesScalarAssign, + EOpMatrixTimesScalarAssign, + EOpMatrixTimesMatrixAssign, + + EOpDivAssign, + EOpIModAssign, + EOpBitShiftLeftAssign, + EOpBitShiftRightAssign, + EOpBitwiseAndAssign, + EOpBitwiseXorAssign, + EOpBitwiseOrAssign +}; + +// Returns the string corresponding to the operator in GLSL +const char* GetOperatorString(TOperator op); + +#endif // COMPILER_TRANSLATOR_OPERATOR_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp index 65635af1ff..77e0a8fb37 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.cpp @@ -6,13 +6,21 @@ #include "compiler/translator/OutputESSL.h" -TOutputESSL::TOutputESSL(TInfoSinkBase& objSink, +TOutputESSL::TOutputESSL(TInfoSinkBase &objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, - NameMap& nameMap, - TSymbolTable& symbolTable, - int shaderVersion) - : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) + NameMap &nameMap, + TSymbolTable &symbolTable, + int shaderVersion, + bool forceHighp) + : TOutputGLSLBase(objSink, + clampingStrategy, + hashFunction, + nameMap, + symbolTable, + shaderVersion, + SH_ESSL_OUTPUT), + mForceHighp(forceHighp) { } @@ -22,6 +30,9 @@ bool TOutputESSL::writeVariablePrecision(TPrecision precision) return false; TInfoSinkBase& out = objSink(); - out << getPrecisionString(precision); + if (mForceHighp) + out << getPrecisionString(EbpHigh); + else + out << getPrecisionString(precision); return true; } diff --git a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h index 8a567fb8aa..813f1e944b 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputESSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputESSL.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_ -#define CROSSCOMPILERGLSL_OUTPUTESSL_H_ +#ifndef COMPILER_TRANSLATOR_OUTPUTESSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTESSL_H_ #include "compiler/translator/OutputGLSLBase.h" @@ -17,10 +17,13 @@ public: ShHashFunction64 hashFunction, NameMap& nameMap, TSymbolTable& symbolTable, - int shaderVersion); + int shaderVersion, + bool forceHighp); protected: virtual bool writeVariablePrecision(TPrecision precision); +private: + bool mForceHighp; }; -#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTESSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp index eb7cbb4ae8..9badf0e2fc 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.cpp @@ -11,8 +11,15 @@ TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink, ShHashFunction64 hashFunction, NameMap& nameMap, TSymbolTable& symbolTable, - int shaderVersion) - : TOutputGLSLBase(objSink, clampingStrategy, hashFunction, nameMap, symbolTable, shaderVersion) + int shaderVersion, + ShShaderOutput output) + : TOutputGLSLBase(objSink, + clampingStrategy, + hashFunction, + nameMap, + symbolTable, + shaderVersion, + output) { } @@ -21,21 +28,30 @@ bool TOutputGLSL::writeVariablePrecision(TPrecision) return false; } -void TOutputGLSL::visitSymbol(TIntermSymbol* node) +void TOutputGLSL::visitSymbol(TIntermSymbol *node) { TInfoSinkBase& out = objSink(); - if (node->getSymbol() == "gl_FragDepthEXT") + const TString &symbol = node->getSymbol(); + if (symbol == "gl_FragDepthEXT") { out << "gl_FragDepth"; } + else if (symbol == "gl_FragColor" && getShaderOutput() == SH_GLSL_CORE_OUTPUT) + { + out << "webgl_FragColor"; + } + else if (symbol == "gl_FragData" && getShaderOutput() == SH_GLSL_CORE_OUTPUT) + { + out << "webgl_FragData"; + } else { TOutputGLSLBase::visitSymbol(node); } } -TString TOutputGLSL::translateTextureFunction(TString& name) +TString TOutputGLSL::translateTextureFunction(TString &name) { static const char *simpleRename[] = { "texture2DLodEXT", "texture2DLod", @@ -46,10 +62,30 @@ TString TOutputGLSL::translateTextureFunction(TString& name) "textureCubeGradEXT", "textureCubeGradARB", NULL, NULL }; + static const char *legacyToCoreRename[] = { + "texture2D", "texture", + "texture2DProj", "textureProj", + "texture2DLod", "textureLod", + "texture2DProjLod", "textureProjLod", + "textureCube", "texture", + "textureCubeLod", "textureLod", + // Extensions + "texture2DLodEXT", "textureLod", + "texture2DProjLodEXT", "textureProjLod", + "textureCubeLodEXT", "textureLod", + "texture2DGradEXT", "textureGrad", + "texture2DProjGradEXT", "textureProjGrad", + "textureCubeGradEXT", "textureGrad", + NULL, NULL + }; + const char **mapping = (getShaderOutput() == SH_GLSL_CORE_OUTPUT) ? + legacyToCoreRename : simpleRename; - for (int i = 0; simpleRename[i] != NULL; i += 2) { - if (name == simpleRename[i]) { - return simpleRename[i+1]; + for (int i = 0; mapping[i] != NULL; i += 2) + { + if (name == mapping[i]) + { + return mapping[i+1]; } } diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h index bceebe397d..21b2d079d3 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSL.h @@ -4,25 +4,26 @@ // found in the LICENSE file. // -#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_ -#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_ +#ifndef COMPILER_TRANSLATOR_OUTPUTGLSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTGLSL_H_ #include "compiler/translator/OutputGLSLBase.h" class TOutputGLSL : public TOutputGLSLBase { -public: + public: TOutputGLSL(TInfoSinkBase& objSink, ShArrayIndexClampingStrategy clampingStrategy, ShHashFunction64 hashFunction, NameMap& nameMap, TSymbolTable& symbolTable, - int shaderVersion); + int shaderVersion, + ShShaderOutput output); -protected: + protected: virtual bool writeVariablePrecision(TPrecision); virtual void visitSymbol(TIntermSymbol* node); virtual TString translateTextureFunction(TString& name); }; -#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp index ed590967b1..4bb6305d05 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp @@ -36,8 +36,17 @@ bool isSingleStatement(TIntermNode *node) { return false; } + else if (node->getAsSwitchNode()) + { + return false; + } + else if (node->getAsCaseNode()) + { + return false; + } return true; } + } // namespace TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, @@ -45,7 +54,8 @@ TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, ShHashFunction64 hashFunction, NameMap &nameMap, TSymbolTable &symbolTable, - int shaderVersion) + int shaderVersion, + ShShaderOutput output) : TIntermTraverser(true, true, true), mObjSink(objSink), mDeclaringVariables(false), @@ -53,7 +63,8 @@ TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink, mHashFunction(hashFunction), mNameMap(nameMap), mSymbolTable(symbolTable), - mShaderVersion(shaderVersion) + mShaderVersion(shaderVersion), + mOutput(output) { } @@ -83,7 +94,34 @@ void TOutputGLSLBase::writeVariableType(const TType &type) TQualifier qualifier = type.getQualifier(); if (qualifier != EvqTemporary && qualifier != EvqGlobal) { - out << type.getQualifierString() << " "; + if (mOutput == SH_GLSL_CORE_OUTPUT) + { + switch (qualifier) + { + case EvqAttribute: + out << "in" << " "; + break; + case EvqVaryingIn: + out << "in" << " "; + break; + case EvqVaryingOut: + out << "out" << " "; + break; + case EvqInvariantVaryingIn: + out << "invariant in" << " "; + break; + case EvqInvariantVaryingOut: + out << "invariant out" << " "; + break; + default: + out << type.getQualifierString() << " "; + break; + } + } + else + { + out << type.getQualifierString() << " "; + } } // Declare the struct if we have not done so already. if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) @@ -166,6 +204,9 @@ const ConstantUnion *TOutputGLSLBase::writeConstantUnion( case EbtInt: out << pConstUnion->getIConst(); break; + case EbtUInt: + out << pConstUnion->getUConst() << "u"; + break; case EbtBool: out << pConstUnion->getBConst(); break; @@ -223,6 +264,9 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break; + case EOpIModAssign: + writeTriplet(visit, "(", " %= ", ")"); + break; // Notice the fall-through. case EOpMulAssign: case EOpVectorTimesMatrixAssign: @@ -231,6 +275,21 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) case EOpMatrixTimesMatrixAssign: writeTriplet(visit, "(", " *= ", ")"); break; + case EOpBitShiftLeftAssign: + writeTriplet(visit, "(", " <<= ", ")"); + break; + case EOpBitShiftRightAssign: + writeTriplet(visit, "(", " >>= ", ")"); + break; + case EOpBitwiseAndAssign: + writeTriplet(visit, "(", " &= ", ")"); + break; + case EOpBitwiseXorAssign: + writeTriplet(visit, "(", " ^= ", ")"); + break; + case EOpBitwiseOrAssign: + writeTriplet(visit, "(", " |= ", ")"); + break; case EOpIndexDirect: writeTriplet(visit, NULL, "[", "]"); @@ -340,9 +399,25 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node) case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break; - case EOpMod: - UNIMPLEMENTED(); + case EOpIMod: + writeTriplet(visit, "(", " % ", ")"); + break; + case EOpBitShiftLeft: + writeTriplet(visit, "(", " << ", ")"); break; + case EOpBitShiftRight: + writeTriplet(visit, "(", " >> ", ")"); + break; + case EOpBitwiseAnd: + writeTriplet(visit, "(", " & ", ")"); + break; + case EOpBitwiseXor: + writeTriplet(visit, "(", " ^ ", ")"); + break; + case EOpBitwiseOr: + writeTriplet(visit, "(", " | ", ")"); + break; + case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break; @@ -398,6 +473,7 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) case EOpPositive: preString = "(+"; break; case EOpVectorLogicalNot: preString = "not("; break; case EOpLogicalNot: preString = "(!"; break; + case EOpBitwiseNot: preString = "(~"; break; case EOpPostIncrement: preString = "("; postString = "++)"; break; case EOpPostDecrement: preString = "("; postString = "--)"; break; @@ -429,6 +505,25 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) preString = "atan("; break; + case EOpSinh: + preString = "sinh("; + break; + case EOpCosh: + preString = "cosh("; + break; + case EOpTanh: + preString = "tanh("; + break; + case EOpAsinh: + preString = "asinh("; + break; + case EOpAcosh: + preString = "acosh("; + break; + case EOpAtanh: + preString = "atanh("; + break; + case EOpExp: preString = "exp("; break; @@ -457,12 +552,59 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) case EOpFloor: preString = "floor("; break; + case EOpTrunc: + preString = "trunc("; + break; + case EOpRound: + preString = "round("; + break; + case EOpRoundEven: + preString = "roundEven("; + break; case EOpCeil: preString = "ceil("; break; case EOpFract: preString = "fract("; break; + case EOpIsNan: + preString = "isnan("; + break; + case EOpIsInf: + preString = "isinf("; + break; + + case EOpFloatBitsToInt: + preString = "floatBitsToInt("; + break; + case EOpFloatBitsToUint: + preString = "floatBitsToUint("; + break; + case EOpIntBitsToFloat: + preString = "intBitsToFloat("; + break; + case EOpUintBitsToFloat: + preString = "uintBitsToFloat("; + break; + + case EOpPackSnorm2x16: + preString = "packSnorm2x16("; + break; + case EOpPackUnorm2x16: + preString = "packUnorm2x16("; + break; + case EOpPackHalf2x16: + preString = "packHalf2x16("; + break; + case EOpUnpackSnorm2x16: + preString = "unpackSnorm2x16("; + break; + case EOpUnpackUnorm2x16: + preString = "unpackUnorm2x16("; + break; + case EOpUnpackHalf2x16: + preString = "unpackHalf2x16("; + break; case EOpLength: preString = "length("; @@ -481,6 +623,16 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) preString = "fwidth("; break; + case EOpTranspose: + preString = "transpose("; + break; + case EOpDeterminant: + preString = "determinant("; + break; + case EOpInverse: + preString = "inverse("; + break; + case EOpAny: preString = "any("; break; @@ -536,6 +688,36 @@ bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node) return false; } +bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node) +{ + if (node->getStatementList()) + { + writeTriplet(visit, "switch (", ") ", nullptr); + // The curly braces get written when visiting the statementList aggregate + } + else + { + // No statementList, so it won't output curly braces + writeTriplet(visit, "switch (", ") {", "}\n"); + } + return true; +} + +bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node) +{ + if (node->hasCondition()) + { + writeTriplet(visit, "case (", nullptr, "):\n"); + return true; + } + else + { + TInfoSinkBase &out = objSink(); + out << "default:\n"; + return false; + } +} + bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = true; @@ -555,11 +737,11 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) for (TIntermSequence::const_iterator iter = node->getSequence()->begin(); iter != node->getSequence()->end(); ++iter) { - TIntermNode *node = *iter; - ASSERT(node != NULL); - node->traverse(this); + TIntermNode *curNode = *iter; + ASSERT(curNode != NULL); + curNode->traverse(this); - if (isSingleStatement(node)) + if (isSingleStatement(curNode)) out << ";\n"; } decrementDepth(); @@ -622,6 +804,15 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) else out << ")"; break; + case EOpInternalFunctionCall: + // Function call to an internal helper function. + if (visit == PreVisit) + out << node->getName() << "("; + else if (visit == InVisit) + out << ", "; + else + out << ")"; + break; case EOpParameters: // Function parameters. ASSERT(visit == PreVisit); @@ -724,6 +915,10 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) } break; + case EOpOuterProduct: + writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction); + break; + case EOpLessThan: writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction); break; @@ -749,6 +944,9 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) case EOpMod: writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction); break; + case EOpModf: + writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction); + break; case EOpPow: writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction); break; diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h index e5174f5660..4e66059c21 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ -#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ +#ifndef COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ +#define COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ #include @@ -21,7 +21,13 @@ class TOutputGLSLBase : public TIntermTraverser ShHashFunction64 hashFunction, NameMap &nameMap, TSymbolTable& symbolTable, - int shaderVersion); + int shaderVersion, + ShShaderOutput output); + + ShShaderOutput getShaderOutput() const + { + return mOutput; + } protected: TInfoSinkBase &objSink() { return mObjSink; } @@ -37,6 +43,8 @@ class TOutputGLSLBase : public TIntermTraverser virtual bool visitBinary(Visit visit, TIntermBinary *node); virtual bool visitUnary(Visit visit, TIntermUnary *node); virtual bool visitSelection(Visit visit, TIntermSelection *node); + virtual bool visitSwitch(Visit visit, TIntermSwitch *node); + virtual bool visitCase(Visit visit, TIntermCase *node); virtual bool visitAggregate(Visit visit, TIntermAggregate *node); virtual bool visitLoop(Visit visit, TIntermLoop *node); virtual bool visitBranch(Visit visit, TIntermBranch *node); @@ -78,6 +86,8 @@ class TOutputGLSLBase : public TIntermTraverser TSymbolTable &mSymbolTable; const int mShaderVersion; + + ShShaderOutput mOutput; }; -#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp index 30bbbff0f5..94225b81c4 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp @@ -6,26 +6,29 @@ #include "compiler/translator/OutputHLSL.h" +#include +#include +#include + #include "common/angleutils.h" #include "common/utilities.h" -#include "common/blocklayout.h" -#include "compiler/translator/compilerdebug.h" -#include "compiler/translator/InfoSink.h" +#include "compiler/translator/BuiltInFunctionEmulator.h" +#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h" #include "compiler/translator/DetectDiscontinuity.h" -#include "compiler/translator/SearchSymbol.h" -#include "compiler/translator/UnfoldShortCircuit.h" #include "compiler/translator/FlagStd140Structs.h" +#include "compiler/translator/InfoSink.h" #include "compiler/translator/NodeSearch.h" +#include "compiler/translator/RemoveSwitchFallThrough.h" #include "compiler/translator/RewriteElseBlocks.h" -#include "compiler/translator/UtilsHLSL.h" -#include "compiler/translator/util.h" -#include "compiler/translator/UniformHLSL.h" +#include "compiler/translator/SearchSymbol.h" #include "compiler/translator/StructureHLSL.h" #include "compiler/translator/TranslatorHLSL.h" - -#include -#include -#include +#include "compiler/translator/UnfoldShortCircuit.h" +#include "compiler/translator/UniformHLSL.h" +#include "compiler/translator/UtilsHLSL.h" +#include "compiler/translator/blocklayout.h" +#include "compiler/translator/compilerdebug.h" +#include "compiler/translator/util.h" namespace sh { @@ -94,12 +97,21 @@ bool OutputHLSL::TextureFunction::operator<(const TextureFunction &rhs) const return false; } -OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator) +OutputHLSL::OutputHLSL(sh::GLenum shaderType, int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, ShShaderOutput outputType, + int numRenderTargets, const std::vector &uniforms, + int compileOptions) : TIntermTraverser(true, true, true), - mContext(context), - mOutputType(parentTranslator->getOutputType()) + mShaderType(shaderType), + mShaderVersion(shaderVersion), + mExtensionBehavior(extensionBehavior), + mSourcePath(sourcePath), + mOutputType(outputType), + mNumRenderTargets(numRenderTargets), + mCompileOptions(compileOptions) { - mUnfoldShortCircuit = new UnfoldShortCircuit(context, this); + mUnfoldShortCircuit = new UnfoldShortCircuit(this); mInsideFunction = false; mUsesFragColor = false; @@ -109,28 +121,12 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator) mUsesPointCoord = false; mUsesFrontFacing = false; mUsesPointSize = false; + mUsesInstanceID = false; mUsesFragDepth = 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; - mUsesAtan2_1 = false; - mUsesAtan2_2 = false; - mUsesAtan2_3 = false; - mUsesAtan2_4 = false; mUsesDiscardRewriting = false; mUsesNestedBreak = false; - - const ShBuiltInResources &resources = parentTranslator->getResources(); - mNumRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; + mRequiresIEEEStrictCompiling = false; mUniqueIndex = 0; @@ -143,20 +139,14 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator) mExcessiveLoopIndex = NULL; mStructureHLSL = new StructureHLSL; - mUniformHLSL = new UniformHLSL(mStructureHLSL, parentTranslator); + mUniformHLSL = new UniformHLSL(mStructureHLSL, outputType, uniforms); if (mOutputType == SH_HLSL9_OUTPUT) { - if (mContext.shaderType == GL_FRAGMENT_SHADER) - { - // Reserve registers for dx_DepthRange, dx_ViewCoords and dx_DepthFront - mUniformHLSL->reserveUniformRegisters(3); - } - else - { - // Reserve registers for dx_DepthRange and dx_ViewAdjust - mUniformHLSL->reserveUniformRegisters(2); - } + // Fragment shaders need dx_DepthRange, dx_ViewCoords and dx_DepthFront. + // Vertex shaders need a slightly different set: dx_DepthRange, dx_ViewCoords and dx_ViewAdjust. + // In both cases total 3 uniform registers need to be reserved. + mUniformHLSL->reserveUniformRegisters(3); } // Reserve registers for the default uniform block and driver constants @@ -168,27 +158,55 @@ OutputHLSL::~OutputHLSL() SafeDelete(mUnfoldShortCircuit); SafeDelete(mStructureHLSL); SafeDelete(mUniformHLSL); + for (auto it = mStructEqualityFunctions.begin(); it != mStructEqualityFunctions.end(); ++it) + { + SafeDelete(*it); + } + for (auto it = mArrayEqualityFunctions.begin(); it != mArrayEqualityFunctions.end(); ++it) + { + SafeDelete(*it); + } } -void OutputHLSL::output() +void OutputHLSL::output(TIntermNode *treeRoot, TInfoSinkBase &objSink) { - mContainsLoopDiscontinuity = mContext.shaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot); - mContainsAnyLoop = containsAnyLoop(mContext.treeRoot); - const std::vector &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot); + mContainsLoopDiscontinuity = mShaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(treeRoot); + mContainsAnyLoop = containsAnyLoop(treeRoot); + const std::vector &flaggedStructs = FlagStd140ValueStructs(treeRoot); makeFlaggedStructMaps(flaggedStructs); // Work around D3D9 bug that would manifest in vertex shaders with selection blocks which // use a vertex attribute as a condition, and some related computation in the else block. - if (mOutputType == SH_HLSL9_OUTPUT && mContext.shaderType == GL_VERTEX_SHADER) + if (mOutputType == SH_HLSL9_OUTPUT && mShaderType == GL_VERTEX_SHADER) + { + RewriteElseBlocks(treeRoot); + } + + BuiltInFunctionEmulator builtInFunctionEmulator; + InitBuiltInFunctionEmulatorForHLSL(&builtInFunctionEmulator); + builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(treeRoot); + + // Output the body and footer first to determine what has to go in the header + mInfoSinkStack.push(&mBody); + treeRoot->traverse(this); + mInfoSinkStack.pop(); + + mInfoSinkStack.push(&mFooter); + if (!mDeferredGlobalInitializers.empty()) { - RewriteElseBlocks(mContext.treeRoot); + writeDeferredGlobalInitializers(mFooter); } + mInfoSinkStack.pop(); + + mInfoSinkStack.push(&mHeader); + header(&builtInFunctionEmulator); + mInfoSinkStack.pop(); - mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header - header(); + objSink << mHeader.c_str(); + objSink << mBody.c_str(); + objSink << mFooter.c_str(); - mContext.infoSink().obj << mHeader.c_str(); - mContext.infoSink().obj << mBody.c_str(); + builtInFunctionEmulator.Cleanup(); } void OutputHLSL::makeFlaggedStructMaps(const std::vector &flaggedStructs) @@ -197,10 +215,14 @@ void OutputHLSL::makeFlaggedStructMaps(const std::vector &flagge { TIntermTyped *flaggedNode = flaggedStructs[structIndex]; + TInfoSinkBase structInfoSink; + mInfoSinkStack.push(&structInfoSink); + // This will mark the necessary block elements as referenced flaggedNode->traverse(this); - TString structName(mBody.c_str()); - mBody.erase(); + + TString structName(structInfoSink.c_str()); + mInfoSinkStack.pop(); mFlaggedStructOriginalNames[flaggedNode] = structName; @@ -213,11 +235,6 @@ void OutputHLSL::makeFlaggedStructMaps(const std::vector &flagge } } -TInfoSinkBase &OutputHLSL::getBodyStream() -{ - return mBody; -} - const std::map &OutputHLSL::getInterfaceBlockRegisterMap() const { return mUniformHLSL->getInterfaceBlockRegisterMap(); @@ -277,9 +294,9 @@ TString OutputHLSL::structInitializerString(int indent, const TStructure &struct return init; } -void OutputHLSL::header() +void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator) { - TInfoSinkBase &out = mHeader; + TInfoSinkBase &out = getInfoSink(); TString varyings; TString attributes; @@ -320,6 +337,23 @@ void OutputHLSL::header() out << mUniformHLSL->uniformsHeader(mOutputType, mReferencedUniforms); out << mUniformHLSL->interfaceBlocksHeader(mReferencedInterfaceBlocks); + if (!mEqualityFunctions.empty()) + { + out << "\n// Equality functions\n\n"; + for (auto it = mEqualityFunctions.cbegin(); it != mEqualityFunctions.cend(); ++it) + { + out << (*it)->functionDefinition << "\n"; + } + } + if (!mArrayAssignmentFunctions.empty()) + { + out << "\n// Assignment functions\n\n"; + for (auto it = mArrayAssignmentFunctions.cbegin(); it != mArrayAssignmentFunctions.cend(); ++it) + { + out << it->functionDefinition << "\n"; + } + } + if (mUsesDiscardRewriting) { out << "#define ANGLE_USES_DISCARD_REWRITING\n"; @@ -330,6 +364,11 @@ void OutputHLSL::header() out << "#define ANGLE_USES_NESTED_BREAK\n"; } + if (mRequiresIEEEStrictCompiling) + { + out << "#define ANGLE_REQUIRES_IEEE_STRICT_COMPILING\n"; + } + out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n" "#define LOOP [loop]\n" "#define FLATTEN [flatten]\n" @@ -338,16 +377,16 @@ void OutputHLSL::header() "#define FLATTEN\n" "#endif\n"; - if (mContext.shaderType == GL_FRAGMENT_SHADER) + if (mShaderType == GL_FRAGMENT_SHADER) { - TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers"); - const bool usingMRTExtension = (iter != mContext.extensionBehavior().end() && (iter->second == EBhEnable || iter->second == EBhRequire)); + TExtensionBehavior::const_iterator iter = mExtensionBehavior.find("GL_EXT_draw_buffers"); + const bool usingMRTExtension = (iter != mExtensionBehavior.end() && (iter->second == EBhEnable || iter->second == EBhRequire)); out << "// Varyings\n"; out << varyings; out << "\n"; - if (mContext.getShaderVersion() >= 300) + if (mShaderVersion >= 300) { for (ReferencedSymbols::const_iterator outputVariableIt = mReferencedOutputVariables.begin(); outputVariableIt != mReferencedOutputVariables.end(); outputVariableIt++) { @@ -493,6 +532,11 @@ void OutputHLSL::header() out << "static float gl_PointSize = float(1);\n"; } + if (mUsesInstanceID) + { + out << "static int gl_InstanceID;"; + } + out << "\n" "// Varyings\n"; out << varyings; @@ -511,14 +555,22 @@ void OutputHLSL::header() if (mOutputType == SH_HLSL11_OUTPUT) { + out << "cbuffer DriverConstants : register(b1)\n" + "{\n"; + if (mUsesDepthRange) { - out << "cbuffer DriverConstants : register(b1)\n" - "{\n" - " float3 dx_DepthRange : packoffset(c0);\n" - "};\n" - "\n"; + out << " float3 dx_DepthRange : packoffset(c0);\n"; } + + // dx_ViewAdjust and dx_ViewCoords will only be used in Feature Level 9 shaders. + // However, we declare it for all shaders (including Feature Level 10+). + // The bytecode is the same whether we declare it or not, since D3DCompiler removes it if it's unused. + out << " float4 dx_ViewAdjust : packoffset(c1);\n"; + out << " float2 dx_ViewCoords : packoffset(c2);\n"; + + out << "};\n" + "\n"; } else { @@ -527,7 +579,8 @@ void OutputHLSL::header() out << "uniform float3 dx_DepthRange : register(c0);\n"; } - out << "uniform float4 dx_ViewAdjust : register(c1);\n" + out << "uniform float4 dx_ViewAdjust : register(c1);\n"; + out << "uniform float2 dx_ViewCoords : register(c2);\n" "\n"; } @@ -980,7 +1033,15 @@ void OutputHLSL::header() } else if (IsShadowSampler(textureFunction->sampler)) { - out << "x.SampleCmp(s, "; + switch(textureFunction->method) + { + case TextureFunction::IMPLICIT: out << "x.SampleCmp(s, "; break; + case TextureFunction::BIAS: out << "x.SampleCmp(s, "; break; + case TextureFunction::LOD: out << "x.SampleCmp(s, "; break; + case TextureFunction::LOD0: out << "x.SampleCmpLevelZero(s, "; break; + case TextureFunction::LOD0BIAS: out << "x.SampleCmpLevelZero(s, "; break; + default: UNREACHABLE(); + } } else { @@ -1111,11 +1172,20 @@ void OutputHLSL::header() else if (IsShadowSampler(textureFunction->sampler)) { // Compare value - switch(textureFunction->coords) + if (textureFunction->proj) { - case 3: out << "), t.z"; break; - case 4: out << "), t.w"; break; - default: UNREACHABLE(); + // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: + // The resulting third component of P' in the shadow forms is used as Dref + out << "), t.z" << proj; + } + else + { + switch(textureFunction->coords) + { + case 3: out << "), t.z"; break; + case 4: out << "), t.w"; break; + default: UNREACHABLE(); + } } } else @@ -1131,11 +1201,20 @@ void OutputHLSL::header() else if (IsShadowSampler(textureFunction->sampler)) { // Compare value - switch(textureFunction->coords) + if (textureFunction->proj) { - case 3: out << "), t.z"; break; - case 4: out << "), t.w"; break; - default: UNREACHABLE(); + // According to ESSL 3.00.4 sec 8.8 p95 on textureProj: + // The resulting third component of P' in the shadow forms is used as Dref + out << "), t.z" << proj; + } + else + { + switch(textureFunction->coords) + { + case 3: out << "), t.z"; break; + case 4: out << "), t.w"; break; + default: UNREACHABLE(); + } } } else @@ -1205,179 +1284,12 @@ void OutputHLSL::header() "\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 (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"; - } + builtInFunctionEmulator->OutputEmulatedFunctions(out); } void OutputHLSL::visitSymbol(TIntermSymbol *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); // Handle accessing std140 structs by value if (mFlaggedStructMappedNames.count(node) > 0) @@ -1458,6 +1370,11 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) mUsesPointSize = true; out << name; } + else if (qualifier == EvqInstanceID) + { + mUsesInstanceID = true; + out << name; + } else if (name == "gl_FragDepthEXT") { mUsesFragDepth = true; @@ -1476,12 +1393,51 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) void OutputHLSL::visitRaw(TIntermRaw *node) { - mBody << node->getRawText(); + getInfoSink() << node->getRawText(); +} + +void OutputHLSL::outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out) +{ + if (type.isScalar() && !type.isArray()) + { + if (op == EOpEqual) + { + outputTriplet(visit, "(", " == ", ")", out); + } + else + { + outputTriplet(visit, "(", " != ", ")", out); + } + } + else + { + if (visit == PreVisit && op == EOpNotEqual) + { + out << "!"; + } + + if (type.isArray()) + { + const TString &functionName = addArrayEqualityFunction(type); + outputTriplet(visit, (functionName + "(").c_str(), ", ", ")", out); + } + else if (type.getBasicType() == EbtStruct) + { + const TStructure &structure = *type.getStruct(); + const TString &functionName = addStructEqualityFunction(structure); + outputTriplet(visit, (functionName + "(").c_str(), ", ", ")", out); + } + else + { + ASSERT(type.isMatrix() || type.isVector()); + outputTriplet(visit, "all(", " == ", ")", out); + } + } } bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); // Handle accessing std140 structs by value if (mFlaggedStructMappedNames.count(node) > 0) @@ -1492,7 +1448,17 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) switch (node->getOp()) { - case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break; + case EOpAssign: + if (node->getLeft()->isArray()) + { + const TString &functionName = addArrayAssignmentFunction(node->getType()); + outputTriplet(visit, (functionName + "(").c_str(), ", ", ")"); + } + else + { + outputTriplet(visit, "(", " = ", ")"); + } + break; case EOpInitialize: if (visit == PreVisit) { @@ -1502,22 +1468,21 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) // this to "float t = x, x = t;". TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode(); + ASSERT(symbolNode); TIntermTyped *expression = node->getRight(); - sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); - expression->traverse(&searchSymbol); - bool sameSymbol = searchSymbol.foundMatch(); - - if (sameSymbol) + // TODO (jmadill): do a 'deep' scan to know if an expression is statically const + if (symbolNode->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst) { - // Type already printed - out << "t" + str(mUniqueIndex) + " = "; - expression->traverse(this); - out << ", "; - symbolNode->traverse(this); - out << " = t" + str(mUniqueIndex); - - mUniqueIndex++; + // For variables which are not constant, defer their real initialization until + // after we initialize other globals: uniforms, attributes and varyings. + mDeferredGlobalInitializers.push_back(std::make_pair(symbolNode, expression)); + const TString &initString = initializer(node->getType()); + node->setRight(new TIntermRaw(node->getType(), initString)); + } + else if (writeSameSymbolInitializer(out, symbolNode, expression)) + { + // Skip initializing the rest of the expression return false; } } @@ -1554,16 +1519,22 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) } else if (visit == InVisit) { - out << " = mul("; + out << " = transpose(mul(transpose("; node->getLeft()->traverse(this); - out << ", "; + out << "), transpose("; } else { - out << "))"; + out << "))))"; } break; case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break; + case EOpIModAssign: outputTriplet(visit, "(", " %= ", ")"); break; + case EOpBitShiftLeftAssign: outputTriplet(visit, "(", " <<= ", ")"); break; + case EOpBitShiftRightAssign: outputTriplet(visit, "(", " >>= ", ")"); break; + case EOpBitwiseAndAssign: outputTriplet(visit, "(", " &= ", ")"); break; + case EOpBitwiseXorAssign: outputTriplet(visit, "(", " ^= ", ")"); break; + case EOpBitwiseOrAssign: outputTriplet(visit, "(", " |= ", ")"); break; case EOpIndexDirect: { const TType& leftType = node->getLeft()->getType(); @@ -1651,65 +1622,15 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) case EOpSub: outputTriplet(visit, "(", " - ", ")"); break; case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break; + case EOpIMod: outputTriplet(visit, "(", " % ", ")"); break; + case EOpBitShiftLeft: outputTriplet(visit, "(", " << ", ")"); break; + case EOpBitShiftRight: outputTriplet(visit, "(", " >> ", ")"); break; + case EOpBitwiseAnd: outputTriplet(visit, "(", " & ", ")"); break; + case EOpBitwiseXor: outputTriplet(visit, "(", " ^ ", ")"); break; + case EOpBitwiseOr: 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 TStructure &structure = *node->getLeft()->getType().getStruct(); - const TFieldList &fields = structure.fields(); - - for (size_t i = 0; i < fields.size(); i++) - { - const TField *field = fields[i]; - - node->getLeft()->traverse(this); - out << "." + DecorateField(field->name(), structure) + " == "; - node->getRight()->traverse(this); - out << "." + DecorateField(field->name(), structure); - - if (i < fields.size() - 1) - { - out << " && "; - } - } - - out << ")"; - - return false; - } - else - { - ASSERT(node->getLeft()->isMatrix() || node->getLeft()->isVector()); - - if (node->getOp() == EOpEqual) - { - outputTriplet(visit, "all(", " == ", ")"); - } - else - { - outputTriplet(visit, "!all(", " == ", ")"); - } - } + outputEqual(visit, node->getLeft()->getType(), node->getOp(), out); break; case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; @@ -1760,6 +1681,7 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) case EOpPositive: outputTriplet(visit, "(+", "", ")"); break; case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break; case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break; + case EOpBitwiseNot: outputTriplet(visit, "(~", "", ")"); break; case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break; case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break; case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break; @@ -1772,6 +1694,21 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break; case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break; case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break; + case EOpSinh: outputTriplet(visit, "sinh(", "", ")"); break; + case EOpCosh: outputTriplet(visit, "cosh(", "", ")"); break; + case EOpTanh: outputTriplet(visit, "tanh(", "", ")"); break; + case EOpAsinh: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "asinh("); + break; + case EOpAcosh: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "acosh("); + break; + case EOpAtanh: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "atanh("); + break; case EOpExp: outputTriplet(visit, "exp(", "", ")"); break; case EOpLog: outputTriplet(visit, "log(", "", ")"); break; case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break; @@ -1781,8 +1718,47 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break; case EOpSign: outputTriplet(visit, "sign(", "", ")"); break; case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break; + case EOpTrunc: outputTriplet(visit, "trunc(", "", ")"); break; + case EOpRound: outputTriplet(visit, "round(", "", ")"); break; + case EOpRoundEven: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "roundEven("); + break; case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break; case EOpFract: outputTriplet(visit, "frac(", "", ")"); break; + case EOpIsNan: + outputTriplet(visit, "isnan(", "", ")"); + mRequiresIEEEStrictCompiling = true; + break; + case EOpIsInf: outputTriplet(visit, "isinf(", "", ")"); break; + case EOpFloatBitsToInt: outputTriplet(visit, "asint(", "", ")"); break; + case EOpFloatBitsToUint: outputTriplet(visit, "asuint(", "", ")"); break; + case EOpIntBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break; + case EOpUintBitsToFloat: outputTriplet(visit, "asfloat(", "", ")"); break; + case EOpPackSnorm2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "packSnorm2x16("); + break; + case EOpPackUnorm2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "packUnorm2x16("); + break; + case EOpPackHalf2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "packHalf2x16("); + break; + case EOpUnpackSnorm2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "unpackSnorm2x16("); + break; + case EOpUnpackUnorm2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "unpackUnorm2x16("); + break; + case EOpUnpackHalf2x16: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "unpackHalf2x16("); + break; case EOpLength: outputTriplet(visit, "length(", "", ")"); break; case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break; case EOpDFdx: @@ -1815,6 +1791,13 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) outputTriplet(visit, "fwidth(", "", ")"); } break; + case EOpTranspose: outputTriplet(visit, "transpose(", "", ")"); break; + case EOpDeterminant: outputTriplet(visit, "determinant(transpose(", "", "))"); break; + case EOpInverse: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "inverse("); + break; + case EOpAny: outputTriplet(visit, "any(", "", ")"); break; case EOpAll: outputTriplet(visit, "all(", "", ")"); break; default: UNREACHABLE(); @@ -1825,7 +1808,7 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); switch (node->getOp()) { @@ -1843,7 +1826,11 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) traverseStatements(*sit); - out << ";\n"; + // Don't output ; after case labels, they're terminated by : + // This is needed especially since outputting a ; after a case statement would turn empty + // case statements into non-empty case statements, disallowing fall-through from them. + if ((*sit)->getAsCaseNode() == nullptr) + out << ";\n"; } if (mInsideFunction) @@ -1871,11 +1858,12 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration { - for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) + for (auto it = sequence->cbegin(); it != sequence->cend(); ++it) { - if (isSingleStatement(*sit)) + const auto &seqElement = *it; + if (isSingleStatement(seqElement)) { - mUnfoldShortCircuit->traverse(*sit); + mUnfoldShortCircuit->traverse(seqElement); } if (!mInsideFunction) @@ -1885,7 +1873,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) out << TypeString(variable->getType()) + " "; - TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); + TIntermSymbol *symbol = seqElement->getAsSymbolNode(); if (symbol) { @@ -1895,10 +1883,10 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) } else { - (*sit)->traverse(this); + seqElement->traverse(this); } - if (*sit != sequence->back()) + if (seqElement != sequence->back()) { out << ";\n"; } @@ -2149,7 +2137,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) bool bias = (arguments->size() > mandatoryArgumentCount); // Bias argument is optional - if (lod0 || mContext.shaderType == GL_VERTEX_SHADER) + if (lod0 || mShaderType == GL_VERTEX_SHADER) { if (bias) { @@ -2217,7 +2205,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) { const TString &structName = StructNameString(*node->getType().getStruct()); mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence()); - outputTriplet(visit, structName + "_ctor(", ", ", ")"); + outputTriplet(visit, (structName + "_ctor(").c_str(), ", ", ")"); } break; case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; @@ -2227,37 +2215,15 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break; case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break; case EOpMod: - { - // We need to look at the number of components in both arguments - const int modValue = (*node->getSequence())[0]->getAsTyped()->getNominalSize() * 10 + - (*node->getSequence())[1]->getAsTyped()->getNominalSize(); - switch (modValue) - { - 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(", ", ", ")"); - } + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "mod("); break; + case EOpModf: outputTriplet(visit, "modf(", ", ", ")"); 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(", ", ", ")"); + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "atan("); break; case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break; case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break; @@ -2269,21 +2235,15 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) 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(", ", ", ")"); - } + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "faceforward("); break; case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break; case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break; + case EOpOuterProduct: + ASSERT(node->getUseEmulatedFunction()); + writeEmulatedFunctionTriplet(visit, "outerProduct("); + break; case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; default: UNREACHABLE(); } @@ -2293,7 +2253,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); if (node->usesTernaryOperator()) { @@ -2307,7 +2267,7 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) // however flattening all the ifs in branch heavy shaders made D3D error too. // As a temporary workaround we flatten the ifs only if there is at least a loop // present somewhere in the shader. - if (mContext.shaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop) + if (mShaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop) { out << "FLATTEN "; } @@ -2361,6 +2321,37 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) return false; } +bool OutputHLSL::visitSwitch(Visit visit, TIntermSwitch *node) +{ + if (node->getStatementList()) + { + node->setStatementList(RemoveSwitchFallThrough::removeFallThrough(node->getStatementList())); + outputTriplet(visit, "switch (", ") ", ""); + // The curly braces get written when visiting the statementList aggregate + } + else + { + // No statementList, so it won't output curly braces + outputTriplet(visit, "switch (", ") {", "}\n"); + } + return true; +} + +bool OutputHLSL::visitCase(Visit visit, TIntermCase *node) +{ + if (node->hasCondition()) + { + outputTriplet(visit, "case (", "", "):\n"); + return true; + } + else + { + TInfoSinkBase &out = getInfoSink(); + out << "default:\n"; + return false; + } +} + void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node) { writeConstantUnion(node->getType(), node->getUnionArrayPointer()); @@ -2388,7 +2379,7 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) } } - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); if (node->getType() == ELoopDoWhile) { @@ -2454,7 +2445,7 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); switch (node->getFlowOp()) { @@ -2556,7 +2547,7 @@ bool OutputHLSL::isSingleStatement(TIntermNode *node) bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) { const int MAX_LOOP_ITERATIONS = 254; - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); // Parse loops of the form: // for(int index = initial; index [comparator] limit; index += increment) @@ -2756,10 +2747,8 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) return false; // Not handled as an excessive loop } -void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString) +void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString, TInfoSinkBase &out) { - TInfoSinkBase &out = mBody; - if (visit == PreVisit) { out << preString; @@ -2774,19 +2763,26 @@ void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TStr } } +void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString) +{ + outputTriplet(visit, preString, inString, postString, getInfoSink()); +} + void OutputHLSL::outputLineDirective(int line) { - if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0)) + if ((mCompileOptions & SH_LINE_DIRECTIVES) && (line > 0)) { - mBody << "\n"; - mBody << "#line " << line; + TInfoSinkBase &out = getInfoSink(); + + out << "\n"; + out << "#line " << line; - if (mContext.sourcePath) + if (mSourcePath) { - mBody << " \"" << mContext.sourcePath << "\""; + out << " \"" << mSourcePath << "\""; } - mBody << "\n"; + out << "\n"; } } @@ -2832,15 +2828,15 @@ TString OutputHLSL::initializer(const TType &type) return "{" + string + "}"; } -void OutputHLSL::outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters) +void OutputHLSL::outputConstructor(Visit visit, const TType &type, const char *name, const TIntermSequence *parameters) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); if (visit == PreVisit) { mStructureHLSL->addConstructor(type, name, parameters); - out << name + "("; + out << name << "("; } else if (visit == InVisit) { @@ -2854,7 +2850,7 @@ void OutputHLSL::outputConstructor(Visit visit, const TType &type, const TString const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion) { - TInfoSinkBase &out = mBody; + TInfoSinkBase &out = getInfoSink(); const TStructure* structure = type.getStruct(); if (structure) @@ -2912,4 +2908,209 @@ const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const Con return constUnion; } +void OutputHLSL::writeEmulatedFunctionTriplet(Visit visit, const char *preStr) +{ + TString preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr); + outputTriplet(visit, preString.c_str(), ", ", ")"); +} + +bool OutputHLSL::writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression) +{ + sh::SearchSymbol searchSymbol(symbolNode->getSymbol()); + expression->traverse(&searchSymbol); + + if (searchSymbol.foundMatch()) + { + // Type already printed + out << "t" + str(mUniqueIndex) + " = "; + expression->traverse(this); + out << ", "; + symbolNode->traverse(this); + out << " = t" + str(mUniqueIndex); + + mUniqueIndex++; + return true; + } + + return false; +} + +void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out) +{ + out << "#define ANGLE_USES_DEFERRED_INIT\n" + << "\n" + << "void initializeDeferredGlobals()\n" + << "{\n"; + + for (auto it = mDeferredGlobalInitializers.cbegin(); it != mDeferredGlobalInitializers.cend(); ++it) + { + const auto &deferredGlobal = *it; + TIntermSymbol *symbol = deferredGlobal.first; + TIntermTyped *expression = deferredGlobal.second; + ASSERT(symbol); + ASSERT(symbol->getQualifier() == EvqGlobal && expression->getQualifier() != EvqConst); + + out << " " << Decorate(symbol->getSymbol()) << " = "; + + if (!writeSameSymbolInitializer(out, symbol, expression)) + { + ASSERT(mInfoSinkStack.top() == &out); + expression->traverse(this); + } + + out << ";\n"; + } + + out << "}\n" + << "\n"; +} + +TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) +{ + const TFieldList &fields = structure.fields(); + + for (auto it = mStructEqualityFunctions.cbegin(); it != mStructEqualityFunctions.cend(); ++it) + { + auto *eqFunction = *it; + if (eqFunction->structure == &structure) + { + return eqFunction->functionName; + } + } + + const TString &structNameString = StructNameString(structure); + + StructEqualityFunction *function = new StructEqualityFunction(); + function->structure = &structure; + function->functionName = "angle_eq_" + structNameString; + + TInfoSinkBase fnOut; + + fnOut << "bool " << function->functionName << "(" << structNameString << " a, " << structNameString + " b)\n" + << "{\n" + " return "; + + for (size_t i = 0; i < fields.size(); i++) + { + const TField *field = fields[i]; + const TType *fieldType = field->type(); + + const TString &fieldNameA = "a." + Decorate(field->name()); + const TString &fieldNameB = "b." + Decorate(field->name()); + + if (i > 0) + { + fnOut << " && "; + } + + fnOut << "("; + outputEqual(PreVisit, *fieldType, EOpEqual, fnOut); + fnOut << fieldNameA; + outputEqual(InVisit, *fieldType, EOpEqual, fnOut); + fnOut << fieldNameB; + outputEqual(PostVisit, *fieldType, EOpEqual, fnOut); + fnOut << ")"; + } + + fnOut << ";\n" << "}\n"; + + function->functionDefinition = fnOut.c_str(); + + mStructEqualityFunctions.push_back(function); + mEqualityFunctions.push_back(function); + + return function->functionName; +} + +TString OutputHLSL::addArrayEqualityFunction(const TType& type) +{ + for (auto it = mArrayEqualityFunctions.cbegin(); it != mArrayEqualityFunctions.cend(); ++it) + { + const auto &eqFunction = *it; + if (eqFunction->type == type) + { + return eqFunction->functionName; + } + } + + const TString &typeName = TypeString(type); + + ArrayHelperFunction *function = new ArrayHelperFunction(); + function->type = type; + + TInfoSinkBase fnNameOut; + fnNameOut << "angle_eq_" << type.getArraySize() << "_" << typeName; + function->functionName = fnNameOut.c_str(); + + TType nonArrayType = type; + nonArrayType.clearArrayness(); + + TInfoSinkBase fnOut; + + fnOut << "bool " << function->functionName << "(" + << typeName << " a[" << type.getArraySize() << "], " + << typeName << " b[" << type.getArraySize() << "])\n" + << "{\n" + " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n" + " {\n" + " if ("; + + outputEqual(PreVisit, nonArrayType, EOpNotEqual, fnOut); + fnOut << "a[i]"; + outputEqual(InVisit, nonArrayType, EOpNotEqual, fnOut); + fnOut << "b[i]"; + outputEqual(PostVisit, nonArrayType, EOpNotEqual, fnOut); + + fnOut << ") { return false; }\n" + " }\n" + " return true;\n" + "}\n"; + + function->functionDefinition = fnOut.c_str(); + + mArrayEqualityFunctions.push_back(function); + mEqualityFunctions.push_back(function); + + return function->functionName; +} + +TString OutputHLSL::addArrayAssignmentFunction(const TType& type) +{ + for (auto it = mArrayAssignmentFunctions.cbegin(); it != mArrayAssignmentFunctions.cend(); ++it) + { + const auto &assignFunction = *it; + if (assignFunction.type == type) + { + return assignFunction.functionName; + } + } + + const TString &typeName = TypeString(type); + + ArrayHelperFunction function; + function.type = type; + + TInfoSinkBase fnNameOut; + fnNameOut << "angle_assign_" << type.getArraySize() << "_" << typeName; + function.functionName = fnNameOut.c_str(); + + TInfoSinkBase fnOut; + + fnOut << "void " << function.functionName << "(out " + << typeName << " a[" << type.getArraySize() << "], " + << typeName << " b[" << type.getArraySize() << "])\n" + << "{\n" + " for (int i = 0; i < " << type.getArraySize() << "; ++i)\n" + " {\n" + " a[i] = b[i];\n" + " }\n" + "}\n"; + + function.functionDefinition = fnOut.c_str(); + + mArrayAssignmentFunctions.push_back(function); + + return function.functionName; +} + } diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h index 5525e6eaa6..51da877c72 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h @@ -4,18 +4,20 @@ // found in the LICENSE file. // -#ifndef COMPILER_OUTPUTHLSL_H_ -#define COMPILER_OUTPUTHLSL_H_ +#ifndef COMPILER_TRANSLATOR_OUTPUTHLSL_H_ +#define COMPILER_TRANSLATOR_OUTPUTHLSL_H_ #include #include #include +#include #include "angle_gl.h" - #include "compiler/translator/IntermNode.h" #include "compiler/translator/ParseContext.h" +class BuiltInFunctionEmulator; + namespace sh { class UnfoldShortCircuit; @@ -27,20 +29,25 @@ typedef std::map ReferencedSymbols; class OutputHLSL : public TIntermTraverser { public: - OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator); - ~OutputHLSL(); + OutputHLSL(sh::GLenum shaderType, int shaderVersion, + const TExtensionBehavior &extensionBehavior, + const char *sourcePath, ShShaderOutput outputType, + int numRenderTargets, const std::vector &uniforms, + int compileOptions); - void output(); + ~OutputHLSL(); - TInfoSinkBase &getBodyStream(); + void output(TIntermNode *treeRoot, TInfoSinkBase &objSink); const std::map &getInterfaceBlockRegisterMap() const; const std::map &getUniformRegisterMap() const; static TString initializer(const TType &type); + TInfoSinkBase &getInfoSink() { ASSERT(!mInfoSinkStack.empty()); return *mInfoSinkStack.top(); } + protected: - void header(); + void header(const BuiltInFunctionEmulator *builtInFunctionEmulator); // Visit AST nodes and output their code to the body stream void visitSymbol(TIntermSymbol*); @@ -49,6 +56,8 @@ class OutputHLSL : public TIntermTraverser bool visitBinary(Visit visit, TIntermBinary*); bool visitUnary(Visit visit, TIntermUnary*); bool visitSelection(Visit visit, TIntermSelection*); + bool visitSwitch(Visit visit, TIntermSwitch *); + bool visitCase(Visit visit, TIntermCase *); bool visitAggregate(Visit visit, TIntermAggregate*); bool visitLoop(Visit visit, TIntermLoop*); bool visitBranch(Visit visit, TIntermBranch*); @@ -56,16 +65,39 @@ class OutputHLSL : public TIntermTraverser 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); + + // Emit one of three strings depending on traverse phase. Called with literal strings so using const char* instead of TString. + void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString, TInfoSinkBase &out); + void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString); void outputLineDirective(int line); TString argumentString(const TIntermSymbol *symbol); int vectorSize(const TType &type) const; - void outputConstructor(Visit visit, const TType &type, const TString &name, const TIntermSequence *parameters); + // Emit constructor. Called with literal names so using const char* instead of TString. + void outputConstructor(Visit visit, const TType &type, const char *name, const TIntermSequence *parameters); const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion); - TParseContext &mContext; + void outputEqual(Visit visit, const TType &type, TOperator op, TInfoSinkBase &out); + + void writeEmulatedFunctionTriplet(Visit visit, const char *preStr); + void makeFlaggedStructMaps(const std::vector &flaggedStructs); + + // Returns true if it found a 'same symbol' initializer (initializer that references the variable it's initting) + bool writeSameSymbolInitializer(TInfoSinkBase &out, TIntermSymbol *symbolNode, TIntermTyped *expression); + void writeDeferredGlobalInitializers(TInfoSinkBase &out); + + // Returns the function name + TString addStructEqualityFunction(const TStructure &structure); + TString addArrayEqualityFunction(const TType &type); + TString addArrayAssignmentFunction(const TType &type); + + sh::GLenum mShaderType; + int mShaderVersion; + const TExtensionBehavior &mExtensionBehavior; + const char *mSourcePath; const ShShaderOutput mOutputType; + int mCompileOptions; + UnfoldShortCircuit *mUnfoldShortCircuit; bool mInsideFunction; @@ -74,6 +106,11 @@ class OutputHLSL : public TIntermTraverser TInfoSinkBase mBody; TInfoSinkBase mFooter; + // A stack is useful when we want to traverse in the header, or in helper functions, but not always + // write to the body. Instead use an InfoSink stack to keep our current state intact. + // TODO (jmadill): Just passing an InfoSink in function parameters would be simpler. + std::stack mInfoSinkStack; + ReferencedSymbols mReferencedUniforms; ReferencedSymbols mReferencedInterfaceBlocks; ReferencedSymbols mReferencedAttributes; @@ -119,25 +156,13 @@ class OutputHLSL : public TIntermTraverser bool mUsesPointCoord; bool mUsesFrontFacing; bool mUsesPointSize; + bool mUsesInstanceID; bool mUsesFragDepth; 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 mUsesAtan2_1; - bool mUsesAtan2_2; - bool mUsesAtan2_3; - bool mUsesAtan2_4; bool mUsesDiscardRewriting; bool mUsesNestedBreak; + bool mRequiresIEEEStrictCompiling; + int mNumRenderTargets; @@ -156,9 +181,41 @@ class OutputHLSL : public TIntermTraverser std::map mFlaggedStructMappedNames; std::map mFlaggedStructOriginalNames; - void makeFlaggedStructMaps(const std::vector &flaggedStructs); + // Some initializers use varyings, uniforms or attributes, thus we can't evaluate some variables + // at global static scope in HLSL. These variables depend on values which we retrieve from the + // shader input structure, which we set in the D3D main function. Instead, we can initialize + // these static globals after we initialize our other globals. + std::vector> mDeferredGlobalInitializers; + + struct HelperFunction + { + TString functionName; + TString functionDefinition; + + virtual ~HelperFunction() {} + }; + + // A list of all equality comparison functions. It's important to preserve the order at + // which we add the functions, since nested structures call each other recursively, and + // structure equality functions may need to call array equality functions and vice versa. + // The ownership of the pointers is maintained by the type-specific arrays. + std::vector mEqualityFunctions; + + struct StructEqualityFunction : public HelperFunction + { + const TStructure *structure; + }; + std::vector mStructEqualityFunctions; + + struct ArrayHelperFunction : public HelperFunction + { + TType type; + }; + std::vector mArrayEqualityFunctions; + + std::vector mArrayAssignmentFunctions; }; } -#endif // COMPILER_OUTPUTHLSL_H_ +#endif // COMPILER_TRANSLATOR_OUTPUTHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp index 37969b5468..7ad3f817ad 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp @@ -9,8 +9,9 @@ #include #include -#include "compiler/translator/glslang.h" #include "compiler/preprocessor/SourceLocation.h" +#include "compiler/translator/glslang.h" +#include "compiler/translator/ValidateSwitch.h" /////////////////////////////////////////////////////////////////////// // @@ -796,9 +797,24 @@ bool TParseContext::arrayErrorCheck(const TSourceLoc& line, const TString& ident bool sameScope = false; TSymbol* symbol = symbolTable.find(identifier, 0, &builtIn, &sameScope); if (symbol == 0 || !sameScope) { - if (reservedErrorCheck(line, identifier)) - return true; - + bool needsReservedErrorCheck = true; + + // gl_LastFragData may be redeclared with a new precision qualifier + if (identifier.compare(0, 15, "gl_LastFragData") == 0) { + if (type.arraySize == static_cast(symbolTable.findBuiltIn("gl_MaxDrawBuffers", shaderVersion))->getConstPointer()->getIConst()) { + if (TSymbol* builtInSymbol = symbolTable.findBuiltIn(identifier, shaderVersion)) { + needsReservedErrorCheck = extensionErrorCheck(line, builtInSymbol->getExtension()); + } + } else { + error(line, "redeclaration of array with size != gl_MaxDrawBuffers", identifier.c_str()); + return true; + } + } + + if (needsReservedErrorCheck) + if (reservedErrorCheck(line, identifier)) + return true; + variable = new TVariable(&identifier, TType(type)); if (type.arraySize) @@ -976,6 +992,26 @@ bool TParseContext::layoutLocationErrorCheck(const TSourceLoc& location, const T return false; } +bool TParseContext::functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *aggregate) +{ + for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) + { + TQualifier qual = fnCandidate->getParam(i).type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) + { + TIntermTyped *node = (*(aggregate->getSequence()))[i]->getAsTyped(); + if (lValueErrorCheck(node->getLine(), "assign", node)) + { + error(node->getLine(), + "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error"); + recover(); + return true; + } + } + } + return false; +} + bool TParseContext::supportsExtension(const char* extension) { const TExtensionBehavior& extbehavior = extensionBehavior(); @@ -1062,14 +1098,14 @@ const TVariable *TParseContext::getNamedVariable(const TSourceLoc &location, // // Return the function symbol if found, otherwise 0. // -const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int shaderVersion, bool *builtIn) +const TFunction* TParseContext::findFunction(const TSourceLoc& line, TFunction* call, int inputShaderVersion, bool *builtIn) { // First find by unmangled name to check whether the function name has been // hidden by a variable name or struct typename. // If a function is found, check for one with a matching argument list. - const TSymbol* symbol = symbolTable.find(call->getName(), shaderVersion, builtIn); + const TSymbol* symbol = symbolTable.find(call->getName(), inputShaderVersion, builtIn); if (symbol == 0 || symbol->isFunction()) { - symbol = symbolTable.find(call->getMangledName(), shaderVersion, builtIn); + symbol = symbolTable.find(call->getMangledName(), inputShaderVersion, builtIn); } if (symbol == 0) { @@ -1162,7 +1198,7 @@ bool TParseContext::executeInitializer(const TSourceLoc& line, const TString& id if (qualifier != EvqConst) { TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); - intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); + intermNode = createAssign(EOpInitialize, intermSymbol, initializer, line); if (intermNode == 0) { assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); return true; @@ -1375,7 +1411,7 @@ TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &inv recover(); return NULL; } - symbolTable.addInvariantVarying(*identifier); + symbolTable.addInvariantVarying(std::string(identifier->c_str())); const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); ASSERT(variable); const TType &type = variable->getType(); @@ -1605,7 +1641,7 @@ TFunction *TParseContext::addConstructorFunc(TPublicType publicType) // // Returns 0 for an error or the constructed node (aggregate or typed) for no error. // -TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, const TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line) +TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, TType *type, TOperator op, TFunction *fnCall, const TSourceLoc &line) { TIntermAggregate *aggregateArguments = arguments->getAsAggregate(); @@ -1633,13 +1669,21 @@ TIntermTyped *TParseContext::addConstructor(TIntermNode *arguments, const TType } // Turn the argument list itself into a constructor - TIntermTyped *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line); - TIntermTyped *constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); + TIntermAggregate *constructor = intermediate.setAggregateOperator(aggregateArguments, op, line); + TIntermTyped *constConstructor = foldConstConstructor(constructor, *type); if (constConstructor) { return constConstructor; } + // Structs should not be precision qualified, the individual members may be. + // Built-in types on the other hand should be precision qualified. + if (op != EOpConstructStruct) + { + constructor->setPrecisionFromChildren(); + type->setPrecision(constructor->getPrecision()); + } + return constructor; } @@ -2028,9 +2072,11 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co recover(); } - if (indexExpression->getQualifier() == EvqConst) + TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion(); + + if (indexExpression->getQualifier() == EvqConst && indexConstantUnion) { - int index = indexExpression->getAsConstantUnion()->getIConst(0); + int index = indexConstantUnion->getIConst(0); if (index < 0) { std::stringstream infoStream; @@ -2091,7 +2137,7 @@ TIntermTyped* TParseContext::addIndexExpression(TIntermTyped *baseExpression, co index = baseExpression->getType().getNominalSize() - 1; } - indexExpression->getAsConstantUnion()->getUnionArrayPointer()->setIConst(index); + indexConstantUnion->getUnionArrayPointer()->setIConst(index); indexedExpression = intermediate.addIndex(EOpIndexDirect, baseExpression, indexExpression, location); } } @@ -2520,7 +2566,10 @@ TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSou TStructure* structure = new TStructure(structName, fieldList); TType* structureType = new TType(structure); + // Store a bool in the struct if we're at global scope, to allow us to + // skip the local struct scoping workaround in HLSL. structure->setUniqueId(TSymbolTable::nextUniqueId()); + structure->setAtGlobalScope(symbolTable.atGlobalLevel()); if (!structName->empty()) { @@ -2560,6 +2609,553 @@ TPublicType TParseContext::addStructure(const TSourceLoc& structLine, const TSou return publicType; } +TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc) +{ + TBasicType switchType = init->getBasicType(); + if ((switchType != EbtInt && switchType != EbtUInt) || + init->isMatrix() || + init->isArray() || + init->isVector()) + { + error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch"); + recover(); + return nullptr; + } + + if (statementList) + { + if (!ValidateSwitch::validate(switchType, this, statementList, loc)) + { + recover(); + return nullptr; + } + } + + TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc); + if (node == nullptr) + { + error(loc, "erroneous switch statement", "switch"); + recover(); + return nullptr; + } + return node; +} + +TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc) +{ + if (mSwitchNestingLevel == 0) + { + error(loc, "case labels need to be inside switch statements", "case"); + recover(); + return nullptr; + } + if (condition == nullptr) + { + error(loc, "case label must have a condition", "case"); + recover(); + return nullptr; + } + if ((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) || + condition->isMatrix() || + condition->isArray() || + condition->isVector()) + { + error(condition->getLine(), "case label must be a scalar integer", "case"); + recover(); + } + TIntermConstantUnion *conditionConst = condition->getAsConstantUnion(); + if (conditionConst == nullptr) + { + error(condition->getLine(), "case label must be constant", "case"); + recover(); + } + TIntermCase *node = intermediate.addCase(condition, loc); + if (node == nullptr) + { + error(loc, "erroneous case statement", "case"); + recover(); + return nullptr; + } + return node; +} + +TIntermCase *TParseContext::addDefault(const TSourceLoc &loc) +{ + if (mSwitchNestingLevel == 0) + { + error(loc, "default labels need to be inside switch statements", "default"); + recover(); + return nullptr; + } + TIntermCase *node = intermediate.addCase(nullptr, loc); + if (node == nullptr) + { + error(loc, "erroneous default statement", "default"); + recover(); + return nullptr; + } + return node; +} + +TIntermTyped *TParseContext::createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc, + const TType *funcReturnType) +{ + if (child == nullptr) + { + return nullptr; + } + + switch (op) + { + case EOpLogicalNot: + if (child->getBasicType() != EbtBool || + child->isMatrix() || + child->isArray() || + child->isVector()) + { + return nullptr; + } + break; + case EOpBitwiseNot: + if ((child->getBasicType() != EbtInt && child->getBasicType() != EbtUInt) || + child->isMatrix() || + child->isArray()) + { + return nullptr; + } + break; + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + case EOpPositive: + if (child->getBasicType() == EbtStruct || + child->getBasicType() == EbtBool || + child->isArray()) + { + return nullptr; + } + // Operators for built-ins are already type checked against their prototype. + default: + break; + } + + return intermediate.addUnaryMath(op, child, loc, funcReturnType); +} + +TIntermTyped *TParseContext::addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc) +{ + TIntermTyped *node = createUnaryMath(op, child, loc, nullptr); + if (node == nullptr) + { + unaryOpError(loc, GetOperatorString(op), child->getCompleteString()); + recover(); + return child; + } + return node; +} + +TIntermTyped *TParseContext::addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &loc) +{ + if (lValueErrorCheck(loc, GetOperatorString(op), child)) + recover(); + return addUnaryMath(op, child, loc); +} + +bool TParseContext::binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + if (left->isArray() || right->isArray()) + { + if (shaderVersion < 300) + { + error(loc, "Invalid operation for arrays", GetOperatorString(op)); + return false; + } + + if (left->isArray() != right->isArray()) + { + error(loc, "array / non-array mismatch", GetOperatorString(op)); + return false; + } + + switch (op) + { + case EOpEqual: + case EOpNotEqual: + case EOpAssign: + case EOpInitialize: + break; + default: + error(loc, "Invalid operation for arrays", GetOperatorString(op)); + return false; + } + if (left->getArraySize() != right->getArraySize()) + { + error(loc, "array size mismatch", GetOperatorString(op)); + return false; + } + } + + // Check ops which require integer / ivec parameters + bool isBitShift = false; + switch (op) + { + case EOpBitShiftLeft: + case EOpBitShiftRight: + case EOpBitShiftLeftAssign: + case EOpBitShiftRightAssign: + // Unsigned can be bit-shifted by signed and vice versa, but we need to + // check that the basic type is an integer type. + isBitShift = true; + if (!IsInteger(left->getBasicType()) || !IsInteger(right->getBasicType())) + { + return false; + } + break; + case EOpBitwiseAnd: + case EOpBitwiseXor: + case EOpBitwiseOr: + case EOpBitwiseAndAssign: + case EOpBitwiseXorAssign: + case EOpBitwiseOrAssign: + // It is enough to check the type of only one operand, since later it + // is checked that the operand types match. + if (!IsInteger(left->getBasicType())) + { + return false; + } + break; + default: + break; + } + + // GLSL ES 1.00 and 3.00 do not support implicit type casting. + // So the basic type should usually match. + if (!isBitShift && left->getBasicType() != right->getBasicType()) + { + return false; + } + + // Check that type sizes match exactly on ops that require that. + // Also check restrictions for structs that contain arrays or samplers. + switch(op) + { + case EOpAssign: + case EOpInitialize: + case EOpEqual: + case EOpNotEqual: + // ESSL 1.00 sections 5.7, 5.8, 5.9 + if (shaderVersion < 300 && left->getType().isStructureContainingArrays()) + { + error(loc, "undefined operation for structs containing arrays", GetOperatorString(op)); + return false; + } + // Samplers as l-values are disallowed also in ESSL 3.00, see section 4.1.7, + // we interpret the spec so that this extends to structs containing samplers, + // similarly to ESSL 1.00 spec. + if ((shaderVersion < 300 || op == EOpAssign || op == EOpInitialize) && + left->getType().isStructureContainingSamplers()) + { + error(loc, "undefined operation for structs containing samplers", GetOperatorString(op)); + return false; + } + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if ((left->getNominalSize() != right->getNominalSize()) || + (left->getSecondarySize() != right->getSecondarySize())) + { + return false; + } + default: + break; + } + + return true; +} + +TIntermTyped *TParseContext::addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + if (!binaryOpCommonCheck(op, left, right, loc)) + return nullptr; + + switch (op) + { + case EOpEqual: + case EOpNotEqual: + break; + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + ASSERT(!left->isArray() && !right->isArray()); + if (left->isMatrix() || left->isVector() || + left->getBasicType() == EbtStruct) + { + return nullptr; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + ASSERT(!left->isArray() && !right->isArray()); + if (left->getBasicType() != EbtBool || + left->isMatrix() || left->isVector()) + { + return nullptr; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + ASSERT(!left->isArray() && !right->isArray()); + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool) + { + return nullptr; + } + break; + case EOpIMod: + ASSERT(!left->isArray() && !right->isArray()); + // Note that this is only for the % operator, not for mod() + if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool || left->getBasicType() == EbtFloat) + { + return nullptr; + } + break; + // Note that for bitwise ops, type checking is done in promote() to + // share code between ops and compound assignment + default: + break; + } + + return intermediate.addBinaryMath(op, left, right, loc); +} + +TIntermTyped *TParseContext::addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); + if (node == 0) + { + binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString()); + recover(); + return left; + } + return node; +} + +TIntermTyped *TParseContext::addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + TIntermTyped *node = addBinaryMathInternal(op, left, right, loc); + if (node == 0) + { + binaryOpError(loc, GetOperatorString(op), left->getCompleteString(), right->getCompleteString()); + recover(); + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setBConst(false); + return intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), loc); + } + return node; +} + +TIntermTyped *TParseContext::createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + if (binaryOpCommonCheck(op, left, right, loc)) + { + return intermediate.addAssign(op, left, right, loc); + } + return nullptr; +} + +TIntermTyped *TParseContext::addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc) +{ + TIntermTyped *node = createAssign(op, left, right, loc); + if (node == nullptr) + { + assignError(loc, "assign", left->getCompleteString(), right->getCompleteString()); + recover(); + return left; + } + return node; +} + +TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc) +{ + switch (op) + { + case EOpContinue: + if (mLoopNestingLevel <= 0) + { + error(loc, "continue statement only allowed in loops", ""); + recover(); + } + break; + case EOpBreak: + if (mLoopNestingLevel <= 0 && mSwitchNestingLevel <= 0) + { + error(loc, "break statement only allowed in loops and switch statements", ""); + recover(); + } + break; + case EOpReturn: + if (currentFunctionType->getBasicType() != EbtVoid) + { + error(loc, "non-void function must return a value", "return"); + recover(); + } + break; + default: + // No checks for discard + break; + } + return intermediate.addBranch(op, loc); +} + +TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc) +{ + ASSERT(op == EOpReturn); + mFunctionReturnsValue = true; + if (currentFunctionType->getBasicType() == EbtVoid) + { + error(loc, "void function cannot return a value", "return"); + recover(); + } + else if (*currentFunctionType != returnValue->getType()) + { + error(loc, "function return is not matching type:", "return"); + recover(); + } + return intermediate.addBranch(op, returnValue, loc); +} + +TIntermTyped *TParseContext::addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node, + const TSourceLoc &loc, bool *fatalError) +{ + *fatalError = false; + TOperator op = fnCall->getBuiltInOp(); + TIntermTyped *callNode = nullptr; + + 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 (!constructorErrorCheck(loc, node, *fnCall, op, &type)) + { + // + // It's a constructor, of type 'type'. + // + callNode = addConstructor(node, &type, op, fnCall, loc); + } + + if (callNode == nullptr) + { + recover(); + callNode = intermediate.setAggregateOperator(nullptr, op, loc); + } + callNode->setType(type); + } + else + { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = findFunction(loc, fnCall, shaderVersion, &builtIn); + if (fnCandidate) + { + // + // A declared function. + // + if (builtIn && !fnCandidate->getExtension().empty() && + extensionErrorCheck(loc, fnCandidate->getExtension())) + { + 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. + // + callNode = createUnaryMath(op, node->getAsTyped(), loc, &fnCandidate->getReturnType()); + if (callNode == nullptr) + { + std::stringstream extraInfoStream; + extraInfoStream << "built in unary operator function. Type: " + << static_cast(node)->getCompleteString(); + std::string extraInfo = extraInfoStream.str(); + error(node->getLine(), " wrong operand type", "Internal Error", extraInfo.c_str()); + *fatalError = true; + return nullptr; + } + } + else + { + TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, op, loc); + aggregate->setType(fnCandidate->getReturnType()); + aggregate->setPrecisionFromChildren(); + callNode = aggregate; + + // Some built-in functions have out parameters too. + functionCallLValueErrorCheck(fnCandidate, aggregate); + } + } + else + { + // This is a real function call + + TIntermAggregate *aggregate = intermediate.setAggregateOperator(node, EOpFunctionCall, loc); + aggregate->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) + aggregate->setUserDefined(); + aggregate->setName(fnCandidate->getMangledName()); + + // This needs to happen after the name is set + if (builtIn) + aggregate->setBuiltInFunctionPrecision(); + + callNode = aggregate; + + functionCallLValueErrorCheck(fnCandidate, aggregate); + } + } + else + { + // error message was put out by findFunction() + // Put on a dummy node for error recovery + ConstantUnion *unionArray = new ConstantUnion[1]; + unionArray->setFConst(0.0f); + callNode = intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), loc); + recover(); + } + } + delete fnCall; + return callNode; +} + + // // Parse an array of strings using yyparse. // diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.h b/src/3rdparty/angle/src/compiler/translator/ParseContext.h index 414c475cbb..b6a0f4a637 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.h +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.h @@ -3,8 +3,8 @@ // 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_ +#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_H_ +#define COMPILER_TRANSLATOR_PARSECONTEXT_H_ #include "compiler/translator/Compiler.h" #include "compiler/translator/Diagnostics.h" @@ -25,24 +25,25 @@ struct TMatrixFields { // they can be passed to the parser without needing a global. // struct TParseContext { - TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) : + TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, sh::GLenum type, ShShaderSpec spec, int options, bool checksPrecErrors, TInfoSink& is, bool debugShaderPrecisionSupported) : intermediate(interm), symbolTable(symt), shaderType(type), shaderSpec(spec), compileOptions(options), - sourcePath(sourcePath), treeRoot(0), - loopNestingLevel(0), + mLoopNestingLevel(0), structNestingLevel(0), + mSwitchNestingLevel(0), currentFunctionType(NULL), - functionReturnsValue(false), + mFunctionReturnsValue(false), checksPrecisionErrors(checksPrecErrors), + fragmentPrecisionHigh(false), defaultMatrixPacking(EmpColumnMajor), defaultBlockStorage(EbsShared), diagnostics(is), shaderVersion(100), - directiveHandler(ext, diagnostics, shaderVersion), + directiveHandler(ext, diagnostics, shaderVersion, debugShaderPrecisionSupported), preprocessor(&diagnostics, &directiveHandler), scanner(NULL) { } TIntermediate& intermediate; // to hold and build a parse tree @@ -51,12 +52,12 @@ struct TParseContext { ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL. int shaderVersion; int compileOptions; - const char* sourcePath; // Path of source file or NULL. TIntermNode* treeRoot; // root of parse tree being created - int loopNestingLevel; // 0 if outside all loops + int mLoopNestingLevel; // 0 if outside all loops int structNestingLevel; // incremented while parsing a struct declaration + int mSwitchNestingLevel; // 0 if outside all switch statements 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 mFunctionReturnsValue; // 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. bool fragmentPrecisionHigh; // true if highp precision is supported in the fragment language. TLayoutMatrixPacking defaultMatrixPacking; @@ -110,6 +111,7 @@ struct TParseContext { bool extensionErrorCheck(const TSourceLoc& line, const TString&); bool singleDeclarationErrorCheck(TPublicType &publicType, const TSourceLoc& identifierLocation, const TString &identifier); bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier); + bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *); const TPragma& pragma() const { return directiveHandler.pragma(); } const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); } @@ -120,7 +122,7 @@ struct TParseContext { bool containsSampler(TType& type); bool areAllChildConst(TIntermAggregate* aggrNode); - const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, int shaderVersion, bool *builtIn = 0); + const TFunction* findFunction(const TSourceLoc& line, TFunction* pfnCall, int inputShaderVersion, bool *builtIn = 0); bool executeInitializer(const TSourceLoc& line, const TString& identifier, TPublicType& pType, TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0); @@ -136,7 +138,7 @@ struct TParseContext { TIntermAggregate* parseInitDeclarator(TPublicType &publicType, TIntermAggregate *declaratorList, const TSourceLoc& identifierLocation, const TString &identifier, const TSourceLoc& initLocation, TIntermTyped *initializer); void parseGlobalLayoutQualifier(const TPublicType &typeQualifier); TFunction *addConstructorFunc(TPublicType publicType); - TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, const TSourceLoc&); + TIntermTyped* addConstructor(TIntermNode*, TType*, TOperator, TFunction*, const TSourceLoc&); TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type); TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, const TSourceLoc&); TIntermTyped* addConstMatrixNode(int , TIntermTyped*, const TSourceLoc&); @@ -164,9 +166,42 @@ struct TParseContext { void exitStructDeclaration(); bool structNestingErrorCheck(const TSourceLoc& line, const TField& field); + + TIntermSwitch *addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc); + TIntermCase *addCase(TIntermTyped *condition, const TSourceLoc &loc); + TIntermCase *addDefault(const TSourceLoc &loc); + + TIntermTyped *addUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &); + TIntermTyped *addUnaryMathLValue(TOperator op, TIntermTyped *child, const TSourceLoc &); + TIntermTyped *addBinaryMath(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &); + TIntermTyped *addBinaryMathBooleanResult(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &); + TIntermTyped *addAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc); + + TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc); + TIntermBranch *addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc); + + TIntermTyped *addFunctionCallOrMethod(TFunction *fnCall, TIntermNode *node, + const TSourceLoc &loc, bool *fatalError); + + private: + TIntermTyped *addBinaryMathInternal(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc); + TIntermTyped *createAssign(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc); + // The funcReturnType parameter is expected to be non-null when the operation is a built-in function. + // It is expected to be null for other unary operators. + TIntermTyped *createUnaryMath(TOperator op, TIntermTyped *child, const TSourceLoc &loc, + const TType *funcReturnType); + + // Return true if the checks pass + bool binaryOpCommonCheck(TOperator op, TIntermTyped *left, TIntermTyped *right, + const TSourceLoc &loc); }; int PaParseStrings(size_t count, const char* const string[], const int length[], TParseContext* context); -#endif // _PARSER_HELPER_INCLUDED_ +#endif // COMPILER_TRANSLATOR_PARSECONTEXT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h index edd249c4d3..6cd8d30114 100644 --- a/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h +++ b/src/3rdparty/angle/src/compiler/translator/PoolAlloc.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _POOLALLOC_INCLUDED_ -#define _POOLALLOC_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_POOLALLOC_H_ +#define COMPILER_TRANSLATOR_POOLALLOC_H_ #ifdef _DEBUG #define GUARD_BLOCKS // define to enable guard block sanity checking @@ -297,4 +297,4 @@ protected: TPoolAllocator* allocator; }; -#endif // _POOLALLOC_INCLUDED_ +#endif // COMPILER_TRANSLATOR_POOLALLOC_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Pragma.h b/src/3rdparty/angle/src/compiler/translator/Pragma.h index 4a930a2962..57b1134970 100644 --- a/src/3rdparty/angle/src/compiler/translator/Pragma.h +++ b/src/3rdparty/angle/src/compiler/translator/Pragma.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_PRAGMA_H_ -#define COMPILER_PRAGMA_H_ +#ifndef COMPILER_TRANSLATOR_PRAGMA_H_ +#define COMPILER_TRANSLATOR_PRAGMA_H_ struct TPragma { @@ -18,12 +18,15 @@ 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) { } + // Precision emulation is turned on by default, but has no effect unless + // the extension is enabled. + TPragma() : optimize(true), debug(false), debugShaderPrecision(true) { } + TPragma(bool o, bool d) : optimize(o), debug(d), debugShaderPrecision(true) { } bool optimize; bool debug; + bool debugShaderPrecision; STDGL stdgl; }; -#endif // COMPILER_PRAGMA_H_ +#endif // COMPILER_TRANSLATOR_PRAGMA_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp index 1f6fb75821..3d950aab5a 100644 --- a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp +++ b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.cpp @@ -49,7 +49,7 @@ void TAliveTraverser::visitSymbol(TIntermSymbol* node) found = true; } -bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node) +bool TAliveTraverser::visitSelection(Visit, TIntermSelection*) { if (wasFound()) return false; diff --git a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h index 872a06f721..3e4f18012a 100644 --- a/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h +++ b/src/3rdparty/angle/src/compiler/translator/QualifierAlive.h @@ -4,4 +4,9 @@ // found in the LICENSE file. // +#ifndef COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ +#define COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ + bool QualifierWritten(TIntermNode* root, TQualifier); + +#endif // COMPILER_TRANSLATOR_QUALIFIERALIVE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h index ac87600347..2acd68be34 100644 --- a/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h +++ b/src/3rdparty/angle/src/compiler/translator/RegenerateStructNames.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATOR_REGENERATE_STRUCT_NAMES_H_ -#define COMPILER_TRANSLATOR_REGENERATE_STRUCT_NAMES_H_ +#ifndef COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ +#define COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ #include "compiler/translator/Intermediate.h" #include "compiler/translator/SymbolTable.h" @@ -37,4 +37,4 @@ class RegenerateStructNames : public TIntermTraverser std::set mDeclaredGlobalStructs; }; -#endif // COMPILER_TRANSLATOR_REGENERATE_STRUCT_NAMES_H_ +#endif // COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp new file mode 100644 index 0000000000..b278b53436 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.cpp @@ -0,0 +1,157 @@ +// +// Copyright (c) 2002-2015 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/translator/RemoveSwitchFallThrough.h" + +TIntermAggregate *RemoveSwitchFallThrough::removeFallThrough(TIntermAggregate *statementList) +{ + RemoveSwitchFallThrough rm(statementList); + ASSERT(statementList); + statementList->traverse(&rm); + bool lastStatementWasBreak = rm.mLastStatementWasBreak; + rm.mLastStatementWasBreak = true; + rm.handlePreviousCase(); + if (!lastStatementWasBreak) + { + TIntermBranch *finalBreak = new TIntermBranch(EOpBreak, nullptr); + rm.mStatementListOut->getSequence()->push_back(finalBreak); + } + return rm.mStatementListOut; +} + +RemoveSwitchFallThrough::RemoveSwitchFallThrough(TIntermAggregate *statementList) + : TIntermTraverser(true, false, false), + mStatementList(statementList), + mLastStatementWasBreak(false), + mPreviousCase(nullptr) +{ + mStatementListOut = new TIntermAggregate(); + mStatementListOut->setOp(EOpSequence); +} + +void RemoveSwitchFallThrough::visitSymbol(TIntermSymbol *node) +{ + // Note that this assumes that switch statements which don't begin by a case statement + // have already been weeded out in validation. + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; +} + +void RemoveSwitchFallThrough::visitConstantUnion(TIntermConstantUnion *node) +{ + // Conditions of case labels are not traversed, so this is some other constant + // Could be just a statement like "0;" + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; +} + +bool RemoveSwitchFallThrough::visitBinary(Visit, TIntermBinary *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitUnary(Visit, TIntermUnary *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitSelection(Visit, TIntermSelection *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitSwitch(Visit, TIntermSwitch *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + // Don't go into nested switch statements + return false; +} + +void RemoveSwitchFallThrough::outputSequence(TIntermSequence *sequence, size_t startIndex) +{ + for (size_t i = startIndex; i < sequence->size(); ++i) + { + mStatementListOut->getSequence()->push_back(sequence->at(i)); + } +} + +void RemoveSwitchFallThrough::handlePreviousCase() +{ + if (mPreviousCase) + mCasesSharingBreak.push_back(mPreviousCase); + if (mLastStatementWasBreak) + { + bool labelsWithNoStatements = true; + for (size_t i = 0; i < mCasesSharingBreak.size(); ++i) + { + if (mCasesSharingBreak.at(i)->getSequence()->size() > 1) + { + labelsWithNoStatements = false; + } + if (labelsWithNoStatements) + { + // Fall-through is allowed in case the label has no statements. + outputSequence(mCasesSharingBreak.at(i)->getSequence(), 0); + } + else + { + // Include all the statements that this case can fall through under the same label. + for (size_t j = i; j < mCasesSharingBreak.size(); ++j) + { + size_t startIndex = j > i ? 1 : 0; // Add the label only from the first sequence. + outputSequence(mCasesSharingBreak.at(j)->getSequence(), startIndex); + + } + } + } + mCasesSharingBreak.clear(); + } + mLastStatementWasBreak = false; + mPreviousCase = nullptr; +} + +bool RemoveSwitchFallThrough::visitCase(Visit, TIntermCase *node) +{ + handlePreviousCase(); + mPreviousCase = new TIntermAggregate(); + mPreviousCase->setOp(EOpSequence); + mPreviousCase->getSequence()->push_back(node); + // Don't traverse the condition of the case statement + return false; +} + +bool RemoveSwitchFallThrough::visitAggregate(Visit, TIntermAggregate *node) +{ + if (node != mStatementList) + { + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; + } + return true; +} + +bool RemoveSwitchFallThrough::visitLoop(Visit, TIntermLoop *node) +{ + mPreviousCase->getSequence()->push_back(node); + mLastStatementWasBreak = false; + return false; +} + +bool RemoveSwitchFallThrough::visitBranch(Visit, TIntermBranch *node) +{ + mPreviousCase->getSequence()->push_back(node); + // TODO: Verify that accepting return or continue statements here doesn't cause problems. + mLastStatementWasBreak = true; + return false; +} diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h new file mode 100644 index 0000000000..db8699327c --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/RemoveSwitchFallThrough.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 2002-2015 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_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ +#define COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ + +#include "compiler/translator/IntermNode.h" + +class RemoveSwitchFallThrough : public TIntermTraverser +{ + public: + // When given a statementList from a switch AST node, return an updated + // statementList that has fall-through removed. + static TIntermAggregate *removeFallThrough(TIntermAggregate *statementList); + + private: + RemoveSwitchFallThrough(TIntermAggregate *statementList); + + void visitSymbol(TIntermSymbol *node) override; + void visitConstantUnion(TIntermConstantUnion *node) override; + bool visitBinary(Visit, TIntermBinary *node) override; + bool visitUnary(Visit, TIntermUnary *node) override; + bool visitSelection(Visit visit, TIntermSelection *node) override; + bool visitSwitch(Visit, TIntermSwitch *node) override; + bool visitCase(Visit, TIntermCase *node) override; + bool visitAggregate(Visit, TIntermAggregate *node) override; + bool visitLoop(Visit, TIntermLoop *node) override; + bool visitBranch(Visit, TIntermBranch *node) override; + + void outputSequence(TIntermSequence *sequence, size_t startIndex); + void handlePreviousCase(); + + TIntermAggregate *mStatementList; + TIntermAggregate *mStatementListOut; + bool mLastStatementWasBreak; + TIntermAggregate *mPreviousCase; + std::vector mCasesSharingBreak; +}; + +#endif // COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp b/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp deleted file mode 100644 index 0cf6910aa2..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/RemoveTree.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// -// 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/translator/IntermNode.h" -#include "compiler/translator/RemoveTree.h" - -// -// Code to delete the intermediate tree. -// -void RemoveAllTreeNodes(TIntermNode* root) -{ - std::queue nodeQueue; - - nodeQueue.push(root); - - while (!nodeQueue.empty()) - { - TIntermNode *node = nodeQueue.front(); - nodeQueue.pop(); - - node->enqueueChildren(&nodeQueue); - - delete node; - } -} - diff --git a/src/3rdparty/angle/src/compiler/translator/RemoveTree.h b/src/3rdparty/angle/src/compiler/translator/RemoveTree.h deleted file mode 100644 index 97a821679c..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/RemoveTree.h +++ /dev/null @@ -1,7 +0,0 @@ -// -// 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/translator/RenameFunction.h b/src/3rdparty/angle/src/compiler/translator/RenameFunction.h index d43e6ef7be..868e5d566b 100644 --- a/src/3rdparty/angle/src/compiler/translator/RenameFunction.h +++ b/src/3rdparty/angle/src/compiler/translator/RenameFunction.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_RENAME_FUNCTION -#define COMPILER_RENAME_FUNCTION +#ifndef COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ +#define COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ #include "compiler/translator/IntermNode.h" @@ -33,4 +33,4 @@ private: const TString mNewFunctionName; }; -#endif // COMPILER_RENAME_FUNCTION +#endif // COMPILER_TRANSLATOR_RENAMEFUNCTION_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h index d87baea0fe..5527d27f83 100644 --- a/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h +++ b/src/3rdparty/angle/src/compiler/translator/RewriteElseBlocks.h @@ -7,8 +7,8 @@ // all if-else blocks to if-if blocks. // -#ifndef COMPILER_REWRITE_ELSE_BLOCKS_H_ -#define COMPILER_REWRITE_ELSE_BLOCKS_H_ +#ifndef COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ +#define COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ #include "compiler/translator/IntermNode.h" @@ -19,4 +19,4 @@ void RewriteElseBlocks(TIntermNode *node); } -#endif // COMPILER_REWRITE_ELSE_BLOCKS_H_ +#endif // COMPILER_TRANSLATOR_REWRITEELSEBLOCKS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h index 7c6d09c1bb..0726ed4c64 100644 --- a/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h +++ b/src/3rdparty/angle/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATOR_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS_H_ -#define COMPILER_TRANSLATOR_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS_H_ +#ifndef COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ +#define COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ #include "compiler/translator/IntermNode.h" @@ -44,4 +44,4 @@ class ScalarizeVecAndMatConstructorArgs : public TIntermTraverser bool mFragmentPrecisionHigh; }; -#endif // COMPILER_TRANSLATOR_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS_H_ +#endif // COMPILER_TRANSLATOR_SCALARIZEVECANDMATCONSTRUCTORARGS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp index f78c84e370..fb7a6cdb9b 100644 --- a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.cpp @@ -9,7 +9,6 @@ #include "compiler/translator/SearchSymbol.h" #include "compiler/translator/InfoSink.h" -#include "compiler/translator/OutputHLSL.h" namespace sh { diff --git a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h index 029ac30b9a..36d5191058 100644 --- a/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h +++ b/src/3rdparty/angle/src/compiler/translator/SearchSymbol.h @@ -6,8 +6,8 @@ // SearchSymbol is an AST traverser to detect the use of a given symbol name // -#ifndef COMPILER_SEARCHSYMBOL_H_ -#define COMPILER_SEARCHSYMBOL_H_ +#ifndef COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ +#define COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ #include "compiler/translator/IntermNode.h" #include "compiler/translator/ParseContext.h" @@ -30,4 +30,4 @@ class SearchSymbol : public TIntermTraverser }; } -#endif // COMPILER_SEARCHSYMBOL_H_ +#endif // COMPILER_TRANSLATOR_SEARCHSYMBOL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp index 0d6a1d64cf..b8040da7f9 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp @@ -14,7 +14,9 @@ #include "compiler/translator/Compiler.h" #include "compiler/translator/InitializeDll.h" #include "compiler/translator/length_limits.h" +#ifdef ANGLE_ENABLE_HLSL #include "compiler/translator/TranslatorHLSL.h" +#endif // ANGLE_ENABLE_HLSL #include "compiler/translator/VariablePacker.h" #include "angle_gl.h" @@ -92,6 +94,7 @@ TCompiler *GetCompilerFromHandle(ShHandle handle) return base->getAsCompiler(); } +#ifdef ANGLE_ENABLE_HLSL TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle) { if (!handle) @@ -99,6 +102,7 @@ TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle) TShHandleBase *base = static_cast(handle); return base->getAsTranslatorHLSL(); } +#endif // ANGLE_ENABLE_HLSL } // namespace anonymous @@ -153,6 +157,10 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) resources->EXT_draw_buffers = 0; resources->EXT_frag_depth = 0; resources->EXT_shader_texture_lod = 0; + resources->WEBGL_debug_shader_precision = 0; + resources->EXT_shader_framebuffer_fetch = 0; + resources->NV_shader_framebuffer_fetch = 0; + resources->ARM_shader_framebuffer_fetch = 0; resources->NV_draw_buffers = 0; @@ -323,6 +331,7 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle, const std::string &interfaceBlockName, unsigned int *indexOut) { +#ifdef ANGLE_ENABLE_HLSL ASSERT(indexOut); TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); @@ -335,12 +344,16 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle, *indexOut = translator->getInterfaceBlockRegister(interfaceBlockName); return true; +#else + return false; +#endif // ANGLE_ENABLE_HLSL } bool ShGetUniformRegister(const ShHandle handle, const std::string &uniformName, unsigned int *indexOut) { +#ifdef ANGLE_ENABLE_HLSL ASSERT(indexOut); TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); ASSERT(translator); @@ -352,4 +365,7 @@ bool ShGetUniformRegister(const ShHandle handle, *indexOut = translator->getUniformRegister(uniformName); return true; +#else + return false; +#endif // ANGLE_ENABLE_HLSL } diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp index 3098a7f0c9..0dbbc9e7f6 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp @@ -14,6 +14,23 @@ namespace sh { +namespace +{ + +InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolation) +{ + return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation); +} + +} +// The ES 3.0 spec is not clear on this point, but the ES 3.1 spec, and discussion +// on Khronos.org, clarifies that a smooth/flat mismatch produces a link error, +// but auxiliary qualifier mismatch (centroid) does not. +bool InterpolationTypesMatch(InterpolationType a, InterpolationType b) +{ + return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b)); +} + ShaderVariable::ShaderVariable() : type(0), precision(0), @@ -86,7 +103,6 @@ bool ShaderVariable::findInfoByMappedName( // 2) the top variable is an array; // 3) otherwise. size_t pos = mappedFullName.find_first_of(".["); - std::string topName; if (pos == std::string::npos) { diff --git a/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp new file mode 100644 index 0000000000..ac5eb67070 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2002-2015 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/translator/SimplifyArrayAssignment.h" + +bool SimplifyArrayAssignment::visitBinary(Visit visit, TIntermBinary *node) +{ + switch (node->getOp()) + { + case EOpAssign: + { + TIntermNode *parent = getParentNode(); + if (node->getLeft()->isArray() && parent != nullptr) + { + TIntermAggregate *parentAgg = parent->getAsAggregate(); + if (parentAgg != nullptr && parentAgg->getOp() == EOpSequence) + { + // This case is fine, the result of the assignment is not used. + break; + } + + // The result of the assignment needs to be stored into a temporary variable, + // the assignment needs to be replaced with a reference to the temporary variable, + // and the temporary variable needs to finally be assigned to the target variable. + + // This also needs to interact correctly with unfolding short circuiting operators. + UNIMPLEMENTED(); + } + } + break; + default: + break; + } + return true; +} diff --git a/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h new file mode 100644 index 0000000000..247eb88d72 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/SimplifyArrayAssignment.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2002-2015 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. +// +// SimplifyArrayAssignment is an AST traverser to replace statements where +// the return value of array assignment is used with statements where +// the return value of array assignment is not used. +// + +#ifndef COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ +#define COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ + +#include "common/angleutils.h" +#include "compiler/translator/IntermNode.h" + +class SimplifyArrayAssignment : public TIntermTraverser +{ + public: + SimplifyArrayAssignment() { } + + virtual bool visitBinary(Visit visit, TIntermBinary *node); +}; + +#endif // COMPILER_TRANSLATOR_SIMPLIFYARRAYASSIGNMENT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp index 48929affe6..fd1a29c1cd 100644 --- a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.cpp @@ -21,9 +21,23 @@ Std140PaddingHelper::Std140PaddingHelper(const std::map &structEle unsigned *uniqueCounter) : mPaddingCounter(uniqueCounter), mElementIndex(0), - mStructElementIndexes(structElementIndexes) + mStructElementIndexes(&structElementIndexes) {} +Std140PaddingHelper::Std140PaddingHelper(const Std140PaddingHelper &other) + : mPaddingCounter(other.mPaddingCounter), + mElementIndex(other.mElementIndex), + mStructElementIndexes(other.mStructElementIndexes) +{} + +Std140PaddingHelper &Std140PaddingHelper::operator=(const Std140PaddingHelper &other) +{ + mPaddingCounter = other.mPaddingCounter; + mElementIndex = other.mElementIndex; + mStructElementIndexes = other.mStructElementIndexes; + return *this; +} + TString Std140PaddingHelper::next() { unsigned value = (*mPaddingCounter)++; @@ -107,7 +121,7 @@ TString Std140PaddingHelper::postPaddingString(const TType &type, bool useHLSLRo { const TString &structName = QualifiedStructNameString(*structure, useHLSLRowMajorPacking, true); - numComponents = mStructElementIndexes.find(structName)->second; + numComponents = mStructElementIndexes->find(structName)->second; if (numComponents == 0) { @@ -274,9 +288,9 @@ void StructureHLSL::addConstructor(const TType &type, const TString &name, const for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++) { - const TType &type = ctorParameters[parameter]; + const TType ¶mType = ctorParameters[parameter]; - constructor += TypeString(type) + " x" + str(parameter) + ArrayString(type); + constructor += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType); if (parameter < ctorParameters.size() - 1) { diff --git a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h index ed002fef30..cffe2a41ae 100644 --- a/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/StructureHLSL.h @@ -7,8 +7,8 @@ // Interfaces of methods for HLSL translation of GLSL structures. // -#ifndef TRANSLATOR_STRUCTUREHLSL_H_ -#define TRANSLATOR_STRUCTUREHLSL_H_ +#ifndef COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ +#define COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ #include "compiler/translator/Common.h" #include "compiler/translator/IntermNode.h" @@ -27,7 +27,9 @@ class Std140PaddingHelper { public: explicit Std140PaddingHelper(const std::map &structElementIndexes, - unsigned *uniqueCounter); + unsigned int *uniqueCounter); + Std140PaddingHelper(const Std140PaddingHelper &other); + Std140PaddingHelper &operator=(const Std140PaddingHelper &other); int elementIndex() const { return mElementIndex; } int prePadding(const TType &type); @@ -39,10 +41,10 @@ class Std140PaddingHelper unsigned *mPaddingCounter; int mElementIndex; - const std::map &mStructElementIndexes; + const std::map *mStructElementIndexes; }; -class StructureHLSL +class StructureHLSL : angle::NonCopyable { public: StructureHLSL(); @@ -76,4 +78,4 @@ class StructureHLSL } -#endif // COMPILER_STRUCTUREHLSL_H_ +#endif // COMPILER_TRANSLATOR_STRUCTUREHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp index 028da21151..0eb663f018 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.cpp @@ -48,6 +48,16 @@ bool TSymbolTableLevel::insert(TSymbol *symbol) return result.second; } +bool TSymbolTableLevel::insertUnmangled(TFunction *function) +{ + function->setUniqueId(TSymbolTable::nextUniqueId()); + + // returning true means symbol was added to the table + tInsertResult result = level.insert(tLevelPair(function->getName(), function)); + + return result.second; +} + TSymbol *TSymbolTableLevel::find(const TString &name) const { tLevel::const_iterator it = level.find(name); @@ -57,47 +67,6 @@ TSymbol *TSymbolTableLevel::find(const TString &name) const return (*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) -{ - 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->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) - { - TSymbol *symbol = it->second; - if (symbol->getName() == name) - symbol->relateToExtension(ext); - } -} - -TSymbol::TSymbol(const TSymbol ©Of) -{ - name = NewPoolTString(copyOf.name->c_str()); - uniqueId = copyOf.uniqueId; -} - TSymbol *TSymbolTable::find(const TString &name, int shaderVersion, bool *builtIn, bool *sameScope) const { @@ -148,68 +117,149 @@ TSymbolTable::~TSymbolTable() pop(); } -void TSymbolTable::insertBuiltIn( - ESymbolLevel level, TType *rvalue, const char *name, - TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5) +bool IsGenType(const TType *type) +{ + if (type) + { + TBasicType basicType = type->getBasicType(); + return basicType == EbtGenType || basicType == EbtGenIType || basicType == EbtGenUType || basicType == EbtGenBType; + } + + return false; +} + +bool IsVecType(const TType *type) +{ + if (type) + { + TBasicType basicType = type->getBasicType(); + return basicType == EbtVec || basicType == EbtIVec || basicType == EbtUVec || basicType == EbtBVec; + } + + return false; +} + +TType *SpecificType(TType *type, int size) +{ + ASSERT(size >= 1 && size <= 4); + + if (!type) + { + return nullptr; + } + + ASSERT(!IsVecType(type)); + + switch(type->getBasicType()) + { + case EbtGenType: return new TType(EbtFloat, size); + case EbtGenIType: return new TType(EbtInt, size); + case EbtGenUType: return new TType(EbtUInt, size); + case EbtGenBType: return new TType(EbtBool, size); + default: return type; + } +} + +TType *VectorType(TType *type, int size) +{ + ASSERT(size >= 2 && size <= 4); + + if (!type) + { + return nullptr; + } + + ASSERT(!IsGenType(type)); + + switch(type->getBasicType()) + { + case EbtVec: return new TType(EbtFloat, size); + case EbtIVec: return new TType(EbtInt, size); + case EbtUVec: return new TType(EbtUInt, size); + case EbtBVec: return new TType(EbtBool, size); + default: return type; + } +} + +void TSymbolTable::insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2, TType *ptype3, TType *ptype4, TType *ptype5) { if (ptype1->getBasicType() == EbtGSampler2D) { bool gvec4 = (rvalue->getBasicType() == EbtGVec4); - insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, - new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5); - insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, - new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5); - insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, - new TType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5); - return; + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, new TType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5); } - if (ptype1->getBasicType() == EbtGSampler3D) + else if (ptype1->getBasicType() == EbtGSampler3D) { bool gvec4 = (rvalue->getBasicType() == EbtGVec4); - insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, - new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5); - insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, - new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5); - insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, - new TType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5); - return; + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, new TType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5); } - if (ptype1->getBasicType() == EbtGSamplerCube) + else if (ptype1->getBasicType() == EbtGSamplerCube) { bool gvec4 = (rvalue->getBasicType() == EbtGVec4); - insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, - new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5); - insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, - new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5); - insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, - new TType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5); - return; + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, new TType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5); } - if (ptype1->getBasicType() == EbtGSampler2DArray) + else if (ptype1->getBasicType() == EbtGSampler2DArray) { bool gvec4 = (rvalue->getBasicType() == EbtGVec4); - insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, - new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5); - insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, - new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5); - insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, - new TType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5); - return; + insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5); + insertBuiltIn(level, gvec4 ? new TType(EbtUInt, 4) : rvalue, name, new TType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5); + } + else if (IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3)) + { + ASSERT(!ptype4 && !ptype5); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 1), name, SpecificType(ptype1, 1), SpecificType(ptype2, 1), SpecificType(ptype3, 1)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 2), name, SpecificType(ptype1, 2), SpecificType(ptype2, 2), SpecificType(ptype3, 2)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 3), name, SpecificType(ptype1, 3), SpecificType(ptype2, 3), SpecificType(ptype3, 3)); + insertBuiltIn(level, op, ext, SpecificType(rvalue, 4), name, SpecificType(ptype1, 4), SpecificType(ptype2, 4), SpecificType(ptype3, 4)); + } + else if (IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3)) + { + ASSERT(!ptype4 && !ptype5); + insertBuiltIn(level, op, ext, VectorType(rvalue, 2), name, VectorType(ptype1, 2), VectorType(ptype2, 2), VectorType(ptype3, 2)); + insertBuiltIn(level, op, ext, VectorType(rvalue, 3), name, VectorType(ptype1, 3), VectorType(ptype2, 3), VectorType(ptype3, 3)); + insertBuiltIn(level, op, ext, VectorType(rvalue, 4), name, VectorType(ptype1, 4), VectorType(ptype2, 4), VectorType(ptype3, 4)); } + else + { + TFunction *function = new TFunction(NewPoolTString(name), *rvalue, op, ext); - TFunction *function = new TFunction(NewPoolTString(name), *rvalue); + TParameter param1 = {0, ptype1}; + function->addParameter(param1); - TType *types[] = {ptype1, ptype2, ptype3, ptype4, ptype5}; - for (size_t ii = 0; ii < sizeof(types) / sizeof(types[0]); ++ii) - { - if (types[ii]) + if (ptype2) { - TParameter param = {NULL, types[ii]}; - function->addParameter(param); + TParameter param2 = {0, ptype2}; + function->addParameter(param2); } - } - insert(level, function); + if (ptype3) + { + TParameter param3 = {0, ptype3}; + function->addParameter(param3); + } + + if (ptype4) + { + TParameter param4 = {0, ptype4}; + function->addParameter(param4); + } + + if (ptype5) + { + TParameter param5 = {0, ptype5}; + function->addParameter(param5); + } + + insert(level, function); + } } TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h index 9cd74218dc..dfc65cb957 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _SYMBOL_TABLE_INCLUDED_ -#define _SYMBOL_TABLE_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_H_ +#define COMPILER_TRANSLATOR_SYMBOLTABLE_H_ // // Symbol table for parsing. Has these design characteristics: @@ -38,7 +38,7 @@ #include "compiler/translator/IntermNode.h" // Symbol base class. (Can build functions or variables out of these...) -class TSymbol +class TSymbol : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); @@ -86,8 +86,6 @@ class TSymbol } private: - DISALLOW_COPY_AND_ASSIGN(TSymbol); - int uniqueId; // For real comparing during code generation const TString *name; TString extension; @@ -158,8 +156,6 @@ class TVariable : public TSymbol } private: - DISALLOW_COPY_AND_ASSIGN(TVariable); - TType type; bool userType; // we are assuming that Pool Allocator will free the memory @@ -186,13 +182,14 @@ class TFunction : public TSymbol defined(false) { } - TFunction(const TString *name, const TType &retType, TOperator tOp = EOpNull) + TFunction(const TString *name, const TType &retType, TOperator tOp = EOpNull, const char *ext = "") : TSymbol(name), returnType(retType), mangledName(TFunction::mangleName(*name)), op(tOp), defined(false) { + relateToExtension(ext); } virtual ~TFunction(); virtual bool isFunction() const @@ -224,10 +221,6 @@ class TFunction : public TSymbol return returnType; } - void relateToOperator(TOperator o) - { - op = o; - } TOperator getBuiltInOp() const { return op; @@ -252,8 +245,6 @@ class TFunction : public TSymbol } private: - DISALLOW_COPY_AND_ASSIGN(TFunction); - typedef TVector TParamList; TParamList parameters; TType returnType; @@ -291,10 +282,10 @@ class TSymbolTableLevel bool insert(TSymbol *symbol); - TSymbol *find(const TString &name) const; + // Insert a function using its unmangled name as the key. + bool insertUnmangled(TFunction *function); - void relateToOperator(const char *name, TOperator op); - void relateToExtension(const char *name, const TString &ext); + TSymbol *find(const TString &name) const; protected: tLevel level; @@ -310,7 +301,7 @@ const int ESSL3_BUILTINS = 2; const int LAST_BUILTIN_LEVEL = ESSL3_BUILTINS; const int GLOBAL_LEVEL = 3; -class TSymbolTable +class TSymbolTable : angle::NonCopyable { public: TSymbolTable() @@ -363,6 +354,12 @@ class TSymbolTable return table[level]->insert(symbol); } + bool insert(ESymbolLevel level, const char *ext, TSymbol *symbol) + { + symbol->relateToExtension(ext); + return table[level]->insert(symbol); + } + bool insertConstInt(ESymbolLevel level, const char *name, int value) { TVariable *constant = new TVariable( @@ -371,9 +368,26 @@ class TSymbolTable return insert(level, constant); } + void insertBuiltIn(ESymbolLevel level, TOperator op, const char *ext, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0); + void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, - TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, - TType *ptype4 = 0, TType *ptype5 = 0); + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) + { + insertBuiltIn(level, EOpNull, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); + } + + void insertBuiltIn(ESymbolLevel level, const char *ext, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) + { + insertBuiltIn(level, EOpNull, ext, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); + } + + void insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name, + TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0) + { + insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5); + } TSymbol *find(const TString &name, int shaderVersion, bool *builtIn = NULL, bool *sameScope = NULL) const; @@ -385,14 +399,6 @@ class TSymbolTable return table[currentLevel() - 1]; } - void relateToOperator(ESymbolLevel level, const char *name, TOperator op) - { - table[level]->relateToOperator(name, op); - } - void relateToExtension(ESymbolLevel level, const char *name, const TString &ext) - { - table[level]->relateToExtension(name, ext); - } void dump(TInfoSink &infoSink) const; bool setDefaultPrecision(const TPublicType &type, TPrecision prec) @@ -413,7 +419,7 @@ class TSymbolTable // This records invariant varyings declared through // "invariant varying_name;". - void addInvariantVarying(const TString &originalName) + void addInvariantVarying(const std::string &originalName) { mInvariantVaryings.insert(originalName); } @@ -421,7 +427,7 @@ class TSymbolTable // if it is set as invariant during the varying variable // declaration - this piece of information is stored in the // variable's type, not here. - bool isVaryingInvariant(const TString &originalName) const + bool isVaryingInvariant(const std::string &originalName) const { return (mGlobalInvariant || mInvariantVaryings.count(originalName) > 0); @@ -445,10 +451,10 @@ class TSymbolTable typedef TMap PrecisionStackLevel; std::vector< PrecisionStackLevel *> precisionStack; - std::set mInvariantVaryings; + std::set mInvariantVaryings; bool mGlobalInvariant; static int uniqueIdCounter; }; -#endif // _SYMBOL_TABLE_INCLUDED_ +#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp index dcbf3cea1d..238bc97576 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp @@ -6,40 +6,91 @@ #include "compiler/translator/TranslatorESSL.h" +#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" +#include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/OutputESSL.h" #include "angle_gl.h" TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec) - : TCompiler(type, spec, SH_ESSL_OUTPUT) { + : TCompiler(type, spec, SH_ESSL_OUTPUT) +{ } -void TranslatorESSL::translate(TIntermNode* root) { +void TranslatorESSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) +{ + if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) + InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType()); +} + +void TranslatorESSL::translate(TIntermNode *root, int) { TInfoSinkBase& sink = getInfoSink().obj; + int shaderVersion = getShaderVersion(); + if (shaderVersion > 100) + { + sink << "#version " << shaderVersion << " es\n"; + } + writePragma(); // Write built-in extension behaviors. writeExtensionBehavior(); + bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision; + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(sink, SH_ESSL_OUTPUT); + } + // Write emulated built-in functions if needed. - getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( - sink, getShaderType() == GL_FRAGMENT_SHADER); + if (!getBuiltInFunctionEmulator().IsOutputEmpty()) + { + sink << "// BEGIN: Generated code for built-in function emulation\n\n"; + if (getShaderType() == GL_FRAGMENT_SHADER) + { + sink << "#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 + { + sink << "#define webgl_emu_precision highp\n"; + } + + getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink); + sink << "// END: Generated code for built-in function emulation\n\n"; + } // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); // Write translated shader. - TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); + TOutputESSL outputESSL(sink, + getArrayIndexClampingStrategy(), + getHashFunction(), + getNameMap(), + getSymbolTable(), + shaderVersion, + precisionEmulation); 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) { + const TExtensionBehavior& extBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) { if (iter->second != EBhUndefined) { - if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") { + if (getResources().NV_shader_framebuffer_fetch && iter->first == "GL_EXT_shader_framebuffer_fetch") { + sink << "#extension GL_NV_shader_framebuffer_fetch : " + << getBehaviorString(iter->second) << "\n"; + } else if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") { sink << "#extension GL_NV_draw_buffers : " << getBehaviorString(iter->second) << "\n"; } else { diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h index 55766822d1..89a3e473e9 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.h @@ -4,20 +4,23 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATORESSL_H_ -#define COMPILER_TRANSLATORESSL_H_ +#ifndef COMPILER_TRANSLATOR_TRANSLATORESSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORESSL_H_ #include "compiler/translator/Compiler.h" -class TranslatorESSL : public TCompiler { -public: +class TranslatorESSL : public TCompiler +{ + public: TranslatorESSL(sh::GLenum type, ShShaderSpec spec); -protected: - virtual void translate(TIntermNode* root); + protected: + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override; -private: + virtual void translate(TIntermNode *root, int compileOptions); + + private: void writeExtensionBehavior(); }; -#endif // COMPILER_TRANSLATORESSL_H_ +#endif // COMPILER_TRANSLATOR_TRANSLATORESSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp index 6acbf7c5a8..aea3f77c4e 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp @@ -6,14 +6,69 @@ #include "compiler/translator/TranslatorGLSL.h" +#include "angle_gl.h" +#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h" +#include "compiler/translator/EmulatePrecision.h" #include "compiler/translator/OutputGLSL.h" #include "compiler/translator/VersionGLSL.h" -TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec) - : TCompiler(type, spec, SH_GLSL_OUTPUT) { +namespace +{ + +// To search for what output variables are used in a fragment shader. +// We handle gl_FragColor and gl_FragData at the moment. +class TFragmentOutSearcher : public TIntermTraverser +{ + public: + TFragmentOutSearcher() + : mUsesGlFragColor(false), + mUsesGlFragData(false) + { + } + + bool usesGlFragColor() const + { + return mUsesGlFragColor; + } + + bool usesGlFragData() const + { + return mUsesGlFragData; + } + + protected: + virtual void visitSymbol(TIntermSymbol *node) override + { + if (node->getSymbol() == "gl_FragColor") + { + mUsesGlFragColor = true; + } + else if (node->getSymbol() == "gl_FragData") + { + mUsesGlFragData = true; + } + } + + private: + bool mUsesGlFragColor; + bool mUsesGlFragData; +}; + +} // namespace anonymous + +TranslatorGLSL::TranslatorGLSL(sh::GLenum type, + ShShaderSpec spec, + ShShaderOutput output) + : TCompiler(type, spec, output) { +} + +void TranslatorGLSL::initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) +{ + if (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS) + InitBuiltInFunctionEmulatorForGLSL(emu, getShaderType()); } -void TranslatorGLSL::translate(TIntermNode* root) { +void TranslatorGLSL::translate(TIntermNode *root, int) { TInfoSinkBase& sink = getInfoSink().obj; // Write GLSL version. @@ -24,21 +79,60 @@ void TranslatorGLSL::translate(TIntermNode* root) { // Write extension behaviour as needed writeExtensionBehavior(); + bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; + + if (precisionEmulation) + { + EmulatePrecision emulatePrecision; + root->traverse(&emulatePrecision); + emulatePrecision.updateTree(); + emulatePrecision.writeEmulationHelpers(sink, getOutputType()); + } + // Write emulated built-in functions if needed. - getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition( - sink, false); + if (!getBuiltInFunctionEmulator().IsOutputEmpty()) + { + sink << "// BEGIN: Generated code for built-in function emulation\n\n"; + sink << "#define webgl_emu_precision\n\n"; + getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink); + sink << "// END: Generated code for built-in function emulation\n\n"; + } // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); + // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData + // if it's core profile shaders and they are used. + if (getShaderType() == GL_FRAGMENT_SHADER && + getOutputType() == SH_GLSL_CORE_OUTPUT) + { + TFragmentOutSearcher searcher; + root->traverse(&searcher); + ASSERT(!(searcher.usesGlFragData() && searcher.usesGlFragColor())); + if (searcher.usesGlFragColor()) + { + sink << "out vec4 webgl_FragColor;\n"; + } + if (searcher.usesGlFragData()) + { + sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; + } + } + // Write translated shader. - TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion()); + TOutputGLSL outputGLSL(sink, + getArrayIndexClampingStrategy(), + getHashFunction(), + getNameMap(), + getSymbolTable(), + getShaderVersion(), + getOutputType()); root->traverse(&outputGLSL); } void TranslatorGLSL::writeVersion(TIntermNode *root) { - TVersionGLSL versionGLSL(getShaderType(), getPragma()); + TVersionGLSL versionGLSL(getShaderType(), getPragma(), getOutputType()); root->traverse(&versionGLSL); int version = versionGLSL.getVersion(); // We need to write version directive only if it is greater than 110. @@ -52,9 +146,9 @@ void TranslatorGLSL::writeVersion(TIntermNode *root) void TranslatorGLSL::writeExtensionBehavior() { TInfoSinkBase& sink = getInfoSink().obj; - const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); - for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); - iter != extensionBehavior.end(); ++iter) { + const TExtensionBehavior& extBehavior = getExtensionBehavior(); + for (TExtensionBehavior::const_iterator iter = extBehavior.begin(); + iter != extBehavior.end(); ++iter) { if (iter->second == EBhUndefined) continue; diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h index 766d8d910e..4a5a641096 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h @@ -4,22 +4,24 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATORGLSL_H_ -#define COMPILER_TRANSLATORGLSL_H_ +#ifndef COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ #include "compiler/translator/Compiler.h" class TranslatorGLSL : public TCompiler { public: - TranslatorGLSL(sh::GLenum type, ShShaderSpec spec); + TranslatorGLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output); protected: - virtual void translate(TIntermNode *root); + void initBuiltInFunctionEmulator(BuiltInFunctionEmulator *emu, int compileOptions) override; + + virtual void translate(TIntermNode *root, int compileOptions); private: void writeVersion(TIntermNode *root); void writeExtensionBehavior(); }; -#endif // COMPILER_TRANSLATORGLSL_H_ +#endif // COMPILER_TRANSLATOR_TRANSLATORGLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp index 22bf60e86e..f6275defa1 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.cpp @@ -6,20 +6,26 @@ #include "compiler/translator/TranslatorHLSL.h" -#include "compiler/translator/InitializeParseContext.h" #include "compiler/translator/OutputHLSL.h" +#include "compiler/translator/SimplifyArrayAssignment.h" TranslatorHLSL::TranslatorHLSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) : TCompiler(type, spec, output) { } -void TranslatorHLSL::translate(TIntermNode *root) +void TranslatorHLSL::translate(TIntermNode *root, int compileOptions) { - TParseContext& parseContext = *GetGlobalParseContext(); - sh::OutputHLSL outputHLSL(parseContext, this); + const ShBuiltInResources &resources = getResources(); + int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1; - outputHLSL.output(); + SimplifyArrayAssignment simplify; + root->traverse(&simplify); + + sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(), + getSourcePath(), getOutputType(), numRenderTargets, getUniforms(), compileOptions); + + outputHLSL.output(root, getInfoSink().obj); mInterfaceBlockRegisterMap = outputHLSL.getInterfaceBlockRegisterMap(); mUniformRegisterMap = outputHLSL.getUniformRegisterMap(); diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h index 11a042d83a..1920ed5755 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorHLSL.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATORHLSL_H_ -#define COMPILER_TRANSLATORHLSL_H_ +#ifndef COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ +#define COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ #include "compiler/translator/Compiler.h" @@ -22,10 +22,10 @@ class TranslatorHLSL : public TCompiler unsigned int getUniformRegister(const std::string &uniformName) const; protected: - virtual void translate(TIntermNode* root); + virtual void translate(TIntermNode *root, int compileOptions); std::map mInterfaceBlockRegisterMap; std::map mUniformRegisterMap; }; -#endif // COMPILER_TRANSLATORHLSL_H_ +#endif // COMPILER_TRANSLATOR_TRANSLATORHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/Types.cpp b/src/3rdparty/angle/src/compiler/translator/Types.cpp index d36936fb23..b970bf5ac4 100644 --- a/src/3rdparty/angle/src/compiler/translator/Types.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Types.cpp @@ -178,11 +178,12 @@ size_t TType::getObjectSize() const if (isArray()) { - size_t arraySize = getArraySize(); - if (arraySize > INT_MAX / totalSize) + // TODO: getArraySize() returns an int, not a size_t + size_t currentArraySize = getArraySize(); + if (currentArraySize > INT_MAX / totalSize) totalSize = INT_MAX; else - totalSize *= arraySize; + totalSize *= currentArraySize; } return totalSize; @@ -199,6 +200,17 @@ bool TStructure::containsArrays() const return false; } +bool TStructure::containsSamplers() const +{ + for (size_t i = 0; i < mFields->size(); ++i) + { + const TType *fieldType = (*mFields)[i]->type(); + if (IsSampler(fieldType->getBasicType()) || fieldType->isStructureContainingSamplers()) + return true; + } + return false; +} + TString TFieldListCollection::buildMangledName() const { TString mangledName(mangledNamePrefix()); diff --git a/src/3rdparty/angle/src/compiler/translator/Types.h b/src/3rdparty/angle/src/compiler/translator/Types.h index 075196daa3..044f22c3c1 100644 --- a/src/3rdparty/angle/src/compiler/translator/Types.h +++ b/src/3rdparty/angle/src/compiler/translator/Types.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _TYPES_INCLUDED -#define _TYPES_INCLUDED +#ifndef COMPILER_TRANSLATOR_TYPES_H_ +#define COMPILER_TRANSLATOR_TYPES_H_ #include "common/angleutils.h" @@ -17,7 +17,7 @@ struct TPublicType; class TType; class TSymbol; -class TField +class TField : angle::NonCopyable { public: POOL_ALLOCATOR_NEW_DELETE(); @@ -49,7 +49,6 @@ class TField } private: - DISALLOW_COPY_AND_ASSIGN(TField); TType *mType; TString *mName; TSourceLoc mLine; @@ -62,7 +61,7 @@ inline TFieldList *NewPoolTFieldList() return new(memory) TFieldList; } -class TFieldListCollection +class TFieldListCollection : angle::NonCopyable { public: const TString &name() const @@ -113,7 +112,8 @@ class TStructure : public TFieldListCollection TStructure(const TString *name, TFieldList *fields) : TFieldListCollection(name, fields), mDeepestNesting(0), - mUniqueId(0) + mUniqueId(0), + mAtGlobalScope(false) { } @@ -124,6 +124,7 @@ class TStructure : public TFieldListCollection return mDeepestNesting; } bool containsArrays() const; + bool containsSamplers() const; bool equals(const TStructure &other) const; @@ -138,9 +139,17 @@ class TStructure : public TFieldListCollection return mUniqueId; } - private: - DISALLOW_COPY_AND_ASSIGN(TStructure); + void setAtGlobalScope(bool atGlobalScope) + { + mAtGlobalScope = atGlobalScope; + } + + bool atGlobalScope() const + { + return mAtGlobalScope; + } + private: // TODO(zmo): Find a way to get rid of the const_cast in function // setName(). At the moment keep this function private so only // friend class RegenerateStructNames may call it. @@ -159,6 +168,7 @@ class TStructure : public TFieldListCollection mutable int mDeepestNesting; int mUniqueId; + bool mAtGlobalScope; }; class TInterfaceBlock : public TFieldListCollection @@ -201,7 +211,6 @@ class TInterfaceBlock : public TFieldListCollection } private: - DISALLOW_COPY_AND_ASSIGN(TInterfaceBlock); virtual TString mangledNamePrefix() const { return "iblock-"; @@ -325,6 +334,10 @@ class TType { return primarySize > 1 && secondarySize > 1; } + bool isNonSquareMatrix() const + { + return isMatrix() && primarySize != secondarySize; + } bool isArray() const { return array ? true : false; @@ -464,6 +477,11 @@ class TType return structure ? structure->containsArrays() : false; } + bool isStructureContainingSamplers() const + { + return structure ? structure->containsSamplers() : false; + } + protected: TString buildMangledName() const; size_t getStructSize() const; @@ -584,4 +602,4 @@ struct TPublicType } }; -#endif // _TYPES_INCLUDED_ +#endif // COMPILER_TRANSLATOR_TYPES_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp index 65f50c4cc3..f79f9dd7fb 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.cpp @@ -16,7 +16,7 @@ namespace sh { -UnfoldShortCircuit::UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL) +UnfoldShortCircuit::UnfoldShortCircuit(OutputHLSL *outputHLSL) : mOutputHLSL(outputHLSL) { mTemporaryIndex = 0; } @@ -30,7 +30,7 @@ void UnfoldShortCircuit::traverse(TIntermNode *node) bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) { - TInfoSinkBase &out = mOutputHLSL->getBodyStream(); + TInfoSinkBase &out = mOutputHLSL->getInfoSink(); // If our right node doesn't have side effects, we know we don't need to unfold this // expression: there will be no short-circuiting side effects to avoid @@ -111,7 +111,7 @@ bool UnfoldShortCircuit::visitBinary(Visit visit, TIntermBinary *node) bool UnfoldShortCircuit::visitSelection(Visit visit, TIntermSelection *node) { - TInfoSinkBase &out = mOutputHLSL->getBodyStream(); + TInfoSinkBase &out = mOutputHLSL->getInfoSink(); // Unfold "b ? x : y" into "type s; if(b) s = x; else s = y;" if (node->usesTernaryOperator()) diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h index 6fd3b457bd..eaceb0a0b3 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuit.h @@ -6,8 +6,8 @@ // UnfoldShortCircuit is an AST traverser to output short-circuiting operators as if-else statements // -#ifndef COMPILER_UNFOLDSHORTCIRCUIT_H_ -#define COMPILER_UNFOLDSHORTCIRCUIT_H_ +#ifndef COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ +#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ #include "compiler/translator/IntermNode.h" #include "compiler/translator/ParseContext.h" @@ -19,7 +19,7 @@ class OutputHLSL; class UnfoldShortCircuit : public TIntermTraverser { public: - UnfoldShortCircuit(TParseContext &context, OutputHLSL *outputHLSL); + UnfoldShortCircuit(OutputHLSL *outputHLSL); void traverse(TIntermNode *node); bool visitBinary(Visit visit, TIntermBinary*); @@ -29,11 +29,10 @@ class UnfoldShortCircuit : public TIntermTraverser int getNextTemporaryIndex(); protected: - TParseContext &mContext; OutputHLSL *const mOutputHLSL; int mTemporaryIndex; }; } -#endif // COMPILER_UNFOLDSHORTCIRCUIT_H_ +#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUIT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp index 29c4397d56..d548d421d2 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.cpp @@ -50,32 +50,8 @@ bool UnfoldShortCircuitAST::visitBinary(Visit visit, TIntermBinary *node) } if (replacement) { - replacements.push_back( - NodeUpdateEntry(getParentNode(), node, replacement)); + mReplacements.push_back( + NodeUpdateEntry(getParentNode(), node, replacement, false)); } return true; } - -void UnfoldShortCircuitAST::updateTree() -{ - for (size_t ii = 0; ii < replacements.size(); ++ii) - { - const NodeUpdateEntry& entry = replacements[ii]; - ASSERT(entry.parent); - bool replaced = entry.parent->replaceChildNode( - entry.original, entry.replacement); - ASSERT(replaced); - - // In AST traversing, a parent is visited before its children. - // After we replace a node, if an immediate child is to - // be replaced, we need to make sure we don't update the replaced - // node; instead, we update the replacement node. - for (size_t jj = ii + 1; jj < replacements.size(); ++jj) - { - NodeUpdateEntry& entry2 = replacements[jj]; - if (entry2.parent == entry.original) - entry2.parent = entry.replacement; - } - } -} - diff --git a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h index 3acaf7ee7c..7b698ccb63 100644 --- a/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h +++ b/src/3rdparty/angle/src/compiler/translator/UnfoldShortCircuitAST.h @@ -7,8 +7,8 @@ // operations with ternary operations. // -#ifndef COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ -#define COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ +#ifndef COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_ +#define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_ #include "common/angleutils.h" #include "compiler/translator/IntermNode.h" @@ -23,29 +23,6 @@ class UnfoldShortCircuitAST : public TIntermTraverser UnfoldShortCircuitAST() { } virtual bool visitBinary(Visit visit, TIntermBinary *); - - void updateTree(); - - private: - struct NodeUpdateEntry - { - NodeUpdateEntry(TIntermNode *_parent, - TIntermNode *_original, - TIntermNode *_replacement) - : parent(_parent), - original(_original), - replacement(_replacement) {} - - TIntermNode *parent; - TIntermNode *original; - TIntermNode *replacement; - }; - - // During traversing, save all the replacements that need to happen; - // then replace them by calling updateNodes(). - std::vector replacements; - - DISALLOW_COPY_AND_ASSIGN(UnfoldShortCircuitAST); }; -#endif // COMPILER_UNFOLD_SHORT_CIRCUIT_AST_H_ +#endif // COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp index 61b6ed7455..71659fe354 100644 --- a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.cpp @@ -7,14 +7,13 @@ // Methods for GLSL to HLSL translation for uniforms and interface blocks. // -#include "OutputHLSL.h" -#include "common/blocklayout.h" -#include "common/utilities.h" #include "compiler/translator/UniformHLSL.h" + +#include "common/utilities.h" #include "compiler/translator/StructureHLSL.h" -#include "compiler/translator/util.h" #include "compiler/translator/UtilsHLSL.h" -#include "compiler/translator/TranslatorHLSL.h" +#include "compiler/translator/blocklayoutHLSL.h" +#include "compiler/translator/util.h" namespace sh { @@ -61,13 +60,13 @@ static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) return DecoratePrivate(interfaceBlock.name()) + "_type"; } -UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator) +UniformHLSL::UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector &uniforms) : mUniformRegister(0), mInterfaceBlockRegister(0), mSamplerRegister(0), mStructureHLSL(structureHLSL), - mOutputType(translator->getOutputType()), - mUniforms(translator->getUniforms()) + mOutputType(outputType), + mUniforms(uniforms) {} void UniformHLSL::reserveUniformRegisters(unsigned int registerCount) @@ -105,7 +104,7 @@ unsigned int UniformHLSL::declareUniformAndAssignRegister(const TType &type, con unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType); - if (gl::IsSampler(uniform->type)) + if (gl::IsSamplerType(uniform->type)) { mSamplerRegister += registerCount; } diff --git a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h index 91fa51588b..4ab9ccdf53 100644 --- a/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/UniformHLSL.h @@ -7,19 +7,19 @@ // Methods for GLSL to HLSL translation for uniforms and interface blocks. // -#ifndef TRANSLATOR_UNIFORMHLSL_H_ -#define TRANSLATOR_UNIFORMHLSL_H_ +#ifndef COMPILER_TRANSLATOR_UNIFORMHLSL_H_ +#define COMPILER_TRANSLATOR_UNIFORMHLSL_H_ -#include "compiler/translator/Types.h" +#include "compiler/translator/OutputHLSL.h" namespace sh { class StructureHLSL; -class UniformHLSL +class UniformHLSL : angle::NonCopyable { public: - UniformHLSL(StructureHLSL *structureHLSL, TranslatorHLSL *translator); + UniformHLSL(StructureHLSL *structureHLSL, ShShaderOutput outputType, const std::vector &uniforms); void reserveUniformRegisters(unsigned int registerCount); void reserveInterfaceBlockRegisters(unsigned int registerCount); @@ -60,4 +60,4 @@ class UniformHLSL } -#endif // TRANSLATOR_UNIFORMHLSL_H_ +#endif // COMPILER_TRANSLATOR_UNIFORMHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp index de0c36ca65..94e19ac40d 100644 --- a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.cpp @@ -175,6 +175,13 @@ TString StructNameString(const TStructure &structure) return ""; } + // For structures at global scope we use a consistent + // translation so that we can link between shader stages. + if (structure.atGlobalScope()) + { + return Decorate(structure.name()); + } + return "ss" + str(structure.uniqueId()) + "_" + structure.name(); } diff --git a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h index aaa3ddf5d2..9800a3bbf3 100644 --- a/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/UtilsHLSL.h @@ -7,8 +7,8 @@ // Utility methods for GLSL to HLSL translation. // -#ifndef TRANSLATOR_UTILSHLSL_H_ -#define TRANSLATOR_UTILSHLSL_H_ +#ifndef COMPILER_TRANSLATOR_UTILSHLSL_H_ +#define COMPILER_TRANSLATOR_UTILSHLSL_H_ #include #include "compiler/translator/Types.h" @@ -34,4 +34,4 @@ TString QualifierString(TQualifier qualifier); } -#endif // TRANSLATOR_UTILSHLSL_H_ +#endif // COMPILER_TRANSLATOR_UTILSHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp index 896e1cd7a0..12367066e8 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp @@ -47,93 +47,6 @@ class ValidateConstIndexExpr : public TIntermTraverser TLoopStack& mLoopStack; }; -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: - case EOpIndexDirectInterfaceBlock: 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 EOpPositive: return "+"; - case EOpVectorLogicalNot: return "not"; - case EOpLogicalNot: return "!"; - case EOpPostIncrement: return "++"; - case EOpPostDecrement: return "--"; - case EOpPreIncrement: return "++"; - case EOpPreDecrement: return "--"; - - 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 ""; -} - } // namespace anonymous ValidateLimitations::ValidateLimitations(sh::GLenum shaderType, diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h index e6e8a9619f..59cccb565f 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.h @@ -4,6 +4,9 @@ // found in the LICENSE file. // +#ifndef COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ +#define COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ + #include "compiler/translator/IntermNode.h" #include "compiler/translator/LoopInfo.h" @@ -53,3 +56,4 @@ class ValidateLimitations : public TIntermTraverser TLoopStack mLoopStack; }; +#endif // COMPILER_TRANSLATOR_VALIDATELIMITATIONS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h index 0f808dbb97..1538e0f157 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h +++ b/src/3rdparty/angle/src/compiler/translator/ValidateOutputs.h @@ -4,6 +4,9 @@ // found in the LICENSE file. // +#ifndef COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ +#define COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ + #include "compiler/translator/IntermNode.h" #include @@ -31,3 +34,5 @@ class ValidateOutputs : public TIntermTraverser void error(TSourceLoc loc, const char *reason, const char* token); }; + +#endif // COMPILER_TRANSLATOR_VALIDATEOUTPUTS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp new file mode 100644 index 0000000000..9a4ed33632 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.cpp @@ -0,0 +1,200 @@ +// +// Copyright (c) 2002-2015 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/translator/ValidateSwitch.h" + +#include "compiler/translator/ParseContext.h" + +bool ValidateSwitch::validate(TBasicType switchType, TParseContext *context, + TIntermAggregate *statementList, const TSourceLoc &loc) +{ + ValidateSwitch validate(switchType, context); + ASSERT(statementList); + statementList->traverse(&validate); + return validate.validateInternal(loc); +} + +ValidateSwitch::ValidateSwitch(TBasicType switchType, TParseContext *context) + : TIntermTraverser(true, false, true), + mSwitchType(switchType), + mContext(context), + mCaseTypeMismatch(false), + mFirstCaseFound(false), + mStatementBeforeCase(false), + mLastStatementWasCase(false), + mControlFlowDepth(0), + mCaseInsideControlFlow(false), + mDefaultCount(0), + mDuplicateCases(false) +{} + +void ValidateSwitch::visitSymbol(TIntermSymbol *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; +} + +void ValidateSwitch::visitConstantUnion(TIntermConstantUnion *) +{ + // Conditions of case labels are not traversed, so this is some other constant + // Could be just a statement like "0;" + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; +} + +bool ValidateSwitch::visitBinary(Visit, TIntermBinary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitUnary(Visit, TIntermUnary *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitSelection(Visit visit, TIntermSelection *) +{ + if (visit == PreVisit) + ++mControlFlowDepth; + if (visit == PostVisit) + --mControlFlowDepth; + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitSwitch(Visit, TIntermSwitch *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + // Don't go into nested switch statements + return false; +} + +bool ValidateSwitch::visitCase(Visit, TIntermCase *node) +{ + const char *nodeStr = node->hasCondition() ? "case" : "default"; + if (mControlFlowDepth > 0) + { + mContext->error(node->getLine(), "label statement nested inside control flow", nodeStr); + mCaseInsideControlFlow = true; + } + mFirstCaseFound = true; + mLastStatementWasCase = true; + if (!node->hasCondition()) + { + ++mDefaultCount; + if (mDefaultCount > 1) + { + mContext->error(node->getLine(), "duplicate default label", nodeStr); + } + } + else + { + TIntermConstantUnion *condition = node->getCondition()->getAsConstantUnion(); + if (condition == nullptr) + { + // This can happen in error cases. + return false; + } + TBasicType conditionType = condition->getBasicType(); + if (conditionType != mSwitchType) + { + mContext->error(condition->getLine(), + "case label type does not match switch init-expression type", nodeStr); + mCaseTypeMismatch = true; + } + + if (conditionType == EbtInt) + { + int iConst = condition->getIConst(0); + if (mCasesSigned.find(iConst) != mCasesSigned.end()) + { + mContext->error(condition->getLine(), "duplicate case label", nodeStr); + mDuplicateCases = true; + } + else + { + mCasesSigned.insert(iConst); + } + } + else if (conditionType == EbtUInt) + { + unsigned int uConst = condition->getUConst(0); + if (mCasesUnsigned.find(uConst) != mCasesUnsigned.end()) + { + mContext->error(condition->getLine(), "duplicate case label", nodeStr); + mDuplicateCases = true; + } + else + { + mCasesUnsigned.insert(uConst); + } + } + // Other types are possible only in error cases, where the error has already been generated + // when parsing the case statement. + } + // Don't traverse the condition of the case statement + return false; +} + +bool ValidateSwitch::visitAggregate(Visit visit, TIntermAggregate *) +{ + if (getParentNode() != nullptr) + { + // This is not the statementList node, but some other node. + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + } + return true; +} + +bool ValidateSwitch::visitLoop(Visit visit, TIntermLoop *) +{ + if (visit == PreVisit) + ++mControlFlowDepth; + if (visit == PostVisit) + --mControlFlowDepth; + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::visitBranch(Visit, TIntermBranch *) +{ + if (!mFirstCaseFound) + mStatementBeforeCase = true; + mLastStatementWasCase = false; + return true; +} + +bool ValidateSwitch::validateInternal(const TSourceLoc &loc) +{ + if (mStatementBeforeCase) + { + mContext->error(loc, + "statement before the first label", "switch"); + } + if (mLastStatementWasCase) + { + mContext->error(loc, + "no statement between the last label and the end of the switch statement", "switch"); + } + return !mStatementBeforeCase && !mLastStatementWasCase && !mCaseInsideControlFlow && + !mCaseTypeMismatch && mDefaultCount <= 1 && !mDuplicateCases; +} diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h new file mode 100644 index 0000000000..88b68a500e --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/ValidateSwitch.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2002-2015 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_TRANSLATOR_VALIDATESWITCH_H_ +#define COMPILER_TRANSLATOR_VALIDATESWITCH_H_ + +#include "compiler/translator/IntermNode.h" + +struct TParseContext; + +class ValidateSwitch : public TIntermTraverser +{ + public: + // Check for errors and output messages any remaining errors on the context. + // Returns true if there are no errors. + static bool validate(TBasicType switchType, TParseContext *context, + TIntermAggregate *statementList, const TSourceLoc &loc); + + void visitSymbol(TIntermSymbol *) override; + void visitConstantUnion(TIntermConstantUnion *) override; + bool visitBinary(Visit, TIntermBinary *) override; + bool visitUnary(Visit, TIntermUnary *) override; + bool visitSelection(Visit visit, TIntermSelection *) override; + bool visitSwitch(Visit, TIntermSwitch *) override; + bool visitCase(Visit, TIntermCase *node) override; + bool visitAggregate(Visit, TIntermAggregate *) override; + bool visitLoop(Visit visit, TIntermLoop *) override; + bool visitBranch(Visit, TIntermBranch *) override; + + private: + ValidateSwitch(TBasicType switchType, TParseContext *context); + + bool validateInternal(const TSourceLoc &loc); + + TBasicType mSwitchType; + TParseContext *mContext; + bool mCaseTypeMismatch; + bool mFirstCaseFound; + bool mStatementBeforeCase; + bool mLastStatementWasCase; + int mControlFlowDepth; + bool mCaseInsideControlFlow; + int mDefaultCount; + std::set mCasesSigned; + std::set mCasesUnsigned; + bool mDuplicateCases; +}; + +#endif // COMPILER_TRANSLATOR_VALIDATESWITCH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp index d8e13788b7..cf229ec96a 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp @@ -142,8 +142,10 @@ CollectVariables::CollectVariables(std::vector *attribs, mPointCoordAdded(false), mFrontFacingAdded(false), mFragCoordAdded(false), + mInstanceIDAdded(false), mPositionAdded(false), mPointSizeAdded(false), + mLastFragDataAdded(false), mHashFunction(hashFunction), mSymbolTable(symbolTable) { @@ -249,6 +251,22 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) mPointCoordAdded = true; } return; + case EvqInstanceID: + if (!mInstanceIDAdded) + { + Attribute info; + const char kName[] = "gl_InstanceID"; + info.name = kName; + info.mappedName = kName; + info.type = GL_INT; + info.arraySize = 0; + info.precision = GL_HIGH_INT; // Defined by spec. + info.staticUse = true; + info.location = -1; + mAttribs->push_back(info); + mInstanceIDAdded = true; + } + return; case EvqPosition: if (!mPositionAdded) { @@ -281,6 +299,22 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) mPointSizeAdded = true; } return; + case EvqLastFragData: + if (!mLastFragDataAdded) + { + Varying info; + const char kName[] = "gl_LastFragData"; + info.name = kName; + info.mappedName = kName; + info.type = GL_FLOAT_VEC4; + info.arraySize = static_cast(mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))->getConstPointer()->getIConst(); + info.precision = GL_MEDIUM_FLOAT; // Defined by spec. + info.staticUse = true; + info.isInvariant = mSymbolTable.isVaryingInvariant(kName); + mVaryings->push_back(info); + mLastFragDataAdded = true; + } + return; default: break; } @@ -301,8 +335,6 @@ class NameHashingTraverser : public GetVariableTraverser {} private: - DISALLOW_COPY_AND_ASSIGN(NameHashingTraverser); - virtual void visitVariable(ShaderVariable *variable) { TString stringName = TString(variable->name.c_str()); diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h index 92d376d879..bb1328a507 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h +++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_VARIABLE_INFO_H_ -#define COMPILER_VARIABLE_INFO_H_ +#ifndef COMPILER_TRANSLATOR_VARIABLEINFO_H_ +#define COMPILER_TRANSLATOR_VARIABLEINFO_H_ #include @@ -51,8 +51,10 @@ class CollectVariables : public TIntermTraverser bool mFrontFacingAdded; bool mFragCoordAdded; + bool mInstanceIDAdded; bool mPositionAdded; bool mPointSizeAdded; + bool mLastFragDataAdded; ShHashFunction64 mHashFunction; @@ -65,4 +67,4 @@ void ExpandUniforms(const std::vector &compact, } -#endif // COMPILER_VARIABLE_INFO_H_ +#endif // COMPILER_TRANSLATOR_VARIABLEINFO_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VariablePacker.h b/src/3rdparty/angle/src/compiler/translator/VariablePacker.h index 1de5332d8a..9c80eea618 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariablePacker.h +++ b/src/3rdparty/angle/src/compiler/translator/VariablePacker.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef _VARIABLEPACKER_INCLUDED_ -#define _VARIABLEPACKER_INCLUDED_ +#ifndef COMPILER_TRANSLATOR_VARIABLEPACKER_H_ +#define COMPILER_TRANSLATOR_VARIABLEPACKER_H_ #include #include "compiler/translator/VariableInfo.h" @@ -38,4 +38,4 @@ class VariablePacker { std::vector rows_; }; -#endif // _VARIABLEPACKER_INCLUDED_ +#endif // COMPILER_TRANSLATOR_VARIABLEPACKER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp index 05b111a7a7..f6f568897d 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp @@ -8,6 +8,7 @@ static const int GLSL_VERSION_110 = 110; static const int GLSL_VERSION_120 = 120; +static const int GLSL_VERSION_150 = 150; // We need to scan for the following: // 1. "invariant" keyword: This can occur in both - vertex and fragment shaders @@ -26,12 +27,22 @@ static const int GLSL_VERSION_120 = 120; // 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." // -TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma) +TVersionGLSL::TVersionGLSL(sh::GLenum type, + const TPragma &pragma, + ShShaderOutput output) { - if (pragma.stdgl.invariantAll) - mVersion = GLSL_VERSION_120; + if (output == SH_GLSL_CORE_OUTPUT) + { + mVersion = GLSL_VERSION_150; + } else - mVersion = GLSL_VERSION_110; + { + ASSERT(output == SH_GLSL_COMPATIBILITY_OUTPUT); + if (pragma.stdgl.invariantAll) + mVersion = GLSL_VERSION_120; + else + mVersion = GLSL_VERSION_110; + } } void TVersionGLSL::visitSymbol(TIntermSymbol *node) diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h index 72368e39d6..2b63d5f25d 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h @@ -29,14 +29,16 @@ class TVersionGLSL : public TIntermTraverser { public: - TVersionGLSL(sh::GLenum type, const TPragma &pragma); - - // Returns 120 if the following is used the shader: - // - "invariant", - // - "gl_PointCoord", - // - matrix/matrix constructors - // - array "out" parameters - // Else 110 is returned. + TVersionGLSL(sh::GLenum type, const TPragma &pragma, ShShaderOutput output); + + // If output is core profile, returns 150. + // If output is legacy profile, + // 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 *); diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp b/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp new file mode 100644 index 0000000000..7c74105680 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/blocklayout.cpp @@ -0,0 +1,123 @@ +// +// Copyright (c) 2013-2014 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. +// +// blocklayout.cpp: +// Implementation for block layout classes and methods. +// + +#include "compiler/translator/blocklayout.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace sh +{ + +BlockLayoutEncoder::BlockLayoutEncoder() + : mCurrentOffset(0) +{ +} + +BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix) +{ + int arrayStride; + int matrixStride; + + getBlockLayoutInfo(type, arraySize, isRowMajorMatrix, &arrayStride, &matrixStride); + + const BlockMemberInfo memberInfo(mCurrentOffset * BytesPerComponent, arrayStride * BytesPerComponent, matrixStride * BytesPerComponent, isRowMajorMatrix); + + advanceOffset(type, arraySize, isRowMajorMatrix, arrayStride, matrixStride); + + return memberInfo; +} + +// static +size_t BlockLayoutEncoder::getBlockRegister(const BlockMemberInfo &info) +{ + return (info.offset / BytesPerComponent) / ComponentsPerRegister; +} + +// static +size_t BlockLayoutEncoder::getBlockRegisterElement(const BlockMemberInfo &info) +{ + return (info.offset / BytesPerComponent) % ComponentsPerRegister; +} + +void BlockLayoutEncoder::nextRegister() +{ + mCurrentOffset = rx::roundUp(mCurrentOffset, ComponentsPerRegister); +} + +Std140BlockEncoder::Std140BlockEncoder() +{ +} + +void Std140BlockEncoder::enterAggregateType() +{ + nextRegister(); +} + +void Std140BlockEncoder::exitAggregateType() +{ + nextRegister(); +} + +void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) +{ + // We assume we are only dealing with 4 byte components (no doubles or half-words currently) + ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); + + size_t baseAlignment = 0; + int matrixStride = 0; + int arrayStride = 0; + + if (gl::IsMatrixType(type)) + { + baseAlignment = ComponentsPerRegister; + matrixStride = ComponentsPerRegister; + + if (arraySize > 0) + { + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + arrayStride = ComponentsPerRegister * numRegisters; + } + } + else if (arraySize > 0) + { + baseAlignment = ComponentsPerRegister; + arrayStride = ComponentsPerRegister; + } + else + { + const int numComponents = gl::VariableComponentCount(type); + baseAlignment = (numComponents == 3 ? 4u : static_cast(numComponents)); + } + + mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment); + + *matrixStrideOut = matrixStride; + *arrayStrideOut = arrayStride; +} + +void Std140BlockEncoder::advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) +{ + if (arraySize > 0) + { + mCurrentOffset += arrayStride * arraySize; + } + else if (gl::IsMatrixType(type)) + { + ASSERT(matrixStride == ComponentsPerRegister); + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + mCurrentOffset += ComponentsPerRegister * numRegisters; + } + else + { + mCurrentOffset += gl::VariableComponentCount(type); + } +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayout.h b/src/3rdparty/angle/src/compiler/translator/blocklayout.h new file mode 100644 index 0000000000..c11357fe66 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/blocklayout.h @@ -0,0 +1,94 @@ +// +// Copyright (c) 2013-2014 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. +// +// blocklayout.h: +// Methods and classes related to uniform layout and packing in GLSL and HLSL. +// + +#ifndef COMMON_BLOCKLAYOUT_H_ +#define COMMON_BLOCKLAYOUT_H_ + +#include +#include + +#include "angle_gl.h" +#include + +namespace sh +{ +struct ShaderVariable; +struct InterfaceBlockField; +struct Uniform; +struct Varying; +struct InterfaceBlock; + +struct COMPILER_EXPORT BlockMemberInfo +{ + BlockMemberInfo(int offset, int arrayStride, int matrixStride, bool isRowMajorMatrix) + : offset(offset), + arrayStride(arrayStride), + matrixStride(matrixStride), + isRowMajorMatrix(isRowMajorMatrix) + {} + + static BlockMemberInfo getDefaultBlockInfo() + { + return BlockMemberInfo(-1, -1, -1, false); + } + + int offset; + int arrayStride; + int matrixStride; + bool isRowMajorMatrix; +}; + +class COMPILER_EXPORT BlockLayoutEncoder +{ + public: + BlockLayoutEncoder(); + + BlockMemberInfo encodeType(GLenum type, unsigned int arraySize, bool isRowMajorMatrix); + + size_t getBlockSize() const { return mCurrentOffset * BytesPerComponent; } + size_t getCurrentRegister() const { return mCurrentOffset / ComponentsPerRegister; } + size_t getCurrentElement() const { return mCurrentOffset % ComponentsPerRegister; } + + virtual void enterAggregateType() = 0; + virtual void exitAggregateType() = 0; + + static const size_t BytesPerComponent = 4u; + static const unsigned int ComponentsPerRegister = 4u; + + static size_t getBlockRegister(const BlockMemberInfo &info); + static size_t getBlockRegisterElement(const BlockMemberInfo &info); + + protected: + size_t mCurrentOffset; + + void nextRegister(); + + virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) = 0; + virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) = 0; +}; + +// Block layout according to the std140 block layout +// See "Standard Uniform Block Layout" in Section 2.11.6 of the OpenGL ES 3.0 specification + +class COMPILER_EXPORT Std140BlockEncoder : public BlockLayoutEncoder +{ + public: + Std140BlockEncoder(); + + virtual void enterAggregateType(); + virtual void exitAggregateType(); + + protected: + virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut); + virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride); +}; + +} + +#endif // COMMON_BLOCKLAYOUT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp new file mode 100644 index 0000000000..f32cf2cf89 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.cpp @@ -0,0 +1,165 @@ +// +// Copyright (c) 2013-2014 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. +// +// blocklayout.cpp: +// Implementation for block layout classes and methods. +// + +#include "compiler/translator/blocklayoutHLSL.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace sh +{ + +HLSLBlockEncoder::HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy) + : mEncoderStrategy(strategy), + mTransposeMatrices(false) +{ +} + +void HLSLBlockEncoder::enterAggregateType() +{ + nextRegister(); +} + +void HLSLBlockEncoder::exitAggregateType() +{ +} + +void HLSLBlockEncoder::getBlockLayoutInfo(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut) +{ + GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); + + // We assume we are only dealing with 4 byte components (no doubles or half-words currently) + ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == BytesPerComponent); + + int matrixStride = 0; + int arrayStride = 0; + + // if variables are not to be packed, or we're about to + // pack a matrix or array, skip to the start of the next + // register + if (!isPacked() || + gl::IsMatrixType(type) || + arraySize > 0) + { + nextRegister(); + } + + if (gl::IsMatrixType(type)) + { + matrixStride = ComponentsPerRegister; + + if (arraySize > 0) + { + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + arrayStride = ComponentsPerRegister * numRegisters; + } + } + else if (arraySize > 0) + { + arrayStride = ComponentsPerRegister; + } + else if (isPacked()) + { + int numComponents = gl::VariableComponentCount(type); + if ((numComponents + (mCurrentOffset % ComponentsPerRegister)) > ComponentsPerRegister) + { + nextRegister(); + } + } + + *matrixStrideOut = matrixStride; + *arrayStrideOut = arrayStride; +} + +void HLSLBlockEncoder::advanceOffset(GLenum typeIn, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride) +{ + GLenum type = (mTransposeMatrices ? gl::TransposeMatrixType(typeIn) : typeIn); + + if (arraySize > 0) + { + mCurrentOffset += arrayStride * (arraySize - 1); + } + + if (gl::IsMatrixType(type)) + { + ASSERT(matrixStride == ComponentsPerRegister); + const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); + const int numComponents = gl::MatrixComponentCount(type, isRowMajorMatrix); + mCurrentOffset += ComponentsPerRegister * (numRegisters - 1); + mCurrentOffset += numComponents; + } + else if (isPacked()) + { + mCurrentOffset += gl::VariableComponentCount(type); + } + else + { + mCurrentOffset += ComponentsPerRegister; + } +} + +void HLSLBlockEncoder::skipRegisters(unsigned int numRegisters) +{ + mCurrentOffset += (numRegisters * ComponentsPerRegister); +} + +HLSLBlockEncoder::HLSLBlockEncoderStrategy HLSLBlockEncoder::GetStrategyFor(ShShaderOutput outputType) +{ + switch (outputType) + { + case SH_HLSL9_OUTPUT: return ENCODE_LOOSE; + case SH_HLSL11_OUTPUT: return ENCODE_PACKED; + default: UNREACHABLE(); return ENCODE_PACKED; + } +} + +template +void HLSLVariableRegisterCount(const ShaderVarType &variable, HLSLBlockEncoder *encoder) +{ + if (variable.isStruct()) + { + for (size_t arrayElement = 0; arrayElement < variable.elementCount(); arrayElement++) + { + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < variable.fields.size(); fieldIndex++) + { + HLSLVariableRegisterCount(variable.fields[fieldIndex], encoder); + } + + encoder->exitAggregateType(); + } + } + else + { + // We operate only on varyings and uniforms, which do not have matrix layout qualifiers + encoder->encodeType(variable.type, variable.arraySize, false); + } +} + +unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMatrices) +{ + HLSLBlockEncoder encoder(HLSLBlockEncoder::ENCODE_PACKED); + encoder.setTransposeMatrices(transposeMatrices); + HLSLVariableRegisterCount(variable, &encoder); + + const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); + return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / registerBytes); +} + +unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType) +{ + HLSLBlockEncoder encoder(HLSLBlockEncoder::GetStrategyFor(outputType)); + HLSLVariableRegisterCount(variable, &encoder); + + const size_t registerBytes = (encoder.BytesPerComponent * encoder.ComponentsPerRegister); + return static_cast(rx::roundUp(encoder.getBlockSize(), registerBytes) / registerBytes); +} + +} diff --git a/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h new file mode 100644 index 0000000000..c61cb1ae57 --- /dev/null +++ b/src/3rdparty/angle/src/compiler/translator/blocklayoutHLSL.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2013-2014 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. +// +// blocklayout.h: +// Methods and classes related to uniform layout and packing in GLSL and HLSL. +// + +#ifndef COMMON_BLOCKLAYOUTHLSL_H_ +#define COMMON_BLOCKLAYOUTHLSL_H_ + +#include +#include + +#include "angle_gl.h" +#include "blocklayout.h" +#include + +namespace sh +{ +// Block layout packed according to the D3D9 or default D3D10+ register packing rules +// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb509632(v=vs.85).aspx +// The strategy should be ENCODE_LOOSE for D3D9 constant blocks, and ENCODE_PACKED +// for everything else (D3D10+ constant blocks and all attributes/varyings). + +class COMPILER_EXPORT HLSLBlockEncoder : public BlockLayoutEncoder +{ + public: + enum HLSLBlockEncoderStrategy + { + ENCODE_PACKED, + ENCODE_LOOSE + }; + + HLSLBlockEncoder(HLSLBlockEncoderStrategy strategy); + + virtual void enterAggregateType(); + virtual void exitAggregateType(); + void skipRegisters(unsigned int numRegisters); + + bool isPacked() const { return mEncoderStrategy == ENCODE_PACKED; } + void setTransposeMatrices(bool enabled) { mTransposeMatrices = enabled; } + + static HLSLBlockEncoderStrategy GetStrategyFor(ShShaderOutput outputType); + + protected: + virtual void getBlockLayoutInfo(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int *arrayStrideOut, int *matrixStrideOut); + virtual void advanceOffset(GLenum type, unsigned int arraySize, bool isRowMajorMatrix, int arrayStride, int matrixStride); + + HLSLBlockEncoderStrategy mEncoderStrategy; + bool mTransposeMatrices; +}; + +// This method returns the number of used registers for a ShaderVariable. It is dependent on the HLSLBlockEncoder +// class to count the number of used registers in a struct (which are individually packed according to the same rules). +COMPILER_EXPORT unsigned int HLSLVariableRegisterCount(const Varying &variable, bool transposeMatrices); +COMPILER_EXPORT unsigned int HLSLVariableRegisterCount(const Uniform &variable, ShShaderOutput outputType); + +} + +#endif // COMMON_BLOCKLAYOUTHLSL_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/compilerdebug.h b/src/3rdparty/angle/src/compiler/translator/compilerdebug.h index 7a371516af..84a12ad2f8 100644 --- a/src/3rdparty/angle/src/compiler/translator/compilerdebug.h +++ b/src/3rdparty/angle/src/compiler/translator/compilerdebug.h @@ -6,8 +6,8 @@ // debug.h: Debugging utilities. -#ifndef COMPILER_DEBUG_H_ -#define COMPILER_DEBUG_H_ +#ifndef COMPILER_TRANSLATOR_COMPILERDEBUG_H_ +#define COMPILER_TRANSLATOR_COMPILERDEBUG_H_ #include @@ -49,5 +49,5 @@ void Trace(const char* format, ...); assert(false); \ } while(0) -#endif // COMPILER_DEBUG_H_ +#endif // COMPILER_TRANSLATOR_COMPILERDEBUG_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h index bc25fe7cbc..22db633678 100644 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h +++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraph.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H -#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_H +#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ +#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ #include "compiler/translator/IntermNode.h" @@ -186,7 +186,7 @@ private: // // When using this, just fill in the methods for nodes you want visited. // -class TDependencyGraphTraverser { +class TDependencyGraphTraverser : angle::NonCopyable { public: TDependencyGraphTraverser() : mDepth(0) {} @@ -209,4 +209,4 @@ private: TGraphNodeSet mVisited; }; -#endif +#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPH_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h index b76f075e68..f7b3bd4b43 100644 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h +++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphBuilder.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H -#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ +#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ #include "compiler/translator/depgraph/DependencyGraph.h" @@ -104,7 +104,7 @@ class TDependencyGraphBuilder : public TIntermTraverser // 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 + class TNodeSetMaintainer : angle::NonCopyable { public: TNodeSetMaintainer(TDependencyGraphBuilder *factory) @@ -122,7 +122,7 @@ class TDependencyGraphBuilder : public TIntermTraverser // 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 + class TNodeSetPropagatingMaintainer : angle::NonCopyable { public: TNodeSetPropagatingMaintainer(TDependencyGraphBuilder *factory) @@ -147,7 +147,7 @@ class TDependencyGraphBuilder : public TIntermTraverser // kRightSubtree will never be replaced by a real symbol because we are tracking // the leftmost symbol. // - class TLeftmostSymbolMaintainer + class TLeftmostSymbolMaintainer : angle::NonCopyable { public: TLeftmostSymbolMaintainer( @@ -196,4 +196,4 @@ class TDependencyGraphBuilder : public TIntermTraverser TSymbolStack mLeftmostSymbols; }; -#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCY_GRAPH_BUILDER_H +#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHBUILDER_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h index c3a4112278..b201e0a671 100644 --- a/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h +++ b/src/3rdparty/angle/src/compiler/translator/depgraph/DependencyGraphOutput.h @@ -4,27 +4,28 @@ // found in the LICENSE file. // -#ifndef COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H -#define COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H +#ifndef COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ +#define COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ #include "compiler/translator/depgraph/DependencyGraph.h" #include "compiler/translator/InfoSink.h" -class TDependencyGraphOutput : public TDependencyGraphTraverser { -public: +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 visitSymbol(TGraphSymbol* symbol) override; + void visitArgument(TGraphArgument* parameter) override; + void visitFunctionCall(TGraphFunctionCall* functionCall) override; + void visitSelection(TGraphSelection* selection) override; + void visitLoop(TGraphLoop* loop) override; + void visitLogicalOp(TGraphLogicalOp* logicalOp) override; void outputAllSpanningTrees(TDependencyGraph& graph); -private: + private: void outputIndentation(); TInfoSinkBase& mSink; }; -#endif // COMPILER_DEPGRAPH_DEPENDENCY_GRAPH_OUTPUT_H +#endif // COMPILER_TRANSLATOR_DEPGRAPH_DEPENDENCYGRAPHOUTPUT_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.h b/src/3rdparty/angle/src/compiler/translator/glslang.h index f221199093..db31e6946c 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.h +++ b/src/3rdparty/angle/src/compiler/translator/glslang.h @@ -4,6 +4,9 @@ // found in the LICENSE file. // +#ifndef COMPILER_TRANSLATOR_GLSLANG_H_ +#define COMPILER_TRANSLATOR_GLSLANG_H_ + struct TParseContext; extern int glslang_initialize(TParseContext* context); extern int glslang_finalize(TParseContext* context); @@ -14,3 +17,4 @@ extern int glslang_scan(size_t count, TParseContext* context); extern int glslang_parse(TParseContext* context); +#endif // COMPILER_TRANSLATOR_GLSLANG_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.l b/src/3rdparty/angle/src/compiler/translator/glslang.l index 518b78df11..ee4d28b6d6 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.l +++ b/src/3rdparty/angle/src/compiler/translator/glslang.l @@ -32,6 +32,7 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp). #pragma warning(disable: 4189) #pragma warning(disable: 4505) #pragma warning(disable: 4701) +#pragma warning(disable: 4702) #endif } @@ -70,6 +71,7 @@ static int floatsuffix_check(TParseContext* context); %option noyywrap nounput never-interactive %option yylineno reentrant bison-bridge bison-locations %option extra-type="TParseContext*" +%x FIELDS D [0-9] L [a-zA-Z_] @@ -358,7 +360,7 @@ O [0-7] ")" { return RIGHT_PAREN; } ("["|"<:") { return LEFT_BRACKET; } ("]"|":>") { return RIGHT_BRACKET; } -"." { return DOT; } +"." { BEGIN(FIELDS); return DOT; } "!" { return BANG; } "-" { return DASH; } "~" { return TILDE; } @@ -373,9 +375,16 @@ O [0-7] "&" { 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] { } -<> { yyterminate(); } -. { assert(false); return 0; } +<*><> { yyterminate(); } +<*>. { assert(false); return 0; } %% @@ -492,8 +501,8 @@ int floatsuffix_check(TParseContext* context) return(FLOATCONSTANT); } -void yyerror(YYLTYPE* lloc, TParseContext* context, const char* reason) { - context->error(*lloc, reason, yyget_text(context->scanner)); +void yyerror(YYLTYPE* lloc, TParseContext* context, void *scanner, const char* reason) { + context->error(*lloc, reason, yyget_text(scanner)); context->recover(); } diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.y b/src/3rdparty/angle/src/compiler/translator/glslang.y index e271de978c..6024898cb0 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.y +++ b/src/3rdparty/angle/src/compiler/translator/glslang.y @@ -32,6 +32,7 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). #pragma warning(disable: 4189) #pragma warning(disable: 4505) #pragma warning(disable: 4701) +#pragma warning(disable: 4702) #endif #include "angle_gl.h" @@ -41,12 +42,11 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). #define YYENABLE_NLS 0 -#define YYLEX_PARAM context->scanner - %} %expect 1 /* One shift reduce conflict because of if | else */ -%pure-parser %parse-param {TParseContext* context} +%param {void *scanner} +%define api.pure full %locations %code requires { @@ -72,6 +72,8 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). TIntermNodePair nodePair; TIntermTyped* intermTypedNode; TIntermAggregate* intermAggregate; + TIntermSwitch* intermSwitch; + TIntermCase* intermCase; }; union { TPublicType type; @@ -88,11 +90,11 @@ WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h). %{ extern int yylex(YYSTYPE* yylval, YYLTYPE* yylloc, void* yyscanner); -extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason); +extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, const char* reason); #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ - if (YYID(N)) { \ + if (N) { \ (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ (Current).last_file = YYRHSLOC(Rhs, N).last_file; \ @@ -179,6 +181,8 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, const char* reason) %type declaration external_declaration %type for_init_statement compound_statement_no_new_scope %type selection_rest_statement for_rest_statement +%type switch_statement +%type case_label %type iteration_statement jump_statement statement_no_new_scope statement_with_scope %type single_declaration init_declarator_list @@ -269,28 +273,14 @@ postfix_expression | function_call { $$ = $1; } - | postfix_expression DOT identifier { + | postfix_expression DOT FIELD_SELECTION { $$ = context->addFieldSelectionExpression($1, @2, *$3.string, @3); } | postfix_expression INC_OP { - if (context->lValueErrorCheck(@2, "++", $1)) - context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, @2); - if ($$ == 0) { - context->unaryOpError(@2, "++", $1->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addUnaryMathLValue(EOpPostIncrement, $1, @2); } | postfix_expression DEC_OP { - if (context->lValueErrorCheck(@2, "--", $1)) - context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, @2); - if ($$ == 0) { - context->unaryOpError(@2, "--", $1->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addUnaryMathLValue(EOpPostDecrement, $1, @2); } ; @@ -304,118 +294,12 @@ integer_expression function_call : function_call_or_method { - TFunction* fnCall = $1.function; - TOperator op = fnCall->getBuiltInOp(); - - if (op != EOpNull) + bool fatalError = false; + $$ = context->addFunctionCallOrMethod($1.function, $1.intermNode, @1, &fatalError); + if (fatalError) { - // - // 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, $1.intermNode, *fnCall, op, &type)) { - $$ = 0; - } else { - // - // It's a constructor, of type 'type'. - // - $$ = context->addConstructor($1.intermNode, &type, op, fnCall, @1); - } - - if ($$ == 0) { - context->recover(); - $$ = context->intermediate.setAggregateOperator(0, op, @1); - } - $$->setType(type); - } else { - // - // Not a constructor. Find it in the symbol table. - // - const TFunction* fnCandidate; - bool builtIn; - fnCandidate = context->findFunction(@1, fnCall, context->shaderVersion, &builtIn); - if (fnCandidate) { - // - // A declared function. - // - if (builtIn && !fnCandidate->getExtension().empty() && - context->extensionErrorCheck(@1, 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, @1); - const TType& returnType = fnCandidate->getReturnType(); - if (returnType.getBasicType() == EbtBool) { - // Bool types should not have precision, so we'll override any precision - // that might have been set by addUnaryMath. - $$->setType(returnType); - } else { - // addUnaryMath has set the precision of the node based on the operand. - $$->setTypePreservePrecision(returnType); - } - 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 { - TIntermAggregate *aggregate = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1); - aggregate->setType(fnCandidate->getReturnType()); - aggregate->setPrecisionFromChildren(); - $$ = aggregate; - } - } else { - // This is a real function call - - TIntermAggregate *aggregate = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1); - aggregate->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) - aggregate->setUserDefined(); - aggregate->setName(fnCandidate->getMangledName()); - - // This needs to happen after the name is set - if (builtIn) - aggregate->setBuiltInFunctionPrecision(); - - $$ = aggregate; - - TQualifier qual; - for (size_t 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(); - } - } - } - } - } 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); - context->recover(); - } + YYERROR; } - delete fnCall; } ; @@ -484,6 +368,13 @@ function_identifier TFunction *function = new TFunction($1.string, type); $$ = function; } + | FIELD_SELECTION { + if (context->reservedErrorCheck(@1, *$1.string)) + context->recover(); + TType type(EbtVoid, EbpUndefined); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } ; unary_expression @@ -491,40 +382,14 @@ unary_expression $$ = $1; } | INC_OP unary_expression { - if (context->lValueErrorCheck(@1, "++", $2)) - context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, @1); - if ($$ == 0) { - context->unaryOpError(@1, "++", $2->getCompleteString()); - context->recover(); - $$ = $2; - } + $$ = context->addUnaryMathLValue(EOpPreIncrement, $2, @1); } | DEC_OP unary_expression { - if (context->lValueErrorCheck(@1, "--", $2)) - context->recover(); - $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, @1); - if ($$ == 0) { - context->unaryOpError(@1, "--", $2->getCompleteString()); - context->recover(); - $$ = $2; - } + $$ = context->addUnaryMathLValue(EOpPreDecrement, $2, @1); } | unary_operator unary_expression { if ($1.op != EOpNull) { - $$ = context->intermediate.addUnaryMath($1.op, $2, @1); - if ($$ == 0) { - const char* errorOp = ""; - switch($1.op) { - case EOpNegative: errorOp = "-"; break; - case EOpPositive: errorOp = "+"; break; - case EOpLogicalNot: errorOp = "!"; break; - default: break; - } - context->unaryOpError(@1, errorOp, $2->getCompleteString()); - context->recover(); - $$ = $2; - } + $$ = context->addUnaryMath($1.op, $2, @1); } else $$ = $2; } @@ -535,172 +400,117 @@ unary_operator : PLUS { $$.op = EOpPositive; } | DASH { $$.op = EOpNegative; } | BANG { $$.op = EOpLogicalNot; } + | TILDE { + ES3_ONLY("~", @$, "bit-wise operator"); + $$.op = EOpBitwiseNot; + } ; // Grammar Note: No '*' or '&' unary ops. Pointers are not supported. multiplicative_expression : unary_expression { $$ = $1; } | multiplicative_expression STAR unary_expression { - $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "*", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addBinaryMath(EOpMul, $1, $3, @2); } | multiplicative_expression SLASH unary_expression { - $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "/", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addBinaryMath(EOpDiv, $1, $3, @2); + } + | multiplicative_expression PERCENT unary_expression { + ES3_ONLY("%", @2, "integer modulus operator"); + $$ = context->addBinaryMath(EOpIMod, $1, $3, @2); } ; additive_expression : multiplicative_expression { $$ = $1; } | additive_expression PLUS multiplicative_expression { - $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "+", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addBinaryMath(EOpAdd, $1, $3, @2); } | additive_expression DASH multiplicative_expression { - $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "-", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addBinaryMath(EOpSub, $1, $3, @2); } ; shift_expression : additive_expression { $$ = $1; } + | shift_expression LEFT_OP additive_expression { + ES3_ONLY("<<", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitShiftLeft, $1, $3, @2); + } + | shift_expression RIGHT_OP additive_expression { + ES3_ONLY(">>", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitShiftRight, $1, $3, @2); + } ; relational_expression : shift_expression { $$ = $1; } | relational_expression LEFT_ANGLE shift_expression { - $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "<", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLessThan, $1, $3, @2); } | relational_expression RIGHT_ANGLE shift_expression { - $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, ">", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpGreaterThan, $1, $3, @2); } | relational_expression LE_OP shift_expression { - $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "<=", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLessThanEqual, $1, $3, @2); } | relational_expression GE_OP shift_expression { - $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, ">=", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpGreaterThanEqual, $1, $3, @2); } ; equality_expression : relational_expression { $$ = $1; } | equality_expression EQ_OP relational_expression { - $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "==", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpEqual, $1, $3, @2); } | equality_expression NE_OP relational_expression { - $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "!=", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpNotEqual, $1, $3, @2); } ; and_expression : equality_expression { $$ = $1; } + | and_expression AMPERSAND equality_expression { + ES3_ONLY("&", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitwiseAnd, $1, $3, @2); + } ; exclusive_or_expression : and_expression { $$ = $1; } + | exclusive_or_expression CARET and_expression { + ES3_ONLY("^", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitwiseXor, $1, $3, @2); + } ; inclusive_or_expression : exclusive_or_expression { $$ = $1; } + | inclusive_or_expression VERTICAL_BAR exclusive_or_expression { + ES3_ONLY("|", @2, "bit-wise operator"); + $$ = context->addBinaryMath(EOpBitwiseOr, $1, $3, @2); + } ; logical_and_expression : inclusive_or_expression { $$ = $1; } | logical_and_expression AND_OP inclusive_or_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "&&", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLogicalAnd, $1, $3, @2); } ; logical_xor_expression : logical_and_expression { $$ = $1; } | logical_xor_expression XOR_OP logical_and_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "^^", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLogicalXor, $1, $3, @2); } ; logical_or_expression : logical_xor_expression { $$ = $1; } | logical_or_expression OR_OP logical_xor_expression { - $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, @2); - if ($$ == 0) { - context->binaryOpError(@2, "||", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - ConstantUnion *unionArray = new ConstantUnion[1]; - unionArray->setBConst(false); - $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), @2); - } + $$ = context->addBinaryMathBooleanResult(EOpLogicalOr, $1, $3, @2); } ; @@ -727,12 +537,7 @@ assignment_expression | unary_expression assignment_operator assignment_expression { if (context->lValueErrorCheck(@2, "assign", $1)) context->recover(); - $$ = context->intermediate.addAssign($2.op, $1, $3, @2); - if ($$ == 0) { - context->assignError(@2, "assign", $1->getCompleteString(), $3->getCompleteString()); - context->recover(); - $$ = $1; - } + $$ = context->addAssign($2.op, $1, $3, @2); } ; @@ -740,8 +545,32 @@ assignment_operator : EQUAL { $$.op = EOpAssign; } | MUL_ASSIGN { $$.op = EOpMulAssign; } | DIV_ASSIGN { $$.op = EOpDivAssign; } + | MOD_ASSIGN { + ES3_ONLY("%=", @$, "integer modulus operator"); + $$.op = EOpIModAssign; + } | ADD_ASSIGN { $$.op = EOpAddAssign; } | SUB_ASSIGN { $$.op = EOpSubAssign; } + | LEFT_ASSIGN { + ES3_ONLY("<<=", @$, "bit-wise operator"); + $$.op = EOpBitShiftLeftAssign; + } + | RIGHT_ASSIGN { + ES3_ONLY(">>=", @$, "bit-wise operator"); + $$.op = EOpBitShiftRightAssign; + } + | AND_ASSIGN { + ES3_ONLY("&=", @$, "bit-wise operator"); + $$.op = EOpBitwiseAndAssign; + } + | XOR_ASSIGN { + ES3_ONLY("^=", @$, "bit-wise operator"); + $$.op = EOpBitwiseXorAssign; + } + | OR_ASSIGN { + ES3_ONLY("|=", @$, "bit-wise operator"); + $$.op = EOpBitwiseOrAssign; + } ; expression @@ -877,7 +706,7 @@ function_prototype { // Insert the unmangled name to detect potential future redefinition as a variable. TFunction *function = new TFunction(NewPoolTString($1->getName().c_str()), $1->getReturnType()); - context->symbolTable.getOuterLevel()->insert(function); + context->symbolTable.getOuterLevel()->insertUnmangled(function); } // @@ -1599,12 +1428,14 @@ statement | simple_statement { $$ = $1; } ; -// Grammar Note: No labeled statements; 'goto' is not supported. +// Grammar Note: Labeled statements for SWITCH only; 'goto' is not supported. simple_statement : declaration_statement { $$ = $1; } | expression_statement { $$ = $1; } | selection_statement { $$ = $1; } + | switch_statement { $$ = $1; } + | case_label { $$ = $1; } | iteration_statement { $$ = $1; } | jump_statement { $$ = $1; } ; @@ -1677,7 +1508,21 @@ selection_rest_statement } ; -// Grammar Note: No 'switch'. Switch statements not supported. +switch_statement + : SWITCH LEFT_PAREN expression RIGHT_PAREN { ++context->mSwitchNestingLevel; } compound_statement { + $$ = context->addSwitch($3, $6, @1); + --context->mSwitchNestingLevel; + } + ; + +case_label + : CASE constant_expression COLON { + $$ = context->addCase($2, @1); + } + | DEFAULT COLON { + $$ = context->addDefault(@1); + } + ; condition // In 1996 c++ draft, conditions can include single declarations @@ -1703,22 +1548,22 @@ condition ; iteration_statement - : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { + : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { context->symbolTable.pop(); $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, @1); - --context->loopNestingLevel; + --context->mLoopNestingLevel; } - | DO { ++context->loopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { + | DO { ++context->mLoopNestingLevel; } statement_with_scope WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { if (context->boolErrorCheck(@8, $6)) context->recover(); $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, @4); - --context->loopNestingLevel; + --context->mLoopNestingLevel; } - | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { + | FOR LEFT_PAREN { context->symbolTable.push(); ++context->mLoopNestingLevel; } 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); - --context->loopNestingLevel; + --context->mLoopNestingLevel; } ; @@ -1753,40 +1598,20 @@ for_rest_statement jump_statement : CONTINUE SEMICOLON { - if (context->loopNestingLevel <= 0) { - context->error(@1, "continue statement only allowed in loops", ""); - context->recover(); - } - $$ = context->intermediate.addBranch(EOpContinue, @1); + $$ = context->addBranch(EOpContinue, @1); } | BREAK SEMICOLON { - if (context->loopNestingLevel <= 0) { - context->error(@1, "break statement only allowed in loops", ""); - context->recover(); - } - $$ = context->intermediate.addBranch(EOpBreak, @1); + $$ = context->addBranch(EOpBreak, @1); } | RETURN SEMICOLON { - $$ = context->intermediate.addBranch(EOpReturn, @1); - if (context->currentFunctionType->getBasicType() != EbtVoid) { - context->error(@1, "non-void function must return a value", "return"); - context->recover(); - } + $$ = context->addBranch(EOpReturn, @1); } | RETURN expression SEMICOLON { - $$ = context->intermediate.addBranch(EOpReturn, $2, @1); - context->functionReturnsValue = true; - if (context->currentFunctionType->getBasicType() == EbtVoid) { - context->error(@1, "void function cannot return a value", "return"); - context->recover(); - } else if (*(context->currentFunctionType) != $2->getType()) { - context->error(@1, "function return is not matching type:", "return"); - context->recover(); - } + $$ = context->addBranch(EOpReturn, $2, @1); } | DISCARD SEMICOLON { FRAG_ONLY("discard", @1); - $$ = context->intermediate.addBranch(EOpKill, @1); + $$ = context->addBranch(EOpKill, @1); } ; @@ -1857,7 +1682,7 @@ function_definition // Remember the return type for later checking for RETURN statements. // context->currentFunctionType = &(prevDec->getReturnType()); - context->functionReturnsValue = false; + context->mFunctionReturnsValue = false; // // Insert parameters into the symbol table. @@ -1896,12 +1721,12 @@ function_definition } context->intermediate.setAggregateOperator(paramNodes, EOpParameters, @1); $1.intermAggregate = paramNodes; - context->loopNestingLevel = 0; + context->mLoopNestingLevel = 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) { + if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->mFunctionReturnsValue) { context->error(@1, "function does not return a value:", "", $1.function->getName().c_str()); context->recover(); } @@ -1923,5 +1748,5 @@ function_definition %% int glslang_parse(TParseContext* context) { - return yyparse(context); + return yyparse(context, context->scanner); } diff --git a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp index 00780f0454..07c50f0ce5 100644 --- a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp +++ b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp @@ -131,6 +131,25 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) case EOpDivAssign: out << "divide second child into first child"; break; + case EOpIModAssign: + out << "modulo second child into first child"; + break; + case EOpBitShiftLeftAssign: + out << "bit-wise shift first child left by second child"; + break; + case EOpBitShiftRightAssign: + out << "bit-wise shift first child right by second child"; + break; + case EOpBitwiseAndAssign: + out << "bit-wise and second child into first child"; + break; + case EOpBitwiseXorAssign: + out << "bit-wise xor second child into first child"; + break; + case EOpBitwiseOrAssign: + out << "bit-wise or second child into first child"; + break; + case EOpIndexDirect: out << "direct index"; break; @@ -159,6 +178,25 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) case EOpDiv: out << "divide"; break; + case EOpIMod: + out << "modulo"; + break; + case EOpBitShiftLeft: + out << "bit-wise shift left"; + break; + case EOpBitShiftRight: + out << "bit-wise shift right"; + break; + case EOpBitwiseAnd: + out << "bit-wise and"; + break; + case EOpBitwiseXor: + out << "bit-wise xor"; + break; + case EOpBitwiseOr: + out << "bit-wise or"; + break; + case EOpEqual: out << "Compare Equal"; break; @@ -211,6 +249,36 @@ bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node) out << "\n"; + // Special handling for direct indexes. Because constant + // unions are not aware they are struct indexes, treat them + // here where we have that contextual knowledge. + if (node->getOp() == EOpIndexDirectStruct || + node->getOp() == EOpIndexDirectInterfaceBlock) + { + mDepth++; + node->getLeft()->traverse(this); + mDepth--; + + TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion(); + ASSERT(intermConstantUnion); + + OutputTreeText(out, intermConstantUnion, mDepth + 1); + + // The following code finds the field name from the constant union + const ConstantUnion *constantUnion = intermConstantUnion->getUnionArrayPointer(); + const TStructure *structure = node->getLeft()->getType().getStruct(); + const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock(); + ASSERT(structure || interfaceBlock); + + const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields(); + + const TField *field = fields[constantUnion->getIConst()]; + + out << constantUnion->getIConst() << " (field '" << field->name() << "')"; + + return false; + } + return true; } @@ -226,6 +294,7 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) case EOpPositive: out << "Positive sign"; break; case EOpVectorLogicalNot: case EOpLogicalNot: out << "Negate conditional"; break; + case EOpBitwiseNot: out << "bit-wise not"; break; case EOpPostIncrement: out << "Post-Increment"; break; case EOpPostDecrement: out << "Post-Decrement"; break; @@ -241,6 +310,13 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) case EOpAcos: out << "arc cosine"; break; case EOpAtan: out << "arc tangent"; break; + case EOpSinh: out << "hyperbolic sine"; break; + case EOpCosh: out << "hyperbolic cosine"; break; + case EOpTanh: out << "hyperbolic tangent"; break; + case EOpAsinh: out << "arc hyperbolic sine"; break; + case EOpAcosh: out << "arc hyperbolic cosine"; break; + case EOpAtanh: out << "arc hyperbolic tangent"; break; + case EOpExp: out << "exp"; break; case EOpLog: out << "log"; break; case EOpExp2: out << "exp2"; break; @@ -251,8 +327,26 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) case EOpAbs: out << "Absolute value"; break; case EOpSign: out << "Sign"; break; case EOpFloor: out << "Floor"; break; + case EOpTrunc: out << "Truncate"; break; + case EOpRound: out << "Round"; break; + case EOpRoundEven: out << "Round half even"; break; case EOpCeil: out << "Ceiling"; break; case EOpFract: out << "Fraction"; break; + case EOpIsNan: out << "Is not a number"; break; + case EOpIsInf: out << "Is infinity"; break; + + case EOpFloatBitsToInt: out << "float bits to int"; break; + case EOpFloatBitsToUint: out << "float bits to uint"; break; + case EOpIntBitsToFloat: out << "int bits to float"; break; + case EOpUintBitsToFloat: out << "uint bits to float"; break; + + case EOpPackSnorm2x16: out << "pack Snorm 2x16"; break; + case EOpPackUnorm2x16: out << "pack Unorm 2x16"; break; + case EOpPackHalf2x16: out << "pack half 2x16"; break; + + case EOpUnpackSnorm2x16: out << "unpack Snorm 2x16"; break; + case EOpUnpackUnorm2x16: out << "unpack Unorm 2x16"; break; + case EOpUnpackHalf2x16: out << "unpack half 2x16"; break; case EOpLength: out << "length"; break; case EOpNormalize: out << "normalize"; break; @@ -260,6 +354,10 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) // case EOpDPdy: out << "dPdy"; break; // case EOpFwidth: out << "fwidth"; break; + case EOpDeterminant: out << "determinant"; break; + case EOpTranspose: out << "transpose"; break; + case EOpInverse: out << "inverse"; break; + case EOpAny: out << "any"; break; case EOpAll: out << "all"; break; @@ -326,6 +424,7 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) case EOpVectorNotEqual: out << "NotEqual"; break; case EOpMod: out << "mod"; break; + case EOpModf: out << "modf"; break; case EOpPow: out << "pow"; break; case EOpAtan: out << "arc tangent"; break; @@ -345,6 +444,8 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) case EOpRefract: out << "refract"; break; case EOpMul: out << "component-wise multiply"; break; + case EOpOuterProduct: out << "outer product"; break; + case EOpDeclaration: out << "Declaration: "; break; case EOpInvariantDeclaration: out << "Invariant Declaration: "; break; @@ -518,14 +619,13 @@ bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node) // // 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. +// type of node. Its children will still be processed. // -void TIntermediate::outputTree(TIntermNode *root) +void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink) { - if (root == NULL) - return; + TOutputTraverser it(infoSink); - TOutputTraverser it(mInfoSink.info); + ASSERT(root); root->traverse(&it); } diff --git a/src/3rdparty/angle/src/compiler/translator/intermediate.h b/src/3rdparty/angle/src/compiler/translator/intermediate.h deleted file mode 100644 index 3b7e7bd802..0000000000 --- a/src/3rdparty/angle/src/compiler/translator/intermediate.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (c) 2002-2014 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_TRANSLATOR_LOCAL_INTERMEDIATE_H_ -#define COMPILER_TRANSLATOR_LOCAL_INTERMEDIATE_H_ - -#include "compiler/translator/IntermNode.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(); - TIntermediate(TInfoSink &i) - : mInfoSink(i) { } - - TIntermSymbol *addSymbol( - int id, const TString &, const TType &, const TSourceLoc &); - TIntermTyped *addBinaryMath( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); - TIntermTyped *addAssign( - TOperator op, TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); - TIntermTyped *addIndex( - TOperator op, TIntermTyped *base, TIntermTyped *index, const TSourceLoc &); - TIntermTyped *addUnaryMath( - TOperator op, TIntermNode *child, const TSourceLoc &); - TIntermAggregate *growAggregate( - TIntermNode *left, TIntermNode *right, const TSourceLoc &); - TIntermAggregate *makeAggregate(TIntermNode *node, const TSourceLoc &); - TIntermAggregate *setAggregateOperator(TIntermNode *, TOperator, const TSourceLoc &); - TIntermNode *addSelection(TIntermTyped *cond, TIntermNodePair code, const TSourceLoc &); - TIntermTyped *addSelection( - TIntermTyped *cond, TIntermTyped *trueBlock, TIntermTyped *falseBlock, const TSourceLoc &); - TIntermTyped *addComma( - TIntermTyped *left, TIntermTyped *right, const TSourceLoc &); - TIntermConstantUnion *addConstantUnion(ConstantUnion *, const TType &, const TSourceLoc &); - // TODO(zmo): Get rid of default value. - bool parseConstTree(const TSourceLoc &, TIntermNode *, ConstantUnion *, - TOperator, TType, bool singleConstantParam = false); - TIntermNode *addLoop(TLoopType, TIntermNode *, TIntermTyped *, TIntermTyped *, - TIntermNode *, const TSourceLoc &); - TIntermBranch *addBranch(TOperator, const TSourceLoc &); - TIntermBranch *addBranch(TOperator, TIntermTyped *, const TSourceLoc &); - TIntermTyped *addSwizzle(TVectorFields &, const TSourceLoc &); - bool postProcess(TIntermNode *); - void remove(TIntermNode *); - void outputTree(TIntermNode *); - - private: - void operator=(TIntermediate &); // prevent assignments - - TInfoSink & mInfoSink; -}; - -#endif // COMPILER_TRANSLATOR_LOCAL_INTERMEDIATE_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/length_limits.h b/src/3rdparty/angle/src/compiler/translator/length_limits.h index df70ee5d84..88634381fa 100644 --- a/src/3rdparty/angle/src/compiler/translator/length_limits.h +++ b/src/3rdparty/angle/src/compiler/translator/length_limits.h @@ -8,8 +8,8 @@ // length_limits.h // -#if !defined(__LENGTH_LIMITS_H) -#define __LENGTH_LIMITS_H 1 +#ifndef COMPILER_TRANSLATOR_LENGTHLIMITS_H_ +#define COMPILER_TRANSLATOR_LENGTHLIMITS_H_ #include "GLSLANG/ShaderLang.h" @@ -18,4 +18,4 @@ size_t GetGlobalMaxTokenSize(ShShaderSpec spec); -#endif // !(defined(__LENGTH_LIMITS_H) +#endif // COMPILER_TRANSLATOR_LENGTHLIMITS_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h index 80d5f7fa7f..b8c7e82956 100644 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h +++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictFragmentShaderTiming.h @@ -4,35 +4,36 @@ // found in the LICENSE file. // -#ifndef COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ -#define COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ +#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ +#define COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ #include "compiler/translator/IntermNode.h" #include "compiler/translator/depgraph/DependencyGraph.h" class TInfoSinkBase; -class RestrictFragmentShaderTiming : TDependencyGraphTraverser { -public: - RestrictFragmentShaderTiming(TInfoSinkBase& sink); - void enforceRestrictions(const TDependencyGraph& graph); +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); + void visitArgument(TGraphArgument *parameter) override; + void visitSelection(TGraphSelection *selection) override; + void visitLoop(TGraphLoop *loop) override; + void visitLogicalOp(TGraphLogicalOp *logicalOp) override; -private: - void beginError(const TIntermNode* node); - void validateUserDefinedFunctionCallUsage(const TDependencyGraph& graph); - bool isSamplingOp(const TIntermAggregate* intermFunctionCall) const; + private: + void beginError(const TIntermNode *node); + void validateUserDefinedFunctionCallUsage(const TDependencyGraph &graph); + bool isSamplingOp(const TIntermAggregate *intermFunctionCall) const; - TInfoSinkBase& mSink; + TInfoSinkBase &mSink; int mNumErrors; typedef std::set StringSet; StringSet mSamplingOps; }; -#endif // COMPILER_TIMING_RESTRICT_FRAGMENT_SHADER_TIMING_H_ +#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTFRAGMENTSHADERTIMING_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h index a6263567b4..74bfd0b5c2 100644 --- a/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h +++ b/src/3rdparty/angle/src/compiler/translator/timing/RestrictVertexShaderTiming.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ -#define COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ +#ifndef COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ +#define COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ #include "compiler/translator/IntermNode.h" #include "compiler/translator/InfoSink.h" @@ -28,4 +28,4 @@ private: int mNumErrors; }; -#endif // COMPILER_TIMING_RESTRICT_VERTEX_SHADER_TIMING_H_ +#endif // COMPILER_TRANSLATOR_TIMING_RESTRICTVERTEXSHADERTIMING_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/util.cpp b/src/3rdparty/angle/src/compiler/translator/util.cpp index 8cc06a658a..42a995ee6f 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.cpp +++ b/src/3rdparty/angle/src/compiler/translator/util.cpp @@ -307,7 +307,7 @@ void GetVariableTraverser::setTypeSpecificInfo( break; case EvqVaryingIn: case EvqVaryingOut: - if (mSymbolTable.isVaryingInvariant(name)) + if (mSymbolTable.isVaryingInvariant(std::string(name.c_str()))) { variable->isInvariant = true; } diff --git a/src/3rdparty/angle/src/compiler/translator/util.h b/src/3rdparty/angle/src/compiler/translator/util.h index fb5308759e..68bae66168 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.h +++ b/src/3rdparty/angle/src/compiler/translator/util.h @@ -4,8 +4,8 @@ // found in the LICENSE file. // -#ifndef COMPILER_UTIL_H -#define COMPILER_UTIL_H +#ifndef COMPILER_TRANSLATOR_UTIL_H_ +#define COMPILER_TRANSLATOR_UTIL_H_ #include @@ -37,7 +37,7 @@ bool IsVarying(TQualifier qualifier); InterpolationType GetInterpolationType(TQualifier qualifier); TString ArrayString(const TType &type); -class GetVariableTraverser +class GetVariableTraverser : angle::NonCopyable { public: GetVariableTraverser(const TSymbolTable &symbolTable); @@ -57,10 +57,8 @@ class GetVariableTraverser const TType &type, const TString &name, VarT *variable) {} const TSymbolTable &mSymbolTable; - - DISALLOW_COPY_AND_ASSIGN(GetVariableTraverser); }; } -#endif // COMPILER_UTIL_H +#endif // COMPILER_TRANSLATOR_UTIL_H_ diff --git a/src/3rdparty/angle/src/id/commit.h b/src/3rdparty/angle/src/id/commit.h new file mode 100644 index 0000000000..fd9a011d0c --- /dev/null +++ b/src/3rdparty/angle/src/id/commit.h @@ -0,0 +1,3 @@ +#define ANGLE_COMMIT_HASH "99f075dade7c" +#define ANGLE_COMMIT_HASH_SIZE 12 +#define ANGLE_COMMIT_DATE "2015-04-02 17:07:24 +0000" diff --git a/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp b/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp new file mode 100644 index 0000000000..651a012037 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2014 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 "libANGLE/AttributeMap.h" + +namespace egl +{ + +AttributeMap::AttributeMap() +{ +} + +AttributeMap::AttributeMap(const EGLint *attributes) +{ + if (attributes) + { + for (const EGLint *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) + { + insert(curAttrib[0], curAttrib[1]); + } + } +} + +void AttributeMap::insert(EGLint key, EGLint value) +{ + mAttributes[key] = value; +} + +bool AttributeMap::contains(EGLint key) const +{ + return (mAttributes.find(key) != mAttributes.end()); +} + +EGLint AttributeMap::get(EGLint key, EGLint defaultValue) const +{ + std::map::const_iterator iter = mAttributes.find(key); + return (mAttributes.find(key) != mAttributes.end()) ? iter->second : defaultValue; +} + +AttributeMap::const_iterator AttributeMap::begin() const +{ + return mAttributes.begin(); +} + +AttributeMap::const_iterator AttributeMap::end() const +{ + return mAttributes.end(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/AttributeMap.h b/src/3rdparty/angle/src/libANGLE/AttributeMap.h new file mode 100644 index 0000000000..72b6edc3c7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/AttributeMap.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2014 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 LIBANGLE_ATTRIBUTEMAP_H_ +#define LIBANGLE_ATTRIBUTEMAP_H_ + + +#include + +#include + +namespace egl +{ + +class AttributeMap +{ + public: + AttributeMap(); + explicit AttributeMap(const EGLint *attributes); + + virtual void insert(EGLint key, EGLint value); + virtual bool contains(EGLint key) const; + virtual EGLint get(EGLint key, EGLint defaultValue) const; + + typedef std::map::const_iterator const_iterator; + + const_iterator begin() const; + const_iterator end() const; + + private: + std::map mAttributes; +}; + +} + +#endif // LIBANGLE_ATTRIBUTEMAP_H_ diff --git a/src/3rdparty/angle/src/libANGLE/BinaryStream.h b/src/3rdparty/angle/src/libANGLE/BinaryStream.h new file mode 100644 index 0000000000..50392e1d3f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/BinaryStream.h @@ -0,0 +1,218 @@ +// +// 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 LIBANGLE_BINARYSTREAM_H_ +#define LIBANGLE_BINARYSTREAM_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" + +#include +#include +#include +#include + +template +void StaticAssertIsFundamental() +{ + // c++11 STL is not available on OSX or Android +#if !defined(ANGLE_PLATFORM_APPLE) && !defined(ANGLE_PLATFORM_ANDROID) + static_assert(std::is_fundamental::value, "T must be a fundamental type."); +#else + union { T dummy; } dummy; + static_cast(dummy); +#endif +} + +namespace gl +{ + +class BinaryInputStream : angle::NonCopyable +{ + public: + BinaryInputStream(const void *data, size_t length) + { + mError = false; + mOffset = 0; + mData = static_cast(data); + mLength = length; + } + + // readInt will generate an error for bool types + template + IntT readInt() + { + int value; + read(&value); + return static_cast(value); + } + + template + void readInt(IntT *outValue) + { + *outValue = readInt(); + } + + bool readBool() + { + int value; + read(&value); + return (value > 0); + } + + void readBool(bool *outValue) + { + *outValue = readBool(); + } + + void readBytes(unsigned char outArray[], size_t count) + { + read(outArray, count); + } + + std::string readString() + { + std::string outString; + readString(&outString); + return outString; + } + + void readString(std::string *v) + { + size_t length; + readInt(&length); + + if (mError) + { + return; + } + + if (mOffset + length > mLength) + { + mError = true; + return; + } + + v->assign(reinterpret_cast(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; + } + + const uint8_t *data() + { + return mData; + } + + private: + bool mError; + size_t mOffset; + const uint8_t *mData; + size_t mLength; + + template + void read(T *v, size_t num) + { + StaticAssertIsFundamental(); + + 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); + } + +}; + +class BinaryOutputStream : angle::NonCopyable +{ + public: + BinaryOutputStream() + { + } + + // writeInt also handles bool types + template + void writeInt(IntT param) + { + ASSERT(rx::IsIntegerCastSafe(param)); + int intValue = static_cast(param); + write(&intValue, 1); + } + + void writeString(const std::string &v) + { + writeInt(v.length()); + write(v.c_str(), v.length()); + } + + void writeBytes(const unsigned char *bytes, size_t count) + { + write(bytes, count); + } + + size_t length() const + { + return mData.size(); + } + + const void* data() const + { + return mData.size() ? &mData[0] : NULL; + } + + private: + std::vector mData; + + template + void write(const T *v, size_t num) + { + StaticAssertIsFundamental(); + const char *asBytes = reinterpret_cast(v); + mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); + } + +}; +} + +#endif // LIBANGLE_BINARYSTREAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.cpp b/src/3rdparty/angle/src/libANGLE/Buffer.cpp new file mode 100644 index 0000000000..f394a6b1d1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Buffer.cpp @@ -0,0 +1,121 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/Buffer.h" +#include "libANGLE/renderer/BufferImpl.h" +#include "libANGLE/renderer/Renderer.h" + +namespace gl +{ + +Buffer::Buffer(rx::BufferImpl *impl, GLuint id) + : RefCountObject(id), + mBuffer(impl), + mUsage(GL_DYNAMIC_DRAW), + mSize(0), + mAccessFlags(0), + mMapped(GL_FALSE), + mMapPointer(NULL), + mMapOffset(0), + mMapLength(0) +{ +} + +Buffer::~Buffer() +{ + SafeDelete(mBuffer); +} + +Error Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) +{ + gl::Error error = mBuffer->setData(data, size, usage); + if (error.isError()) + { + return error; + } + + mIndexRangeCache.clear(); + mUsage = usage; + mSize = size; + + return error; +} + +Error Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) +{ + gl::Error error = mBuffer->setSubData(data, size, offset); + if (error.isError()) + { + return error; + } + + mIndexRangeCache.invalidateRange(offset, size); + + return error; +} + +Error Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + gl::Error error = mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size); + if (error.isError()) + { + return error; + } + + mIndexRangeCache.invalidateRange(destOffset, size); + + return error; +} + +Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) +{ + ASSERT(!mMapped); + ASSERT(offset + length <= mSize); + + Error error = mBuffer->map(offset, length, access, &mMapPointer); + if (error.isError()) + { + mMapPointer = NULL; + return error; + } + + mMapped = GL_TRUE; + mMapOffset = static_cast(offset); + mMapLength = static_cast(length); + mAccessFlags = static_cast(access); + + if ((access & GL_MAP_WRITE_BIT) > 0) + { + mIndexRangeCache.invalidateRange(offset, length); + } + + return error; +} + +Error Buffer::unmap() +{ + ASSERT(mMapped); + + Error error = mBuffer->unmap(); + if (error.isError()) + { + return error; + } + + mMapped = GL_FALSE; + mMapPointer = NULL; + mMapOffset = 0; + mMapLength = 0; + mAccessFlags = 0; + + return error; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Buffer.h b/src/3rdparty/angle/src/libANGLE/Buffer.h new file mode 100644 index 0000000000..6793028e3b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Buffer.h @@ -0,0 +1,70 @@ +// +// Copyright (c) 2002-2014 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 LIBANGLE_BUFFER_H_ +#define LIBANGLE_BUFFER_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/renderer/IndexRangeCache.h" + +#include "common/angleutils.h" + +namespace rx +{ +class BufferImpl; +}; + +namespace gl +{ + +class Buffer : public RefCountObject +{ + public: + Buffer(rx::BufferImpl *impl, GLuint id); + + virtual ~Buffer(); + + Error bufferData(const void *data, GLsizeiptr size, GLenum usage); + Error bufferSubData(const void *data, GLsizeiptr size, GLintptr offset); + Error copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + Error mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access); + Error unmap(); + + GLenum getUsage() const { return mUsage; } + GLint getAccessFlags() const { return mAccessFlags; } + GLboolean isMapped() const { return mMapped; } + GLvoid *getMapPointer() const { return mMapPointer; } + GLint64 getMapOffset() const { return mMapOffset; } + GLint64 getMapLength() const { return mMapLength; } + GLint64 getSize() const { return mSize; } + + rx::BufferImpl *getImplementation() const { return mBuffer; } + + rx::IndexRangeCache *getIndexRangeCache() { return &mIndexRangeCache; } + const rx::IndexRangeCache *getIndexRangeCache() const { return &mIndexRangeCache; } + + private: + rx::BufferImpl *mBuffer; + + GLenum mUsage; + GLint64 mSize; + GLint mAccessFlags; + GLboolean mMapped; + GLvoid *mMapPointer; + GLint64 mMapOffset; + GLint64 mMapLength; + + rx::IndexRangeCache mIndexRangeCache; +}; + +} + +#endif // LIBANGLE_BUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Caps.cpp b/src/3rdparty/angle/src/libANGLE/Caps.cpp new file mode 100644 index 0000000000..086d0a02a2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Caps.cpp @@ -0,0 +1,527 @@ +// +// Copyright (c) 2014 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 "libANGLE/Caps.h" +#include "common/debug.h" +#include "common/angleutils.h" + +#include "angle_gl.h" + +#include +#include + +static void InsertExtensionString(const std::string &extension, bool supported, std::vector *extensionVector) +{ + if (supported) + { + extensionVector->push_back(extension); + } +} + +namespace gl +{ + +TextureCaps::TextureCaps() + : texturable(false), + filterable(false), + renderable(false), + sampleCounts() +{ +} + +GLuint TextureCaps::getMaxSamples() const +{ + return !sampleCounts.empty() ? *sampleCounts.rbegin() : 0; +} + +GLuint TextureCaps::getNearestSamples(GLuint requestedSamples) const +{ + if (requestedSamples == 0) + { + return 0; + } + + for (SupportedSampleSet::const_iterator i = sampleCounts.begin(); i != sampleCounts.end(); i++) + { + GLuint samples = *i; + if (samples >= requestedSamples) + { + return samples; + } + } + + return 0; +} + +void TextureCapsMap::insert(GLenum internalFormat, const TextureCaps &caps) +{ + mCapsMap.insert(std::make_pair(internalFormat, caps)); +} + +void TextureCapsMap::remove(GLenum internalFormat) +{ + InternalFormatToCapsMap::iterator i = mCapsMap.find(internalFormat); + if (i != mCapsMap.end()) + { + mCapsMap.erase(i); + } +} + +const TextureCaps &TextureCapsMap::get(GLenum internalFormat) const +{ + static TextureCaps defaultUnsupportedTexture; + InternalFormatToCapsMap::const_iterator iter = mCapsMap.find(internalFormat); + return (iter != mCapsMap.end()) ? iter->second : defaultUnsupportedTexture; +} + +TextureCapsMap::const_iterator TextureCapsMap::begin() const +{ + return mCapsMap.begin(); +} + +TextureCapsMap::const_iterator TextureCapsMap::end() const +{ + return mCapsMap.end(); +} + +size_t TextureCapsMap::size() const +{ + return mCapsMap.size(); +} + +Extensions::Extensions() + : elementIndexUint(false), + packedDepthStencil(false), + getProgramBinary(false), + rgb8rgba8(false), + textureFormatBGRA8888(false), + readFormatBGRA(false), + pixelBufferObject(false), + mapBuffer(false), + mapBufferRange(false), + textureHalfFloat(false), + textureHalfFloatLinear(false), + textureFloat(false), + textureFloatLinear(false), + textureRG(false), + textureCompressionDXT1(false), + textureCompressionDXT3(false), + textureCompressionDXT5(false), + depthTextures(false), + textureNPOT(false), + drawBuffers(false), + textureStorage(false), + textureFilterAnisotropic(false), + maxTextureAnisotropy(false), + occlusionQueryBoolean(false), + fence(false), + timerQuery(false), + robustness(false), + blendMinMax(false), + framebufferBlit(false), + framebufferMultisample(false), + instancedArrays(false), + packReverseRowOrder(false), + standardDerivatives(false), + shaderTextureLOD(false), + shaderFramebufferFetch(false), + ARMshaderFramebufferFetch(false), + NVshaderFramebufferFetch(false), + fragDepth(false), + textureUsage(false), + translatedShaderSource(false), + colorBufferFloat(false) +{ +} + +std::vector Extensions::getStrings() const +{ + std::vector extensionStrings; + + // | Extension name | Supported flag | Output vector | + InsertExtensionString("GL_OES_element_index_uint", elementIndexUint, &extensionStrings); + InsertExtensionString("GL_OES_packed_depth_stencil", packedDepthStencil, &extensionStrings); + InsertExtensionString("GL_OES_get_program_binary", getProgramBinary, &extensionStrings); + InsertExtensionString("GL_OES_rgb8_rgba8", rgb8rgba8, &extensionStrings); + InsertExtensionString("GL_EXT_texture_format_BGRA8888", textureFormatBGRA8888, &extensionStrings); + InsertExtensionString("GL_EXT_read_format_bgra", readFormatBGRA, &extensionStrings); + InsertExtensionString("GL_NV_pixel_buffer_object", pixelBufferObject, &extensionStrings); + InsertExtensionString("GL_OES_mapbuffer", mapBuffer, &extensionStrings); + InsertExtensionString("GL_EXT_map_buffer_range", mapBufferRange, &extensionStrings); + InsertExtensionString("GL_OES_texture_half_float", textureHalfFloat, &extensionStrings); + InsertExtensionString("GL_OES_texture_half_float_linear", textureHalfFloatLinear, &extensionStrings); + InsertExtensionString("GL_OES_texture_float", textureFloat, &extensionStrings); + InsertExtensionString("GL_OES_texture_float_linear", textureFloatLinear, &extensionStrings); + InsertExtensionString("GL_EXT_texture_rg", textureRG, &extensionStrings); + InsertExtensionString("GL_EXT_texture_compression_dxt1", textureCompressionDXT1, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_compression_dxt3", textureCompressionDXT3, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_compression_dxt5", textureCompressionDXT5, &extensionStrings); + InsertExtensionString("GL_EXT_sRGB", sRGB, &extensionStrings); + InsertExtensionString("GL_ANGLE_depth_texture", depthTextures, &extensionStrings); + InsertExtensionString("GL_EXT_texture_storage", textureStorage, &extensionStrings); + InsertExtensionString("GL_OES_texture_npot", textureNPOT, &extensionStrings); + InsertExtensionString("GL_EXT_draw_buffers", drawBuffers, &extensionStrings); + InsertExtensionString("GL_EXT_texture_filter_anisotropic", textureFilterAnisotropic, &extensionStrings); + InsertExtensionString("GL_EXT_occlusion_query_boolean", occlusionQueryBoolean, &extensionStrings); + InsertExtensionString("GL_NV_fence", fence, &extensionStrings); + InsertExtensionString("GL_ANGLE_timer_query", timerQuery, &extensionStrings); + InsertExtensionString("GL_EXT_robustness", robustness, &extensionStrings); + InsertExtensionString("GL_EXT_blend_minmax", blendMinMax, &extensionStrings); + InsertExtensionString("GL_ANGLE_framebuffer_blit", framebufferBlit, &extensionStrings); + InsertExtensionString("GL_ANGLE_framebuffer_multisample", framebufferMultisample, &extensionStrings); + InsertExtensionString("GL_ANGLE_instanced_arrays", instancedArrays, &extensionStrings); + InsertExtensionString("GL_ANGLE_pack_reverse_row_order", packReverseRowOrder, &extensionStrings); + InsertExtensionString("GL_OES_standard_derivatives", standardDerivatives, &extensionStrings); + InsertExtensionString("GL_EXT_shader_texture_lod", shaderTextureLOD, &extensionStrings); + InsertExtensionString("GL_NV_shader_framebuffer_fetch", NVshaderFramebufferFetch, &extensionStrings); + InsertExtensionString("GL_ARM_shader_framebuffer_fetch", ARMshaderFramebufferFetch,&extensionStrings); + InsertExtensionString("GL_EXT_shader_framebuffer_fetch", shaderFramebufferFetch, &extensionStrings); + InsertExtensionString("GL_EXT_frag_depth", fragDepth, &extensionStrings); + InsertExtensionString("GL_ANGLE_texture_usage", textureUsage, &extensionStrings); + InsertExtensionString("GL_ANGLE_translated_shader_source", translatedShaderSource, &extensionStrings); + InsertExtensionString("GL_EXT_color_buffer_float", colorBufferFloat, &extensionStrings); + + return extensionStrings; +} + +static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vector &requiredFormats, + bool requiresTexturing, bool requiresFiltering, bool requiresRendering) +{ + for (size_t i = 0; i < requiredFormats.size(); i++) + { + const TextureCaps &cap = textureCaps.get(requiredFormats[i]); + + if (requiresTexturing && !cap.texturable) + { + return false; + } + + if (requiresFiltering && !cap.filterable) + { + return false; + } + + if (requiresRendering && !cap.renderable) + { + return false; + } + } + + return true; +} + +// Checks for GL_OES_rgb8_rgba8 support +static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB8); + requiredFormats.push_back(GL_RGBA8); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, true); +} + +// Checks for GL_EXT_texture_format_BGRA8888 support +static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_BGRA8_EXT); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, true); +} + +// Checks for GL_OES_texture_half_float support +static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB16F); + requiredFormats.push_back(GL_RGBA16F); + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + +// Checks for GL_OES_texture_half_float_linear support +static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB16F); + requiredFormats.push_back(GL_RGBA16F); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Checks for GL_OES_texture_float support +static bool DetermineFloatTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB32F); + requiredFormats.push_back(GL_RGBA32F); + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + +// Checks for GL_OES_texture_float_linear support +static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_RGB32F); + requiredFormats.push_back(GL_RGBA32F); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Checks for GL_EXT_texture_rg support +static bool DetermineRGTextureSupport(const TextureCapsMap &textureCaps, bool checkHalfFloatFormats, bool checkFloatFormats) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_R8); + requiredFormats.push_back(GL_RG8); + if (checkHalfFloatFormats) + { + requiredFormats.push_back(GL_R16F); + requiredFormats.push_back(GL_RG16F); + } + if (checkFloatFormats) + { + requiredFormats.push_back(GL_R32F); + requiredFormats.push_back(GL_RG32F); + } + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_EXT_texture_compression_dxt1 +static bool DetermineDXT1TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt3 +static bool DetermineDXT3TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt5 +static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, false); +} + +// Check for GL_ANGLE_texture_compression_dxt5 +static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFilterFormats; + requiredFilterFormats.push_back(GL_SRGB8); + requiredFilterFormats.push_back(GL_SRGB8_ALPHA8); + + std::vector requiredRenderFormats; + requiredRenderFormats.push_back(GL_SRGB8_ALPHA8); + + return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) && + GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true); +} + +// Check for GL_ANGLE_depth_texture +static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_DEPTH_COMPONENT16); + requiredFormats.push_back(GL_DEPTH_COMPONENT32_OES); + requiredFormats.push_back(GL_DEPTH24_STENCIL8_OES); + + return GetFormatSupport(textureCaps, requiredFormats, true, true, true); +} + +// Check for GL_EXT_color_buffer_float +static bool DetermineColorBufferFloatSupport(const TextureCapsMap &textureCaps) +{ + std::vector requiredFormats; + requiredFormats.push_back(GL_R16F); + requiredFormats.push_back(GL_RG16F); + requiredFormats.push_back(GL_RGBA16F); + requiredFormats.push_back(GL_R32F); + requiredFormats.push_back(GL_RG32F); + requiredFormats.push_back(GL_RGBA32F); + requiredFormats.push_back(GL_R11F_G11F_B10F); + + return GetFormatSupport(textureCaps, requiredFormats, true, false, true); +} + +void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) +{ + rgb8rgba8 = DetermineRGB8AndRGBA8TextureSupport(textureCaps); + textureFormatBGRA8888 = DetermineBGRA8TextureSupport(textureCaps); + textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps); + textureHalfFloatLinear = DetermineHalfFloatTextureFilteringSupport(textureCaps); + textureFloat = DetermineFloatTextureSupport(textureCaps); + textureFloatLinear = DetermineFloatTextureFilteringSupport(textureCaps); + textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat); + textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps); + textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps); + textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps); + sRGB = DetermineSRGBTextureSupport(textureCaps); + depthTextures = DetermineDepthTextureSupport(textureCaps); + colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps); +} + +TypePrecision::TypePrecision() +{ + range[0] = 0; + range[1] = 0; + precision = 0; +} + +void TypePrecision::setIEEEFloat() +{ + range[0] = 127; + range[1] = 127; + precision = 23; +} + +void TypePrecision::setTwosComplementInt(unsigned int bits) +{ + range[0] = GLint(bits) - 1; + range[1] = GLint(bits) - 2; + precision = 0; +} + +void TypePrecision::setSimulatedInt(unsigned int r) +{ + range[0] = GLint(r); + range[1] = GLint(r); + precision = 0; +} + +void TypePrecision::get(GLint *returnRange, GLint *returnPrecision) const +{ + returnRange[0] = range[0]; + returnRange[1] = range[1]; + *returnPrecision = precision; +} + +Caps::Caps() + : maxElementIndex(0), + max3DTextureSize(0), + max2DTextureSize(0), + maxArrayTextureLayers(0), + maxLODBias(0), + maxCubeMapTextureSize(0), + maxRenderbufferSize(0), + maxDrawBuffers(0), + maxColorAttachments(0), + maxViewportWidth(0), + maxViewportHeight(0), + minAliasedPointSize(0), + maxAliasedPointSize(0), + minAliasedLineWidth(0), + // Table 6.29 + maxElementsIndices(0), + maxElementsVertices(0), + maxServerWaitTimeout(0), + // Table 6.31 + maxVertexAttributes(0), + maxVertexUniformComponents(0), + maxVertexUniformVectors(0), + maxVertexUniformBlocks(0), + maxVertexOutputComponents(0), + maxVertexTextureImageUnits(0), + // Table 6.32 + maxFragmentUniformComponents(0), + maxFragmentUniformVectors(0), + maxFragmentUniformBlocks(0), + maxFragmentInputComponents(0), + maxTextureImageUnits(0), + minProgramTexelOffset(0), + maxProgramTexelOffset(0), + + maxUniformBufferBindings(0), + maxUniformBlockSize(0), + uniformBufferOffsetAlignment(0), + maxCombinedUniformBlocks(0), + maxCombinedVertexUniformComponents(0), + maxCombinedFragmentUniformComponents(0), + maxVaryingComponents(0), + maxVaryingVectors(0), + maxCombinedTextureImageUnits(0), + + maxTransformFeedbackInterleavedComponents(0), + maxTransformFeedbackSeparateAttributes(0), + maxTransformFeedbackSeparateComponents(0) +{ +} + +} + +namespace egl +{ + +Caps::Caps() + : textureNPOT(false) +{ +} + +DisplayExtensions::DisplayExtensions() + : createContextRobustness(false), + d3dShareHandleClientBuffer(false), + surfaceD3DTexture2DShareHandle(false), + querySurfacePointer(false), + windowFixedSize(false), + postSubBuffer(false), + createContext(false) +{ +} + +std::vector DisplayExtensions::getStrings() const +{ + std::vector extensionStrings; + + // | Extension name | Supported flag | Output vector | + InsertExtensionString("EGL_EXT_create_context_robustness", createContextRobustness, &extensionStrings); + InsertExtensionString("EGL_ANGLE_d3d_share_handle_client_buffer", d3dShareHandleClientBuffer, &extensionStrings); + InsertExtensionString("EGL_ANGLE_surface_d3d_texture_2d_share_handle", surfaceD3DTexture2DShareHandle, &extensionStrings); + InsertExtensionString("EGL_ANGLE_query_surface_pointer", querySurfacePointer, &extensionStrings); + InsertExtensionString("EGL_ANGLE_window_fixed_size", windowFixedSize, &extensionStrings); + InsertExtensionString("EGL_NV_post_sub_buffer", postSubBuffer, &extensionStrings); + InsertExtensionString("EGL_KHR_create_context", createContext, &extensionStrings); + + return extensionStrings; +} + + +ClientExtensions::ClientExtensions() + : clientExtensions(false), + platformBase(false), + platformANGLE(false), + platformANGLED3D(false), + platformANGLEOpenGL(false) +{ +} + +std::vector ClientExtensions::getStrings() const +{ + std::vector extensionStrings; + + // | Extension name | Supported flag | Output vector | + InsertExtensionString("EGL_EXT_client_extensions", clientExtensions, &extensionStrings); + InsertExtensionString("EGL_EXT_platform_base", platformBase, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle", platformANGLE, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle_d3d", platformANGLED3D, &extensionStrings); + InsertExtensionString("EGL_ANGLE_platform_angle_opengl", platformANGLEOpenGL, &extensionStrings); + + return extensionStrings; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Caps.h b/src/3rdparty/angle/src/libANGLE/Caps.h new file mode 100644 index 0000000000..37a634226a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Caps.h @@ -0,0 +1,374 @@ +// +// Copyright (c) 2014 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 LIBANGLE_CAPS_H_ +#define LIBANGLE_CAPS_H_ + +#include "angle_gl.h" +#include "libANGLE/angletypes.h" + +#include +#include +#include +#include + +namespace gl +{ + +typedef std::set SupportedSampleSet; + +struct TextureCaps +{ + TextureCaps(); + + // Supports for basic texturing: glTexImage, glTexSubImage, etc + bool texturable; + + // Support for linear or anisotropic filtering + bool filterable; + + // Support for being used as a framebuffer attachment or renderbuffer format + bool renderable; + + SupportedSampleSet sampleCounts; + + // Get the maximum number of samples supported + GLuint getMaxSamples() const; + + // Get the number of supported samples that is at least as many as requested. Returns 0 if + // there are no sample counts available + GLuint getNearestSamples(GLuint requestedSamples) const; +}; + +class TextureCapsMap +{ + public: + typedef std::map::const_iterator const_iterator; + + void insert(GLenum internalFormat, const TextureCaps &caps); + void remove(GLenum internalFormat); + + const TextureCaps &get(GLenum internalFormat) const; + + const_iterator begin() const; + const_iterator end() const; + + size_t size() const; + + private: + typedef std::map InternalFormatToCapsMap; + InternalFormatToCapsMap mCapsMap; +}; + +struct Extensions +{ + Extensions(); + + // Generate a vector of supported extension strings + std::vector getStrings() const; + + // Set all texture related extension support based on the supported textures. + // Determines support for: + // GL_OES_rgb8_rgba8 + // GL_EXT_texture_format_BGRA8888 + // GL_OES_texture_half_float, GL_OES_texture_half_float_linear + // GL_OES_texture_float, GL_OES_texture_float_linear + // GL_EXT_texture_rg + // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3, GL_ANGLE_texture_compression_dxt5 + // GL_EXT_sRGB + // GL_ANGLE_depth_texture + // GL_EXT_color_buffer_float + void setTextureExtensionSupport(const TextureCapsMap &textureCaps); + + // ES2 Extension support + + // GL_OES_element_index_uint + bool elementIndexUint; + + // GL_OES_packed_depth_stencil + bool packedDepthStencil; + + // GL_OES_get_program_binary + bool getProgramBinary; + + // GL_OES_rgb8_rgba8 + // Implies that TextureCaps for GL_RGB8 and GL_RGBA8 exist + bool rgb8rgba8; + + // GL_EXT_texture_format_BGRA8888 + // Implies that TextureCaps for GL_BGRA8 exist + bool textureFormatBGRA8888; + + // GL_EXT_read_format_bgra + bool readFormatBGRA; + + // GL_NV_pixel_buffer_object + bool pixelBufferObject; + + // GL_OES_mapbuffer and GL_EXT_map_buffer_range + bool mapBuffer; + bool mapBufferRange; + + // GL_OES_texture_half_float and GL_OES_texture_half_float_linear + // Implies that TextureCaps for GL_RGB16F, GL_RGBA16F, GL_ALPHA32F_EXT, GL_LUMINANCE32F_EXT and + // GL_LUMINANCE_ALPHA32F_EXT exist + bool textureHalfFloat; + bool textureHalfFloatLinear; + + // GL_OES_texture_float and GL_OES_texture_float_linear + // Implies that TextureCaps for GL_RGB32F, GL_RGBA32F, GL_ALPHA16F_EXT, GL_LUMINANCE16F_EXT and + // GL_LUMINANCE_ALPHA16F_EXT exist + bool textureFloat; + bool textureFloatLinear; + + // GL_EXT_texture_rg + // Implies that TextureCaps for GL_R8, GL_RG8 (and floating point R/RG texture formats if floating point extensions + // are also present) exist + bool textureRG; + + // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3 and GL_ANGLE_texture_compression_dxt5 + // Implies that TextureCaps for GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + // GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE and GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE + bool textureCompressionDXT1; + bool textureCompressionDXT3; + bool textureCompressionDXT5; + + // GL_EXT_sRGB + // Implies that TextureCaps for GL_SRGB8_ALPHA8 and GL_SRGB8 exist + // TODO: Don't advertise this extension in ES3 + bool sRGB; + + // GL_ANGLE_depth_texture + bool depthTextures; + + // GL_EXT_texture_storage + bool textureStorage; + + // GL_OES_texture_npot + bool textureNPOT; + + // GL_EXT_draw_buffers + bool drawBuffers; + + // GL_EXT_texture_filter_anisotropic + bool textureFilterAnisotropic; + GLfloat maxTextureAnisotropy; + + // GL_EXT_occlusion_query_boolean + bool occlusionQueryBoolean; + + // GL_NV_fence + bool fence; + + // GL_ANGLE_timer_query + bool timerQuery; + + // GL_EXT_robustness + bool robustness; + + // GL_EXT_blend_minmax + bool blendMinMax; + + // GL_ANGLE_framebuffer_blit + bool framebufferBlit; + + // GL_ANGLE_framebuffer_multisample + bool framebufferMultisample; + GLuint maxSamples; + + // GL_ANGLE_instanced_arrays + bool instancedArrays; + + // GL_ANGLE_pack_reverse_row_order + bool packReverseRowOrder; + + // GL_OES_standard_derivatives + bool standardDerivatives; + + // GL_EXT_shader_texture_lod + bool shaderTextureLOD; + + // GL_EXT_shader_framebuffer_fetch + bool shaderFramebufferFetch; + + // GL_ARM_shader_framebuffer_fetch + bool ARMshaderFramebufferFetch; + + // GL_NV_shader_framebuffer_fetch + bool NVshaderFramebufferFetch; + + // GL_EXT_frag_depth + bool fragDepth; + + // GL_ANGLE_texture_usage + bool textureUsage; + + // GL_ANGLE_translated_shader_source + bool translatedShaderSource; + + // ES3 Extension support + + // GL_EXT_color_buffer_float + bool colorBufferFloat; +}; + +struct TypePrecision +{ + TypePrecision(); + + void setIEEEFloat(); + void setTwosComplementInt(unsigned int bits); + void setSimulatedInt(unsigned int range); + + void get(GLint *returnRange, GLint *returnPrecision) const; + + GLint range[2]; + GLint precision; +}; + +struct Caps +{ + Caps(); + + // Table 6.28, implementation dependent values + GLuint64 maxElementIndex; + GLuint max3DTextureSize; + GLuint max2DTextureSize; + GLuint maxArrayTextureLayers; + GLfloat maxLODBias; + GLuint maxCubeMapTextureSize; + GLuint maxRenderbufferSize; + GLuint maxDrawBuffers; + GLuint maxColorAttachments; + GLuint maxViewportWidth; + GLuint maxViewportHeight; + GLfloat minAliasedPointSize; + GLfloat maxAliasedPointSize; + GLfloat minAliasedLineWidth; + GLfloat maxAliasedLineWidth; + + // Table 6.29, implementation dependent values (cont.) + GLuint maxElementsIndices; + GLuint maxElementsVertices; + std::vector compressedTextureFormats; + std::vector programBinaryFormats; + std::vector shaderBinaryFormats; + TypePrecision vertexHighpFloat; + TypePrecision vertexMediumpFloat; + TypePrecision vertexLowpFloat; + TypePrecision vertexHighpInt; + TypePrecision vertexMediumpInt; + TypePrecision vertexLowpInt; + TypePrecision fragmentHighpFloat; + TypePrecision fragmentMediumpFloat; + TypePrecision fragmentLowpFloat; + TypePrecision fragmentHighpInt; + TypePrecision fragmentMediumpInt; + TypePrecision fragmentLowpInt; + GLuint64 maxServerWaitTimeout; + + // Table 6.31, implementation dependent vertex shader limits + GLuint maxVertexAttributes; + GLuint maxVertexUniformComponents; + GLuint maxVertexUniformVectors; + GLuint maxVertexUniformBlocks; + GLuint maxVertexOutputComponents; + GLuint maxVertexTextureImageUnits; + + // Table 6.32, implementation dependent fragment shader limits + GLuint maxFragmentUniformComponents; + GLuint maxFragmentUniformVectors; + GLuint maxFragmentUniformBlocks; + GLuint maxFragmentInputComponents; + GLuint maxTextureImageUnits; + GLint minProgramTexelOffset; + GLint maxProgramTexelOffset; + + // Table 6.33, implementation dependent aggregate shader limits + GLuint maxUniformBufferBindings; + GLuint64 maxUniformBlockSize; + GLuint uniformBufferOffsetAlignment; + GLuint maxCombinedUniformBlocks; + GLuint64 maxCombinedVertexUniformComponents; + GLuint64 maxCombinedFragmentUniformComponents; + GLuint maxVaryingComponents; + GLuint maxVaryingVectors; + GLuint maxCombinedTextureImageUnits; + + // Table 6.34, implementation dependent transform feedback limits + GLuint maxTransformFeedbackInterleavedComponents; + GLuint maxTransformFeedbackSeparateAttributes; + GLuint maxTransformFeedbackSeparateComponents; +}; + +} + +namespace egl +{ + +struct Caps +{ + Caps(); + + // Support for NPOT surfaces + bool textureNPOT; +}; + +struct DisplayExtensions +{ + DisplayExtensions(); + + // Generate a vector of supported extension strings + std::vector getStrings() const; + + // EGL_EXT_create_context_robustness + bool createContextRobustness; + + // EGL_ANGLE_d3d_share_handle_client_buffer + bool d3dShareHandleClientBuffer; + + // EGL_ANGLE_surface_d3d_texture_2d_share_handle + bool surfaceD3DTexture2DShareHandle; + + // EGL_ANGLE_query_surface_pointer + bool querySurfacePointer; + + // EGL_ANGLE_window_fixed_size + bool windowFixedSize; + + // EGL_NV_post_sub_buffer + bool postSubBuffer; + + // EGL_KHR_create_context + bool createContext; +}; + +struct ClientExtensions +{ + ClientExtensions(); + + // Generate a vector of supported extension strings + std::vector getStrings() const; + + // EGL_EXT_client_extensions + bool clientExtensions; + + // EGL_EXT_platform_base + bool platformBase; + + // EGL_ANGLE_platform_angle + bool platformANGLE; + + // EGL_ANGLE_platform_angle_d3d + bool platformANGLED3D; + + // EGL_ANGLE_platform_angle_opengl + bool platformANGLEOpenGL; +}; + +} + +#endif // LIBANGLE_CAPS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.cpp b/src/3rdparty/angle/src/libANGLE/Compiler.cpp new file mode 100644 index 0000000000..7d0efea220 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Compiler.cpp @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 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. +// + +// Compiler.cpp: implements the gl::Compiler class. + +#include "libANGLE/Compiler.h" +#include "libANGLE/renderer/CompilerImpl.h" + +#include "common/debug.h" + +namespace gl +{ + +Compiler::Compiler(rx::CompilerImpl *impl) + : mCompiler(impl) +{ + ASSERT(mCompiler); +} + +Compiler::~Compiler() +{ + SafeDelete(mCompiler); +} + +Error Compiler::release() +{ + return mCompiler->release(); +} + +rx::CompilerImpl *Compiler::getImplementation() +{ + return mCompiler; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Compiler.h b/src/3rdparty/angle/src/libANGLE/Compiler.h new file mode 100644 index 0000000000..05de15ec97 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Compiler.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2014 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. +// + +// Compiler.h: Defines the gl::Compiler class, abstracting the ESSL compiler +// that a GL context holds. + +#ifndef LIBANGLE_COMPILER_H_ +#define LIBANGLE_COMPILER_H_ + +#include "libANGLE/Error.h" + +namespace rx +{ +class CompilerImpl; +} + +namespace gl +{ + +class Compiler final +{ + public: + explicit Compiler(rx::CompilerImpl *impl); + ~Compiler(); + + Error release(); + + rx::CompilerImpl *getImplementation(); + + private: + rx::CompilerImpl *mCompiler; +}; + +} + +#endif // LIBANGLE_COMPILER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Config.cpp b/src/3rdparty/angle/src/libANGLE/Config.cpp new file mode 100644 index 0000000000..1b1fc50cb3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Config.cpp @@ -0,0 +1,275 @@ +// +// 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.5] section 3.4 page 19. + +#include "libANGLE/Config.h" +#include "libANGLE/AttributeMap.h" + +#include +#include + +#include "angle_gl.h" +#include + +#include "common/debug.h" + +namespace egl +{ + +Config::Config() + : renderTargetFormat(GL_NONE), + depthStencilFormat(GL_NONE), + bufferSize(0), + redSize(0), + greenSize(0), + blueSize(0), + luminanceSize(0), + alphaSize(0), + alphaMaskSize(0), + bindToTextureRGB(EGL_FALSE), + bindToTextureRGBA(EGL_FALSE), + colorBufferType(EGL_NONE), + configCaveat(EGL_NONE), + configID(0), + conformant(0), + depthSize(0), + level(0), + matchNativePixmap(EGL_FALSE), + maxPBufferWidth(0), + maxPBufferHeight(0), + maxPBufferPixels(0), + maxSwapInterval(0), + minSwapInterval(0), + nativeRenderable(EGL_FALSE), + nativeVisualID(0), + nativeVisualType(0), + renderableType(0), + sampleBuffers(0), + samples(0), + stencilSize(0), + surfaceType(0), + transparentType(EGL_NONE), + transparentRedValue(0), + transparentGreenValue(0), + transparentBlueValue(0) +{ +} + +EGLint ConfigSet::add(const Config &config) +{ + // Set the config's ID to a small number that starts at 1 ([EGL 1.5] section 3.4) + EGLint id = mConfigs.size() + 1; + + Config copyConfig(config); + copyConfig.configID = id; + mConfigs.insert(std::make_pair(id, copyConfig)); + + return id; +} + +const Config &ConfigSet::get(EGLint id) const +{ + ASSERT(mConfigs.find(id) != mConfigs.end()); + return mConfigs.find(id)->second; +} + +void ConfigSet::clear() +{ + mConfigs.clear(); +} + +size_t ConfigSet::size() const +{ + return mConfigs.size(); +} + +bool ConfigSet::contains(const Config *config) const +{ + for (auto i = mConfigs.begin(); i != mConfigs.end(); i++) + { + const Config &item = i->second; + if (config == &item) + { + return true; + } + } + + return false; +} + +// Function object used by STL sorting routines for ordering Configs according to [EGL 1.5] section 3.4.1.2 page 28. +class ConfigSorter +{ + public: + explicit ConfigSorter(const AttributeMap &attributeMap) + : mWantRed(false), + mWantGreen(false), + mWantBlue(false), + mWantAlpha(false), + mWantLuminance(false) + { + scanForWantedComponents(attributeMap); + } + + bool operator()(const Config *x, const Config *y) const + { + return (*this)(*x, *y); + } + + bool operator()(const Config &x, const Config &y) const + { + #define SORT(attribute) \ + if (x.attribute != y.attribute) \ + { \ + return x.attribute < y.attribute; \ + } + + static_assert(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG, "Unexpected EGL enum value."); + SORT(configCaveat); + + static_assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER, "Unexpected EGL enum value."); + SORT(colorBufferType); + + // 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(bufferSize); + SORT(sampleBuffers); + SORT(samples); + SORT(depthSize); + SORT(stencilSize); + SORT(alphaMaskSize); + SORT(nativeVisualType); + SORT(configID); + + #undef SORT + + return false; + } + + private: + void scanForWantedComponents(const AttributeMap &attributeMap) + { + // [EGL 1.5] section 3.4.1.2 page 30 + // Sorting rule #3: by larger total number of color bits, not considering + // components that are 0 or don't-care. + for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++) + { + EGLint attributeKey = attribIter->first; + EGLint attributeValue = attribIter->second; + if (attributeKey != 0 && attributeValue != EGL_DONT_CARE) + { + switch (attributeKey) + { + 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 wantedComponentsSize(const Config &config) const + { + EGLint total = 0; + + if (mWantRed) total += config.redSize; + if (mWantGreen) total += config.greenSize; + if (mWantBlue) total += config.blueSize; + if (mWantAlpha) total += config.alphaSize; + if (mWantLuminance) total += config.luminanceSize; + + return total; + } + + bool mWantRed; + bool mWantGreen; + bool mWantBlue; + bool mWantAlpha; + bool mWantLuminance; +}; + +std::vector ConfigSet::filter(const AttributeMap &attributeMap) const +{ + std::vector result; + result.reserve(mConfigs.size()); + + for (auto configIter = mConfigs.begin(); configIter != mConfigs.end(); configIter++) + { + const Config &config = configIter->second; + bool match = true; + + for (auto attribIter = attributeMap.begin(); attribIter != attributeMap.end(); attribIter++) + { + EGLint attributeKey = attribIter->first; + EGLint attributeValue = attribIter->second; + + switch (attributeKey) + { + case EGL_BUFFER_SIZE: match = config.bufferSize >= attributeValue; break; + case EGL_ALPHA_SIZE: match = config.alphaSize >= attributeValue; break; + case EGL_BLUE_SIZE: match = config.blueSize >= attributeValue; break; + case EGL_GREEN_SIZE: match = config.greenSize >= attributeValue; break; + case EGL_RED_SIZE: match = config.redSize >= attributeValue; break; + case EGL_DEPTH_SIZE: match = config.depthSize >= attributeValue; break; + case EGL_STENCIL_SIZE: match = config.stencilSize >= attributeValue; break; + case EGL_CONFIG_CAVEAT: match = config.configCaveat == (EGLenum)attributeValue; break; + case EGL_CONFIG_ID: match = config.configID == attributeValue; break; + case EGL_LEVEL: match = config.level >= attributeValue; break; + case EGL_NATIVE_RENDERABLE: match = config.nativeRenderable == (EGLBoolean)attributeValue; break; + case EGL_NATIVE_VISUAL_TYPE: match = config.nativeVisualType == attributeValue; break; + case EGL_SAMPLES: match = config.samples >= attributeValue; break; + case EGL_SAMPLE_BUFFERS: match = config.sampleBuffers >= attributeValue; break; + case EGL_SURFACE_TYPE: match = (config.surfaceType & attributeValue) == attributeValue; break; + case EGL_TRANSPARENT_TYPE: match = config.transparentType == (EGLenum)attributeValue; break; + case EGL_TRANSPARENT_BLUE_VALUE: match = config.transparentBlueValue == attributeValue; break; + case EGL_TRANSPARENT_GREEN_VALUE: match = config.transparentGreenValue == attributeValue; break; + case EGL_TRANSPARENT_RED_VALUE: match = config.transparentRedValue == attributeValue; break; + case EGL_BIND_TO_TEXTURE_RGB: match = config.bindToTextureRGB == (EGLBoolean)attributeValue; break; + case EGL_BIND_TO_TEXTURE_RGBA: match = config.bindToTextureRGBA == (EGLBoolean)attributeValue; break; + case EGL_MIN_SWAP_INTERVAL: match = config.minSwapInterval == attributeValue; break; + case EGL_MAX_SWAP_INTERVAL: match = config.maxSwapInterval == attributeValue; break; + case EGL_LUMINANCE_SIZE: match = config.luminanceSize >= attributeValue; break; + case EGL_ALPHA_MASK_SIZE: match = config.alphaMaskSize >= attributeValue; break; + case EGL_COLOR_BUFFER_TYPE: match = config.colorBufferType == (EGLenum)attributeValue; break; + case EGL_RENDERABLE_TYPE: match = (config.renderableType & attributeValue) == attributeValue; break; + case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: match = (config.conformant & attributeValue) == attributeValue; break; + case EGL_MAX_PBUFFER_WIDTH: match = config.maxPBufferWidth >= attributeValue; break; + case EGL_MAX_PBUFFER_HEIGHT: match = config.maxPBufferHeight >= attributeValue; break; + case EGL_MAX_PBUFFER_PIXELS: match = config.maxPBufferPixels >= attributeValue; break; + default: UNREACHABLE(); + } + + if (!match) + { + break; + } + } + + if (match) + { + result.push_back(&config); + } + } + + // Sort the result + std::sort(result.begin(), result.end(), ConfigSorter(attributeMap)); + + return result; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Config.h b/src/3rdparty/angle/src/libANGLE/Config.h new file mode 100644 index 0000000000..aed8aedb1d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Config.h @@ -0,0 +1,91 @@ +// +// 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.5] section 3.4 page 19. + +#ifndef INCLUDE_CONFIG_H_ +#define INCLUDE_CONFIG_H_ + +#include "libANGLE/AttributeMap.h" + +#include "common/angleutils.h" + +#include +#include + +#include +#include + +namespace egl +{ + +struct Config +{ + Config(); + + GLenum renderTargetFormat; // TODO(geofflang): remove this + GLenum depthStencilFormat; // TODO(geofflang): remove this + + EGLint bufferSize; // Depth of the color buffer + EGLint redSize; // Bits of Red in the color buffer + EGLint greenSize; // Bits of Green in the color buffer + EGLint blueSize; // Bits of Blue in the color buffer + EGLint luminanceSize; // Bits of Luminance in the color buffer + EGLint alphaSize; // Bits of Alpha in the color buffer + EGLint alphaMaskSize; // Bits of Alpha Mask in the mask buffer + EGLBoolean bindToTextureRGB; // True if bindable to RGB textures. + EGLBoolean bindToTextureRGBA; // True if bindable to RGBA textures. + EGLenum colorBufferType; // Color buffer type + EGLenum configCaveat; // Any caveats for the configuration + EGLint configID; // Unique EGLConfig identifier + EGLint conformant; // Whether contexts created with this config are conformant + EGLint depthSize; // Bits of Z in the depth buffer + EGLint level; // Frame buffer level + EGLBoolean matchNativePixmap; // Match the native pixmap format + EGLint maxPBufferWidth; // Maximum width of pbuffer + EGLint maxPBufferHeight; // Maximum height of pbuffer + EGLint maxPBufferPixels; // Maximum size of pbuffer + EGLint maxSwapInterval; // Maximum swap interval + EGLint minSwapInterval; // Minimum swap interval + EGLBoolean nativeRenderable; // EGL_TRUE if native rendering APIs can render to surface + EGLint nativeVisualID; // Handle of corresponding native visual + EGLint nativeVisualType; // Native visual type of the associated visual + EGLint renderableType; // Which client rendering APIs are supported. + EGLint sampleBuffers; // Number of multisample buffers + EGLint samples; // Number of samples per pixel + EGLint stencilSize; // Bits of Stencil in the stencil buffer + EGLint surfaceType; // Which types of EGL surfaces are supported. + EGLenum transparentType; // Type of transparency supported + EGLint transparentRedValue; // Transparent red value + EGLint transparentGreenValue; // Transparent green value + EGLint transparentBlueValue; // Transparent blue value +}; + +class ConfigSet +{ + public: + EGLint add(const Config &config); + const Config &get(EGLint id) const; + + void clear(); + + size_t size() const; + + bool contains(const Config *config) const; + + // Filter configurations based on the table in [EGL 1.5] section 3.4.1.2 page 29 + std::vector filter(const AttributeMap &attributeMap) const; + + private: + typedef std::map ConfigMap; + ConfigMap mConfigs; +}; + +} + +#endif // INCLUDE_CONFIG_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Constants.h b/src/3rdparty/angle/src/libANGLE/Constants.h new file mode 100644 index 0000000000..dc8f9555b8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Constants.h @@ -0,0 +1,44 @@ +// +// Copyright (c) 2013 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. +// + +// Contants.h: Defines some implementation specific and gl constants + +#ifndef LIBANGLE_CONSTANTS_H_ +#define LIBANGLE_CONSTANTS_H_ + +namespace gl +{ + +enum +{ + MAX_VERTEX_ATTRIBS = 16, + + // Implementation upper limits, real maximums depend on the hardware + IMPLEMENTATION_MAX_VARYING_VECTORS = 32, + IMPLEMENTATION_MAX_DRAW_BUFFERS = 8, + IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS = IMPLEMENTATION_MAX_DRAW_BUFFERS + 2, // 2 extra for depth and/or stencil buffers + + IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS = 16, + IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS = 16, + IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS = IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS + + IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS, + + IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4, + + // 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_2D_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, + IMPLEMENTATION_MAX_3D_TEXTURE_SIZE = 2048, + IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS = 2048, + + IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE +}; + +} + +#endif // LIBANGLE_CONSTANTS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp new file mode 100644 index 0000000000..1da5fdae95 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Context.cpp @@ -0,0 +1,1587 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/Context.h" + +#include +#include + +#include "common/platform.h" +#include "common/utilities.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Compiler.h" +#include "libANGLE/Display.h" +#include "libANGLE/Fence.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Program.h" +#include "libANGLE/Query.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/Sampler.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/validationES.h" +#include "libANGLE/renderer/Renderer.h" + +namespace gl +{ + +Context::Context(const egl::Config *config, int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) + : mRenderer(renderer) +{ + ASSERT(robustAccess == false); // Unimplemented + + initCaps(clientVersion); + mState.initialize(mCaps, clientVersion); + + mClientVersion = clientVersion; + + mConfigID = config->configID; + mClientType = EGL_OPENGL_ES_API; + mRenderBuffer = EGL_NONE; + + mFenceNVHandleAllocator.setBaseHandle(0); + + if (shareContext != NULL) + { + mResourceManager = shareContext->mResourceManager; + mResourceManager->addRef(); + } + else + { + mResourceManager = new ResourceManager(mRenderer); + } + + // [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. + + Texture *zeroTexture2D = new Texture(mRenderer->createTexture(GL_TEXTURE_2D), 0, GL_TEXTURE_2D); + mZeroTextures[GL_TEXTURE_2D].set(zeroTexture2D); + + Texture *zeroTextureCube = new Texture(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), 0, GL_TEXTURE_CUBE_MAP); + mZeroTextures[GL_TEXTURE_CUBE_MAP].set(zeroTextureCube); + + if (mClientVersion >= 3) + { + // TODO: These could also be enabled via extension + Texture *zeroTexture3D = new Texture(mRenderer->createTexture(GL_TEXTURE_3D), 0, GL_TEXTURE_3D); + mZeroTextures[GL_TEXTURE_3D].set(zeroTexture3D); + + Texture *zeroTexture2DArray = new Texture(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), 0, GL_TEXTURE_2D_ARRAY); + mZeroTextures[GL_TEXTURE_2D_ARRAY].set(zeroTexture2DArray); + } + + mState.initializeZeroTextures(mZeroTextures); + + bindVertexArray(0); + bindArrayBuffer(0); + bindElementArrayBuffer(0); + + bindReadFramebuffer(0); + bindDrawFramebuffer(0); + bindRenderbuffer(0); + + bindGenericUniformBuffer(0); + for (unsigned int i = 0; i < mCaps.maxCombinedUniformBlocks; i++) + { + bindIndexedUniformBuffer(0, i, 0, -1); + } + + bindGenericTransformFeedbackBuffer(0); + for (unsigned int i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++) + { + bindIndexedTransformFeedbackBuffer(0, i, 0, -1); + } + + bindCopyReadBuffer(0); + bindCopyWriteBuffer(0); + bindPixelPackBuffer(0); + bindPixelUnpackBuffer(0); + + // [OpenGL ES 3.0.2] section 2.14.1 pg 85: + // In the initial state, a default transform feedback object is bound and treated as + // a transform feedback object with a name of zero. That object is bound any time + // BindTransformFeedback is called with id of zero + mTransformFeedbackZero.set(new TransformFeedback(mRenderer->createTransformFeedback(), 0)); + bindTransformFeedback(0); + + mHasBeenCurrent = false; + mContextLost = false; + mResetStatus = GL_NO_ERROR; + mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); + mRobustAccess = robustAccess; + + mCompiler = new Compiler(mRenderer->createCompiler(getData())); +} + +Context::~Context() +{ + mState.reset(); + + while (!mFramebufferMap.empty()) + { + // Delete the framebuffer in reverse order to destroy the framebuffer zero last. + deleteFramebuffer(mFramebufferMap.rbegin()->first); + } + + while (!mFenceNVMap.empty()) + { + deleteFenceNV(mFenceNVMap.begin()->first); + } + + while (!mQueryMap.empty()) + { + deleteQuery(mQueryMap.begin()->first); + } + + while (!mVertexArrayMap.empty()) + { + deleteVertexArray(mVertexArrayMap.begin()->first); + } + + mTransformFeedbackZero.set(NULL); + while (!mTransformFeedbackMap.empty()) + { + deleteTransformFeedback(mTransformFeedbackMap.begin()->first); + } + + for (auto it = mZeroTextures.begin(); it != mZeroTextures.end(); ++it) + { + it->second.set(NULL); + } + mZeroTextures.clear(); + + if (mResourceManager) + { + mResourceManager->release(); + } + + SafeDelete(mCompiler); +} + +void Context::makeCurrent(egl::Surface *surface) +{ + if (!mHasBeenCurrent) + { + initRendererString(); + initExtensionStrings(); + + mState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight()); + mState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight()); + + mHasBeenCurrent = true; + } + + // TODO(jmadill): do not allocate new pointers here + Framebuffer *framebufferZero = new DefaultFramebuffer(mCaps, mRenderer, surface); + + setFramebufferZero(framebufferZero); + + mRenderBuffer = surface->getRenderBuffer(); +} + +// NOTE: this function should not assume that this context is current! +void Context::markContextLost() +{ + if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; + mContextLost = true; +} + +bool Context::isContextLost() +{ + return mContextLost; +} + +GLuint Context::createBuffer() +{ + return mResourceManager->createBuffer(); +} + +GLuint Context::createProgram() +{ + return mResourceManager->createProgram(); +} + +GLuint Context::createShader(GLenum type) +{ + return mResourceManager->createShader(getData(), type); +} + +GLuint Context::createTexture() +{ + return mResourceManager->createTexture(); +} + +GLuint Context::createRenderbuffer() +{ + return mResourceManager->createRenderbuffer(); +} + +GLsync Context::createFenceSync() +{ + GLuint handle = mResourceManager->createFenceSync(); + + return reinterpret_cast(static_cast(handle)); +} + +GLuint Context::createVertexArray() +{ + GLuint handle = mVertexArrayHandleAllocator.allocate(); + + // Although the spec states VAO state is not initialized until the object is bound, + // we create it immediately. The resulting behaviour is transparent to the application, + // since it's not currently possible to access the state until the object is bound. + VertexArray *vertexArray = new VertexArray(mRenderer->createVertexArray(), handle, MAX_VERTEX_ATTRIBS); + mVertexArrayMap[handle] = vertexArray; + return handle; +} + +GLuint Context::createSampler() +{ + return mResourceManager->createSampler(); +} + +GLuint Context::createTransformFeedback() +{ + GLuint handle = mTransformFeedbackAllocator.allocate(); + TransformFeedback *transformFeedback = new TransformFeedback(mRenderer->createTransformFeedback(), handle); + transformFeedback->addRef(); + mTransformFeedbackMap[handle] = transformFeedback; + return handle; +} + +// Returns an unused framebuffer name +GLuint Context::createFramebuffer() +{ + GLuint handle = mFramebufferHandleAllocator.allocate(); + + mFramebufferMap[handle] = NULL; + + return handle; +} + +GLuint Context::createFenceNV() +{ + GLuint handle = mFenceNVHandleAllocator.allocate(); + + mFenceNVMap[handle] = new FenceNV(mRenderer->createFenceNV()); + + 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::deleteFenceSync(GLsync fenceSync) +{ + // The spec specifies the underlying Fence object is not deleted until all current + // wait commands finish. However, since the name becomes invalid, we cannot query the fence, + // and since our API is currently designed for being called from a single thread, we can delete + // the fence immediately. + mResourceManager->deleteFenceSync(reinterpret_cast(fenceSync)); +} + +void Context::deleteVertexArray(GLuint vertexArray) +{ + auto vertexArrayObject = mVertexArrayMap.find(vertexArray); + + if (vertexArrayObject != mVertexArrayMap.end()) + { + detachVertexArray(vertexArray); + + mVertexArrayHandleAllocator.release(vertexArrayObject->first); + delete vertexArrayObject->second; + mVertexArrayMap.erase(vertexArrayObject); + } +} + +void Context::deleteSampler(GLuint sampler) +{ + if (mResourceManager->getSampler(sampler)) + { + detachSampler(sampler); + } + + mResourceManager->deleteSampler(sampler); +} + +void Context::deleteTransformFeedback(GLuint transformFeedback) +{ + auto iter = mTransformFeedbackMap.find(transformFeedback); + if (iter != mTransformFeedbackMap.end()) + { + detachTransformFeedback(transformFeedback); + mTransformFeedbackAllocator.release(transformFeedback); + iter->second->release(); + mTransformFeedbackMap.erase(iter); + } +} + +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::deleteFenceNV(GLuint fence) +{ + FenceNVMap::iterator fenceObject = mFenceNVMap.find(fence); + + if (fenceObject != mFenceNVMap.end()) + { + mFenceNVHandleAllocator.release(fenceObject->first); + delete fenceObject->second; + mFenceNVMap.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) const +{ + return mResourceManager->getShader(handle); +} + +Program *Context::getProgram(GLuint handle) const +{ + return mResourceManager->getProgram(handle); +} + +Texture *Context::getTexture(GLuint handle) const +{ + return mResourceManager->getTexture(handle); +} + +Renderbuffer *Context::getRenderbuffer(GLuint handle) +{ + return mResourceManager->getRenderbuffer(handle); +} + +FenceSync *Context::getFenceSync(GLsync handle) const +{ + return mResourceManager->getFenceSync(reinterpret_cast(handle)); +} + +VertexArray *Context::getVertexArray(GLuint handle) const +{ + auto vertexArray = mVertexArrayMap.find(handle); + + if (vertexArray == mVertexArrayMap.end()) + { + return NULL; + } + else + { + return vertexArray->second; + } +} + +Sampler *Context::getSampler(GLuint handle) const +{ + return mResourceManager->getSampler(handle); +} + +TransformFeedback *Context::getTransformFeedback(GLuint handle) const +{ + if (handle == 0) + { + return mTransformFeedbackZero.get(); + } + else + { + TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle); + return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL; + } +} + +bool Context::isSampler(GLuint samplerName) const +{ + return mResourceManager->isSampler(samplerName); +} + +void Context::bindArrayBuffer(unsigned int buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setArrayBufferBinding(getBuffer(buffer)); +} + +void Context::bindElementArrayBuffer(unsigned int buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.getVertexArray()->setElementArrayBuffer(getBuffer(buffer)); +} + +void Context::bindTexture(GLenum target, GLuint handle) +{ + Texture *texture = NULL; + + if (handle == 0) + { + texture = mZeroTextures[target].get(); + } + else + { + mResourceManager->checkTextureAllocation(handle, target); + texture = getTexture(handle); + } + + ASSERT(texture); + + mState.setSamplerTexture(target, texture); +} + +void Context::bindReadFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(mCaps, mRenderer, framebuffer); + } + + mState.setReadFramebufferBinding(getFramebuffer(framebuffer)); +} + +void Context::bindDrawFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(mCaps, mRenderer, framebuffer); + } + + mState.setDrawFramebufferBinding(getFramebuffer(framebuffer)); +} + +void Context::bindRenderbuffer(GLuint renderbuffer) +{ + mResourceManager->checkRenderbufferAllocation(renderbuffer); + + mState.setRenderbufferBinding(getRenderbuffer(renderbuffer)); +} + +void Context::bindVertexArray(GLuint vertexArray) +{ + if (!getVertexArray(vertexArray)) + { + VertexArray *vertexArrayObject = new VertexArray(mRenderer->createVertexArray(), vertexArray, MAX_VERTEX_ATTRIBS); + mVertexArrayMap[vertexArray] = vertexArrayObject; + } + + mState.setVertexArrayBinding(getVertexArray(vertexArray)); +} + +void Context::bindSampler(GLuint textureUnit, GLuint sampler) +{ + ASSERT(textureUnit < mCaps.maxCombinedTextureImageUnits); + mResourceManager->checkSamplerAllocation(sampler); + + mState.setSamplerBinding(textureUnit, getSampler(sampler)); +} + +void Context::bindGenericUniformBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setGenericUniformBufferBinding(getBuffer(buffer)); +} + +void Context::bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setIndexedUniformBufferBinding(index, getBuffer(buffer), offset, size); +} + +void Context::bindGenericTransformFeedbackBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setGenericTransformFeedbackBufferBinding(getBuffer(buffer)); +} + +void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setIndexedTransformFeedbackBufferBinding(index, getBuffer(buffer), offset, size); +} + +void Context::bindCopyReadBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setCopyReadBufferBinding(getBuffer(buffer)); +} + +void Context::bindCopyWriteBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setCopyWriteBufferBinding(getBuffer(buffer)); +} + +void Context::bindPixelPackBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setPixelPackBufferBinding(getBuffer(buffer)); +} + +void Context::bindPixelUnpackBuffer(GLuint buffer) +{ + mResourceManager->checkBufferAllocation(buffer); + + mState.setPixelUnpackBufferBinding(getBuffer(buffer)); +} + +void Context::useProgram(GLuint program) +{ + mState.setProgram(getProgram(program)); +} + +void Context::bindTransformFeedback(GLuint transformFeedback) +{ + mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); +} + +Error Context::beginQuery(GLenum target, GLuint query) +{ + Query *queryObject = getQuery(query, true, target); + ASSERT(queryObject); + + // begin query + Error error = queryObject->begin(); + if (error.isError()) + { + return error; + } + + // set query as active for specified target only if begin succeeded + mState.setActiveQuery(target, queryObject); + + return Error(GL_NO_ERROR); +} + +Error Context::endQuery(GLenum target) +{ + Query *queryObject = mState.getActiveQuery(target); + ASSERT(queryObject); + + gl::Error error = queryObject->end(); + + // Always unbind the query, even if there was an error. This may delete the query object. + mState.setActiveQuery(target, NULL); + + return error; +} + +void Context::setFramebufferZero(Framebuffer *buffer) +{ + // First, check to see if the old default framebuffer + // was set for draw or read framebuffer, and change + // the bindings to point to the new one before deleting it. + if (mState.getDrawFramebuffer()->id() == 0) + { + mState.setDrawFramebufferBinding(buffer); + } + + if (mState.getReadFramebuffer()->id() == 0) + { + mState.setReadFramebufferBinding(buffer); + } + + delete mFramebufferMap[0]; + mFramebufferMap[0] = buffer; +} + +Framebuffer *Context::getFramebuffer(unsigned int handle) const +{ + FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle); + + if (framebuffer == mFramebufferMap.end()) + { + return NULL; + } + else + { + return framebuffer->second; + } +} + +FenceNV *Context::getFenceNV(unsigned int handle) +{ + FenceNVMap::iterator fence = mFenceNVMap.find(handle); + + if (fence == mFenceNVMap.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(mRenderer->createQuery(type), handle); + query->second->addRef(); + } + return query->second; + } +} + +Texture *Context::getTargetTexture(GLenum target) const +{ + ASSERT(ValidTextureTarget(this, target)); + + return getSamplerTexture(mState.getActiveSampler(), target); +} + +Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const +{ + return mState.getSamplerTexture(sampler, type); +} + +Compiler *Context::getCompiler() const +{ + return mCompiler; +} + +void Context::getBooleanv(GLenum pname, GLboolean *params) +{ + switch (pname) + { + case GL_SHADER_COMPILER: *params = GL_TRUE; break; + case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; + default: + mState.getBooleanv(pname, params); + break; + } +} + +void Context::getFloatv(GLenum pname, GLfloat *params) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + switch (pname) + { + case GL_ALIASED_LINE_WIDTH_RANGE: + params[0] = mCaps.minAliasedLineWidth; + params[1] = mCaps.maxAliasedLineWidth; + break; + case GL_ALIASED_POINT_SIZE_RANGE: + params[0] = mCaps.minAliasedPointSize; + params[1] = mCaps.maxAliasedPointSize; + break; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + ASSERT(mExtensions.textureFilterAnisotropic); + *params = mExtensions.maxTextureAnisotropy; + break; + default: + mState.getFloatv(pname, params); + break; + } +} + +void Context::getIntegerv(GLenum pname, GLint *params) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + + switch (pname) + { + case GL_MAX_VERTEX_ATTRIBS: *params = mCaps.maxVertexAttributes; break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mCaps.maxVertexUniformVectors; break; + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: *params = mCaps.maxVertexUniformComponents; break; + case GL_MAX_VARYING_VECTORS: *params = mCaps.maxVaryingVectors; break; + case GL_MAX_VARYING_COMPONENTS: *params = mCaps.maxVertexOutputComponents; break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mCaps.maxCombinedTextureImageUnits; break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxVertexTextureImageUnits; break; + case GL_MAX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxTextureImageUnits; break; + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mCaps.maxFragmentUniformVectors; break; + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mCaps.maxFragmentInputComponents; break; + case GL_MAX_RENDERBUFFER_SIZE: *params = mCaps.maxRenderbufferSize; break; + case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mCaps.maxColorAttachments; break; + case GL_MAX_DRAW_BUFFERS_EXT: *params = mCaps.maxDrawBuffers; break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_SUBPIXEL_BITS: *params = 4; break; + case GL_MAX_TEXTURE_SIZE: *params = mCaps.max2DTextureSize; break; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = mCaps.maxCubeMapTextureSize; break; + case GL_MAX_3D_TEXTURE_SIZE: *params = mCaps.max3DTextureSize; break; + case GL_MAX_ARRAY_TEXTURE_LAYERS: *params = mCaps.maxArrayTextureLayers; break; + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: *params = mCaps.uniformBufferOffsetAlignment; break; + case GL_MAX_UNIFORM_BUFFER_BINDINGS: *params = mCaps.maxUniformBufferBindings; break; + case GL_MAX_VERTEX_UNIFORM_BLOCKS: *params = mCaps.maxVertexUniformBlocks; break; + case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: *params = mCaps.maxFragmentUniformBlocks; break; + case GL_MAX_COMBINED_UNIFORM_BLOCKS: *params = mCaps.maxCombinedTextureImageUnits; break; + case GL_MAJOR_VERSION: *params = mClientVersion; break; + case GL_MINOR_VERSION: *params = 0; break; + case GL_MAX_ELEMENTS_INDICES: *params = mCaps.maxElementsIndices; break; + case GL_MAX_ELEMENTS_VERTICES: *params = mCaps.maxElementsVertices; break; + case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: *params = mCaps.maxTransformFeedbackInterleavedComponents; break; + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: *params = mCaps.maxTransformFeedbackSeparateAttributes; break; + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: *params = mCaps.maxTransformFeedbackSeparateComponents; break; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: *params = mCaps.compressedTextureFormats.size(); break; + case GL_MAX_SAMPLES_ANGLE: *params = mExtensions.maxSamples; break; + case GL_MAX_VIEWPORT_DIMS: + { + params[0] = mCaps.maxViewportWidth; + params[1] = mCaps.maxViewportHeight; + } + break; + case GL_COMPRESSED_TEXTURE_FORMATS: + std::copy(mCaps.compressedTextureFormats.begin(), mCaps.compressedTextureFormats.end(), params); + break; + case GL_RESET_NOTIFICATION_STRATEGY_EXT: + *params = mResetStrategy; + break; + case GL_NUM_SHADER_BINARY_FORMATS: + *params = mCaps.shaderBinaryFormats.size(); + break; + case GL_SHADER_BINARY_FORMATS: + std::copy(mCaps.shaderBinaryFormats.begin(), mCaps.shaderBinaryFormats.end(), params); + break; + case GL_NUM_PROGRAM_BINARY_FORMATS: + *params = mCaps.programBinaryFormats.size(); + break; + case GL_PROGRAM_BINARY_FORMATS: + std::copy(mCaps.programBinaryFormats.begin(), mCaps.programBinaryFormats.end(), params); + break; + case GL_NUM_EXTENSIONS: + *params = static_cast(mExtensionStrings.size()); + break; + default: + mState.getIntegerv(getData(), pname, params); + break; + } +} + +void Context::getInteger64v(GLenum pname, GLint64 *params) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + switch (pname) + { + case GL_MAX_ELEMENT_INDEX: + *params = mCaps.maxElementIndex; + break; + case GL_MAX_UNIFORM_BLOCK_SIZE: + *params = mCaps.maxUniformBlockSize; + break; + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: + *params = mCaps.maxCombinedVertexUniformComponents; + break; + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: + *params = mCaps.maxCombinedFragmentUniformComponents; + break; + case GL_MAX_SERVER_WAIT_TIMEOUT: + *params = mCaps.maxServerWaitTimeout; + break; + default: + UNREACHABLE(); + break; + } +} + +bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + // Indexed integer queries all refer to current state, so this function is a + // mere passthrough. + return mState.getIndexedIntegerv(target, index, data); +} + +bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +{ + // Queries about context capabilities and maximums are answered by Context. + // Queries about current GL state values are answered by State. + // Indexed integer queries all refer to current state, so this function is a + // mere passthrough. + return mState.getIndexedInteger64v(target, index, data); +} + +bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) +{ + if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + { + *type = GL_INT; + *numParams = 1; + return true; + } + + // 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 = mCaps.compressedTextureFormats.size(); + } + return true; + case GL_PROGRAM_BINARY_FORMATS_OES: + { + *type = GL_INT; + *numParams = mCaps.programBinaryFormats.size(); + } + return true; + case GL_SHADER_BINARY_FORMATS: + { + *type = GL_INT; + *numParams = mCaps.shaderBinaryFormats.size(); + } + return true; + + 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_MAX_COLOR_ATTACHMENTS_EXT: + case GL_MAX_DRAW_BUFFERS_EXT: + case GL_NUM_SHADER_BINARY_FORMATS: + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: + case GL_ARRAY_BUFFER_BINDING: + //case GL_FRAMEBUFFER_BINDING: // equivalent to DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: + 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: + { + *type = GL_INT; + *numParams = 1; + } + return true; + case GL_MAX_SAMPLES_ANGLE: + { + if (mExtensions.framebufferMultisample) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + return true; + case GL_PIXEL_PACK_BUFFER_BINDING: + case GL_PIXEL_UNPACK_BUFFER_BINDING: + { + if (mExtensions.pixelBufferObject) + { + *type = GL_INT; + *numParams = 1; + } + else + { + return false; + } + } + return true; + case GL_MAX_VIEWPORT_DIMS: + { + *type = GL_INT; + *numParams = 2; + } + return true; + case GL_VIEWPORT: + case GL_SCISSOR_BOX: + { + *type = GL_INT; + *numParams = 4; + } + return true; + 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; + } + return true; + case GL_COLOR_WRITEMASK: + { + *type = GL_BOOL; + *numParams = 4; + } + return true; + 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; + } + return true; + case GL_ALIASED_LINE_WIDTH_RANGE: + case GL_ALIASED_POINT_SIZE_RANGE: + case GL_DEPTH_RANGE: + { + *type = GL_FLOAT; + *numParams = 2; + } + return true; + case GL_COLOR_CLEAR_VALUE: + case GL_BLEND_COLOR: + { + *type = GL_FLOAT; + *numParams = 4; + } + return true; + case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: + if (!mExtensions.maxTextureAnisotropy) + { + return false; + } + *type = GL_FLOAT; + *numParams = 1; + return true; + } + + if (mClientVersion < 3) + { + return false; + } + + // Check for ES3.0+ parameter names + switch (pname) + { + case GL_MAX_UNIFORM_BUFFER_BINDINGS: + case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: + case GL_UNIFORM_BUFFER_BINDING: + case GL_TRANSFORM_FEEDBACK_BINDING: + case GL_COPY_READ_BUFFER_BINDING: + case GL_COPY_WRITE_BUFFER_BINDING: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + case GL_MAX_3D_TEXTURE_SIZE: + case GL_MAX_ARRAY_TEXTURE_LAYERS: + case GL_MAX_VERTEX_UNIFORM_BLOCKS: + case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: + case GL_MAX_COMBINED_UNIFORM_BLOCKS: + case GL_MAX_VARYING_COMPONENTS: + case GL_VERTEX_ARRAY_BINDING: + case GL_MAX_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: + case GL_NUM_EXTENSIONS: + case GL_MAJOR_VERSION: + case GL_MINOR_VERSION: + case GL_MAX_ELEMENTS_INDICES: + case GL_MAX_ELEMENTS_VERTICES: + case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: + case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: + { + *type = GL_INT; + *numParams = 1; + } + return true; + + case GL_MAX_ELEMENT_INDEX: + case GL_MAX_UNIFORM_BLOCK_SIZE: + case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: + case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: + case GL_MAX_SERVER_WAIT_TIMEOUT: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + } + return true; + + case GL_TRANSFORM_FEEDBACK_ACTIVE: + case GL_TRANSFORM_FEEDBACK_PAUSED: + { + *type = GL_BOOL; + *numParams = 1; + } + return true; + } + + return false; +} + +bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams) +{ + if (mClientVersion < 3) + { + return false; + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + case GL_UNIFORM_BUFFER_BINDING: + { + *type = GL_INT; + *numParams = 1; + } + return true; + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + { + *type = GL_INT_64_ANGLEX; + *numParams = 1; + } + } + + return false; +} + +Error Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) +{ + return mRenderer->drawArrays(getData(), mode, first, count, instances); +} + +Error Context::drawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const rx::RangeUI &indexRange) +{ + return mRenderer->drawElements(getData(), mode, count, type, indices, instances, indexRange); +} + +Error Context::flush() +{ + return mRenderer->flush(); +} + +Error Context::finish() +{ + return mRenderer->finish(); +} + +void Context::recordError(const Error &error) +{ + if (error.isError()) + { + mErrors.insert(error.getCode()); + } +} + +// 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 (mErrors.empty()) + { + return GL_NO_ERROR; + } + else + { + GLenum error = *mErrors.begin(); + mErrors.erase(mErrors.begin()); + return error; + } +} + +GLenum Context::getResetStatus() +{ + //TODO(jmadill): needs MANGLE reworking + if (mResetStatus == GL_NO_ERROR && !mContextLost) + { + // mResetStatus will be set by the markContextLost callback + // in the case a notification is sent + if (mRenderer->testDeviceLost()) + { + mRenderer->notifyDeviceLost(); + } + } + + GLenum status = mResetStatus; + + if (mResetStatus != GL_NO_ERROR) + { + ASSERT(mContextLost); + + if (mRenderer->testDeviceResettable()) + { + mResetStatus = GL_NO_ERROR; + } + } + + return status; +} + +bool Context::isResetNotificationEnabled() +{ + return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); +} + +int Context::getClientVersion() const +{ + return mClientVersion; +} + +EGLint Context::getConfigID() const +{ + return mConfigID; +} + +EGLenum Context::getClientType() const +{ + return mClientType; +} + +EGLenum Context::getRenderBuffer() const +{ + return mRenderBuffer; +} + +const Caps &Context::getCaps() const +{ + return mCaps; +} + +const TextureCapsMap &Context::getTextureCaps() const +{ + return mTextureCaps; +} + +const Extensions &Context::getExtensions() const +{ + return mExtensions; +} + +void Context::detachTexture(GLuint texture) +{ + // Simple pass-through to State's detachTexture method, as textures do not require + // allocation map management either here or in the resource manager at detach time. + // Zero textures are held by the Context, and we don't attempt to request them from + // the State. + mState.detachTexture(mZeroTextures, texture); +} + +void Context::detachBuffer(GLuint buffer) +{ + // Buffer detachment is handled by Context, because the buffer must also be + // attached from any VAOs in existence, and Context holds the VAO map. + + // [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. + + mState.removeArrayBufferBinding(buffer); + + // mark as freed among the vertex array objects + for (auto vaoIt = mVertexArrayMap.begin(); vaoIt != mVertexArrayMap.end(); vaoIt++) + { + vaoIt->second->detachBuffer(buffer); + } +} + +void Context::detachFramebuffer(GLuint framebuffer) +{ + // Framebuffer detachment is handled by Context, because 0 is a valid + // Framebuffer object, and a pointer to it must be passed from Context + // to State at binding time. + + // [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.removeReadFramebufferBinding(framebuffer) && framebuffer != 0) + { + bindReadFramebuffer(0); + } + + if (mState.removeDrawFramebufferBinding(framebuffer) && framebuffer != 0) + { + bindDrawFramebuffer(0); + } +} + +void Context::detachRenderbuffer(GLuint renderbuffer) +{ + mState.detachRenderbuffer(renderbuffer); +} + +void Context::detachVertexArray(GLuint vertexArray) +{ + // Vertex array detachment is handled by Context, because 0 is a valid + // VAO, and a pointer to it must be passed from Context to State at + // binding time. + + // [OpenGL ES 3.0.2] section 2.10 page 43: + // If a vertex array object that is currently bound is deleted, the binding + // for that object reverts to zero and the default vertex array becomes current. + if (mState.removeVertexArrayBinding(vertexArray)) + { + bindVertexArray(0); + } +} + +void Context::detachTransformFeedback(GLuint transformFeedback) +{ + mState.detachTransformFeedback(transformFeedback); +} + +void Context::detachSampler(GLuint sampler) +{ + mState.detachSampler(sampler); +} + +void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) +{ + mState.getVertexArray()->setVertexAttribDivisor(index, divisor); +} + +void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) +{ + mResourceManager->checkSamplerAllocation(sampler); + + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); + + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast(param)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast(param)); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast(param)); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(static_cast(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(static_cast(param)); break; + default: UNREACHABLE(); break; + } +} + +void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param) +{ + mResourceManager->checkSamplerAllocation(sampler); + + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); + + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround(param)); break; + case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround(param)); break; + case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround(param)); break; + case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround(param)); break; + case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround(param)); break; + case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break; + case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break; + case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(uiround(param)); break; + case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(uiround(param)); break; + default: UNREACHABLE(); break; + } +} + +GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname) +{ + mResourceManager->checkSamplerAllocation(sampler); + + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); + + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); + case GL_TEXTURE_MIN_LOD: return uiround(samplerObject->getMinLod()); + case GL_TEXTURE_MAX_LOD: return uiround(samplerObject->getMaxLod()); + case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); + default: UNREACHABLE(); return 0; + } +} + +GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname) +{ + mResourceManager->checkSamplerAllocation(sampler); + + Sampler *samplerObject = getSampler(sampler); + ASSERT(samplerObject); + + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); + case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); + case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); + case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); + case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); + case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod(); + case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod(); + case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); + case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); + default: UNREACHABLE(); return 0; + } +} + +void Context::initRendererString() +{ + std::ostringstream rendererString; + rendererString << "ANGLE ("; + rendererString << mRenderer->getRendererDescription(); + rendererString << ")"; + + mRendererString = MakeStaticString(rendererString.str()); +} + +const std::string &Context::getRendererString() const +{ + return mRendererString; +} + +void Context::initExtensionStrings() +{ + mExtensionStrings = mExtensions.getStrings(); + + std::ostringstream combinedStringStream; + std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator(combinedStringStream, " ")); + mExtensionString = combinedStringStream.str(); +} + +const std::string &Context::getExtensionString() const +{ + return mExtensionString; +} + +const std::string &Context::getExtensionString(size_t idx) const +{ + return mExtensionStrings[idx]; +} + +size_t Context::getExtensionStringCount() const +{ + return mExtensionStrings.size(); +} + +void Context::initCaps(GLuint clientVersion) +{ + mCaps = mRenderer->getRendererCaps(); + + mExtensions = mRenderer->getRendererExtensions(); + + if (clientVersion < 3) + { + // Disable ES3+ extensions + mExtensions.colorBufferFloat = false; + } + + if (clientVersion > 2) + { + // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts + //mExtensions.sRGB = false; + } + + // Apply implementation limits + mCaps.maxVertexAttributes = std::min(mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS); + mCaps.maxVertexUniformBlocks = std::min(mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS); + mCaps.maxVertexOutputComponents = std::min(mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + + mCaps.maxFragmentInputComponents = std::min(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); + + GLuint maxSamples = 0; + mCaps.compressedTextureFormats.clear(); + + const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps(); + for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++) + { + GLenum format = i->first; + TextureCaps formatCaps = i->second; + + const InternalFormat &formatInfo = GetInternalFormatInfo(format); + + // Update the format caps based on the client version and extensions + formatCaps.texturable = formatInfo.textureSupport(clientVersion, mExtensions); + formatCaps.renderable = formatInfo.renderSupport(clientVersion, mExtensions); + formatCaps.filterable = formatInfo.filterSupport(clientVersion, mExtensions); + + // OpenGL ES does not support multisampling with integer formats + if (!formatInfo.renderSupport || formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT) + { + formatCaps.sampleCounts.clear(); + } + maxSamples = std::max(maxSamples, formatCaps.getMaxSamples()); + + if (formatCaps.texturable && formatInfo.compressed) + { + mCaps.compressedTextureFormats.push_back(format); + } + + mTextureCaps.insert(format, formatCaps); + } + + mExtensions.maxSamples = maxSamples; +} + +Data Context::getData() const +{ + return Data(mClientVersion, mState, mCaps, mTextureCaps, mExtensions, mResourceManager); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Context.h b/src/3rdparty/angle/src/libANGLE/Context.h new file mode 100644 index 0000000000..eeada43355 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Context.h @@ -0,0 +1,277 @@ +// +// Copyright (c) 2002-2014 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 LIBANGLE_CONTEXT_H_ +#define LIBANGLE_CONTEXT_H_ + +#include "common/angleutils.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Data.h" +#include "libANGLE/Error.h" +#include "libANGLE/HandleAllocator.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/angletypes.h" + +#include "angle_gl.h" + +#include +#include +#include + +namespace rx +{ +class Renderer; +} + +namespace egl +{ +class Surface; +struct Config; +} + +namespace gl +{ +class Compiler; +class Shader; +class Program; +class Texture; +class Framebuffer; +class Renderbuffer; +class FenceNV; +class FenceSync; +class Query; +class ResourceManager; +class Buffer; +struct VertexAttribute; +class VertexArray; +class Sampler; +class TransformFeedback; + +class Context final : angle::NonCopyable +{ + public: + Context(const egl::Config *config, int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); + + virtual ~Context(); + + void makeCurrent(egl::Surface *surface); + + virtual void markContextLost(); + bool isContextLost(); + + // 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(); + GLuint createSampler(); + GLuint createTransformFeedback(); + GLsync createFenceSync(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteRenderbuffer(GLuint renderbuffer); + void deleteSampler(GLuint sampler); + void deleteTransformFeedback(GLuint transformFeedback); + void deleteFenceSync(GLsync fenceSync); + + // Framebuffers are owned by the Context, so these methods do not pass through + GLuint createFramebuffer(); + void deleteFramebuffer(GLuint framebuffer); + + // NV Fences are owned by the Context. + GLuint createFenceNV(); + void deleteFenceNV(GLuint fence); + + // Queries are owned by the Context; + GLuint createQuery(); + void deleteQuery(GLuint query); + + // Vertex arrays are owned by the Context + GLuint createVertexArray(); + void deleteVertexArray(GLuint vertexArray); + + void bindArrayBuffer(GLuint buffer); + void bindElementArrayBuffer(GLuint buffer); + void bindTexture(GLenum target, GLuint handle); + void bindReadFramebuffer(GLuint framebuffer); + void bindDrawFramebuffer(GLuint framebuffer); + void bindRenderbuffer(GLuint renderbuffer); + void bindVertexArray(GLuint vertexArray); + void bindSampler(GLuint textureUnit, GLuint sampler); + void bindGenericUniformBuffer(GLuint buffer); + void bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); + void bindGenericTransformFeedbackBuffer(GLuint buffer); + void bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); + void bindCopyReadBuffer(GLuint buffer); + void bindCopyWriteBuffer(GLuint buffer); + void bindPixelPackBuffer(GLuint buffer); + void bindPixelUnpackBuffer(GLuint buffer); + void useProgram(GLuint program); + void bindTransformFeedback(GLuint transformFeedback); + + Error beginQuery(GLenum target, GLuint query); + Error endQuery(GLenum target); + + void setFramebufferZero(Framebuffer *framebuffer); + + void setVertexAttribDivisor(GLuint index, GLuint divisor); + + void samplerParameteri(GLuint sampler, GLenum pname, GLint param); + void samplerParameterf(GLuint sampler, GLenum pname, GLfloat param); + GLint getSamplerParameteri(GLuint sampler, GLenum pname); + GLfloat getSamplerParameterf(GLuint sampler, GLenum pname); + + Buffer *getBuffer(GLuint handle); + FenceNV *getFenceNV(GLuint handle); + FenceSync *getFenceSync(GLsync handle) const; + Shader *getShader(GLuint handle) const; + Program *getProgram(GLuint handle) const; + Texture *getTexture(GLuint handle) const; + Framebuffer *getFramebuffer(GLuint handle) const; + Renderbuffer *getRenderbuffer(GLuint handle); + VertexArray *getVertexArray(GLuint handle) const; + Sampler *getSampler(GLuint handle) const; + Query *getQuery(GLuint handle, bool create, GLenum type); + TransformFeedback *getTransformFeedback(GLuint handle) const; + + Texture *getTargetTexture(GLenum target) const; + Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; + + Compiler *getCompiler() const; + + bool isSampler(GLuint samplerName) const; + + void getBooleanv(GLenum pname, GLboolean *params); + void getFloatv(GLenum pname, GLfloat *params); + void getIntegerv(GLenum pname, GLint *params); + void getInteger64v(GLenum pname, GLint64 *params); + + bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); + bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); + + bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); + bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); + + Error drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances); + Error drawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const rx::RangeUI &indexRange); + Error flush(); + Error finish(); + + void recordError(const Error &error); + + GLenum getError(); + GLenum getResetStatus(); + virtual bool isResetNotificationEnabled(); + + virtual int getClientVersion() const; + + EGLint getConfigID() const; + EGLenum getClientType() const; + EGLenum getRenderBuffer() const; + + const Caps &getCaps() const; + const TextureCapsMap &getTextureCaps() const; + const Extensions &getExtensions() const; + + const std::string &getRendererString() const; + + const std::string &getExtensionString() const; + const std::string &getExtensionString(size_t idx) const; + size_t getExtensionStringCount() const; + + rx::Renderer *getRenderer() { return mRenderer; } + + State &getState() { return mState; } + const State &getState() const { return mState; } + + Data getData() const; + + private: + void detachBuffer(GLuint buffer); + void detachTexture(GLuint texture); + void detachFramebuffer(GLuint framebuffer); + void detachRenderbuffer(GLuint renderbuffer); + void detachVertexArray(GLuint vertexArray); + void detachTransformFeedback(GLuint transformFeedback); + void detachSampler(GLuint sampler); + + void initRendererString(); + void initExtensionStrings(); + + void initCaps(GLuint clientVersion); + + // Caps to use for validation + Caps mCaps; + TextureCapsMap mTextureCaps; + Extensions mExtensions; + + // Shader compiler + Compiler *mCompiler; + + rx::Renderer *const mRenderer; + State mState; + + int mClientVersion; + + EGLint mConfigID; + EGLenum mClientType; + EGLenum mRenderBuffer; + + TextureMap mZeroTextures; + + typedef std::map FramebufferMap; + FramebufferMap mFramebufferMap; + HandleAllocator mFramebufferHandleAllocator; + + typedef std::map FenceNVMap; + FenceNVMap mFenceNVMap; + HandleAllocator mFenceNVHandleAllocator; + + typedef std::map QueryMap; + QueryMap mQueryMap; + HandleAllocator mQueryHandleAllocator; + + typedef std::map VertexArrayMap; + VertexArrayMap mVertexArrayMap; + HandleAllocator mVertexArrayHandleAllocator; + + BindingPointer mTransformFeedbackZero; + typedef std::map TransformFeedbackMap; + TransformFeedbackMap mTransformFeedbackMap; + HandleAllocator mTransformFeedbackAllocator; + + std::string mRendererString; + std::string mExtensionString; + std::vector mExtensionStrings; + + // Recorded errors + typedef std::set ErrorSet; + ErrorSet mErrors; + + // Current/lost context flags + bool mHasBeenCurrent; + bool mContextLost; + GLenum mResetStatus; + GLenum mResetStrategy; + bool mRobustAccess; + + ResourceManager *mResourceManager; +}; +} + +#endif // LIBANGLE_CONTEXT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Data.cpp b/src/3rdparty/angle/src/libANGLE/Data.cpp new file mode 100644 index 0000000000..7832e21b23 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Data.cpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2014 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. +// + +// Data.cpp: Container class for all GL relevant state, caps and objects + +#include "libANGLE/Data.h" +#include "libANGLE/ResourceManager.h" + +namespace gl +{ + +Data::Data(GLint clientVersionIn, const State &stateIn, const Caps &capsIn, + const TextureCapsMap &textureCapsIn, const Extensions &extensionsIn, + const ResourceManager *resourceManagerIn) + : clientVersion(clientVersionIn), + state(&stateIn), + caps(&capsIn), + textureCaps(&textureCapsIn), + extensions(&extensionsIn), + resourceManager(resourceManagerIn) +{} + +Data::~Data() +{ +} + +Data::Data(const Data &other) + : clientVersion(other.clientVersion), + state(other.state), + caps(other.caps), + textureCaps(other.textureCaps), + extensions(other.extensions), + resourceManager(other.resourceManager) +{ +} + +Data &Data::operator=(const Data &other) +{ + clientVersion = other.clientVersion; + state = other.state; + caps = other.caps; + textureCaps = other.textureCaps; + extensions = other.extensions; + resourceManager = other.resourceManager; + return *this; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Data.h b/src/3rdparty/angle/src/libANGLE/Data.h new file mode 100644 index 0000000000..7eb6827dfc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Data.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 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. +// + +// Data.h: Container class for all GL relevant state, caps and objects + +#ifndef LIBANGLE_DATA_H_ +#define LIBANGLE_DATA_H_ + +#include "libANGLE/State.h" + +namespace gl +{ + +struct Data final +{ + public: + Data(GLint clientVersion, const State &state, const Caps &caps, + const TextureCapsMap &textureCaps, const Extensions &extensions, + const ResourceManager *resourceManager); + ~Data(); + + Data(const Data &other); + Data &operator=(const Data &other); + + GLint clientVersion; + const State *state; + const Caps *caps; + const TextureCapsMap *textureCaps; + const Extensions *extensions; + const ResourceManager *resourceManager; +}; + +} + +#endif // LIBANGLE_DATA_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp new file mode 100644 index 0000000000..1f54f82dea --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Display.cpp @@ -0,0 +1,675 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/Display.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "common/debug.h" +#include "common/mathutil.h" +#include "common/platform.h" +#include "libANGLE/Context.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/DisplayImpl.h" + +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) +# include "libANGLE/renderer/d3d/DisplayD3D.h" +#endif + +#if defined(ANGLE_ENABLE_OPENGL) +# if defined(ANGLE_PLATFORM_WINDOWS) +# include "libANGLE/renderer/gl/wgl/DisplayWGL.h" +# else +# error Unsupported OpenGL platform. +# endif +#endif + +namespace egl +{ + +namespace +{ + +class DefaultPlatform : public angle::Platform +{ +public: + DefaultPlatform() {} + ~DefaultPlatform() override {} +}; + +DefaultPlatform *defaultPlatform = nullptr; + +void InitDefaultPlatformImpl() +{ + if (ANGLEPlatformCurrent() == nullptr) + { + if (defaultPlatform == nullptr) + { + defaultPlatform = new DefaultPlatform(); + } + + ANGLEPlatformInitialize(defaultPlatform); + } +} + +void DeinitDefaultPlatformImpl() +{ + if (defaultPlatform != nullptr) + { + if (ANGLEPlatformCurrent() == defaultPlatform) + { + ANGLEPlatformShutdown(); + } + + SafeDelete(defaultPlatform); + } +} + +typedef std::map WindowSurfaceMap; +// Get a map of all EGL window surfaces to validate that no window has more than one EGL surface +// associated with it. +static WindowSurfaceMap *GetWindowSurfaces() +{ + static WindowSurfaceMap windowSurfaces; + return &windowSurfaces; +} + +typedef std::map DisplayMap; +static DisplayMap *GetDisplayMap() +{ + static DisplayMap displays; + return &displays; +} + +rx::DisplayImpl *CreateDisplayImpl(const AttributeMap &attribMap) +{ + rx::DisplayImpl *impl = nullptr; + EGLint displayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + switch (displayType) + { + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) + // Default to D3D displays + impl = new rx::DisplayD3D(); +#else + // No display available + UNREACHABLE(); +#endif + break; + + case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) + impl = new rx::DisplayD3D(); +#else + // A D3D display was requested on a platform that doesn't support it + UNREACHABLE(); +#endif + break; + + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: +#if defined(ANGLE_ENABLE_OPENGL) +#if defined(ANGLE_PLATFORM_WINDOWS) + impl = new rx::DisplayWGL(); +#else +#error Unsupported OpenGL platform. +#endif +#else + UNREACHABLE(); +#endif + break; + + default: + UNREACHABLE(); + break; + } + + ASSERT(impl != nullptr); + return impl; +} + +} + +Display *Display::getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap) +{ + // Initialize the global platform if not already + InitDefaultPlatformImpl(); + + Display *display = NULL; + + DisplayMap *displays = GetDisplayMap(); + DisplayMap::const_iterator iter = displays->find(displayId); + if (iter != displays->end()) + { + display = iter->second; + } + + if (display == nullptr) + { + // Validate the native display + if (!Display::isValidNativeDisplay(displayId)) + { + return NULL; + } + + display = new Display(displayId); + displays->insert(std::make_pair(displayId, display)); + } + + // Apply new attributes if the display is not initialized yet. + if (!display->isInitialized()) + { + rx::DisplayImpl* impl = CreateDisplayImpl(attribMap); + display->setAttributes(impl, attribMap); + } + + return display; +} + +Display::Display(EGLNativeDisplayType displayId) + : mImplementation(nullptr), + mDisplayId(displayId), + mAttributeMap(), + mConfigSet(), + mContextSet(), + mInitialized(false), + mCaps(), + mDisplayExtensions(), + mDisplayExtensionString(), + mVendorString() +{ +} + +Display::~Display() +{ + terminate(); + + DisplayMap *displays = GetDisplayMap(); + DisplayMap::iterator iter = displays->find(mDisplayId); + if (iter != displays->end()) + { + displays->erase(iter); + } + + SafeDelete(mImplementation); +} + +void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap) +{ + ASSERT(!mInitialized); + + ASSERT(impl != nullptr); + SafeDelete(mImplementation); + mImplementation = impl; + + mAttributeMap = attribMap; +} + +Error Display::initialize() +{ + ASSERT(mImplementation != nullptr); + + if (isInitialized()) + { + return Error(EGL_SUCCESS); + } + + Error error = mImplementation->initialize(this); + if (error.isError()) + { + return error; + } + + mCaps = mImplementation->getCaps(); + + mConfigSet = mImplementation->generateConfigs(); + if (mConfigSet.size() == 0) + { + mImplementation->terminate(); + return Error(EGL_NOT_INITIALIZED); + } + + initDisplayExtensions(); + initVendorString(); + + mInitialized = true; + return Error(EGL_SUCCESS); +} + +void Display::terminate() +{ + makeCurrent(nullptr, nullptr, nullptr); + + while (!mContextSet.empty()) + { + destroyContext(*mContextSet.begin()); + } + + mConfigSet.clear(); + + mImplementation->terminate(); + mInitialized = false; + + // De-init default platform + DeinitDefaultPlatformImpl(); +} + +std::vector Display::getConfigs(const egl::AttributeMap &attribs) const +{ + return mConfigSet.filter(attribs); +} + +bool Display::getConfigAttrib(const Config *configuration, EGLint attribute, EGLint *value) +{ + switch (attribute) + { + case EGL_BUFFER_SIZE: *value = configuration->bufferSize; break; + case EGL_ALPHA_SIZE: *value = configuration->alphaSize; break; + case EGL_BLUE_SIZE: *value = configuration->blueSize; break; + case EGL_GREEN_SIZE: *value = configuration->greenSize; break; + case EGL_RED_SIZE: *value = configuration->redSize; break; + case EGL_DEPTH_SIZE: *value = configuration->depthSize; break; + case EGL_STENCIL_SIZE: *value = configuration->stencilSize; break; + case EGL_CONFIG_CAVEAT: *value = configuration->configCaveat; break; + case EGL_CONFIG_ID: *value = configuration->configID; break; + case EGL_LEVEL: *value = configuration->level; break; + case EGL_NATIVE_RENDERABLE: *value = configuration->nativeRenderable; break; + case EGL_NATIVE_VISUAL_TYPE: *value = configuration->nativeVisualType; break; + case EGL_SAMPLES: *value = configuration->samples; break; + case EGL_SAMPLE_BUFFERS: *value = configuration->sampleBuffers; break; + case EGL_SURFACE_TYPE: *value = configuration->surfaceType; break; + case EGL_TRANSPARENT_TYPE: *value = configuration->transparentType; break; + case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->transparentBlueValue; break; + case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->transparentGreenValue; break; + case EGL_TRANSPARENT_RED_VALUE: *value = configuration->transparentRedValue; break; + case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->bindToTextureRGB; break; + case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->bindToTextureRGBA; break; + case EGL_MIN_SWAP_INTERVAL: *value = configuration->minSwapInterval; break; + case EGL_MAX_SWAP_INTERVAL: *value = configuration->maxSwapInterval; break; + case EGL_LUMINANCE_SIZE: *value = configuration->luminanceSize; break; + case EGL_ALPHA_MASK_SIZE: *value = configuration->alphaMaskSize; break; + case EGL_COLOR_BUFFER_TYPE: *value = configuration->colorBufferType; break; + case EGL_RENDERABLE_TYPE: *value = configuration->renderableType; break; + case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: *value = configuration->conformant; break; + case EGL_MAX_PBUFFER_WIDTH: *value = configuration->maxPBufferWidth; break; + case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->maxPBufferHeight; break; + case EGL_MAX_PBUFFER_PIXELS: *value = configuration->maxPBufferPixels; break; + default: + return false; + } + + return true; +} + +Error Display::createWindowSurface(const Config *configuration, EGLNativeWindowType window, const AttributeMap &attribs, + Surface **outSurface) +{ + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + rx::SurfaceImpl *surfaceImpl = nullptr; + Error error = mImplementation->createWindowSurface(configuration, window, attribs, &surfaceImpl); + if (error.isError()) + { + return error; + } + + ASSERT(surfaceImpl != nullptr); + Surface *surface = new Surface(surfaceImpl, EGL_WINDOW_BIT, configuration, attribs); + mImplementation->getSurfaceSet().insert(surface); + + WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); + ASSERT(windowSurfaces && windowSurfaces->find(window) == windowSurfaces->end()); + windowSurfaces->insert(std::make_pair(window, surface)); + + ASSERT(outSurface != nullptr); + *outSurface = surface; + return Error(EGL_SUCCESS); +} + +Error Display::createPbufferSurface(const Config *configuration, const AttributeMap &attribs, Surface **outSurface) +{ + ASSERT(isInitialized()); + + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + rx::SurfaceImpl *surfaceImpl = nullptr; + Error error = mImplementation->createPbufferSurface(configuration, attribs, &surfaceImpl); + if (error.isError()) + { + return error; + } + + ASSERT(surfaceImpl != nullptr); + Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs); + mImplementation->getSurfaceSet().insert(surface); + + ASSERT(outSurface != nullptr); + *outSurface = surface; + return Error(EGL_SUCCESS); +} + +Error Display::createPbufferFromClientBuffer(const Config *configuration, EGLClientBuffer shareHandle, + const AttributeMap &attribs, Surface **outSurface) +{ + ASSERT(isInitialized()); + + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + rx::SurfaceImpl *surfaceImpl = nullptr; + Error error = mImplementation->createPbufferFromClientBuffer(configuration, shareHandle, attribs, &surfaceImpl); + if (error.isError()) + { + return error; + } + + ASSERT(surfaceImpl != nullptr); + Surface *surface = new Surface(surfaceImpl, EGL_PBUFFER_BIT, configuration, attribs); + mImplementation->getSurfaceSet().insert(surface); + + ASSERT(outSurface != nullptr); + *outSurface = surface; + return Error(EGL_SUCCESS); +} + +Error Display::createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs, + Surface **outSurface) +{ + ASSERT(isInitialized()); + + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + rx::SurfaceImpl *surfaceImpl = nullptr; + Error error = mImplementation->createPixmapSurface(configuration, nativePixmap, attribs, &surfaceImpl); + if (error.isError()) + { + return error; + } + + ASSERT(surfaceImpl != nullptr); + Surface *surface = new Surface(surfaceImpl, EGL_PIXMAP_BIT, configuration, attribs); + mImplementation->getSurfaceSet().insert(surface); + + ASSERT(outSurface != nullptr); + *outSurface = surface; + return Error(EGL_SUCCESS); +} + +Error Display::createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, + gl::Context **outContext) +{ + ASSERT(isInitialized()); + + if (mImplementation->testDeviceLost()) + { + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } + } + + gl::Context *context = nullptr; + Error error = mImplementation->createContext(configuration, shareContext, attribs, &context); + if (error.isError()) + { + return error; + } + + ASSERT(context != nullptr); + mContextSet.insert(context); + + ASSERT(outContext != nullptr); + *outContext = context; + return Error(EGL_SUCCESS); +} + +Error Display::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) +{ + Error error = mImplementation->makeCurrent(drawSurface, readSurface, context); + if (error.isError()) + { + return error; + } + + if (context && drawSurface) + { + context->makeCurrent(drawSurface); + } + + return egl::Error(EGL_SUCCESS); +} + +Error Display::restoreLostDevice() +{ + for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) + { + if ((*ctx)->isResetNotificationEnabled()) + { + // If reset notifications have been requested, application must delete all contexts first + return Error(EGL_CONTEXT_LOST); + } + } + + return mImplementation->restoreLostDevice(); +} + +void Display::destroySurface(Surface *surface) +{ + if (surface->getType() == EGL_WINDOW_BIT) + { + WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); + ASSERT(windowSurfaces); + + bool surfaceRemoved = false; + for (WindowSurfaceMap::iterator iter = windowSurfaces->begin(); iter != windowSurfaces->end(); iter++) + { + if (iter->second == surface) + { + windowSurfaces->erase(iter); + surfaceRemoved = true; + break; + } + } + + ASSERT(surfaceRemoved); + } + + mImplementation->destroySurface(surface); +} + +void Display::destroyContext(gl::Context *context) +{ + mContextSet.erase(context); + SafeDelete(context); +} + +bool Display::isDeviceLost() const +{ + ASSERT(isInitialized()); + return mImplementation->isDeviceLost(); +} + +bool Display::testDeviceLost() +{ + ASSERT(isInitialized()); + return mImplementation->testDeviceLost(); +} + +void Display::notifyDeviceLost() +{ + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) + { + (*context)->markContextLost(); + } +} + +const Caps &Display::getCaps() const +{ + return mCaps; +} + +bool Display::isInitialized() const +{ + return mInitialized; +} + +bool Display::isValidConfig(const Config *config) const +{ + return mConfigSet.contains(config); +} + +bool Display::isValidContext(gl::Context *context) const +{ + return mContextSet.find(context) != mContextSet.end(); +} + +bool Display::isValidSurface(Surface *surface) const +{ + return mImplementation->getSurfaceSet().find(surface) != mImplementation->getSurfaceSet().end(); +} + +bool Display::hasExistingWindowSurface(EGLNativeWindowType window) +{ + WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); + ASSERT(windowSurfaces); + + return windowSurfaces->find(window) != windowSurfaces->end(); +} + +static ClientExtensions GenerateClientExtensions() +{ + ClientExtensions extensions; + + extensions.clientExtensions = true; + extensions.platformBase = true; + extensions.platformANGLE = true; + +#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) + extensions.platformANGLED3D = true; +#endif + +#if defined(ANGLE_ENABLE_OPENGL) + extensions.platformANGLEOpenGL = true; +#endif + + return extensions; +} + +template +static std::string GenerateExtensionsString(const T &extensions) +{ + std::vector extensionsVector = extensions.getStrings(); + + std::ostringstream stream; + std::copy(extensionsVector.begin(), extensionsVector.end(), std::ostream_iterator(stream, " ")); + return stream.str(); +} + +const ClientExtensions &Display::getClientExtensions() +{ + static const ClientExtensions clientExtensions = GenerateClientExtensions(); + return clientExtensions; +} + +const std::string &Display::getClientExtensionString() +{ + static const std::string clientExtensionsString = GenerateExtensionsString(getClientExtensions()); + return clientExtensionsString; +} + +void Display::initDisplayExtensions() +{ + mDisplayExtensions = mImplementation->getExtensions(); + mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions); +} + +bool Display::isValidNativeWindow(EGLNativeWindowType window) const +{ + return mImplementation->isValidNativeWindow(window); +} + +bool Display::isValidNativeDisplay(EGLNativeDisplayType display) +{ + // TODO(jmadill): handle this properly + if (display == EGL_DEFAULT_DISPLAY) + { + return true; + } + +#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_ENABLE_WINDOWS_STORE) + if (display == EGL_SOFTWARE_DISPLAY_ANGLE || + display == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || + display == EGL_D3D11_ONLY_DISPLAY_ANGLE) + { + return true; + } + return (WindowFromDC(display) != NULL); +#else + return true; +#endif +} + +void Display::initVendorString() +{ + mVendorString = mImplementation->getVendorString(); +} + +const DisplayExtensions &Display::getExtensions() const +{ + return mDisplayExtensions; +} + +const std::string &Display::getExtensionString() const +{ + return mDisplayExtensionString; +} + +const std::string &Display::getVendorString() const +{ + return mVendorString; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h new file mode 100644 index 0000000000..5ab3f9c0e9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Display.h @@ -0,0 +1,124 @@ +// +// Copyright (c) 2002-2013 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 LIBANGLE_DISPLAY_H_ +#define LIBANGLE_DISPLAY_H_ + +#include +#include + +#include "libANGLE/Error.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Config.h" +#include "libANGLE/AttributeMap.h" + +namespace gl +{ +class Context; +} + +namespace rx +{ +class DisplayImpl; +} + +namespace egl +{ +class Surface; + +class Display final : angle::NonCopyable +{ + public: + ~Display(); + + Error initialize(); + void terminate(); + + static egl::Display *getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap); + + static const ClientExtensions &getClientExtensions(); + static const std::string &getClientExtensionString(); + + std::vector getConfigs(const egl::AttributeMap &attribs) const; + bool getConfigAttrib(const Config *configuration, EGLint attribute, EGLint *value); + + Error createWindowSurface(const Config *configuration, EGLNativeWindowType window, const AttributeMap &attribs, + Surface **outSurface); + Error createPbufferSurface(const Config *configuration, const AttributeMap &attribs, Surface **outSurface); + Error createPbufferFromClientBuffer(const Config *configuration, EGLClientBuffer shareHandle, const AttributeMap &attribs, + Surface **outSurface); + Error createPixmapSurface(const Config *configuration, NativePixmapType nativePixmap, const AttributeMap &attribs, + Surface **outSurface); + + Error createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, + gl::Context **outContext); + + Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context); + + void destroySurface(egl::Surface *surface); + void destroyContext(gl::Context *context); + + bool isInitialized() const; + bool isValidConfig(const Config *config) const; + bool isValidContext(gl::Context *context) const; + bool isValidSurface(egl::Surface *surface) const; + bool isValidNativeWindow(EGLNativeWindowType window) const; + + static bool isValidNativeDisplay(EGLNativeDisplayType display); + static bool hasExistingWindowSurface(EGLNativeWindowType window); + + bool isDeviceLost() const; + bool testDeviceLost(); + void notifyDeviceLost(); + + const Caps &getCaps() const; + + const DisplayExtensions &getExtensions() const; + const std::string &getExtensionString() const; + const std::string &getVendorString() const; + + const AttributeMap &getAttributeMap() const { return mAttributeMap; } + EGLNativeDisplayType getNativeDisplayId() const { return mDisplayId; } + + rx::DisplayImpl *getImplementation() { return mImplementation; } + + private: + Display(EGLNativeDisplayType displayId); + + void setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap); + + Error restoreLostDevice(); + + void initDisplayExtensions(); + void initVendorString(); + + rx::DisplayImpl *mImplementation; + + EGLNativeDisplayType mDisplayId; + AttributeMap mAttributeMap; + + ConfigSet mConfigSet; + + typedef std::set ContextSet; + ContextSet mContextSet; + + bool mInitialized; + + Caps mCaps; + + DisplayExtensions mDisplayExtensions; + std::string mDisplayExtensionString; + + std::string mVendorString; +}; + +} + +#endif // LIBANGLE_DISPLAY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Error.cpp b/src/3rdparty/angle/src/libANGLE/Error.cpp new file mode 100644 index 0000000000..e17f26bec4 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Error.cpp @@ -0,0 +1,86 @@ +// +// Copyright (c) 2014 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. +// + +// Error.cpp: Implements the egl::Error and gl::Error classes which encapsulate API errors +// and optional error messages. + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include + +namespace gl +{ + +Error::Error(GLenum errorCode, const char *msg, ...) + : mCode(errorCode), + mMessage(nullptr) +{ + va_list vararg; + va_start(vararg, msg); + createMessageString(); + *mMessage = FormatString(msg, vararg); + va_end(vararg); +} + +void Error::createMessageString() const +{ + if (mMessage == nullptr) + { + mMessage = new std::string(); + } +} + +const std::string &Error::getMessage() const +{ + createMessageString(); + return *mMessage; +} + +} + +namespace egl +{ + +Error::Error(EGLint errorCode, const char *msg, ...) + : mCode(errorCode), + mID(0), + mMessage(nullptr) +{ + va_list vararg; + va_start(vararg, msg); + createMessageString(); + *mMessage = FormatString(msg, vararg); + va_end(vararg); +} + +Error::Error(EGLint errorCode, EGLint id, const char *msg, ...) + : mCode(errorCode), + mID(id), + mMessage(nullptr) +{ + va_list vararg; + va_start(vararg, msg); + createMessageString(); + *mMessage = FormatString(msg, vararg); + va_end(vararg); +} +void Error::createMessageString() const +{ + if (mMessage == nullptr) + { + mMessage = new std::string(); + } +} + +const std::string &Error::getMessage() const +{ + createMessageString(); + return *mMessage; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Error.h b/src/3rdparty/angle/src/libANGLE/Error.h new file mode 100644 index 0000000000..896b777567 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Error.h @@ -0,0 +1,83 @@ +// +// Copyright (c) 2014 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. + +// Error.h: Defines the egl::Error and gl::Error classes which encapsulate API errors +// and optional error messages. + +#ifndef LIBANGLE_ERROR_H_ +#define LIBANGLE_ERROR_H_ + +#include "angle_gl.h" +#include "common/platform.h" +#include + +#include + +namespace gl +{ + +class Error final +{ + public: + explicit inline Error(GLenum errorCode); + Error(GLenum errorCode, const char *msg, ...); + inline Error(const Error &other); + inline Error(Error &&other); + + inline ~Error(); + + inline Error &operator=(const Error &other); + inline Error &operator=(Error &&other); + + inline GLenum getCode() const; + inline bool isError() const; + + const std::string &getMessage() const; + + private: + void createMessageString() const; + + GLenum mCode; + mutable std::string *mMessage; +}; + +} + +namespace egl +{ + +class Error final +{ + public: + explicit inline Error(EGLint errorCode); + Error(EGLint errorCode, const char *msg, ...); + Error(EGLint errorCode, EGLint id, const char *msg, ...); + inline Error(const Error &other); + inline Error(Error &&other); + + inline ~Error(); + + inline Error &operator=(const Error &other); + inline Error &operator=(Error &&other); + + inline EGLint getCode() const; + inline EGLint getID() const; + inline bool isError() const; + + const std::string &getMessage() const; + + private: + void createMessageString() const; + + EGLint mCode; + EGLint mID; + mutable std::string *mMessage; +}; + +} + +#include "Error.inl" + +#endif // LIBANGLE_ERROR_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Error.inl b/src/3rdparty/angle/src/libANGLE/Error.inl new file mode 100644 index 0000000000..32e8f05828 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Error.inl @@ -0,0 +1,163 @@ +// +// Copyright (c) 2014 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. + +// Error.inl: Inline definitions of egl::Error and gl::Error classes which encapsulate API errors +// and optional error messages. + +#include "common/angleutils.h" + +#include + +namespace gl +{ + +Error::Error(GLenum errorCode) + : mCode(errorCode), + mMessage(nullptr) +{ +} + +Error::Error(const Error &other) + : mCode(other.mCode), + mMessage(nullptr) +{ + if (other.mMessage != nullptr) + { + createMessageString(); + *mMessage = *(other.mMessage); + } +} + +Error::Error(Error &&other) + : mCode(other.mCode), + mMessage(other.mMessage) +{ + other.mMessage = nullptr; +} + +Error::~Error() +{ + SafeDelete(mMessage); +} + +Error &Error::operator=(const Error &other) +{ + mCode = other.mCode; + + if (other.mMessage != nullptr) + { + createMessageString(); + *mMessage = *(other.mMessage); + } + else + { + SafeDelete(mMessage); + } + + return *this; +} + +Error &Error::operator=(Error &&other) +{ + mCode = other.mCode; + mMessage = other.mMessage; + + other.mMessage = nullptr; + + return *this; +} + +GLenum Error::getCode() const +{ + return mCode; +} + +bool Error::isError() const +{ + return (mCode != GL_NO_ERROR); +} + +} + +namespace egl +{ + +Error::Error(EGLint errorCode) + : mCode(errorCode), + mID(0), + mMessage(nullptr) +{ +} + +Error::Error(const Error &other) + : mCode(other.mCode), + mID(other.mID), + mMessage(nullptr) +{ + if (other.mMessage != nullptr) + { + createMessageString(); + *mMessage = *(other.mMessage); + } +} + +Error::Error(Error &&other) + : mCode(other.mCode), + mID(other.mID), + mMessage(other.mMessage) +{ + other.mMessage = nullptr; +} + +Error::~Error() +{ + SafeDelete(mMessage); +} + +Error &Error::operator=(const Error &other) +{ + mCode = other.mCode; + mID = other.mID; + + if (other.mMessage != nullptr) + { + createMessageString(); + *mMessage = *(other.mMessage); + } + else + { + SafeDelete(mMessage); + } + + return *this; +} + +Error &Error::operator=(Error &&other) +{ + mCode = other.mCode; + mID = other.mID; + mMessage = other.mMessage; + + other.mMessage = nullptr; + + return *this; +} + +EGLint Error::getCode() const +{ + return mCode; +} + +EGLint Error::getID() const +{ + return mID; +} + +bool Error::isError() const +{ + return (mCode != EGL_SUCCESS); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Fence.cpp b/src/3rdparty/angle/src/libANGLE/Fence.cpp new file mode 100644 index 0000000000..8ab4cc9daa --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Fence.cpp @@ -0,0 +1,117 @@ +// +// Copyright (c) 2002-2013 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::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// extension and GLES3 sync objects. + +#include "libANGLE/Fence.h" + +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/FenceSyncImpl.h" +#include "libANGLE/renderer/Renderer.h" +#include "common/utilities.h" + +#include "angle_gl.h" + +namespace gl +{ + +FenceNV::FenceNV(rx::FenceNVImpl *impl) + : mFence(impl), + mIsSet(false), + mStatus(GL_FALSE), + mCondition(GL_NONE) +{ +} + +FenceNV::~FenceNV() +{ + SafeDelete(mFence); +} + +GLboolean FenceNV::isFence() const +{ + // GL_NV_fence spec: + // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. + return (mIsSet ? GL_TRUE : GL_FALSE); +} + +Error FenceNV::setFence(GLenum condition) +{ + Error error = mFence->set(); + if (error.isError()) + { + return error; + } + + mCondition = condition; + mStatus = GL_FALSE; + mIsSet = true; + + return Error(GL_NO_ERROR); +} + +Error FenceNV::testFence(GLboolean *outResult) +{ + // Flush the command buffer by default + Error error = mFence->test(true, &mStatus); + if (error.isError()) + { + return error; + } + + *outResult = mStatus; + return Error(GL_NO_ERROR); +} + +Error FenceNV::finishFence() +{ + ASSERT(mIsSet); + + return mFence->finishFence(&mStatus); +} + +FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id) + : RefCountObject(id), + mFence(impl), + mCondition(GL_NONE) +{ +} + +FenceSync::~FenceSync() +{ + SafeDelete(mFence); +} + +Error FenceSync::set(GLenum condition) +{ + Error error = mFence->set(); + if (error.isError()) + { + return error; + } + + mCondition = condition; + return Error(GL_NO_ERROR); +} + +Error FenceSync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +{ + ASSERT(mCondition != GL_NONE); + return mFence->clientWait(flags, timeout, outResult); +} + +Error FenceSync::serverWait(GLbitfield flags, GLuint64 timeout) +{ + return mFence->serverWait(flags, timeout); +} + +Error FenceSync::getStatus(GLint *outResult) const +{ + return mFence->getStatus(outResult); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Fence.h b/src/3rdparty/angle/src/libANGLE/Fence.h new file mode 100644 index 0000000000..bcd66b6831 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Fence.h @@ -0,0 +1,71 @@ +// +// Copyright (c) 2002-2013 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::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// extension and GLES3 sync objects. + +#ifndef LIBANGLE_FENCE_H_ +#define LIBANGLE_FENCE_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +namespace rx +{ +class FenceNVImpl; +class FenceSyncImpl; +} + +namespace gl +{ + +class FenceNV final : angle::NonCopyable +{ + public: + explicit FenceNV(rx::FenceNVImpl *impl); + virtual ~FenceNV(); + + GLboolean isFence() const; + Error setFence(GLenum condition); + Error testFence(GLboolean *outResult); + Error finishFence(); + + GLboolean getStatus() const { return mStatus; } + GLenum getCondition() const { return mCondition; } + + private: + rx::FenceNVImpl *mFence; + + bool mIsSet; + + GLboolean mStatus; + GLenum mCondition; +}; + +class FenceSync final : public RefCountObject +{ + public: + explicit FenceSync(rx::FenceSyncImpl *impl, GLuint id); + virtual ~FenceSync(); + + Error set(GLenum condition); + Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult); + Error serverWait(GLbitfield flags, GLuint64 timeout); + Error getStatus(GLint *outResult) const; + + GLenum getCondition() const { return mCondition; } + + private: + rx::FenceSyncImpl *mFence; + + GLenum mCondition; +}; + +} + +#endif // LIBANGLE_FENCE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp b/src/3rdparty/angle/src/libANGLE/Float16ToFloat32.cpp new file mode 100644 index 0000000000..5bf7b3fce8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/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/libANGLE/Framebuffer.cpp b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp new file mode 100644 index 0000000000..b1dd4a1b0f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp @@ -0,0 +1,658 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/Framebuffer.h" + +#include "common/utilities.h" +#include "libANGLE/Config.h" +#include "libANGLE/Context.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/FramebufferImpl.h" +#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/RenderbufferImpl.h" +#include "libANGLE/renderer/Workarounds.h" + +namespace gl +{ + +namespace +{ +void DeleteMatchingAttachment(FramebufferAttachment *&attachment, GLenum matchType, GLuint matchId) +{ + if (attachment && attachment->type() == matchType && attachment->id() == matchId) + { + SafeDelete(attachment); + } +} +} + +Framebuffer::Data::Data(const Caps &caps) + : mColorAttachments(caps.maxColorAttachments, nullptr), + mDepthAttachment(nullptr), + mStencilAttachment(nullptr), + mDrawBufferStates(caps.maxDrawBuffers, GL_NONE), + mReadBufferState(GL_COLOR_ATTACHMENT0_EXT) +{ + mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; +} + +Framebuffer::Data::~Data() +{ + for (auto it = mColorAttachments.begin(); it != mColorAttachments.end(); ++it) + { + SafeDelete(*it); + } + SafeDelete(mDepthAttachment); + SafeDelete(mStencilAttachment); +} + +FramebufferAttachment *Framebuffer::Data::getReadAttachment() const +{ + ASSERT(mReadBufferState == GL_BACK || (mReadBufferState >= GL_COLOR_ATTACHMENT0 && mReadBufferState <= GL_COLOR_ATTACHMENT15)); + size_t readIndex = (mReadBufferState == GL_BACK ? 0 : static_cast(mReadBufferState - GL_COLOR_ATTACHMENT0)); + ASSERT(readIndex < mColorAttachments.size()); + return mColorAttachments[readIndex]; +} + +FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const +{ + for (auto it = mColorAttachments.cbegin(); it != mColorAttachments.cend(); ++it) + { + if (*it != nullptr) + { + return *it; + } + } + + return nullptr; +} + +FramebufferAttachment *Framebuffer::Data::getDepthOrStencilAttachment() const +{ + return (mDepthAttachment != nullptr ? mDepthAttachment : mStencilAttachment); +} + +Framebuffer::Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id) + : mData(caps), + mImpl(nullptr), + mId(id) +{ + if (mId == 0) + { + mImpl = factory->createDefaultFramebuffer(mData); + } + else + { + mImpl = factory->createFramebuffer(mData); + } + ASSERT(mImpl != nullptr); +} + +Framebuffer::~Framebuffer() +{ + SafeDelete(mImpl); +} + +void Framebuffer::detachTexture(GLuint textureId) +{ + detachResourceById(GL_TEXTURE, textureId); +} + +void Framebuffer::detachRenderbuffer(GLuint renderbufferId) +{ + detachResourceById(GL_RENDERBUFFER, renderbufferId); +} + +void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId) +{ + for (auto it = mData.mColorAttachments.begin(); it != mData.mColorAttachments.end(); ++it) + { + DeleteMatchingAttachment(*it, resourceType, resourceId); + } + + DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId); + DeleteMatchingAttachment(mData.mStencilAttachment, resourceType, resourceId); +} + +FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const +{ + ASSERT(colorAttachment < mData.mColorAttachments.size()); + return mData.mColorAttachments[colorAttachment]; +} + +FramebufferAttachment *Framebuffer::getDepthbuffer() const +{ + return mData.mDepthAttachment; +} + +FramebufferAttachment *Framebuffer::getStencilbuffer() const +{ + return mData.mStencilAttachment; +} + +FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const +{ + return (hasValidDepthStencil() ? mData.mDepthAttachment : NULL); +} + +FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const +{ + return mData.getDepthOrStencilAttachment(); +} + +FramebufferAttachment *Framebuffer::getReadColorbuffer() const +{ + return mData.getReadAttachment(); +} + +GLenum Framebuffer::getReadColorbufferType() const +{ + FramebufferAttachment *readAttachment = mData.getReadAttachment(); + return (readAttachment ? readAttachment->type() : GL_NONE); +} + +FramebufferAttachment *Framebuffer::getFirstColorbuffer() const +{ + return mData.getFirstColorAttachment(); +} + +FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const +{ + if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) + { + return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0); + } + else + { + switch (attachment) + { + case GL_COLOR: + case GL_BACK: + return getColorbuffer(0); + case GL_DEPTH: + case GL_DEPTH_ATTACHMENT: + return getDepthbuffer(); + case GL_STENCIL: + case GL_STENCIL_ATTACHMENT: + return getStencilbuffer(); + case GL_DEPTH_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: + return getDepthStencilBuffer(); + default: + UNREACHABLE(); + return NULL; + } + } +} + +GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const +{ + ASSERT(colorAttachment < mData.mDrawBufferStates.size()); + return mData.mDrawBufferStates[colorAttachment]; +} + +void Framebuffer::setDrawBuffers(size_t count, const GLenum *buffers) +{ + auto &drawStates = mData.mDrawBufferStates; + + ASSERT(count <= drawStates.size()); + std::copy(buffers, buffers + count, drawStates.begin()); + std::fill(drawStates.begin() + count, drawStates.end(), GL_NONE); + mImpl->setDrawBuffers(count, buffers); +} + +GLenum Framebuffer::getReadBufferState() const +{ + return mData.mReadBufferState; +} + +void Framebuffer::setReadBuffer(GLenum buffer) +{ + ASSERT(buffer == GL_BACK || buffer == GL_NONE || + (buffer >= GL_COLOR_ATTACHMENT0 && + (buffer - GL_COLOR_ATTACHMENT0) < mData.mColorAttachments.size())); + mData.mReadBufferState = buffer; + mImpl->setReadBuffer(buffer); +} + +bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const +{ + ASSERT(colorAttachment < mData.mColorAttachments.size()); + return (mData.mColorAttachments[colorAttachment] && + mData.mDrawBufferStates[colorAttachment] != GL_NONE); +} + +bool Framebuffer::hasEnabledColorAttachment() const +{ + for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment) + { + if (isEnabledColorAttachment(colorAttachment)) + { + return true; + } + } + + return false; +} + +bool Framebuffer::hasStencil() const +{ + return (mData.mStencilAttachment && mData.mStencilAttachment->getStencilSize() > 0); +} + +bool Framebuffer::usingExtendedDrawBuffers() const +{ + for (size_t colorAttachment = 1; colorAttachment < mData.mColorAttachments.size(); ++colorAttachment) + { + if (isEnabledColorAttachment(colorAttachment)) + { + return true; + } + } + + return false; +} + +GLenum Framebuffer::checkStatus(const gl::Data &data) const +{ + // The default framebuffer *must* always be complete, though it may not be + // subject to the same rules as application FBOs. ie, it could have 0x0 size. + if (mId == 0) + { + return GL_FRAMEBUFFER_COMPLETE; + } + + int width = 0; + int height = 0; + unsigned int colorbufferSize = 0; + int samples = -1; + bool missingAttachment = true; + + for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { + const auto &colorAttachment = *it; + if (colorAttachment != nullptr) + { + if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + GLenum internalformat = colorAttachment->getInternalFormat(); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); + const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); + if (colorAttachment->type() == GL_TEXTURE) + { + if (!formatCaps.renderable) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (colorAttachment->type() == GL_RENDERBUFFER) + { + if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + + if (!missingAttachment) + { + // all color attachments must have the same width and height + if (colorAttachment->getWidth() != width || colorAttachment->getHeight() != height) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + + // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that + // all color attachments have the same number of samples for the FBO to be complete. + if (colorAttachment->getSamples() != samples) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; + } + + // in GLES 2.0, all color attachments attachments must have the same number of bitplanes + // in GLES 3.0, there is no such restriction + if (data.clientVersion < 3) + { + if (formatInfo.pixelBytes != colorbufferSize) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + } + } + else + { + width = colorAttachment->getWidth(); + height = colorAttachment->getHeight(); + samples = colorAttachment->getSamples(); + colorbufferSize = formatInfo.pixelBytes; + missingAttachment = false; + } + } + } + + const FramebufferAttachment *depthAttachment = mData.mDepthAttachment; + if (depthAttachment != nullptr) + { + if (depthAttachment->getWidth() == 0 || depthAttachment->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + GLenum internalformat = depthAttachment->getInternalFormat(); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); + const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); + if (depthAttachment->type() == GL_TEXTURE) + { + // depth texture attachments require OES/ANGLE_depth_texture + if (!data.extensions->depthTextures) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (!formatCaps.renderable) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if (formatInfo.depthBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (depthAttachment->type() == GL_RENDERBUFFER) + { + if (!formatCaps.renderable || formatInfo.depthBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + + if (missingAttachment) + { + width = depthAttachment->getWidth(); + height = depthAttachment->getHeight(); + samples = depthAttachment->getSamples(); + missingAttachment = false; + } + else if (width != depthAttachment->getWidth() || height != depthAttachment->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + else if (samples != depthAttachment->getSamples()) + { + return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; + } + } + + const FramebufferAttachment *stencilAttachment = mData.mStencilAttachment; + if (stencilAttachment) + { + if (stencilAttachment->getWidth() == 0 || stencilAttachment->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + GLenum internalformat = stencilAttachment->getInternalFormat(); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); + const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); + if (stencilAttachment->type() == GL_TEXTURE) + { + // texture stencil attachments come along as part + // of OES_packed_depth_stencil + OES/ANGLE_depth_texture + if (!data.extensions->depthTextures) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (!formatCaps.renderable) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + if (formatInfo.stencilBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + else if (stencilAttachment->type() == GL_RENDERBUFFER) + { + if (!formatCaps.renderable || formatInfo.stencilBits == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + } + + if (missingAttachment) + { + width = stencilAttachment->getWidth(); + height = stencilAttachment->getHeight(); + samples = stencilAttachment->getSamples(); + missingAttachment = false; + } + else if (width != stencilAttachment->getWidth() || height != stencilAttachment->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + else if (samples != stencilAttachment->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 (depthAttachment && stencilAttachment && !hasValidDepthStencil()) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + + // we need to have at least one attachment to be complete + if (missingAttachment) + { + return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; + } + + return mImpl->checkStatus(); +} + +Error Framebuffer::invalidate(size_t count, const GLenum *attachments) +{ + return mImpl->invalidate(count, attachments); +} + +Error Framebuffer::invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) +{ + return mImpl->invalidateSub(count, attachments, area); +} + +Error Framebuffer::clear(const gl::Data &data, GLbitfield mask) +{ + return mImpl->clear(data, mask); +} + +Error Framebuffer::clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) +{ + return mImpl->clearBufferfv(state, buffer, drawbuffer, values); +} + +Error Framebuffer::clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) +{ + return mImpl->clearBufferuiv(state, buffer, drawbuffer, values); +} + +Error Framebuffer::clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values) +{ + return mImpl->clearBufferiv(state, buffer, drawbuffer, values); +} + +Error Framebuffer::clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +{ + return mImpl->clearBufferfi(state, buffer, drawbuffer, depth, stencil); +} + +GLenum Framebuffer::getImplementationColorReadFormat() const +{ + return mImpl->getImplementationColorReadFormat(); +} + +GLenum Framebuffer::getImplementationColorReadType() const +{ + return mImpl->getImplementationColorReadType(); +} + +Error Framebuffer::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const +{ + return mImpl->readPixels(state, area, format, type, pixels); +} + +Error Framebuffer::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) +{ + return mImpl->blit(state, sourceArea, destArea, mask, filter, sourceFramebuffer); +} + +int Framebuffer::getSamples(const gl::Data &data) const +{ + if (checkStatus(data) == GL_FRAMEBUFFER_COMPLETE) + { + // for a complete framebuffer, all attachments must have the same sample count + // in this case return the first nonzero sample size + for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { + if (*it != nullptr) + { + return (*it)->getSamples(); + } + } + } + + return 0; +} + +bool Framebuffer::hasValidDepthStencil() const +{ + // A valid depth-stencil attachment has the same resource bound to both the + // depth and stencil attachment points. + return (mData.mDepthAttachment && mData.mStencilAttachment && + mData.mDepthAttachment->type() == mData.mStencilAttachment->type() && + mData.mDepthAttachment->id() == mData.mStencilAttachment->id()); +} + +void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex) +{ + setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex)); +} + +void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer) +{ + setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer)); +} + +void Framebuffer::setNULLAttachment(GLenum attachment) +{ + setAttachment(attachment, NULL); +} + +void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj) +{ + if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + mData.mColorAttachments.size())) + { + size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0; + SafeDelete(mData.mColorAttachments[colorAttachment]); + mData.mColorAttachments[colorAttachment] = attachmentObj; + mImpl->setColorAttachment(colorAttachment, attachmentObj); + } + else if (attachment == GL_BACK) + { + SafeDelete(mData.mColorAttachments[0]); + mData.mColorAttachments[0] = attachmentObj; + mImpl->setColorAttachment(0, attachmentObj); + } + else if (attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH) + { + SafeDelete(mData.mDepthAttachment); + mData.mDepthAttachment = attachmentObj; + mImpl->setDepthAttachment(attachmentObj); + } + else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_STENCIL) + { + SafeDelete(mData.mStencilAttachment); + mData.mStencilAttachment = attachmentObj; + mImpl->setStencilAttachment(attachmentObj); + } + else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL) + { + SafeDelete(mData.mDepthAttachment); + SafeDelete(mData.mStencilAttachment); + + // ensure this is a legitimate depth+stencil format + if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0) + { + mData.mDepthAttachment = attachmentObj; + mImpl->setDepthAttachment(attachmentObj); + + // Make a new attachment object to ensure we do not double-delete + // See angle issue 686 + if (attachmentObj->type() == GL_TEXTURE) + { + mData.mStencilAttachment = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(), + *attachmentObj->getTextureImageIndex()); + mImpl->setStencilAttachment(mData.mStencilAttachment); + } + else if (attachmentObj->type() == GL_RENDERBUFFER) + { + mData.mStencilAttachment = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer()); + mImpl->setStencilAttachment(mData.mStencilAttachment); + } + else + { + UNREACHABLE(); + } + } + } + else + { + UNREACHABLE(); + } +} + +DefaultFramebuffer::DefaultFramebuffer(const Caps &caps, rx::ImplFactory *factory, egl::Surface *surface) + : Framebuffer(caps, factory, 0) +{ + const egl::Config *config = surface->getConfig(); + + setAttachment(GL_BACK, new DefaultAttachment(GL_BACK, surface)); + + if (config->depthSize > 0) + { + setAttachment(GL_DEPTH, new DefaultAttachment(GL_DEPTH, surface)); + } + if (config->stencilSize > 0) + { + setAttachment(GL_STENCIL, new DefaultAttachment(GL_STENCIL, surface)); + } + + GLenum drawBufferState = GL_BACK; + setDrawBuffers(1, &drawBufferState); + + setReadBuffer(GL_BACK); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.h b/src/3rdparty/angle/src/libANGLE/Framebuffer.h new file mode 100644 index 0000000000..8b24cf984e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.h @@ -0,0 +1,144 @@ +// +// Copyright (c) 2002-2013 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 LIBANGLE_FRAMEBUFFER_H_ +#define LIBANGLE_FRAMEBUFFER_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +namespace rx +{ +class ImplFactory; +class FramebufferImpl; +class RenderbufferImpl; +struct Workarounds; +} + +namespace egl +{ +class Surface; +} + +namespace gl +{ +class FramebufferAttachment; +class Renderbuffer; +class State; +class Texture; +class TextureCapsMap; +struct Caps; +struct Data; +struct Extensions; +struct ImageIndex; +struct Rectangle; + +typedef std::vector AttachmentList; + +class Framebuffer +{ + public: + + class Data final : angle::NonCopyable + { + public: + explicit Data(const Caps &caps); + ~Data(); + + FramebufferAttachment *getReadAttachment() const; + FramebufferAttachment *getFirstColorAttachment() const; + FramebufferAttachment *getDepthOrStencilAttachment() const; + + AttachmentList mColorAttachments; + FramebufferAttachment *mDepthAttachment; + FramebufferAttachment *mStencilAttachment; + + std::vector mDrawBufferStates; + GLenum mReadBufferState; + }; + + Framebuffer(const Caps &caps, rx::ImplFactory *factory, GLuint id); + virtual ~Framebuffer(); + + const rx::FramebufferImpl *getImplementation() const { return mImpl; } + rx::FramebufferImpl *getImplementation() { return mImpl; } + + GLuint id() const { return mId; } + + void setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex); + void setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer); + void setNULLAttachment(GLenum attachment); + + void detachTexture(GLuint texture); + void detachRenderbuffer(GLuint renderbuffer); + + FramebufferAttachment *getColorbuffer(unsigned int colorAttachment) const; + FramebufferAttachment *getDepthbuffer() const; + FramebufferAttachment *getStencilbuffer() const; + FramebufferAttachment *getDepthStencilBuffer() const; + FramebufferAttachment *getDepthOrStencilbuffer() const; + FramebufferAttachment *getReadColorbuffer() const; + GLenum getReadColorbufferType() const; + FramebufferAttachment *getFirstColorbuffer() const; + + FramebufferAttachment *getAttachment(GLenum attachment) const; + + GLenum getDrawBufferState(unsigned int colorAttachment) const; + void setDrawBuffers(size_t count, const GLenum *buffers); + + GLenum getReadBufferState() const; + void setReadBuffer(GLenum buffer); + + bool isEnabledColorAttachment(unsigned int colorAttachment) const; + bool hasEnabledColorAttachment() const; + bool hasStencil() const; + int getSamples(const gl::Data &data) const; + bool usingExtendedDrawBuffers() const; + + GLenum checkStatus(const gl::Data &data) const; + bool hasValidDepthStencil() const; + + Error invalidate(size_t count, const GLenum *attachments); + Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area); + + Error clear(const gl::Data &data, GLbitfield mask); + Error clearBufferfv(const State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values); + Error clearBufferuiv(const State &state, GLenum buffer, GLint drawbuffer, const GLuint *values); + Error clearBufferiv(const State &state, GLenum buffer, GLint drawbuffer, const GLint *values); + Error clearBufferfi(const State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); + + GLenum getImplementationColorReadFormat() const; + GLenum getImplementationColorReadType() const; + Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const; + + Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer); + + protected: + void setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj); + void detachResourceById(GLenum resourceType, GLuint resourceId); + + Data mData; + rx::FramebufferImpl *mImpl; + GLuint mId; +}; + +class DefaultFramebuffer : public Framebuffer +{ + public: + DefaultFramebuffer(const gl::Caps &caps, rx::ImplFactory *factory, egl::Surface *surface); +}; + +} + +#endif // LIBANGLE_FRAMEBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp new file mode 100644 index 0000000000..e56fc750ad --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.cpp @@ -0,0 +1,302 @@ +// +// Copyright (c) 2014 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. +// + +// FramebufferAttachment.cpp: the gl::FramebufferAttachment class and its derived classes +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#include "libANGLE/FramebufferAttachment.h" + +#include "common/utilities.h" +#include "libANGLE/Config.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/FramebufferImpl.h" + +namespace gl +{ + +////// FramebufferAttachment Implementation ////// + +FramebufferAttachment::FramebufferAttachment(GLenum binding) + : mBinding(binding) +{ +} + +FramebufferAttachment::~FramebufferAttachment() +{ +} + +GLuint FramebufferAttachment::getRedSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).redBits; +} + +GLuint FramebufferAttachment::getGreenSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).greenBits; +} + +GLuint FramebufferAttachment::getBlueSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).blueBits; +} + +GLuint FramebufferAttachment::getAlphaSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).alphaBits; +} + +GLuint FramebufferAttachment::getDepthSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).depthBits; +} + +GLuint FramebufferAttachment::getStencilSize() const +{ + return GetInternalFormatInfo(getInternalFormat()).stencilBits; +} + +GLenum FramebufferAttachment::getComponentType() const +{ + return GetInternalFormatInfo(getInternalFormat()).componentType; +} + +GLenum FramebufferAttachment::getColorEncoding() const +{ + return GetInternalFormatInfo(getInternalFormat()).colorEncoding; +} + +///// TextureAttachment Implementation //////// + +TextureAttachment::TextureAttachment(GLenum binding, Texture *texture, const ImageIndex &index) + : FramebufferAttachment(binding), + mIndex(index) +{ + mTexture.set(texture); +} + +TextureAttachment::~TextureAttachment() +{ + mTexture.set(NULL); +} + +GLsizei TextureAttachment::getSamples() const +{ + return 0; +} + +GLuint TextureAttachment::id() const +{ + return mTexture->id(); +} + +GLsizei TextureAttachment::getWidth() const +{ + return mTexture->getWidth(mIndex.type, mIndex.mipIndex); +} + +GLsizei TextureAttachment::getHeight() const +{ + return mTexture->getHeight(mIndex.type, mIndex.mipIndex); +} + +GLenum TextureAttachment::getInternalFormat() const +{ + return mTexture->getInternalFormat(mIndex.type, mIndex.mipIndex); +} + +GLenum TextureAttachment::type() const +{ + return GL_TEXTURE; +} + +GLint TextureAttachment::mipLevel() const +{ + return mIndex.mipIndex; +} + +GLenum TextureAttachment::cubeMapFace() const +{ + return IsCubeMapTextureTarget(mIndex.type) ? mIndex.type : GL_NONE; +} + +GLint TextureAttachment::layer() const +{ + return mIndex.layerIndex; +} + +Texture *TextureAttachment::getTexture() const +{ + return mTexture.get(); +} + +const ImageIndex *TextureAttachment::getTextureImageIndex() const +{ + return &mIndex; +} + +Renderbuffer *TextureAttachment::getRenderbuffer() const +{ + UNREACHABLE(); + return NULL; +} + +////// RenderbufferAttachment Implementation ////// + +RenderbufferAttachment::RenderbufferAttachment(GLenum binding, Renderbuffer *renderbuffer) + : FramebufferAttachment(binding) +{ + ASSERT(renderbuffer); + mRenderbuffer.set(renderbuffer); +} + +RenderbufferAttachment::~RenderbufferAttachment() +{ + mRenderbuffer.set(NULL); +} + +GLsizei RenderbufferAttachment::getWidth() const +{ + return mRenderbuffer->getWidth(); +} + +GLsizei RenderbufferAttachment::getHeight() const +{ + return mRenderbuffer->getHeight(); +} + +GLenum RenderbufferAttachment::getInternalFormat() const +{ + return mRenderbuffer->getInternalFormat(); +} + +GLsizei RenderbufferAttachment::getSamples() const +{ + return mRenderbuffer->getSamples(); +} + +GLuint RenderbufferAttachment::id() const +{ + return mRenderbuffer->id(); +} + +GLenum RenderbufferAttachment::type() const +{ + return GL_RENDERBUFFER; +} + +GLint RenderbufferAttachment::mipLevel() const +{ + return 0; +} + +GLenum RenderbufferAttachment::cubeMapFace() const +{ + return GL_NONE; +} + +GLint RenderbufferAttachment::layer() const +{ + return 0; +} + +Texture *RenderbufferAttachment::getTexture() const +{ + UNREACHABLE(); + return NULL; +} + +const ImageIndex *RenderbufferAttachment::getTextureImageIndex() const +{ + UNREACHABLE(); + return NULL; +} + +Renderbuffer *RenderbufferAttachment::getRenderbuffer() const +{ + return mRenderbuffer.get(); +} + + +DefaultAttachment::DefaultAttachment(GLenum binding, egl::Surface *surface) + : FramebufferAttachment(binding) +{ + mSurface.set(surface); +} + +DefaultAttachment::~DefaultAttachment() +{ + mSurface.set(nullptr); +} + +GLsizei DefaultAttachment::getWidth() const +{ + return mSurface->getWidth(); +} + +GLsizei DefaultAttachment::getHeight() const +{ + return mSurface->getHeight(); +} + +GLenum DefaultAttachment::getInternalFormat() const +{ + const egl::Config *config = mSurface->getConfig(); + return (getBinding() == GL_BACK ? config->renderTargetFormat : config->depthStencilFormat); +} + +GLsizei DefaultAttachment::getSamples() const +{ + const egl::Config *config = mSurface->getConfig(); + return config->samples; +} + +GLuint DefaultAttachment::id() const +{ + return 0; +} + +GLenum DefaultAttachment::type() const +{ + return GL_FRAMEBUFFER_DEFAULT; +} + +GLint DefaultAttachment::mipLevel() const +{ + return 0; +} + +GLenum DefaultAttachment::cubeMapFace() const +{ + return GL_NONE; +} + +GLint DefaultAttachment::layer() const +{ + return 0; +} + +Texture *DefaultAttachment::getTexture() const +{ + UNREACHABLE(); + return NULL; +} + +const ImageIndex *DefaultAttachment::getTextureImageIndex() const +{ + UNREACHABLE(); + return NULL; +} + +Renderbuffer *DefaultAttachment::getRenderbuffer() const +{ + UNREACHABLE(); + return NULL; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h new file mode 100644 index 0000000000..0662130931 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/FramebufferAttachment.h @@ -0,0 +1,154 @@ +// +// Copyright (c) 2014 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. +// + +// FramebufferAttachment.h: Defines the wrapper class gl::FramebufferAttachment, as well as the +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#ifndef LIBANGLE_FRAMEBUFFERATTACHMENT_H_ +#define LIBANGLE_FRAMEBUFFERATTACHMENT_H_ + +#include "libANGLE/Texture.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace gl +{ +class Renderbuffer; + +// FramebufferAttachment implements a GL framebuffer attachment. +// Attachments are "light" containers, which store pointers to ref-counted GL objects. +// We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments. +// Note: Our old naming scheme used the term "Renderbuffer" for both GL renderbuffers and for +// framebuffer attachments, which confused their usage. + +class FramebufferAttachment : angle::NonCopyable +{ + public: + explicit FramebufferAttachment(GLenum binding); + virtual ~FramebufferAttachment(); + + // Helper methods + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + GLenum getComponentType() const; + GLenum getColorEncoding() const; + + bool isTextureWithId(GLuint textureId) const { return type() == GL_TEXTURE && id() == textureId; } + bool isRenderbufferWithId(GLuint renderbufferId) const { return type() == GL_RENDERBUFFER && id() == renderbufferId; } + + GLenum getBinding() const { return mBinding; } + + // Child class interface + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual GLsizei getSamples() const = 0; + + virtual GLuint id() const = 0; + virtual GLenum type() const = 0; + virtual GLint mipLevel() const = 0; + virtual GLenum cubeMapFace() const = 0; + virtual GLint layer() const = 0; + + virtual Texture *getTexture() const = 0; + virtual const ImageIndex *getTextureImageIndex() const = 0; + virtual Renderbuffer *getRenderbuffer() const = 0; + + private: + GLenum mBinding; +}; + +class TextureAttachment : public FramebufferAttachment +{ + public: + TextureAttachment(GLenum binding, Texture *texture, const ImageIndex &index); + virtual ~TextureAttachment(); + + virtual GLsizei getSamples() const; + virtual GLuint id() const; + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLenum cubeMapFace() const; + virtual GLint layer() const; + + virtual Texture *getTexture() const; + virtual const ImageIndex *getTextureImageIndex() const; + virtual Renderbuffer *getRenderbuffer() const; + + private: + BindingPointer mTexture; + ImageIndex mIndex; +}; + +class RenderbufferAttachment : public FramebufferAttachment +{ + public: + RenderbufferAttachment(GLenum binding, Renderbuffer *renderbuffer); + + virtual ~RenderbufferAttachment(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLsizei getSamples() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLenum cubeMapFace() const; + virtual GLint layer() const; + + virtual Texture *getTexture() const; + virtual const ImageIndex *getTextureImageIndex() const; + virtual Renderbuffer *getRenderbuffer() const; + + private: + BindingPointer mRenderbuffer; +}; + +class DefaultAttachment : public FramebufferAttachment +{ + public: + DefaultAttachment(GLenum binding, egl::Surface *surface); + + virtual ~DefaultAttachment(); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLsizei getSamples() const; + + virtual GLuint id() const; + virtual GLenum type() const; + virtual GLint mipLevel() const; + virtual GLenum cubeMapFace() const; + virtual GLint layer() const; + + virtual Texture *getTexture() const; + virtual const ImageIndex *getTextureImageIndex() const; + virtual Renderbuffer *getRenderbuffer() const; + + const egl::Surface *getSurface() const { return mSurface.get(); } + + private: + BindingPointer mSurface; +}; + +} + +#endif // LIBANGLE_FRAMEBUFFERATTACHMENT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp new file mode 100644 index 0000000000..59d3966758 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.cpp @@ -0,0 +1,133 @@ +// +// 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 "libANGLE/HandleAllocator.h" + +#include + +#include "common/debug.h" + +namespace gl +{ + +struct HandleAllocator::HandleRangeComparator +{ + bool operator()(const HandleRange &range, GLuint handle) const + { + return (handle < range.begin); + } +}; + +HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1) +{ + mUnallocatedList.push_back(HandleRange(1, std::numeric_limits::max() - 1)); +} + +HandleAllocator::HandleAllocator(GLuint maximumHandleValue) : mBaseValue(1), mNextValue(1) +{ + mUnallocatedList.push_back(HandleRange(1, maximumHandleValue)); +} + +HandleAllocator::~HandleAllocator() +{ +} + +void HandleAllocator::setBaseHandle(GLuint value) +{ + ASSERT(mBaseValue == mNextValue); + mBaseValue = value; + mNextValue = value; +} + +GLuint HandleAllocator::allocate() +{ + ASSERT(!mUnallocatedList.empty() || !mReleasedList.empty()); + + // Allocate from released list, constant time. + if (!mReleasedList.empty()) + { + GLuint reusedHandle = mReleasedList.back(); + mReleasedList.pop_back(); + return reusedHandle; + } + + // Allocate from unallocated list, constant time. + auto listIt = mUnallocatedList.begin(); + + GLuint freeListHandle = listIt->begin; + ASSERT(freeListHandle > 0); + + listIt->begin++; + if (listIt->begin == listIt->end) + { + mUnallocatedList.erase(listIt); + } + + return freeListHandle; +} + +void HandleAllocator::release(GLuint handle) +{ + // Add to released list, constant time. + mReleasedList.push_back(handle); +} + +void HandleAllocator::reserve(GLuint handle) +{ + // Clear from released list -- might be a slow operation. + if (!mReleasedList.empty()) + { + auto releasedIt = std::find(mReleasedList.begin(), mReleasedList.end(), handle); + if (releasedIt != mReleasedList.end()) + { + mReleasedList.erase(releasedIt); + return; + } + } + + // Not in released list, reserve in the unallocated list. + auto boundIt = std::lower_bound(mUnallocatedList.begin(), mUnallocatedList.end(), handle, HandleRangeComparator()); + + ASSERT(boundIt != mUnallocatedList.end()); + + GLuint begin = boundIt->begin; + GLuint end = boundIt->end; + + if (handle == begin || handle == end) + { + if (begin + 1 == end) + { + mUnallocatedList.erase(boundIt); + } + else if (handle == begin) + { + boundIt->begin++; + } + else + { + ASSERT(handle == end); + boundIt->end--; + } + return; + } + + // need to split the range + auto placementIt = mUnallocatedList.erase(boundIt); + + if (begin != handle) + { + placementIt = mUnallocatedList.insert(placementIt, HandleRange(begin, handle)); + } + if (handle + 1 != end) + { + mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end)); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/HandleAllocator.h b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h new file mode 100644 index 0000000000..c22f2ba61a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/HandleAllocator.h @@ -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.h: Defines the gl::HandleAllocator class, which is used to +// allocate GL handles. + +#ifndef LIBANGLE_HANDLEALLOCATOR_H_ +#define LIBANGLE_HANDLEALLOCATOR_H_ + +#include "common/angleutils.h" + +#include "angle_gl.h" + +#include + +namespace gl +{ + +class HandleAllocator final : angle::NonCopyable +{ + public: + // Maximum handle = MAX_UINT-1 + HandleAllocator(); + // Specify maximum handle value + HandleAllocator(GLuint maximumHandleValue); + + ~HandleAllocator(); + + void setBaseHandle(GLuint value); + + GLuint allocate(); + void release(GLuint handle); + void reserve(GLuint handle); + + private: + GLuint mBaseValue; + GLuint mNextValue; + typedef std::vector HandleList; + HandleList mFreeValues; + + struct HandleRange + { + HandleRange(GLuint beginIn, GLuint endIn) : begin(beginIn), end(endIn) {} + + GLuint begin; + GLuint end; + }; + + struct HandleRangeComparator; + + // The freelist consists of never-allocated handles, stored + // as ranges, and handles that were previously allocated and + // released, stored in a stack. + std::vector mUnallocatedList; + std::vector mReleasedList; +}; + +} + +#endif // LIBANGLE_HANDLEALLOCATOR_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp new file mode 100644 index 0000000000..ac7302d121 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.cpp @@ -0,0 +1,170 @@ +// +// Copyright 2014 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. +// + +// ImageIndex.cpp: Implementation for ImageIndex methods. + +#include "libANGLE/ImageIndex.h" +#include "libANGLE/Constants.h" +#include "common/utilities.h" + +namespace gl +{ + +ImageIndex::ImageIndex(const ImageIndex &other) + : type(other.type), + mipIndex(other.mipIndex), + layerIndex(other.layerIndex) +{} + +ImageIndex &ImageIndex::operator=(const ImageIndex &other) +{ + type = other.type; + mipIndex = other.mipIndex; + layerIndex = other.layerIndex; + return *this; +} + +ImageIndex ImageIndex::Make2D(GLint mipIndex) +{ + return ImageIndex(GL_TEXTURE_2D, mipIndex, ENTIRE_LEVEL); +} + +ImageIndex ImageIndex::MakeCube(GLenum target, GLint mipIndex) +{ + ASSERT(gl::IsCubeMapTextureTarget(target)); + return ImageIndex(target, mipIndex, CubeMapTextureTargetToLayerIndex(target)); +} + +ImageIndex ImageIndex::Make2DArray(GLint mipIndex, GLint layerIndex) +{ + return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex); +} + +ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex) +{ + return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex); +} + +ImageIndex ImageIndex::MakeGeneric(GLenum target, GLint mipIndex) +{ + GLint layerIndex = IsCubeMapTextureTarget(target) ? CubeMapTextureTargetToLayerIndex(target) : ENTIRE_LEVEL; + return ImageIndex(target, mipIndex, layerIndex); +} + +ImageIndex ImageIndex::MakeInvalid() +{ + return ImageIndex(GL_NONE, -1, -1); +} + +bool ImageIndex::operator<(const ImageIndex &other) const +{ + if (type != other.type) + { + return type < other.type; + } + else if (mipIndex != other.mipIndex) + { + return mipIndex < other.mipIndex; + } + else + { + return layerIndex < other.layerIndex; + } +} + +ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn) + : type(typeIn), + mipIndex(mipIndexIn), + layerIndex(layerIndexIn) +{} + +ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_2D, rx::Range(minMip, maxMip), + rx::Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL); +} + +ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, rx::Range(minMip, maxMip), rx::Range(0, 6), NULL); +} + +ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, + GLint minLayer, GLint maxLayer) +{ + return ImageIndexIterator(GL_TEXTURE_3D, rx::Range(minMip, maxMip), rx::Range(minLayer, maxLayer), NULL); +} + +ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, + const GLsizei *layerCounts) +{ + return ImageIndexIterator(GL_TEXTURE_2D_ARRAY, rx::Range(minMip, maxMip), + rx::Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); +} + +ImageIndexIterator::ImageIndexIterator(GLenum type, const rx::Range &mipRange, + const rx::Range &layerRange, const GLsizei *layerCounts) + : mType(type), + mMipRange(mipRange), + mLayerRange(layerRange), + mLayerCounts(layerCounts), + mCurrentMip(mipRange.start), + mCurrentLayer(layerRange.start) +{} + +GLint ImageIndexIterator::maxLayer() const +{ + return (mLayerCounts ? static_cast(mLayerCounts[mCurrentMip]) : mLayerRange.end); +} + +ImageIndex ImageIndexIterator::next() +{ + ASSERT(hasNext()); + + ImageIndex value = current(); + + // Iterate layers in the inner loop for now. We can add switchable + // layer or mip iteration if we need it. + + if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL) + { + if (mCurrentLayer < maxLayer()-1) + { + mCurrentLayer++; + } + else if (mCurrentMip < mMipRange.end-1) + { + mCurrentMip++; + mCurrentLayer = mLayerRange.start; + } + } + else if (mCurrentMip < mMipRange.end-1) + { + mCurrentMip++; + mCurrentLayer = mLayerRange.start; + } + + return value; +} + +ImageIndex ImageIndexIterator::current() const +{ + ImageIndex value(mType, mCurrentMip, mCurrentLayer); + + if (mType == GL_TEXTURE_CUBE_MAP) + { + value.type = LayerIndexToCubeMapTextureTarget(mCurrentLayer); + } + + return value; +} + +bool ImageIndexIterator::hasNext() const +{ + return (mCurrentMip < mMipRange.end || mCurrentLayer < maxLayer()); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/ImageIndex.h b/src/3rdparty/angle/src/libANGLE/ImageIndex.h new file mode 100644 index 0000000000..820c650f20 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ImageIndex.h @@ -0,0 +1,79 @@ +// +// Copyright 2014 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. +// + +// ImageIndex.h: A helper struct for indexing into an Image array + +#ifndef LIBANGLE_IMAGE_INDEX_H_ +#define LIBANGLE_IMAGE_INDEX_H_ + +#include "common/mathutil.h" + +#include "angle_gl.h" + +namespace gl +{ + +class ImageIndexIterator; + +struct ImageIndex +{ + GLenum type; + GLint mipIndex; + GLint layerIndex; + + ImageIndex(const ImageIndex &other); + ImageIndex &operator=(const ImageIndex &other); + + bool hasLayer() const { return layerIndex != ENTIRE_LEVEL; } + + static ImageIndex Make2D(GLint mipIndex); + static ImageIndex MakeCube(GLenum target, GLint mipIndex); + static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex); + static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL); + static ImageIndex MakeGeneric(GLenum target, GLint mipIndex); + + static ImageIndex MakeInvalid(); + + static const GLint ENTIRE_LEVEL = static_cast(-1); + + bool operator<(const ImageIndex &other) const; + + private: + friend class ImageIndexIterator; + + ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn); +}; + +class ImageIndexIterator +{ + public: + static ImageIndexIterator Make2D(GLint minMip, GLint maxMip); + static ImageIndexIterator MakeCube(GLint minMip, GLint maxMip); + static ImageIndexIterator Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer); + static ImageIndexIterator Make2DArray(GLint minMip, GLint maxMip, const GLsizei *layerCounts); + + ImageIndex next(); + ImageIndex current() const; + bool hasNext() const; + + private: + + ImageIndexIterator(GLenum type, const rx::Range &mipRange, + const rx::Range &layerRange, const GLsizei *layerCounts); + + GLint maxLayer() const; + + GLenum mType; + rx::Range mMipRange; + rx::Range mLayerRange; + const GLsizei *mLayerCounts; + GLint mCurrentMip; + GLint mCurrentLayer; +}; + +} + +#endif // LIBANGLE_IMAGE_INDEX_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Platform.cpp b/src/3rdparty/angle/src/libANGLE/Platform.cpp new file mode 100644 index 0000000000..ab75bbba5a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Platform.cpp @@ -0,0 +1,35 @@ +// +// Copyright 2015 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. +// + +// Platform.cpp: Implementation methods for angle::Platform. + +#include + +#include "common/debug.h" + +namespace +{ +angle::Platform *currentPlatform = nullptr; +} + +// static +ANGLE_EXPORT angle::Platform *ANGLEPlatformCurrent() +{ + return currentPlatform; +} + +// static +ANGLE_EXPORT void ANGLEPlatformInitialize(angle::Platform *platformImpl) +{ + ASSERT(platformImpl != nullptr); + currentPlatform = platformImpl; +} + +// static +ANGLE_EXPORT void ANGLEPlatformShutdown() +{ + currentPlatform = nullptr; +} diff --git a/src/3rdparty/angle/src/libANGLE/Program.cpp b/src/3rdparty/angle/src/libANGLE/Program.cpp new file mode 100644 index 0000000000..daf0a403f0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Program.cpp @@ -0,0 +1,1617 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/Program.h" + +#include + +#include "common/debug.h" +#include "common/platform.h" +#include "common/utilities.h" +#include "common/version.h" +#include "compiler/translator/blocklayout.h" +#include "libANGLE/Data.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/features.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/ProgramImpl.h" + +namespace gl +{ +const char * const g_fakepath = "C:\\fakepath"; + +namespace +{ + +unsigned int ParseAndStripArrayIndex(std::string* name) +{ + unsigned int subscript = GL_INVALID_INDEX; + + // 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); + } + + return subscript; +} + +} + +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", msg.c_str()); +} + +void InfoLog::append(const char *format, ...) +{ + if (!format) + { + return; + } + + va_list vararg; + va_start(vararg, format); + size_t infoLength = vsnprintf(NULL, 0, format, vararg); + va_end(vararg); + + char *logPointer = NULL; + + if (!mInfoLog) + { + mInfoLog = new char[infoLength + 2]; + logPointer = mInfoLog; + } + else + { + size_t currentlogLength = strlen(mInfoLog); + char *newLog = new char[currentlogLength + infoLength + 2]; + strcpy(newLog, mInfoLog); + + delete[] mInfoLog; + mInfoLog = newLog; + + logPointer = mInfoLog + currentlogLength; + } + + va_start(vararg, format); + vsnprintf(logPointer, infoLength, format, vararg); + va_end(vararg); + + logPointer[infoLength] = 0; + strcpy(logPointer + infoLength, "\n"); +} + +void InfoLog::reset() +{ + if (mInfoLog) + { + delete [] mInfoLog; + mInfoLog = NULL; + } +} + +VariableLocation::VariableLocation() + : name(), element(0), index(0) +{ +} + +VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) + : name(name), element(element), index(index) +{ +} + +LinkedVarying::LinkedVarying() +{ +} + +LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, + unsigned int semanticIndex, unsigned int semanticIndexCount) + : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount) +{ +} + +Program::Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle) + : mProgram(impl), + mValidated(false), + mTransformFeedbackVaryings(), + mTransformFeedbackBufferMode(GL_NONE), + mFragmentShader(NULL), + mVertexShader(NULL), + mLinked(false), + mDeleteStatus(false), + mRefCount(0), + mResourceManager(manager), + mHandle(handle) +{ + ASSERT(mProgram); + + resetUniformBlockBindings(); + unlink(); +} + +Program::~Program() +{ + unlink(true); + + if (mVertexShader != NULL) + { + mVertexShader->release(); + } + + if (mFragmentShader != NULL) + { + mFragmentShader->release(); + } + + SafeDelete(mProgram); +} + +bool Program::attachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader) + { + return false; + } + + mVertexShader = shader; + mVertexShader->addRef(); + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader) + { + return false; + } + + mFragmentShader = 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 +Error Program::link(const Data &data) +{ + unlink(false); + + mInfoLog.reset(); + resetUniformBlockBindings(); + + if (!mFragmentShader || !mFragmentShader->isCompiled()) + { + return Error(GL_NO_ERROR); + } + ASSERT(mFragmentShader->getType() == GL_FRAGMENT_SHADER); + + if (!mVertexShader || !mVertexShader->isCompiled()) + { + return Error(GL_NO_ERROR); + } + ASSERT(mVertexShader->getType() == GL_VERTEX_SHADER); + + if (!linkAttributes(mInfoLog, mAttributeBindings, mVertexShader)) + { + return Error(GL_NO_ERROR); + } + + int registers; + std::vector linkedVaryings; + rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode, + ®isters, &linkedVaryings, &mOutputVariables); + if (result.error.isError() || !result.linkSuccess) + { + return result.error; + } + + if (!mProgram->linkUniforms(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps)) + { + return Error(GL_NO_ERROR); + } + + if (!linkUniformBlocks(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps)) + { + return Error(GL_NO_ERROR); + } + + if (!gatherTransformFeedbackLinkedVaryings(mInfoLog, linkedVaryings, mTransformFeedbackVaryings, + mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps)) + { + return Error(GL_NO_ERROR); + } + + // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called, + // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling. + result = mProgram->compileProgramExecutables(mInfoLog, mFragmentShader, mVertexShader, registers); + if (result.error.isError() || !result.linkSuccess) + { + mInfoLog.append("Failed to create D3D shaders."); + unlink(false); + return result.error; + } + + mLinked = true; + return gl::Error(GL_NO_ERROR); +} + +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; + } + } + + std::fill(mLinkedAttribute, mLinkedAttribute + ArraySize(mLinkedAttribute), sh::Attribute()); + mOutputVariables.clear(); + + mProgram->reset(); + + mValidated = false; + + mLinked = false; +} + +bool Program::isLinked() +{ + return mLinked; +} + +Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length) +{ + unlink(false); + +#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED + return Error(GL_NO_ERROR); +#else + ASSERT(binaryFormat == mProgram->getBinaryFormat()); + + BinaryInputStream stream(binary, length); + + GLenum format = stream.readInt(); + if (format != mProgram->getBinaryFormat()) + { + mInfoLog.append("Invalid program binary format."); + return Error(GL_NO_ERROR); + } + + int majorVersion = stream.readInt(); + int minorVersion = stream.readInt(); + if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) + { + mInfoLog.append("Invalid program binary version."); + return Error(GL_NO_ERROR); + } + + unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; + stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE); + if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) + { + mInfoLog.append("Invalid program binary version."); + return Error(GL_NO_ERROR); + } + + for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + { + stream.readInt(&mLinkedAttribute[i].type); + stream.readString(&mLinkedAttribute[i].name); + stream.readInt(&mProgram->getShaderAttributes()[i].type); + stream.readString(&mProgram->getShaderAttributes()[i].name); + stream.readInt(&mProgram->getSemanticIndexes()[i]); + } + + rx::LinkResult result = mProgram->load(mInfoLog, &stream); + if (result.error.isError() || !result.linkSuccess) + { + return result.error; + } + + mLinked = true; + return Error(GL_NO_ERROR); +#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED +} + +Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const +{ + if (binaryFormat) + { + *binaryFormat = mProgram->getBinaryFormat(); + } + + BinaryOutputStream stream; + + stream.writeInt(mProgram->getBinaryFormat()); + stream.writeInt(ANGLE_MAJOR_VERSION); + stream.writeInt(ANGLE_MINOR_VERSION); + stream.writeBytes(reinterpret_cast(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE); + + for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) + { + stream.writeInt(mLinkedAttribute[i].type); + stream.writeString(mLinkedAttribute[i].name); + stream.writeInt(mProgram->getShaderAttributes()[i].type); + stream.writeString(mProgram->getShaderAttributes()[i].name); + stream.writeInt(mProgram->getSemanticIndexes()[i]); + } + + gl::Error error = mProgram->save(&stream); + if (error.isError()) + { + return error; + } + + GLsizei streamLength = stream.length(); + const void *streamData = stream.data(); + + if (streamLength > bufSize) + { + if (length) + { + *length = 0; + } + + // TODO: This should be moved to the validation layer but computing the size of the binary before saving + // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate + // sizes and then copy it. + return Error(GL_INVALID_OPERATION); + } + + if (binary) + { + char *ptr = reinterpret_cast(binary); + + memcpy(ptr, streamData, streamLength); + ptr += streamLength; + + ASSERT(ptr - streamLength == binary); + } + + if (length) + { + *length = streamLength; + } + + return Error(GL_NO_ERROR); +} + +GLint Program::getBinaryLength() const +{ + GLint length; + Error error = saveBinary(NULL, NULL, std::numeric_limits::max(), &length); + if (error.isError()) + { + return 0; + } + + return length; +} + +void Program::release() +{ + mRefCount--; + + if (mRefCount == 0 && mDeleteStatus) + { + mResourceManager->deleteProgram(mHandle); + } +} + +void Program::addRef() +{ + mRefCount++; +} + +unsigned int Program::getRefCount() const +{ + return mRefCount; +} + +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; + } +} + +GLuint Program::getAttributeLocation(const std::string &name) +{ + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + if (mLinkedAttribute[index].name == name) + { + return index; + } + } + + return static_cast(-1); +} + +int Program::getSemanticIndex(int attributeIndex) +{ + ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS); + + return mProgram->getSemanticIndexes()[attributeIndex]; +} + +void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + if (mLinked) + { + // 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; + } + else + { + if (bufsize > 0) + { + name[0] = '\0'; + } + + if (length) + { + *length = 0; + } + + *type = GL_NONE; + *size = 1; + } +} + +GLint Program::getActiveAttributeCount() +{ + int count = 0; + + if (mLinked) + { + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (!mLinkedAttribute[attributeIndex].name.empty()) + { + count++; + } + } + } + + return count; +} + +GLint Program::getActiveAttributeMaxLength() +{ + int maxLength = 0; + + if (mLinked) + { + 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; +} + +// Returns one more than the highest sampler index used. +GLint Program::getUsedSamplerRange(SamplerType type) +{ + return mProgram->getUsedSamplerRange(type); +} + +bool Program::usesPointSize() const +{ + return mProgram->usesPointSize(); +} + +GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps) +{ + return mProgram->getSamplerMapping(type, samplerIndex, caps); +} + +GLenum Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex) +{ + return mProgram->getSamplerTextureType(type, samplerIndex); +} + +GLint Program::getFragDataLocation(const std::string &name) const +{ + std::string baseName(name); + unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName); + for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++) + { + const VariableLocation &outputVariable = locationIt->second; + if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element)) + { + return static_cast(locationIt->first); + } + } + return -1; +} + +void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +{ + if (mLinked) + { + ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount() + LinkedUniform *uniform = mProgram->getUniforms()[index]; + + if (bufsize > 0) + { + std::string string = uniform->name; + if (uniform->isArray()) + { + string += "[0]"; + } + + strncpy(name, string.c_str(), bufsize); + name[bufsize - 1] = '\0'; + + if (length) + { + *length = strlen(name); + } + } + + *size = uniform->elementCount(); + *type = uniform->type; + } + else + { + if (bufsize > 0) + { + name[0] = '\0'; + } + + if (length) + { + *length = 0; + } + + *size = 0; + *type = GL_NONE; + } +} + +GLint Program::getActiveUniformCount() +{ + if (mLinked) + { + return mProgram->getUniforms().size(); + } + else + { + return 0; + } +} + +GLint Program::getActiveUniformMaxLength() +{ + int maxLength = 0; + + if (mLinked) + { + unsigned int numUniforms = mProgram->getUniforms().size(); + for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) + { + if (!mProgram->getUniforms()[uniformIndex]->name.empty()) + { + int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1); + if (mProgram->getUniforms()[uniformIndex]->isArray()) + { + length += 3; // Counting in "[0]". + } + maxLength = std::max(length, maxLength); + } + } + } + + return maxLength; +} + +GLint Program::getActiveUniformi(GLuint index, GLenum pname) const +{ + const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index]; + switch (pname) + { + case GL_UNIFORM_TYPE: return static_cast(uniform.type); + case GL_UNIFORM_SIZE: return static_cast(uniform.elementCount()); + case GL_UNIFORM_NAME_LENGTH: return static_cast(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0)); + case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex; + case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset; + case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride; + case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride; + case GL_UNIFORM_IS_ROW_MAJOR: return static_cast(uniform.blockInfo.isRowMajorMatrix); + default: + UNREACHABLE(); + break; + } + return 0; +} + +bool Program::isValidUniformLocation(GLint location) const +{ + ASSERT(rx::IsIntegerCastSafe(mProgram->getUniformIndices().size())); + return (location >= 0 && location < static_cast(mProgram->getUniformIndices().size())); +} + +LinkedUniform *Program::getUniformByLocation(GLint location) const +{ + return mProgram->getUniformByLocation(location); +} + +LinkedUniform *Program::getUniformByName(const std::string &name) const +{ + return mProgram->getUniformByName(name); +} + +GLint Program::getUniformLocation(const std::string &name) +{ + return mProgram->getUniformLocation(name); +} + +GLuint Program::getUniformIndex(const std::string &name) +{ + return mProgram->getUniformIndex(name); +} + +void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) +{ + mProgram->setUniform1fv(location, count, v); +} + +void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + mProgram->setUniform2fv(location, count, v); +} + +void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + mProgram->setUniform3fv(location, count, v); +} + +void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + mProgram->setUniform4fv(location, count, v); +} + +void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + mProgram->setUniform1iv(location, count, v); +} + +void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v) +{ + mProgram->setUniform2iv(location, count, v); +} + +void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v) +{ + mProgram->setUniform3iv(location, count, v); +} + +void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v) +{ + mProgram->setUniform4iv(location, count, v); +} + +void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) +{ + mProgram->setUniform1uiv(location, count, v); +} + +void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) +{ + mProgram->setUniform2uiv(location, count, v); +} + +void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) +{ + mProgram->setUniform3uiv(location, count, v); +} + +void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) +{ + mProgram->setUniform4uiv(location, count, v); +} + +void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix2fv(location, count, transpose, v); +} + +void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix3fv(location, count, transpose, v); +} + +void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix4fv(location, count, transpose, v); +} + +void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix2x3fv(location, count, transpose, v); +} + +void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix2x4fv(location, count, transpose, v); +} + +void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix3x2fv(location, count, transpose, v); +} + +void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix3x4fv(location, count, transpose, v); +} + +void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix4x2fv(location, count, transpose, v); +} + +void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) +{ + mProgram->setUniformMatrix4x3fv(location, count, transpose, v); +} + +void Program::getUniformfv(GLint location, GLfloat *v) +{ + mProgram->getUniformfv(location, v); +} + +void Program::getUniformiv(GLint location, GLint *v) +{ + mProgram->getUniformiv(location, v); +} + +void Program::getUniformuiv(GLint location, GLuint *v) +{ + mProgram->getUniformuiv(location, v); +} + +// Applies all the uniforms set for this program object to the renderer +Error Program::applyUniforms() +{ + return mProgram->applyUniforms(); +} + +Error Program::applyUniformBuffers(const gl::Data &data) +{ + return mProgram->applyUniformBuffers(data, mUniformBlockBindings); +} + +void Program::flagForDeletion() +{ + mDeleteStatus = true; +} + +bool Program::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} + +void Program::validate(const Caps &caps) +{ + mInfoLog.reset(); + mValidated = false; + + if (mLinked) + { + applyUniforms(); + mValidated = mProgram->validateSamplers(&mInfoLog, caps); + } + else + { + mInfoLog.append("Program has not been successfully linked."); + } +} + +bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps) +{ + return mProgram->validateSamplers(infoLog, caps); +} + +bool Program::isValidated() const +{ + return mValidated; +} + +void Program::updateSamplerMapping() +{ + return mProgram->updateSamplerMapping(); +} + +GLuint Program::getActiveUniformBlockCount() +{ + return mProgram->getUniformBlocks().size(); +} + +void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const +{ + ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount() + + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; + + if (bufSize > 0) + { + std::string string = uniformBlock.name; + + if (uniformBlock.isArrayElement()) + { + string += ArrayString(uniformBlock.elementIndex); + } + + strncpy(uniformBlockName, string.c_str(), bufSize); + uniformBlockName[bufSize - 1] = '\0'; + + if (length) + { + *length = strlen(uniformBlockName); + } + } +} + +void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const +{ + ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount() + + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; + + switch (pname) + { + case GL_UNIFORM_BLOCK_DATA_SIZE: + *params = static_cast(uniformBlock.dataSize); + break; + case GL_UNIFORM_BLOCK_NAME_LENGTH: + *params = static_cast(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0)); + break; + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + *params = static_cast(uniformBlock.memberUniformIndexes.size()); + break; + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + { + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + params[blockMemberIndex] = static_cast(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } + } + break; + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + *params = static_cast(uniformBlock.isReferencedByVertexShader()); + break; + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + *params = static_cast(uniformBlock.isReferencedByFragmentShader()); + break; + default: UNREACHABLE(); + } +} + +GLint Program::getActiveUniformBlockMaxLength() +{ + int maxLength = 0; + + if (mLinked) + { + unsigned int numUniformBlocks = mProgram->getUniformBlocks().size(); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++) + { + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; + if (!uniformBlock.name.empty()) + { + const int length = uniformBlock.name.length() + 1; + + // Counting in "[0]". + const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0); + + maxLength = std::max(length + arrayLength, maxLength); + } + } + } + + return maxLength; +} + +GLuint Program::getUniformBlockIndex(const std::string &name) +{ + return mProgram->getUniformBlockIndex(name); +} + +const UniformBlock *Program::getUniformBlockByIndex(GLuint index) const +{ + return mProgram->getUniformBlockByIndex(index); +} + +void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding) +{ + mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding; +} + +GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const +{ + return mUniformBlockBindings[uniformBlockIndex]; +} + +void Program::resetUniformBlockBindings() +{ + for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++) + { + mUniformBlockBindings[blockId] = 0; + } +} + +void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode) +{ + mTransformFeedbackVaryings.resize(count); + for (GLsizei i = 0; i < count; i++) + { + mTransformFeedbackVaryings[i] = varyings[i]; + } + + mTransformFeedbackBufferMode = bufferMode; +} + +void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const +{ + if (mLinked) + { + ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size()); + const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index]; + GLsizei lastNameIdx = std::min(bufSize - 1, static_cast(varying.name.length())); + if (length) + { + *length = lastNameIdx; + } + if (size) + { + *size = varying.size; + } + if (type) + { + *type = varying.type; + } + if (name) + { + memcpy(name, varying.name.c_str(), lastNameIdx); + name[lastNameIdx] = '\0'; + } + } +} + +GLsizei Program::getTransformFeedbackVaryingCount() const +{ + if (mLinked) + { + return static_cast(mProgram->getTransformFeedbackLinkedVaryings().size()); + } + else + { + return 0; + } +} + +GLsizei Program::getTransformFeedbackVaryingMaxLength() const +{ + if (mLinked) + { + GLsizei maxSize = 0; + for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++) + { + const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i]; + maxSize = std::max(maxSize, static_cast(varying.name.length() + 1)); + } + + return maxSize; + } + else + { + return 0; + } +} + +GLenum Program::getTransformFeedbackBufferMode() const +{ + return mTransformFeedbackBufferMode; +} + +bool Program::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader) +{ + std::vector &fragmentVaryings = fragmentShader->getVaryings(); + std::vector &vertexVaryings = vertexShader->getVaryings(); + + for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++) + { + PackedVarying *input = &fragmentVaryings[fragVaryingIndex]; + bool matched = false; + + // Built-in varyings obey special rules + if (input->isBuiltIn()) + { + continue; + } + + for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) + { + PackedVarying *output = &vertexVaryings[vertVaryingIndex]; + if (output->name == input->name) + { + if (!linkValidateVaryings(infoLog, output->name, *input, *output)) + { + return false; + } + + output->registerIndex = input->registerIndex; + output->columnIndex = input->columnIndex; + + matched = true; + break; + } + } + + // We permit unmatched, unreferenced varyings + if (!matched && input->staticUse) + { + infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); + return false; + } + } + + return true; +} + +bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform) +{ + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) + { + return false; + } + + if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout) + { + infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str()); + return false; + } + + return true; +} + +// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices +bool Program::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader) +{ + unsigned int usedLocations = 0; + const std::vector &shaderAttributes = vertexShader->getActiveAttributes(); + + // Link attributes that have a binding location + for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + const sh::Attribute &attribute = shaderAttributes[attributeIndex]; + + ASSERT(attribute.staticUse); + + const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; + + mProgram->getShaderAttributes()[attributeIndex] = attribute; + + if (location != -1) // Set by glBindAttribLocation or by location layout qualifier + { + const int rows = VariableRegisterCount(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 row = 0; row < rows; row++) + { + const int rowLocation = location + row; + sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation]; + + // In GLSL 3.00, attribute aliasing produces a link error + // In GLSL 1.00, attribute aliasing is allowed + if (mProgram->getShaderVersion() >= 300) + { + if (!linkedAttribute.name.empty()) + { + infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation); + return false; + } + } + + linkedAttribute = attribute; + usedLocations |= 1 << rowLocation; + } + } + } + + // Link attributes that don't have a binding location + for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + const sh::Attribute &attribute = shaderAttributes[attributeIndex]; + + ASSERT(attribute.staticUse); + + const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; + + if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier + { + int rows = VariableRegisterCount(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 = VariableRegisterCount(mLinkedAttribute[attributeIndex].type); + + for (int r = 0; r < rows; r++) + { + mProgram->getSemanticIndexes()[attributeIndex++] = index++; + } + } + + return true; +} + +bool Program::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps) +{ + const std::vector &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(); + const std::vector &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(); + // Check that interface blocks defined in the vertex and fragment shaders are identical + typedef std::map UniformBlockMap; + UniformBlockMap linkedUniformBlocks; + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex]; + linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + } + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex]; + UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); + if (entry != linkedUniformBlocks.end()) + { + const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; + if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) + { + return false; + } + } + } + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex]; + // Note: shared and std140 layouts are always considered active + if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + { + if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps)) + { + return false; + } + } + } + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex]; + // Note: shared and std140 layouts are always considered active + if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + { + if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps)) + { + return false; + } + } + } + return true; +} + +bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock) +{ + const char* blockName = vertexInterfaceBlock.name.c_str(); + // validate blocks for the same member types + if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size()) + { + infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName); + return false; + } + if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize) + { + infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; + } + if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) + { + infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; + } + const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size(); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++) + { + const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex]; + const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex]; + if (vertexMember.name != fragmentMember.name) + { + infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')", + blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str()); + return false; + } + std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; + if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember)) + { + return false; + } + } + return true; +} + +bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, + const sh::ShaderVariable &fragmentVariable, bool validatePrecision) +{ + if (vertexVariable.type != fragmentVariable.type) + { + infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + if (vertexVariable.arraySize != fragmentVariable.arraySize) + { + infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + if (validatePrecision && vertexVariable.precision != fragmentVariable.precision) + { + infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + + if (vertexVariable.fields.size() != fragmentVariable.fields.size()) + { + infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str()); + return false; + } + const unsigned int numMembers = vertexVariable.fields.size(); + for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++) + { + const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex]; + const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex]; + + if (vertexMember.name != fragmentMember.name) + { + infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')", + memberIndex, variableName.c_str(), + vertexMember.name.c_str(), fragmentMember.name.c_str()); + return false; + } + + const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." + + vertexMember.name + "'"; + + if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision)) + { + return false; + } + } + + return true; +} + +bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform) +{ + if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) + { + return false; + } + + return true; +} + +bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying) +{ + if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) + { + return false; + } + + if (!sh::InterpolationTypesMatch(vertexVarying.interpolation, fragmentVarying.interpolation)) + { + infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str()); + return false; + } + + return true; +} + +bool Program::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector &linkedVaryings, + const std::vector &transformFeedbackVaryingNames, + GLenum transformFeedbackBufferMode, + std::vector *outTransformFeedbackLinkedVaryings, + const Caps &caps) const +{ + size_t totalComponents = 0; + + // Gather the linked varyings that are used for transform feedback, they should all exist. + outTransformFeedbackLinkedVaryings->clear(); + for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++) + { + bool found = false; + for (size_t j = 0; j < linkedVaryings.size(); j++) + { + if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name) + { + for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++) + { + if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name) + { + infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str()); + return false; + } + } + + size_t componentCount = linkedVaryings[j].semanticIndexCount * 4; + if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && + componentCount > caps.maxTransformFeedbackSeparateComponents) + { + infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).", + linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents); + return false; + } + + totalComponents += componentCount; + + outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]); + found = true; + break; + } + } + + // All transform feedback varyings are expected to exist since packVaryings checks for them. + ASSERT(found); + } + + if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents) + { + infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).", + totalComponents, caps.maxTransformFeedbackInterleavedComponents); + return false; + } + + return true; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Program.h b/src/3rdparty/angle/src/libANGLE/Program.h new file mode 100644 index 0000000000..38fc83d29d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Program.h @@ -0,0 +1,276 @@ +// +// Copyright (c) 2002-2014 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 LIBANGLE_PROGRAM_H_ +#define LIBANGLE_PROGRAM_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +#include +#include + +#include +#include +#include + +namespace rx +{ +class Renderer; +class Renderer; +struct TranslatedAttribute; +class ProgramImpl; +} + +namespace gl +{ +struct Caps; +struct Data; +class ResourceManager; +class Shader; +class InfoLog; +class AttributeBindings; +class Buffer; +class Framebuffer; +struct UniformBlock; +struct LinkedUniform; + +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 : angle::NonCopyable +{ + 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: + char *mInfoLog; +}; + +// Struct used for correlating uniforms/elements of uniform arrays to handles +struct VariableLocation +{ + VariableLocation(); + VariableLocation(const std::string &name, unsigned int element, unsigned int index); + + std::string name; + unsigned int element; + unsigned int index; +}; + +struct LinkedVarying +{ + LinkedVarying(); + LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, + unsigned int semanticIndex, unsigned int semanticIndexCount); + + // Original GL name + std::string name; + + GLenum type; + GLsizei size; + + // DirectX semantic information + std::string semanticName; + unsigned int semanticIndex; + unsigned int semanticIndexCount; +}; + +class Program : angle::NonCopyable +{ + public: + Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle); + ~Program(); + + GLuint id() const { return mHandle; } + + rx::ProgramImpl *getImplementation() { return mProgram; } + const rx::ProgramImpl *getImplementation() const { return mProgram; } + + bool attachShader(Shader *shader); + bool detachShader(Shader *shader); + int getAttachedShadersCount() const; + + void bindAttributeLocation(GLuint index, const char *name); + + Error link(const Data &data); + bool isLinked(); + + Error loadBinary(GLenum binaryFormat, const void *binary, GLsizei length); + Error saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const; + GLint getBinaryLength() const; + + int getInfoLogLength() const; + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog); + void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); + + GLuint getAttributeLocation(const std::string &name); + int getSemanticIndex(int attributeIndex); + + void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveAttributeCount(); + GLint getActiveAttributeMaxLength(); + + GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps); + GLenum getSamplerTextureType(SamplerType type, unsigned int samplerIndex); + GLint getUsedSamplerRange(SamplerType type); + bool usesPointSize() const; + + GLint getFragDataLocation(const std::string &name) const; + + void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); + GLint getActiveUniformCount(); + GLint getActiveUniformMaxLength(); + GLint getActiveUniformi(GLuint index, GLenum pname) const; + bool isValidUniformLocation(GLint location) const; + LinkedUniform *getUniformByLocation(GLint location) const; + LinkedUniform *getUniformByName(const std::string &name) const; + + GLint getUniformLocation(const std::string &name); + GLuint getUniformIndex(const std::string &name); + void setUniform1fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform1iv(GLint location, GLsizei count, const GLint *v); + void setUniform2iv(GLint location, GLsizei count, const GLint *v); + void setUniform3iv(GLint location, GLsizei count, const GLint *v); + void setUniform4iv(GLint location, GLsizei count, const GLint *v); + void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform2uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform3uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform4uiv(GLint location, GLsizei count, const GLuint *v); + void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + + void getUniformfv(GLint location, GLfloat *params); + void getUniformiv(GLint location, GLint *params); + void getUniformuiv(GLint location, GLuint *params); + + Error applyUniforms(); + Error applyUniformBuffers(const gl::Data &data); + + void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const; + void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const; + GLuint getActiveUniformBlockCount(); + GLint getActiveUniformBlockMaxLength(); + + GLuint getUniformBlockIndex(const std::string &name); + + void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding); + GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const; + + const UniformBlock *getUniformBlockByIndex(GLuint index) const; + + void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode); + void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const; + GLsizei getTransformFeedbackVaryingCount() const; + GLsizei getTransformFeedbackVaryingMaxLength() const; + GLenum getTransformFeedbackBufferMode() const; + + static bool linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader); + static bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform); + static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform); + + void addRef(); + void release(); + unsigned int getRefCount() const; + void flagForDeletion(); + bool isFlaggedForDeletion() const; + + void validate(const Caps &caps); + bool validateSamplers(InfoLog *infoLog, const Caps &caps); + bool isValidated() const; + void updateSamplerMapping(); + + private: + void unlink(bool destroy = false); + void resetUniformBlockBindings(); + + bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader); + bool linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps); + bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock); + + static bool linkValidateVariablesBase(InfoLog &infoLog, + const std::string &variableName, + const sh::ShaderVariable &vertexVariable, + const sh::ShaderVariable &fragmentVariable, + bool validatePrecision); + + static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying); + bool gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector &linkedVaryings, + const std::vector &transformFeedbackVaryingNames, + GLenum transformFeedbackBufferMode, + std::vector *outTransformFeedbackLinkedVaryings, + const Caps &caps) const; + bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps); + void defineOutputVariables(Shader *fragmentShader); + + rx::ProgramImpl *mProgram; + + sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; + + std::map mOutputVariables; + + bool mValidated; + + Shader *mFragmentShader; + Shader *mVertexShader; + + AttributeBindings mAttributeBindings; + + GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; + + std::vector mTransformFeedbackVaryings; + GLenum mTransformFeedbackBufferMode; + + 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 // LIBANGLE_PROGRAM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Query.cpp b/src/3rdparty/angle/src/libANGLE/Query.cpp new file mode 100644 index 0000000000..a402b732bf --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Query.cpp @@ -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. +// + +// Query.cpp: Implements the gl::Query class + +#include "libANGLE/Query.h" +#include "libANGLE/renderer/QueryImpl.h" + +namespace gl +{ +Query::Query(rx::QueryImpl *impl, GLuint id) + : RefCountObject(id), + mQuery(impl) +{ +} + +Query::~Query() +{ + SafeDelete(mQuery); +} + +Error Query::begin() +{ + return mQuery->begin(); +} + +Error Query::end() +{ + return mQuery->end(); +} + +Error Query::getResult(GLuint *params) +{ + return mQuery->getResult(params); +} + +Error Query::isResultAvailable(GLuint *available) +{ + return mQuery->isResultAvailable(available); +} + +GLenum Query::getType() const +{ + return mQuery->getType(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Query.h b/src/3rdparty/angle/src/libANGLE/Query.h new file mode 100644 index 0000000000..8585fde0e2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Query.h @@ -0,0 +1,47 @@ +// +// 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 LIBANGLE_QUERY_H_ +#define LIBANGLE_QUERY_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ +class QueryImpl; +} + +namespace gl +{ + +class Query : public RefCountObject +{ + public: + Query(rx::QueryImpl *impl, GLuint id); + virtual ~Query(); + + Error begin(); + Error end(); + + Error getResult(GLuint *params); + Error isResultAvailable(GLuint *available); + + GLenum getType() const; + + private: + rx::QueryImpl *mQuery; +}; + +} + +#endif // LIBANGLE_QUERY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp b/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp new file mode 100644 index 0000000000..b1210200cf --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/RefCountObject.cpp @@ -0,0 +1,39 @@ +// +// 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; + } +} + diff --git a/src/3rdparty/angle/src/libANGLE/RefCountObject.h b/src/3rdparty/angle/src/libANGLE/RefCountObject.h new file mode 100644 index 0000000000..48c0338c3f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/RefCountObject.h @@ -0,0 +1,110 @@ +// +// 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 LIBANGLE_REFCOUNTOBJECT_H_ +#define LIBANGLE_REFCOUNTOBJECT_H_ + +#include "common/debug.h" + +#include "angle_gl.h" + +#include + +class RefCountObject : angle::NonCopyable +{ + 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; +}; + +template +class BindingPointer +{ +public: + BindingPointer() + : mObject(nullptr) + { + } + + BindingPointer(const BindingPointer &other) + : mObject(nullptr) + { + set(other.mObject); + } + + void operator=(const BindingPointer &other) + { + set(other.mObject); + } + + virtual ~BindingPointer() + { + // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up. + ASSERT(mObject == nullptr); + } + + virtual void set(ObjectType *newObject) + { + // addRef first in case newObject == mObject and this is the last reference to it. + if (newObject != nullptr) reinterpret_cast(newObject)->addRef(); + if (mObject != nullptr) reinterpret_cast(mObject)->release(); + mObject = newObject; + } + + ObjectType *get() const { return mObject; } + ObjectType *operator->() const { return mObject; } + + GLuint id() const { return (mObject != nullptr) ? mObject->id() : 0; } + bool operator!() const { return (mObject == nullptr); } + + private: + ObjectType *mObject; +}; + +template +class OffsetBindingPointer : public BindingPointer +{ + public: + OffsetBindingPointer() : mOffset(0), mSize(0) { } + + void set(ObjectType *newObject) override + { + BindingPointer::set(newObject); + mOffset = 0; + mSize = 0; + } + + void set(ObjectType *newObject, GLintptr offset, GLsizeiptr size) + { + BindingPointer::set(newObject); + mOffset = offset; + mSize = size; + } + + GLintptr getOffset() const { return mOffset; } + GLsizeiptr getSize() const { return mSize; } + + private: + GLintptr mOffset; + GLsizeiptr mSize; +}; + +#endif // LIBANGLE_REFCOUNTOBJECT_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp new file mode 100644 index 0000000000..6a0cde812b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.cpp @@ -0,0 +1,130 @@ +// +// 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. +// + +// Renderbuffer.cpp: Implements the renderer-agnostic gl::Renderbuffer class, +// GL renderbuffer objects and related functionality. +// [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#include "libANGLE/Renderbuffer.h" + +#include "common/utilities.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/RenderbufferImpl.h" + +namespace gl +{ +Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id) + : RefCountObject(id), + mRenderbuffer(impl), + mWidth(0), + mHeight(0), + mInternalFormat(GL_RGBA4), + mSamples(0) +{ +} + +Renderbuffer::~Renderbuffer() +{ + SafeDelete(mRenderbuffer); +} + +Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t height) +{ + Error error = mRenderbuffer->setStorage(internalformat, width, height); + if (error.isError()) + { + return error; + } + + mWidth = width; + mHeight = height; + mInternalFormat = internalformat; + mSamples = 0; + + return Error(GL_NO_ERROR); +} + +Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) +{ + Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height); + if (error.isError()) + { + return error; + } + + mWidth = width; + mHeight = height; + mInternalFormat = internalformat; + mSamples = samples; + + return Error(GL_NO_ERROR); +} + +rx::RenderbufferImpl *Renderbuffer::getImplementation() +{ + ASSERT(mRenderbuffer); + return mRenderbuffer; +} + +const rx::RenderbufferImpl *Renderbuffer::getImplementation() const +{ + return mRenderbuffer; +} + +GLsizei Renderbuffer::getWidth() const +{ + return mWidth; +} + +GLsizei Renderbuffer::getHeight() const +{ + return mHeight; +} + +GLenum Renderbuffer::getInternalFormat() const +{ + return mInternalFormat; +} + +GLsizei Renderbuffer::getSamples() const +{ + return mSamples; +} + +GLuint Renderbuffer::getRedSize() const +{ + return GetInternalFormatInfo(mInternalFormat).redBits; +} + +GLuint Renderbuffer::getGreenSize() const +{ + return GetInternalFormatInfo(mInternalFormat).greenBits; +} + +GLuint Renderbuffer::getBlueSize() const +{ + return GetInternalFormatInfo(mInternalFormat).blueBits; +} + +GLuint Renderbuffer::getAlphaSize() const +{ + return GetInternalFormatInfo(mInternalFormat).alphaBits; +} + +GLuint Renderbuffer::getDepthSize() const +{ + return GetInternalFormatInfo(mInternalFormat).depthBits; +} + +GLuint Renderbuffer::getStencilSize() const +{ + return GetInternalFormatInfo(mInternalFormat).stencilBits; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Renderbuffer.h b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h new file mode 100644 index 0000000000..98c7eb0f10 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Renderbuffer.h @@ -0,0 +1,69 @@ +// +// 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 renderer-agnostic container class gl::Renderbuffer. +// Implements GL renderbuffer objects and related functionality. +// [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#ifndef LIBANGLE_RENDERBUFFER_H_ +#define LIBANGLE_RENDERBUFFER_H_ + +#include "angle_gl.h" + +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +namespace rx +{ +class RenderbufferImpl; +} + +namespace gl +{ +class FramebufferAttachment; + +// A GL renderbuffer object is usually used as a depth or stencil buffer attachment +// for a framebuffer object. The renderbuffer itself is a distinct GL object, see +// FramebufferAttachment and Framebuffer for how they are applied to an FBO via an +// attachment point. + +class Renderbuffer : public RefCountObject +{ + public: + Renderbuffer(rx::RenderbufferImpl *impl, GLuint id); + virtual ~Renderbuffer(); + + Error setStorage(GLenum internalformat, size_t width, size_t height); + Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height); + + rx::RenderbufferImpl *getImplementation(); + const rx::RenderbufferImpl *getImplementation() const; + + GLsizei getWidth() const; + GLsizei getHeight() const; + GLenum getInternalFormat() const; + GLsizei getSamples() const; + GLuint getRedSize() const; + GLuint getGreenSize() const; + GLuint getBlueSize() const; + GLuint getAlphaSize() const; + GLuint getDepthSize() const; + GLuint getStencilSize() const; + + private: + rx::RenderbufferImpl *mRenderbuffer; + + GLsizei mWidth; + GLsizei mHeight; + GLenum mInternalFormat; + GLsizei mSamples; +}; + +} + +#endif // LIBANGLE_RENDERBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp new file mode 100644 index 0000000000..aaf144cfa9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.cpp @@ -0,0 +1,456 @@ +// +// Copyright (c) 2002-2013 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 "libANGLE/ResourceManager.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/Program.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Sampler.h" +#include "libANGLE/Fence.h" +#include "libANGLE/renderer/Renderer.h" + +namespace gl +{ +ResourceManager::ResourceManager(rx::ImplFactory *factory) + : mFactory(factory), + 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); + } + + while (!mSamplerMap.empty()) + { + deleteSampler(mSamplerMap.begin()->first); + } + + while (!mFenceSyncMap.empty()) + { + deleteFenceSync(mFenceSyncMap.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(const gl::Data &data, GLenum type) +{ + GLuint handle = mProgramShaderHandleAllocator.allocate(); + + if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER) + { + mShaderMap[handle] = new Shader(this, mFactory->createShader(type), type, handle); + } + else UNREACHABLE(); + + return handle; +} + +// Returns an unused program/shader name +GLuint ResourceManager::createProgram() +{ + GLuint handle = mProgramShaderHandleAllocator.allocate(); + + mProgramMap[handle] = new Program(mFactory->createProgram(), 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; +} + +// Returns an unused sampler name +GLuint ResourceManager::createSampler() +{ + GLuint handle = mSamplerHandleAllocator.allocate(); + + mSamplerMap[handle] = NULL; + + return handle; +} + +// Returns the next unused fence name, and allocates the fence +GLuint ResourceManager::createFenceSync() +{ + GLuint handle = mFenceSyncHandleAllocator.allocate(); + + FenceSync *fenceSync = new FenceSync(mFactory->createFenceSync(), handle); + fenceSync->addRef(); + mFenceSyncMap[handle] = fenceSync; + + 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); + } +} + +void ResourceManager::deleteSampler(GLuint sampler) +{ + auto samplerObject = mSamplerMap.find(sampler); + + if (samplerObject != mSamplerMap.end()) + { + mSamplerHandleAllocator.release(samplerObject->first); + if (samplerObject->second) samplerObject->second->release(); + mSamplerMap.erase(samplerObject); + } +} + +void ResourceManager::deleteFenceSync(GLuint fenceSync) +{ + auto fenceObjectIt = mFenceSyncMap.find(fenceSync); + + if (fenceObjectIt != mFenceSyncMap.end()) + { + mFenceSyncHandleAllocator.release(fenceObjectIt->first); + if (fenceObjectIt->second) fenceObjectIt->second->release(); + mFenceSyncMap.erase(fenceObjectIt); + } +} + +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) const +{ + ProgramMap::const_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; + } +} + +Sampler *ResourceManager::getSampler(unsigned int handle) +{ + auto sampler = mSamplerMap.find(handle); + + if (sampler == mSamplerMap.end()) + { + return NULL; + } + else + { + return sampler->second; + } +} + +FenceSync *ResourceManager::getFenceSync(unsigned int handle) +{ + auto fenceObjectIt = mFenceSyncMap.find(handle); + + if (fenceObjectIt == mFenceSyncMap.end()) + { + return NULL; + } + else + { + return fenceObjectIt->second; + } +} + +void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer) +{ + mRenderbufferMap[handle] = buffer; +} + +void ResourceManager::checkBufferAllocation(GLuint handle) +{ + if (handle != 0) + { + auto bufferMapIt = mBufferMap.find(handle); + bool handleAllocated = (bufferMapIt != mBufferMap.end()); + + if (handleAllocated && bufferMapIt->second != nullptr) + { + return; + } + + Buffer *buffer = new Buffer(mFactory->createBuffer(), handle); + buffer->addRef(); + + if (handleAllocated) + { + bufferMapIt->second = buffer; + } + else + { + mBufferHandleAllocator.reserve(handle); + mBufferMap[handle] = buffer; + } + } +} + +void ResourceManager::checkTextureAllocation(GLuint handle, GLenum type) +{ + if (handle != 0) + { + auto textureMapIt = mTextureMap.find(handle); + bool handleAllocated = (textureMapIt != mTextureMap.end()); + + if (handleAllocated && textureMapIt->second != nullptr) + { + return; + } + + Texture *texture = new Texture(mFactory->createTexture(type), handle, type); + texture->addRef(); + + if (handleAllocated) + { + textureMapIt->second = texture; + } + else + { + mTextureHandleAllocator.reserve(handle); + mTextureMap[handle] = texture; + } + } +} + +void ResourceManager::checkRenderbufferAllocation(GLuint handle) +{ + if (handle != 0) + { + auto renderbufferMapIt = mRenderbufferMap.find(handle); + bool handleAllocated = (renderbufferMapIt != mRenderbufferMap.end()); + + if (handleAllocated && renderbufferMapIt->second != nullptr) + { + return; + } + + Renderbuffer *renderbuffer = new Renderbuffer(mFactory->createRenderbuffer(), handle); + renderbuffer->addRef(); + + if (handleAllocated) + { + renderbufferMapIt->second = renderbuffer; + } + else + { + mRenderbufferHandleAllocator.reserve(handle); + mRenderbufferMap[handle] = renderbuffer; + } + } +} + +void ResourceManager::checkSamplerAllocation(GLuint sampler) +{ + if (sampler != 0 && !getSampler(sampler)) + { + Sampler *samplerObject = new Sampler(sampler); + mSamplerMap[sampler] = samplerObject; + samplerObject->addRef(); + // Samplers cannot be created via Bind + } +} + +bool ResourceManager::isSampler(GLuint sampler) +{ + return mSamplerMap.find(sampler) != mSamplerMap.end(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/ResourceManager.h b/src/3rdparty/angle/src/libANGLE/ResourceManager.h new file mode 100644 index 0000000000..8e95e8840a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/ResourceManager.h @@ -0,0 +1,114 @@ +// +// Copyright (c) 2002-2013 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 LIBANGLE_RESOURCEMANAGER_H_ +#define LIBANGLE_RESOURCEMANAGER_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/HandleAllocator.h" + +#include + +namespace rx +{ +class ImplFactory; +} + +namespace gl +{ +class Buffer; +class Shader; +class Program; +class Texture; +class Renderbuffer; +class Sampler; +class FenceSync; +struct Data; + +class ResourceManager : angle::NonCopyable +{ + public: + explicit ResourceManager(rx::ImplFactory *factory); + ~ResourceManager(); + + void addRef(); + void release(); + + GLuint createBuffer(); + GLuint createShader(const gl::Data &data, GLenum type); + GLuint createProgram(); + GLuint createTexture(); + GLuint createRenderbuffer(); + GLuint createSampler(); + GLuint createFenceSync(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteRenderbuffer(GLuint renderbuffer); + void deleteSampler(GLuint sampler); + void deleteFenceSync(GLuint fenceSync); + + Buffer *getBuffer(GLuint handle); + Shader *getShader(GLuint handle); + Program *getProgram(GLuint handle) const; + Texture *getTexture(GLuint handle); + Renderbuffer *getRenderbuffer(GLuint handle); + Sampler *getSampler(GLuint handle); + FenceSync *getFenceSync(GLuint handle); + + void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); + + void checkBufferAllocation(GLuint handle); + void checkTextureAllocation(GLuint handle, GLenum type); + void checkRenderbufferAllocation(GLuint handle); + void checkSamplerAllocation(GLuint sampler); + + bool isSampler(GLuint sampler); + + private: + void createTextureInternal(GLuint handle); + + rx::ImplFactory *mFactory; + std::size_t mRefCount; + + typedef std::map BufferMap; + BufferMap mBufferMap; + HandleAllocator mBufferHandleAllocator; + + typedef std::map ShaderMap; + ShaderMap mShaderMap; + + typedef std::map ProgramMap; + ProgramMap mProgramMap; + HandleAllocator mProgramShaderHandleAllocator; + + typedef std::map TextureMap; + TextureMap mTextureMap; + HandleAllocator mTextureHandleAllocator; + + typedef std::map RenderbufferMap; + RenderbufferMap mRenderbufferMap; + HandleAllocator mRenderbufferHandleAllocator; + + typedef std::map SamplerMap; + SamplerMap mSamplerMap; + HandleAllocator mSamplerHandleAllocator; + + typedef std::map FenceMap; + FenceMap mFenceSyncMap; + HandleAllocator mFenceSyncHandleAllocator; +}; + +} + +#endif // LIBANGLE_RESOURCEMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.cpp b/src/3rdparty/angle/src/libANGLE/Sampler.cpp new file mode 100644 index 0000000000..d58bd5a862 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Sampler.cpp @@ -0,0 +1,43 @@ +// +// Copyright (c) 2013 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. +// + +// Sampler.cpp : Implements the Sampler class, which represents a GLES 3 +// sampler object. Sampler objects store some state needed to sample textures. + +#include "libANGLE/Sampler.h" +#include "libANGLE/angletypes.h" + +namespace gl +{ + +Sampler::Sampler(GLuint id) + : RefCountObject(id), + mMinFilter(GL_NEAREST_MIPMAP_LINEAR), + mMagFilter(GL_LINEAR), + mWrapS(GL_REPEAT), + mWrapT(GL_REPEAT), + mWrapR(GL_REPEAT), + mMinLod(-1000.0f), + mMaxLod(1000.0f), + mComparisonMode(GL_NONE), + mComparisonFunc(GL_LEQUAL) +{ +} + +void Sampler::getState(SamplerState *samplerState) const +{ + samplerState->minFilter = mMinFilter; + samplerState->magFilter = mMagFilter; + samplerState->wrapS = mWrapS; + samplerState->wrapT = mWrapT; + samplerState->wrapR = mWrapR; + samplerState->minLod = mMinLod; + samplerState->maxLod = mMaxLod; + samplerState->compareMode = mComparisonMode; + samplerState->compareFunc = mComparisonFunc; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Sampler.h b/src/3rdparty/angle/src/libANGLE/Sampler.h new file mode 100644 index 0000000000..d33798ff15 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Sampler.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2013 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. +// + +// Sampler.h : Defines the Sampler class, which represents a GLES 3 +// sampler object. Sampler objects store some state needed to sample textures. + +#ifndef LIBANGLE_SAMPLER_H_ +#define LIBANGLE_SAMPLER_H_ + +#include "libANGLE/RefCountObject.h" + +namespace gl +{ +struct SamplerState; + +class Sampler : public RefCountObject +{ + public: + Sampler(GLuint id); + + void setMinFilter(GLenum minFilter) { mMinFilter = minFilter; } + void setMagFilter(GLenum magFilter) { mMagFilter = magFilter; } + void setWrapS(GLenum wrapS) { mWrapS = wrapS; } + void setWrapT(GLenum wrapT) { mWrapT = wrapT; } + void setWrapR(GLenum wrapR) { mWrapR = wrapR; } + void setMinLod(GLfloat minLod) { mMinLod = minLod; } + void setMaxLod(GLfloat maxLod) { mMaxLod = maxLod; } + void setComparisonMode(GLenum comparisonMode) { mComparisonMode = comparisonMode; } + void setComparisonFunc(GLenum comparisonFunc) { mComparisonFunc = comparisonFunc; } + + GLenum getMinFilter() const { return mMinFilter; } + GLenum getMagFilter() const { return mMagFilter; } + GLenum getWrapS() const { return mWrapS; } + GLenum getWrapT() const { return mWrapT; } + GLenum getWrapR() const { return mWrapR; } + GLfloat getMinLod() const { return mMinLod; } + GLfloat getMaxLod() const { return mMaxLod; } + GLenum getComparisonMode() const { return mComparisonMode; } + GLenum getComparisonFunc() const { return mComparisonFunc; } + + void getState(SamplerState *samplerState) const; + + private: + GLenum mMinFilter; + GLenum mMagFilter; + GLenum mWrapS; + GLenum mWrapT; + GLenum mWrapR; + GLfloat mMinLod; + GLfloat mMaxLod; + GLenum mComparisonMode; + GLenum mComparisonFunc; +}; + +} + +#endif // LIBANGLE_SAMPLER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Shader.cpp b/src/3rdparty/angle/src/libANGLE/Shader.cpp new file mode 100644 index 0000000000..7af4ff358d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Shader.cpp @@ -0,0 +1,243 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/Shader.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/ShaderImpl.h" +#include "libANGLE/Constants.h" +#include "libANGLE/ResourceManager.h" + +#include "common/utilities.h" + +#include "GLSLANG/ShaderLang.h" + +#include + +namespace gl +{ + +Shader::Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLuint handle) + : mShader(impl), + mType(type), + mHandle(handle), + mResourceManager(manager), + mRefCount(0), + mDeleteStatus(false), + mCompiled(false) +{ + ASSERT(impl); +} + +Shader::~Shader() +{ + SafeDelete(mShader); +} + +GLuint Shader::getHandle() const +{ + return mHandle; +} + +void Shader::setSource(GLsizei count, const char *const *string, const GLint *length) +{ + std::ostringstream stream; + + for (int i = 0; i < count; i++) + { + if (length == nullptr || length[i] < 0) + { + stream.write(string[i], strlen(string[i])); + } + else + { + stream.write(string[i], length[i]); + } + } + + mSource = stream.str(); +} + +int Shader::getInfoLogLength() const +{ + return mShader->getInfoLog().empty() ? 0 : (mShader->getInfoLog().length() + 1); +} + +void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const +{ + int index = 0; + + if (bufSize > 0) + { + index = std::min(bufSize - 1, static_cast(mShader->getInfoLog().length())); + memcpy(infoLog, mShader->getInfoLog().c_str(), index); + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +int Shader::getSourceLength() const +{ + return mSource.empty() ? 0 : (mSource.length() + 1); +} + +int Shader::getTranslatedSourceLength() const +{ + return mShader->getTranslatedSource().empty() ? 0 : (mShader->getTranslatedSource().length() + 1); +} + +void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer) +{ + int index = 0; + + if (bufSize > 0) + { + index = std::min(bufSize - 1, static_cast(source.length())); + memcpy(buffer, source.c_str(), index); + + buffer[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + getSourceImpl(mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + getSourceImpl(mShader->getTranslatedSource(), bufSize, length, buffer); +} + +void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + std::string debugInfo(mShader->getDebugInfo()); + getSourceImpl(debugInfo, bufSize, length, buffer); +} + +void Shader::compile(Compiler *compiler) +{ + mCompiled = mShader->compile(compiler, mSource); +} + +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; +} + +const std::vector &Shader::getVaryings() const +{ + return mShader->getVaryings(); +} + +const std::vector &Shader::getUniforms() const +{ + return mShader->getUniforms(); +} + +const std::vector &Shader::getInterfaceBlocks() const +{ + return mShader->getInterfaceBlocks(); +} + +const std::vector &Shader::getActiveAttributes() const +{ + return mShader->getActiveAttributes(); +} + +const std::vector &Shader::getActiveOutputVariables() const +{ + return mShader->getActiveOutputVariables(); +} + +std::vector &Shader::getVaryings() +{ + return mShader->getVaryings(); +} + +std::vector &Shader::getUniforms() +{ + return mShader->getUniforms(); +} + +std::vector &Shader::getInterfaceBlocks() +{ + return mShader->getInterfaceBlocks(); +} + +std::vector &Shader::getActiveAttributes() +{ + return mShader->getActiveAttributes(); +} + +std::vector &Shader::getActiveOutputVariables() +{ + return mShader->getActiveOutputVariables(); +} + + +int Shader::getSemanticIndex(const std::string &attributeName) const +{ + if (!attributeName.empty()) + { + const auto &activeAttributes = mShader->getActiveAttributes(); + + int semanticIndex = 0; + for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++) + { + const sh::ShaderVariable &attribute = activeAttributes[attributeIndex]; + + if (attribute.name == attributeName) + { + return semanticIndex; + } + + semanticIndex += gl::VariableRegisterCount(attribute.type); + } + } + + return -1; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Shader.h b/src/3rdparty/angle/src/libANGLE/Shader.h new file mode 100644 index 0000000000..10e79c7499 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Shader.h @@ -0,0 +1,118 @@ +// +// Copyright (c) 2002-2013 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 LIBANGLE_SHADER_H_ +#define LIBANGLE_SHADER_H_ + +#include +#include +#include + +#include "angle_gl.h" +#include + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ +class ShaderImpl; +} + +namespace gl +{ +class Compiler; +class ResourceManager; +struct Data; + +struct PackedVarying : public sh::Varying +{ + unsigned int registerIndex; // Assigned during link + unsigned int columnIndex; // Assigned during link, defaults to 0 + + PackedVarying(const sh::Varying &varying) + : sh::Varying(varying), + registerIndex(GL_INVALID_INDEX), + columnIndex(0) + {} + + bool registerAssigned() const { return registerIndex != GL_INVALID_INDEX; } + bool isBuiltIn() const { return name.compare(0, 3, "gl_") == 0; } + + void resetRegisterAssignment() + { + registerIndex = GL_INVALID_INDEX; + } +}; + +class Shader : angle::NonCopyable +{ + public: + Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLuint handle); + + virtual ~Shader(); + + GLenum getType() const { return mType; } + GLuint getHandle() const; + + rx::ShaderImpl *getImplementation() { return mShader; } + const rx::ShaderImpl *getImplementation() const { return mShader; } + + void deleteSource(); + void setSource(GLsizei count, const char *const *string, const GLint *length); + int getInfoLogLength() const; + void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const; + int getSourceLength() const; + void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const; + int getTranslatedSourceLength() const; + void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const; + void getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const; + + void compile(Compiler *compiler); + bool isCompiled() const { return mCompiled; } + + void addRef(); + void release(); + unsigned int getRefCount() const; + bool isFlaggedForDeletion() const; + void flagForDeletion(); + + const std::vector &getVaryings() const; + const std::vector &getUniforms() const; + const std::vector &getInterfaceBlocks() const; + const std::vector &getActiveAttributes() const; + const std::vector &getActiveOutputVariables() const; + + std::vector &getVaryings(); + std::vector &getUniforms(); + std::vector &getInterfaceBlocks(); + std::vector &getActiveAttributes(); + std::vector &getActiveOutputVariables(); + + int getSemanticIndex(const std::string &attributeName) const; + + private: + static void getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer); + + rx::ShaderImpl *mShader; + const GLuint mHandle; + const GLenum mType; + std::string mSource; + 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 + bool mCompiled; // Indicates if this shader has been successfully compiled + + ResourceManager *mResourceManager; +}; + +} + +#endif // LIBANGLE_SHADER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/State.cpp b/src/3rdparty/angle/src/libANGLE/State.cpp new file mode 100644 index 0000000000..4c044d2950 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/State.cpp @@ -0,0 +1,1470 @@ +// +// Copyright (c) 2014 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. +// + +// State.cpp: Implements the State class, encapsulating raw GL state. + +#include "libANGLE/State.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Query.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" + +namespace gl +{ + +State::State() +{ + mMaxDrawBuffers = 0; + mMaxCombinedTextureImageUnits = 0; +} + +State::~State() +{ + reset(); +} + +void State::initialize(const Caps& caps, GLuint clientVersion) +{ + mMaxDrawBuffers = caps.maxDrawBuffers; + mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; + + setColorClearValue(0.0f, 0.0f, 0.0f, 0.0f); + + mDepthClearValue = 1.0f; + mStencilClearValue = 0; + + mRasterizer.rasterizerDiscard = false; + mRasterizer.cullFace = false; + mRasterizer.cullMode = GL_BACK; + mRasterizer.frontFace = GL_CCW; + mRasterizer.polygonOffsetFill = false; + mRasterizer.polygonOffsetFactor = 0.0f; + mRasterizer.polygonOffsetUnits = 0.0f; + mRasterizer.pointDrawMode = false; + mRasterizer.multiSample = false; + mScissorTest = false; + mScissor.x = 0; + mScissor.y = 0; + mScissor.width = 0; + mScissor.height = 0; + + mBlend.blend = false; + mBlend.sourceBlendRGB = GL_ONE; + mBlend.sourceBlendAlpha = GL_ONE; + mBlend.destBlendRGB = GL_ZERO; + mBlend.destBlendAlpha = GL_ZERO; + mBlend.blendEquationRGB = GL_FUNC_ADD; + mBlend.blendEquationAlpha = GL_FUNC_ADD; + mBlend.sampleAlphaToCoverage = false; + mBlend.dither = true; + + mBlendColor.red = 0; + mBlendColor.green = 0; + mBlendColor.blue = 0; + mBlendColor.alpha = 0; + + mDepthStencil.depthTest = false; + mDepthStencil.depthFunc = GL_LESS; + mDepthStencil.depthMask = true; + mDepthStencil.stencilTest = false; + mDepthStencil.stencilFunc = GL_ALWAYS; + mDepthStencil.stencilMask = static_cast(-1); + mDepthStencil.stencilWritemask = static_cast(-1); + mDepthStencil.stencilBackFunc = GL_ALWAYS; + mDepthStencil.stencilBackMask = static_cast(-1); + mDepthStencil.stencilBackWritemask = static_cast(-1); + mDepthStencil.stencilFail = GL_KEEP; + mDepthStencil.stencilPassDepthFail = GL_KEEP; + mDepthStencil.stencilPassDepthPass = GL_KEEP; + mDepthStencil.stencilBackFail = GL_KEEP; + mDepthStencil.stencilBackPassDepthFail = GL_KEEP; + mDepthStencil.stencilBackPassDepthPass = GL_KEEP; + + mStencilRef = 0; + mStencilBackRef = 0; + + mSampleCoverage = false; + mSampleCoverageValue = 1.0f; + mSampleCoverageInvert = false; + mGenerateMipmapHint = GL_DONT_CARE; + mFragmentShaderDerivativeHint = GL_DONT_CARE; + + mLineWidth = 1.0f; + + mViewport.x = 0; + mViewport.y = 0; + mViewport.width = 0; + mViewport.height = 0; + mNearZ = 0.0f; + mFarZ = 1.0f; + + mBlend.colorMaskRed = true; + mBlend.colorMaskGreen = true; + mBlend.colorMaskBlue = true; + mBlend.colorMaskAlpha = true; + + mActiveSampler = 0; + + const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + mVertexAttribCurrentValues.resize(caps.maxVertexAttributes); + for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); ++attribIndex) + { + mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); + } + + mUniformBuffers.resize(caps.maxCombinedUniformBlocks); + mTransformFeedbackBuffers.resize(caps.maxTransformFeedbackSeparateAttributes); + + mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits); + mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits); + if (clientVersion >= 3) + { + // TODO: These could also be enabled via extension + mSamplerTextures[GL_TEXTURE_2D_ARRAY].resize(caps.maxCombinedTextureImageUnits); + mSamplerTextures[GL_TEXTURE_3D].resize(caps.maxCombinedTextureImageUnits); + } + + mSamplers.resize(caps.maxCombinedTextureImageUnits); + + mActiveQueries[GL_ANY_SAMPLES_PASSED].set(NULL); + mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(NULL); + mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(NULL); + + mProgram = NULL; + + mReadFramebuffer = NULL; + mDrawFramebuffer = NULL; + + mPrimitiveRestart = false; +} + +void State::reset() +{ + for (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) + { + TextureBindingVector &textureVector = bindingVec->second; + for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) + { + textureVector[textureIdx].set(NULL); + } + } + for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++) + { + mSamplers[samplerIdx].set(NULL); + } + + mArrayBuffer.set(NULL); + mRenderbuffer.set(NULL); + + if (mProgram) + { + mProgram->release(); + } + mProgram = NULL; + + mTransformFeedback.set(NULL); + + for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++) + { + i->second.set(NULL); + } + + mGenericUniformBuffer.set(NULL); + mGenericTransformFeedbackBuffer.set(NULL); + for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr) + { + bufItr->set(NULL); + } + + for (BufferVector::iterator bufItr = mTransformFeedbackBuffers.begin(); bufItr != mTransformFeedbackBuffers.end(); ++bufItr) + { + bufItr->set(NULL); + } + + mCopyReadBuffer.set(NULL); + mCopyWriteBuffer.set(NULL); + + mPack.pixelBuffer.set(NULL); + mUnpack.pixelBuffer.set(NULL); + + mProgram = NULL; +} + +const RasterizerState &State::getRasterizerState() const +{ + return mRasterizer; +} + +const BlendState &State::getBlendState() const +{ + return mBlend; +} + +const DepthStencilState &State::getDepthStencilState() const +{ + return mDepthStencil; +} + +void State::setColorClearValue(float red, float green, float blue, float alpha) +{ + mColorClearValue.red = red; + mColorClearValue.green = green; + mColorClearValue.blue = blue; + mColorClearValue.alpha = alpha; +} + +void State::setDepthClearValue(float depth) +{ + mDepthClearValue = depth; +} + +void State::setStencilClearValue(int stencil) +{ + mStencilClearValue = stencil; +} + +void State::setColorMask(bool red, bool green, bool blue, bool alpha) +{ + mBlend.colorMaskRed = red; + mBlend.colorMaskGreen = green; + mBlend.colorMaskBlue = blue; + mBlend.colorMaskAlpha = alpha; +} + +void State::setDepthMask(bool mask) +{ + mDepthStencil.depthMask = mask; +} + +bool State::isRasterizerDiscardEnabled() const +{ + return mRasterizer.rasterizerDiscard; +} + +void State::setRasterizerDiscard(bool enabled) +{ + mRasterizer.rasterizerDiscard = enabled; +} + +bool State::isCullFaceEnabled() const +{ + return mRasterizer.cullFace; +} + +void State::setCullFace(bool enabled) +{ + mRasterizer.cullFace = enabled; +} + +void State::setCullMode(GLenum mode) +{ + mRasterizer.cullMode = mode; +} + +void State::setFrontFace(GLenum front) +{ + mRasterizer.frontFace = front; +} + +bool State::isDepthTestEnabled() const +{ + return mDepthStencil.depthTest; +} + +void State::setDepthTest(bool enabled) +{ + mDepthStencil.depthTest = enabled; +} + +void State::setDepthFunc(GLenum depthFunc) +{ + mDepthStencil.depthFunc = depthFunc; +} + +void State::setDepthRange(float zNear, float zFar) +{ + mNearZ = zNear; + mFarZ = zFar; +} + +void State::getDepthRange(float *zNear, float *zFar) const +{ + *zNear = mNearZ; + *zFar = mFarZ; +} + +bool State::isBlendEnabled() const +{ + return mBlend.blend; +} + +void State::setBlend(bool enabled) +{ + mBlend.blend = enabled; +} + +void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha) +{ + mBlend.sourceBlendRGB = sourceRGB; + mBlend.destBlendRGB = destRGB; + mBlend.sourceBlendAlpha = sourceAlpha; + mBlend.destBlendAlpha = destAlpha; +} + +void State::setBlendColor(float red, float green, float blue, float alpha) +{ + mBlendColor.red = red; + mBlendColor.green = green; + mBlendColor.blue = blue; + mBlendColor.alpha = alpha; +} + +void State::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) +{ + mBlend.blendEquationRGB = rgbEquation; + mBlend.blendEquationAlpha = alphaEquation; +} + +const ColorF &State::getBlendColor() const +{ + return mBlendColor; +} + +bool State::isStencilTestEnabled() const +{ + return mDepthStencil.stencilTest; +} + +void State::setStencilTest(bool enabled) +{ + mDepthStencil.stencilTest = enabled; +} + +void State::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask) +{ + mDepthStencil.stencilFunc = stencilFunc; + mStencilRef = (stencilRef > 0) ? stencilRef : 0; + mDepthStencil.stencilMask = stencilMask; +} + +void State::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask) +{ + mDepthStencil.stencilBackFunc = stencilBackFunc; + mStencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0; + mDepthStencil.stencilBackMask = stencilBackMask; +} + +void State::setStencilWritemask(GLuint stencilWritemask) +{ + mDepthStencil.stencilWritemask = stencilWritemask; +} + +void State::setStencilBackWritemask(GLuint stencilBackWritemask) +{ + mDepthStencil.stencilBackWritemask = stencilBackWritemask; +} + +void State::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass) +{ + mDepthStencil.stencilFail = stencilFail; + mDepthStencil.stencilPassDepthFail = stencilPassDepthFail; + mDepthStencil.stencilPassDepthPass = stencilPassDepthPass; +} + +void State::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass) +{ + mDepthStencil.stencilBackFail = stencilBackFail; + mDepthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail; + mDepthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass; +} + +GLint State::getStencilRef() const +{ + return mStencilRef; +} + +GLint State::getStencilBackRef() const +{ + return mStencilBackRef; +} + +bool State::isPolygonOffsetFillEnabled() const +{ + return mRasterizer.polygonOffsetFill; +} + +void State::setPolygonOffsetFill(bool enabled) +{ + mRasterizer.polygonOffsetFill = enabled; +} + +void State::setPolygonOffsetParams(GLfloat factor, GLfloat units) +{ + // An application can pass NaN values here, so handle this gracefully + mRasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor; + mRasterizer.polygonOffsetUnits = units != units ? 0.0f : units; +} + +bool State::isSampleAlphaToCoverageEnabled() const +{ + return mBlend.sampleAlphaToCoverage; +} + +void State::setSampleAlphaToCoverage(bool enabled) +{ + mBlend.sampleAlphaToCoverage = enabled; +} + +bool State::isSampleCoverageEnabled() const +{ + return mSampleCoverage; +} + +void State::setSampleCoverage(bool enabled) +{ + mSampleCoverage = enabled; +} + +void State::setSampleCoverageParams(GLclampf value, bool invert) +{ + mSampleCoverageValue = value; + mSampleCoverageInvert = invert; +} + +void State::getSampleCoverageParams(GLclampf *value, bool *invert) const +{ + ASSERT(value != NULL && invert != NULL); + + *value = mSampleCoverageValue; + *invert = mSampleCoverageInvert; +} + +bool State::isScissorTestEnabled() const +{ + return mScissorTest; +} + +void State::setScissorTest(bool enabled) +{ + mScissorTest = enabled; +} + +void State::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mScissor.x = x; + mScissor.y = y; + mScissor.width = width; + mScissor.height = height; +} + +const Rectangle &State::getScissor() const +{ + return mScissor; +} + +bool State::isDitherEnabled() const +{ + return mBlend.dither; +} + +void State::setDither(bool enabled) +{ + mBlend.dither = enabled; +} + +bool State::isPrimitiveRestartEnabled() const +{ + return mPrimitiveRestart; +} + +void State::setPrimitiveRestart(bool enabled) +{ + mPrimitiveRestart = enabled; +} + +void State::setEnableFeature(GLenum feature, bool enabled) +{ + switch (feature) + { + case GL_CULL_FACE: setCullFace(enabled); break; + case GL_POLYGON_OFFSET_FILL: setPolygonOffsetFill(enabled); break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: setSampleAlphaToCoverage(enabled); break; + case GL_SAMPLE_COVERAGE: setSampleCoverage(enabled); break; + case GL_SCISSOR_TEST: setScissorTest(enabled); break; + case GL_STENCIL_TEST: setStencilTest(enabled); break; + case GL_DEPTH_TEST: setDepthTest(enabled); break; + case GL_BLEND: setBlend(enabled); break; + case GL_DITHER: setDither(enabled); break; + case GL_PRIMITIVE_RESTART_FIXED_INDEX: setPrimitiveRestart(enabled); break; + case GL_RASTERIZER_DISCARD: setRasterizerDiscard(enabled); break; + default: UNREACHABLE(); + } +} + +bool State::getEnableFeature(GLenum feature) +{ + switch (feature) + { + case GL_CULL_FACE: return isCullFaceEnabled(); + case GL_POLYGON_OFFSET_FILL: return isPolygonOffsetFillEnabled(); + case GL_SAMPLE_ALPHA_TO_COVERAGE: return isSampleAlphaToCoverageEnabled(); + case GL_SAMPLE_COVERAGE: return isSampleCoverageEnabled(); + case GL_SCISSOR_TEST: return isScissorTestEnabled(); + case GL_STENCIL_TEST: return isStencilTestEnabled(); + case GL_DEPTH_TEST: return isDepthTestEnabled(); + case GL_BLEND: return isBlendEnabled(); + case GL_DITHER: return isDitherEnabled(); + case GL_PRIMITIVE_RESTART_FIXED_INDEX: return isPrimitiveRestartEnabled(); + case GL_RASTERIZER_DISCARD: return isRasterizerDiscardEnabled(); + default: UNREACHABLE(); return false; + } +} + +void State::setLineWidth(GLfloat width) +{ + mLineWidth = width; +} + +void State::setGenerateMipmapHint(GLenum hint) +{ + mGenerateMipmapHint = hint; +} + +void State::setFragmentShaderDerivativeHint(GLenum hint) +{ + mFragmentShaderDerivativeHint = 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 State::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) +{ + mViewport.x = x; + mViewport.y = y; + mViewport.width = width; + mViewport.height = height; +} + +const Rectangle &State::getViewport() const +{ + return mViewport; +} + +void State::setActiveSampler(unsigned int active) +{ + mActiveSampler = active; +} + +unsigned int State::getActiveSampler() const +{ + return mActiveSampler; +} + +void State::setSamplerTexture(GLenum type, Texture *texture) +{ + mSamplerTextures[type][mActiveSampler].set(texture); +} + +Texture *State::getSamplerTexture(unsigned int sampler, GLenum type) const +{ + const auto it = mSamplerTextures.find(type); + ASSERT(it != mSamplerTextures.end()); + return it->second[sampler].get(); +} + +GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const +{ + const auto it = mSamplerTextures.find(type); + ASSERT(it != mSamplerTextures.end()); + return it->second[sampler].id(); +} + +void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) +{ + // Textures have a detach method on State rather than a simple + // removeBinding, because the zero/null texture objects are managed + // separately, and don't have to go through the Context's maps or + // the ResourceManager. + + // [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 (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) + { + GLenum textureType = bindingVec->first; + TextureBindingVector &textureVector = bindingVec->second; + for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) + { + BindingPointer &binding = textureVector[textureIdx]; + if (binding.id() == texture) + { + auto it = zeroTextures.find(textureType); + ASSERT(it != zeroTextures.end()); + // Zero textures are the "default" textures instead of NULL + binding.set(it->second.get()); + } + } + } + + // [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 Texture2DAttachment had been called, with a texture of 0, for each attachment point to which this + // image was attached in the currently bound framebuffer. + + if (mReadFramebuffer) + { + mReadFramebuffer->detachTexture(texture); + } + + if (mDrawFramebuffer) + { + mDrawFramebuffer->detachTexture(texture); + } +} + +void State::initializeZeroTextures(const TextureMap &zeroTextures) +{ + for (auto it = zeroTextures.cbegin(); it != zeroTextures.cend(); ++it) + { + const auto &zeroTexture = *it; + auto &samplerTextureArray = mSamplerTextures[zeroTexture.first]; + + for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) + { + samplerTextureArray[textureUnit].set(zeroTexture.second.get()); + } + } +} + +void State::setSamplerBinding(GLuint textureUnit, Sampler *sampler) +{ + mSamplers[textureUnit].set(sampler); +} + +GLuint State::getSamplerId(GLuint textureUnit) const +{ + ASSERT(textureUnit < mSamplers.size()); + return mSamplers[textureUnit].id(); +} + +Sampler *State::getSampler(GLuint textureUnit) const +{ + return mSamplers[textureUnit].get(); +} + +void State::detachSampler(GLuint sampler) +{ + // [OpenGL ES 3.0.2] section 3.8.2 pages 123-124: + // If a sampler object that is currently bound to one or more texture units is + // deleted, it is as though BindSampler is called once for each texture unit to + // which the sampler is bound, with unit set to the texture unit and sampler set to zero. + for (size_t textureUnit = 0; textureUnit < mSamplers.size(); textureUnit++) + { + BindingPointer &samplerBinding = mSamplers[textureUnit]; + if (samplerBinding.id() == sampler) + { + samplerBinding.set(NULL); + } + } +} + +void State::setRenderbufferBinding(Renderbuffer *renderbuffer) +{ + mRenderbuffer.set(renderbuffer); +} + +GLuint State::getRenderbufferId() const +{ + return mRenderbuffer.id(); +} + +Renderbuffer *State::getCurrentRenderbuffer() +{ + return mRenderbuffer.get(); +} + +void State::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 (mRenderbuffer.id() == renderbuffer) + { + mRenderbuffer.set(NULL); + } + + // [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 = mReadFramebuffer; + Framebuffer *drawFramebuffer = mDrawFramebuffer; + + if (readFramebuffer) + { + readFramebuffer->detachRenderbuffer(renderbuffer); + } + + if (drawFramebuffer && drawFramebuffer != readFramebuffer) + { + drawFramebuffer->detachRenderbuffer(renderbuffer); + } + +} + +void State::setReadFramebufferBinding(Framebuffer *framebuffer) +{ + mReadFramebuffer = framebuffer; +} + +void State::setDrawFramebufferBinding(Framebuffer *framebuffer) +{ + mDrawFramebuffer = framebuffer; +} + +Framebuffer *State::getTargetFramebuffer(GLenum target) const +{ + switch (target) + { + case GL_READ_FRAMEBUFFER_ANGLE: return mReadFramebuffer; + case GL_DRAW_FRAMEBUFFER_ANGLE: + case GL_FRAMEBUFFER: return mDrawFramebuffer; + default: UNREACHABLE(); return NULL; + } +} + +Framebuffer *State::getReadFramebuffer() +{ + return mReadFramebuffer; +} + +Framebuffer *State::getDrawFramebuffer() +{ + return mDrawFramebuffer; +} + +const Framebuffer *State::getReadFramebuffer() const +{ + return mReadFramebuffer; +} + +const Framebuffer *State::getDrawFramebuffer() const +{ + return mDrawFramebuffer; +} + +bool State::removeReadFramebufferBinding(GLuint framebuffer) +{ + if (mReadFramebuffer->id() == framebuffer) + { + mReadFramebuffer = NULL; + return true; + } + + return false; +} + +bool State::removeDrawFramebufferBinding(GLuint framebuffer) +{ + if (mDrawFramebuffer->id() == framebuffer) + { + mDrawFramebuffer = NULL; + return true; + } + + return false; +} + +void State::setVertexArrayBinding(VertexArray *vertexArray) +{ + mVertexArray = vertexArray; +} + +GLuint State::getVertexArrayId() const +{ + ASSERT(mVertexArray != NULL); + return mVertexArray->id(); +} + +VertexArray *State::getVertexArray() const +{ + ASSERT(mVertexArray != NULL); + return mVertexArray; +} + +bool State::removeVertexArrayBinding(GLuint vertexArray) +{ + if (mVertexArray->id() == vertexArray) + { + mVertexArray = NULL; + return true; + } + + return false; +} + +void State::setProgram(Program *newProgram) +{ + if (mProgram != newProgram) + { + if (mProgram) + { + mProgram->release(); + } + + mProgram = newProgram; + + if (mProgram) + { + newProgram->addRef(); + } + } +} + +Program *State::getProgram() const +{ + return mProgram; +} + +void State::setTransformFeedbackBinding(TransformFeedback *transformFeedback) +{ + mTransformFeedback.set(transformFeedback); +} + +TransformFeedback *State::getCurrentTransformFeedback() const +{ + return mTransformFeedback.get(); +} + +bool State::isTransformFeedbackActiveUnpaused() const +{ + gl::TransformFeedback *curTransformFeedback = getCurrentTransformFeedback(); + return curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused(); +} + +void State::detachTransformFeedback(GLuint transformFeedback) +{ + if (mTransformFeedback.id() == transformFeedback) + { + mTransformFeedback.set(NULL); + } +} + +bool State::isQueryActive() const +{ + for (State::ActiveQueryMap::const_iterator i = mActiveQueries.begin(); + i != mActiveQueries.end(); i++) + { + if (i->second.get() != NULL) + { + return true; + } + } + + return false; +} + +void State::setActiveQuery(GLenum target, Query *query) +{ + mActiveQueries[target].set(query); +} + +GLuint State::getActiveQueryId(GLenum target) const +{ + const Query *query = getActiveQuery(target); + return (query ? query->id() : 0u); +} + +Query *State::getActiveQuery(GLenum target) const +{ + const auto it = mActiveQueries.find(target); + + // All query types should already exist in the activeQueries map + ASSERT(it != mActiveQueries.end()); + + return it->second.get(); +} + +void State::setArrayBufferBinding(Buffer *buffer) +{ + mArrayBuffer.set(buffer); +} + +GLuint State::getArrayBufferId() const +{ + return mArrayBuffer.id(); +} + +bool State::removeArrayBufferBinding(GLuint buffer) +{ + if (mArrayBuffer.id() == buffer) + { + mArrayBuffer.set(NULL); + return true; + } + + return false; +} + +void State::setGenericUniformBufferBinding(Buffer *buffer) +{ + mGenericUniformBuffer.set(buffer); +} + +void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) +{ + mUniformBuffers[index].set(buffer, offset, size); +} + +GLuint State::getIndexedUniformBufferId(GLuint index) const +{ + ASSERT(static_cast(index) < mUniformBuffers.size()); + + return mUniformBuffers[index].id(); +} + +Buffer *State::getIndexedUniformBuffer(GLuint index) const +{ + ASSERT(static_cast(index) < mUniformBuffers.size()); + + return mUniformBuffers[index].get(); +} + +GLintptr State::getIndexedUniformBufferOffset(GLuint index) const +{ + ASSERT(static_cast(index) < mUniformBuffers.size()); + + return mUniformBuffers[index].getOffset(); +} + +GLsizeiptr State::getIndexedUniformBufferSize(GLuint index) const +{ + ASSERT(static_cast(index) < mUniformBuffers.size()); + + return mUniformBuffers[index].getSize(); +} + +void State::setGenericTransformFeedbackBufferBinding(Buffer *buffer) +{ + mGenericTransformFeedbackBuffer.set(buffer); +} + +void State::setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) +{ + mTransformFeedbackBuffers[index].set(buffer, offset, size); +} + +GLuint State::getIndexedTransformFeedbackBufferId(GLuint index) const +{ + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); + + return mTransformFeedbackBuffers[index].id(); +} + +Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const +{ + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); + + return mTransformFeedbackBuffers[index].get(); +} + +GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const +{ + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); + + return mTransformFeedbackBuffers[index].getOffset(); +} + +size_t State::getTransformFeedbackBufferIndexRange() const +{ + return mTransformFeedbackBuffers.size(); +} + +void State::setCopyReadBufferBinding(Buffer *buffer) +{ + mCopyReadBuffer.set(buffer); +} + +void State::setCopyWriteBufferBinding(Buffer *buffer) +{ + mCopyWriteBuffer.set(buffer); +} + +void State::setPixelPackBufferBinding(Buffer *buffer) +{ + mPack.pixelBuffer.set(buffer); +} + +void State::setPixelUnpackBufferBinding(Buffer *buffer) +{ + mUnpack.pixelBuffer.set(buffer); +} + +Buffer *State::getTargetBuffer(GLenum target) const +{ + switch (target) + { + case GL_ARRAY_BUFFER: return mArrayBuffer.get(); + case GL_COPY_READ_BUFFER: return mCopyReadBuffer.get(); + case GL_COPY_WRITE_BUFFER: return mCopyWriteBuffer.get(); + case GL_ELEMENT_ARRAY_BUFFER: return getVertexArray()->getElementArrayBuffer(); + case GL_PIXEL_PACK_BUFFER: return mPack.pixelBuffer.get(); + case GL_PIXEL_UNPACK_BUFFER: return mUnpack.pixelBuffer.get(); + case GL_TRANSFORM_FEEDBACK_BUFFER: return mGenericTransformFeedbackBuffer.get(); + case GL_UNIFORM_BUFFER: return mGenericUniformBuffer.get(); + default: UNREACHABLE(); return NULL; + } +} + +void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) +{ + getVertexArray()->enableAttribute(attribNum, enabled); +} + +void State::setVertexAttribf(GLuint index, const GLfloat values[4]) +{ + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); + mVertexAttribCurrentValues[index].setFloatValues(values); +} + +void State::setVertexAttribu(GLuint index, const GLuint values[4]) +{ + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); + mVertexAttribCurrentValues[index].setUnsignedIntValues(values); +} + +void State::setVertexAttribi(GLuint index, const GLint values[4]) +{ + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); + mVertexAttribCurrentValues[index].setIntValues(values); +} + +void State::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, + bool pureInteger, GLsizei stride, const void *pointer) +{ + getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer); +} + +const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const +{ + ASSERT(static_cast(attribNum) < mVertexAttribCurrentValues.size()); + return mVertexAttribCurrentValues[attribNum]; +} + +const void *State::getVertexAttribPointer(unsigned int attribNum) const +{ + return getVertexArray()->getVertexAttribute(attribNum).pointer; +} + +void State::setPackAlignment(GLint alignment) +{ + mPack.alignment = alignment; +} + +GLint State::getPackAlignment() const +{ + return mPack.alignment; +} + +void State::setPackReverseRowOrder(bool reverseRowOrder) +{ + mPack.reverseRowOrder = reverseRowOrder; +} + +bool State::getPackReverseRowOrder() const +{ + return mPack.reverseRowOrder; +} + +const PixelPackState &State::getPackState() const +{ + return mPack; +} + +PixelPackState &State::getPackState() +{ + return mPack; +} + +void State::setUnpackAlignment(GLint alignment) +{ + mUnpack.alignment = alignment; +} + +GLint State::getUnpackAlignment() const +{ + return mUnpack.alignment; +} + +void State::setUnpackRowLength(GLint rowLength) +{ + mUnpack.rowLength = rowLength; +} + +GLint State::getUnpackRowLength() const +{ + return mUnpack.rowLength; +} + +const PixelUnpackState &State::getUnpackState() const +{ + return mUnpack; +} + +PixelUnpackState &State::getUnpackState() +{ + return mUnpack; +} + +void State::getBooleanv(GLenum pname, GLboolean *params) +{ + switch (pname) + { + case GL_SAMPLE_COVERAGE_INVERT: *params = mSampleCoverageInvert; break; + case GL_DEPTH_WRITEMASK: *params = mDepthStencil.depthMask; break; + case GL_COLOR_WRITEMASK: + params[0] = mBlend.colorMaskRed; + params[1] = mBlend.colorMaskGreen; + params[2] = mBlend.colorMaskBlue; + params[3] = mBlend.colorMaskAlpha; + break; + case GL_CULL_FACE: *params = mRasterizer.cullFace; break; + case GL_POLYGON_OFFSET_FILL: *params = mRasterizer.polygonOffsetFill; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mBlend.sampleAlphaToCoverage; break; + case GL_SAMPLE_COVERAGE: *params = mSampleCoverage; break; + case GL_SCISSOR_TEST: *params = mScissorTest; break; + case GL_STENCIL_TEST: *params = mDepthStencil.stencilTest; break; + case GL_DEPTH_TEST: *params = mDepthStencil.depthTest; break; + case GL_BLEND: *params = mBlend.blend; break; + case GL_DITHER: *params = mBlend.dither; break; + case GL_TRANSFORM_FEEDBACK_ACTIVE: *params = getCurrentTransformFeedback()->isStarted(); break; + case GL_TRANSFORM_FEEDBACK_PAUSED: *params = getCurrentTransformFeedback()->isPaused(); break; + default: + UNREACHABLE(); + break; + } +} + +void State::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 = mLineWidth; break; + case GL_SAMPLE_COVERAGE_VALUE: *params = mSampleCoverageValue; break; + case GL_DEPTH_CLEAR_VALUE: *params = mDepthClearValue; break; + case GL_POLYGON_OFFSET_FACTOR: *params = mRasterizer.polygonOffsetFactor; break; + case GL_POLYGON_OFFSET_UNITS: *params = mRasterizer.polygonOffsetUnits; break; + case GL_DEPTH_RANGE: + params[0] = mNearZ; + params[1] = mFarZ; + break; + case GL_COLOR_CLEAR_VALUE: + params[0] = mColorClearValue.red; + params[1] = mColorClearValue.green; + params[2] = mColorClearValue.blue; + params[3] = mColorClearValue.alpha; + break; + case GL_BLEND_COLOR: + params[0] = mBlendColor.red; + params[1] = mBlendColor.green; + params[2] = mBlendColor.blue; + params[3] = mBlendColor.alpha; + break; + default: + UNREACHABLE(); + break; + } +} + +void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) +{ + if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) + { + unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT); + ASSERT(colorAttachment < mMaxDrawBuffers); + Framebuffer *framebuffer = mDrawFramebuffer; + *params = framebuffer->getDrawBufferState(colorAttachment); + return; + } + + // 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 + // State::getFloatv. + switch (pname) + { + case GL_ARRAY_BUFFER_BINDING: *params = mArrayBuffer.id(); break; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getVertexArray()->getElementArrayBufferId(); break; + //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE + case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mDrawFramebuffer->id(); break; + case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mReadFramebuffer->id(); break; + case GL_RENDERBUFFER_BINDING: *params = mRenderbuffer.id(); break; + case GL_VERTEX_ARRAY_BINDING: *params = mVertexArray->id(); break; + case GL_CURRENT_PROGRAM: *params = mProgram ? mProgram->id() : 0; break; + case GL_PACK_ALIGNMENT: *params = mPack.alignment; break; + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mPack.reverseRowOrder; break; + case GL_UNPACK_ALIGNMENT: *params = mUnpack.alignment; break; + case GL_UNPACK_ROW_LENGTH: *params = mUnpack.rowLength; break; + case GL_GENERATE_MIPMAP_HINT: *params = mGenerateMipmapHint; break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mFragmentShaderDerivativeHint; break; + case GL_ACTIVE_TEXTURE: *params = (mActiveSampler + GL_TEXTURE0); break; + case GL_STENCIL_FUNC: *params = mDepthStencil.stencilFunc; break; + case GL_STENCIL_REF: *params = mStencilRef; break; + case GL_STENCIL_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilMask); break; + case GL_STENCIL_BACK_FUNC: *params = mDepthStencil.stencilBackFunc; break; + case GL_STENCIL_BACK_REF: *params = mStencilBackRef; break; + case GL_STENCIL_BACK_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilBackMask); break; + case GL_STENCIL_FAIL: *params = mDepthStencil.stencilFail; break; + case GL_STENCIL_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilPassDepthFail; break; + case GL_STENCIL_PASS_DEPTH_PASS: *params = mDepthStencil.stencilPassDepthPass; break; + case GL_STENCIL_BACK_FAIL: *params = mDepthStencil.stencilBackFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilBackPassDepthFail; break; + case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mDepthStencil.stencilBackPassDepthPass; break; + case GL_DEPTH_FUNC: *params = mDepthStencil.depthFunc; break; + case GL_BLEND_SRC_RGB: *params = mBlend.sourceBlendRGB; break; + case GL_BLEND_SRC_ALPHA: *params = mBlend.sourceBlendAlpha; break; + case GL_BLEND_DST_RGB: *params = mBlend.destBlendRGB; break; + case GL_BLEND_DST_ALPHA: *params = mBlend.destBlendAlpha; break; + case GL_BLEND_EQUATION_RGB: *params = mBlend.blendEquationRGB; break; + case GL_BLEND_EQUATION_ALPHA: *params = mBlend.blendEquationAlpha; break; + case GL_STENCIL_WRITEMASK: *params = clampToInt(mDepthStencil.stencilWritemask); break; + case GL_STENCIL_BACK_WRITEMASK: *params = clampToInt(mDepthStencil.stencilBackWritemask); break; + case GL_STENCIL_CLEAR_VALUE: *params = mStencilClearValue; break; + case GL_IMPLEMENTATION_COLOR_READ_TYPE: *params = mReadFramebuffer->getImplementationColorReadType(); break; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = mReadFramebuffer->getImplementationColorReadFormat(); break; + case GL_SAMPLE_BUFFERS: + case GL_SAMPLES: + { + gl::Framebuffer *framebuffer = mDrawFramebuffer; + if (framebuffer->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE) + { + switch (pname) + { + case GL_SAMPLE_BUFFERS: + if (framebuffer->getSamples(data) != 0) + { + *params = 1; + } + else + { + *params = 0; + } + break; + case GL_SAMPLES: + *params = framebuffer->getSamples(data); + break; + } + } + else + { + *params = 0; + } + } + break; + case GL_VIEWPORT: + params[0] = mViewport.x; + params[1] = mViewport.y; + params[2] = mViewport.width; + params[3] = mViewport.height; + break; + case GL_SCISSOR_BOX: + params[0] = mScissor.x; + params[1] = mScissor.y; + params[2] = mScissor.width; + params[3] = mScissor.height; + break; + case GL_CULL_FACE_MODE: *params = mRasterizer.cullMode; break; + case GL_FRONT_FACE: *params = mRasterizer.frontFace; break; + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer(); + + 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::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer(); + + if (depthbuffer) + { + *params = depthbuffer->getDepthSize(); + } + else + { + *params = 0; + } + } + break; + case GL_STENCIL_BITS: + { + gl::Framebuffer *framebuffer = getDrawFramebuffer(); + gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer(); + + if (stencilbuffer) + { + *params = stencilbuffer->getStencilSize(); + } + else + { + *params = 0; + } + } + break; + case GL_TEXTURE_BINDING_2D: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_2D) ; + break; + case GL_TEXTURE_BINDING_CUBE_MAP: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_CUBE_MAP); + break; + case GL_TEXTURE_BINDING_3D: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_3D); + break; + case GL_TEXTURE_BINDING_2D_ARRAY: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(mActiveSampler, GL_TEXTURE_2D_ARRAY); + break; + case GL_UNIFORM_BUFFER_BINDING: + *params = mGenericUniformBuffer.id(); + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + *params = mGenericTransformFeedbackBuffer.id(); + break; + case GL_COPY_READ_BUFFER_BINDING: + *params = mCopyReadBuffer.id(); + break; + case GL_COPY_WRITE_BUFFER_BINDING: + *params = mCopyWriteBuffer.id(); + break; + case GL_PIXEL_PACK_BUFFER_BINDING: + *params = mPack.pixelBuffer.id(); + break; + case GL_PIXEL_UNPACK_BUFFER_BINDING: + *params = mUnpack.pixelBuffer.id(); + break; + default: + UNREACHABLE(); + break; + } +} + +bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) +{ + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (static_cast(index) < mTransformFeedbackBuffers.size()) + { + *data = mTransformFeedbackBuffers[index].id(); + } + break; + case GL_UNIFORM_BUFFER_BINDING: + if (static_cast(index) < mUniformBuffers.size()) + { + *data = mUniformBuffers[index].id(); + } + break; + default: + return false; + } + + return true; +} + +bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) +{ + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + if (static_cast(index) < mTransformFeedbackBuffers.size()) + { + *data = mTransformFeedbackBuffers[index].getOffset(); + } + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + if (static_cast(index) < mTransformFeedbackBuffers.size()) + { + *data = mTransformFeedbackBuffers[index].getSize(); + } + break; + case GL_UNIFORM_BUFFER_START: + if (static_cast(index) < mUniformBuffers.size()) + { + *data = mUniformBuffers[index].getOffset(); + } + break; + case GL_UNIFORM_BUFFER_SIZE: + if (static_cast(index) < mUniformBuffers.size()) + { + *data = mUniformBuffers[index].getSize(); + } + break; + default: + return false; + } + + return true; +} + +bool State::hasMappedBuffer(GLenum target) const +{ + if (target == GL_ARRAY_BUFFER) + { + const VertexArray *vao = getVertexArray(); + for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); attribIndex++) + { + const gl::VertexAttribute &vertexAttrib = vao->getVertexAttribute(attribIndex); + gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); + if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) + { + return true; + } + } + + return false; + } + else + { + Buffer *buffer = getTargetBuffer(target); + return (buffer && buffer->isMapped()); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/State.h b/src/3rdparty/angle/src/libANGLE/State.h new file mode 100644 index 0000000000..4370a2f16f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/State.h @@ -0,0 +1,335 @@ +// +// Copyright (c) 2014 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. +// + +// State.h: Defines the State class, encapsulating raw GL state + +#ifndef LIBANGLE_STATE_H_ +#define LIBANGLE_STATE_H_ + +#include "common/angleutils.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Texture.h" +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/Program.h" +#include "libANGLE/Sampler.h" + +namespace gl +{ +class Query; +class VertexArray; +class Context; +struct Caps; +struct Data; + +typedef std::map< GLenum, BindingPointer > TextureMap; + +class State : angle::NonCopyable +{ + public: + State(); + ~State(); + + void initialize(const Caps& caps, GLuint clientVersion); + void reset(); + + // State chunk getters + const RasterizerState &getRasterizerState() const; + const BlendState &getBlendState() const; + const DepthStencilState &getDepthStencilState() const; + + // Clear behavior setters & state parameter block generation function + void setColorClearValue(float red, float green, float blue, float alpha); + void setDepthClearValue(float depth); + void setStencilClearValue(int stencil); + + const ColorF &getColorClearValue() const { return mColorClearValue; } + float getDepthClearValue() const { return mDepthClearValue; } + int getStencilClearValue() const { return mStencilClearValue; } + + // Write mask manipulation + void setColorMask(bool red, bool green, bool blue, bool alpha); + void setDepthMask(bool mask); + + // Discard toggle & query + bool isRasterizerDiscardEnabled() const; + void setRasterizerDiscard(bool enabled); + + // Primitive restart + bool isPrimitiveRestartEnabled() const; + void setPrimitiveRestart(bool enabled); + + // Face culling state manipulation + bool isCullFaceEnabled() const; + void setCullFace(bool enabled); + void setCullMode(GLenum mode); + void setFrontFace(GLenum front); + + // Depth test state manipulation + bool isDepthTestEnabled() const; + void setDepthTest(bool enabled); + void setDepthFunc(GLenum depthFunc); + void setDepthRange(float zNear, float zFar); + void getDepthRange(float *zNear, float *zFar) const; + + // Blend state manipulation + bool isBlendEnabled() const; + void setBlend(bool enabled); + 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); + const ColorF &getBlendColor() const; + + // Stencil state maniupulation + bool isStencilTestEnabled() const; + void setStencilTest(bool enabled); + 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); + GLint getStencilRef() const; + GLint getStencilBackRef() const; + + // Depth bias/polygon offset state manipulation + bool isPolygonOffsetFillEnabled() const; + void setPolygonOffsetFill(bool enabled); + void setPolygonOffsetParams(GLfloat factor, GLfloat units); + + // Multisample coverage state manipulation + bool isSampleAlphaToCoverageEnabled() const; + void setSampleAlphaToCoverage(bool enabled); + bool isSampleCoverageEnabled() const; + void setSampleCoverage(bool enabled); + void setSampleCoverageParams(GLclampf value, bool invert); + void getSampleCoverageParams(GLclampf *value, bool *invert) const; + + // Scissor test state toggle & query + bool isScissorTestEnabled() const; + void setScissorTest(bool enabled); + void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height); + const Rectangle &getScissor() const; + + // Dither state toggle & query + bool isDitherEnabled() const; + void setDither(bool enabled); + + // Generic state toggle & query + void setEnableFeature(GLenum feature, bool enabled); + bool getEnableFeature(GLenum feature); + + // Line width state setter + void setLineWidth(GLfloat width); + + // Hint setters + void setGenerateMipmapHint(GLenum hint); + void setFragmentShaderDerivativeHint(GLenum hint); + + // Viewport state setter/getter + void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); + const Rectangle &getViewport() const; + + // Texture binding & active texture unit manipulation + void setActiveSampler(unsigned int active); + unsigned int getActiveSampler() const; + void setSamplerTexture(GLenum type, Texture *texture); + Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; + GLuint getSamplerTextureId(unsigned int sampler, GLenum type) const; + void detachTexture(const TextureMap &zeroTextures, GLuint texture); + void initializeZeroTextures(const TextureMap &zeroTextures); + + // Sampler object binding manipulation + void setSamplerBinding(GLuint textureUnit, Sampler *sampler); + GLuint getSamplerId(GLuint textureUnit) const; + Sampler *getSampler(GLuint textureUnit) const; + void detachSampler(GLuint sampler); + + // Renderbuffer binding manipulation + void setRenderbufferBinding(Renderbuffer *renderbuffer); + GLuint getRenderbufferId() const; + Renderbuffer *getCurrentRenderbuffer(); + void detachRenderbuffer(GLuint renderbuffer); + + // Framebuffer binding manipulation + void setReadFramebufferBinding(Framebuffer *framebuffer); + void setDrawFramebufferBinding(Framebuffer *framebuffer); + Framebuffer *getTargetFramebuffer(GLenum target) const; + Framebuffer *getReadFramebuffer(); + Framebuffer *getDrawFramebuffer(); + const Framebuffer *getReadFramebuffer() const; + const Framebuffer *getDrawFramebuffer() const; + bool removeReadFramebufferBinding(GLuint framebuffer); + bool removeDrawFramebufferBinding(GLuint framebuffer); + + // Vertex array object binding manipulation + void setVertexArrayBinding(VertexArray *vertexArray); + GLuint getVertexArrayId() const; + VertexArray *getVertexArray() const; + bool removeVertexArrayBinding(GLuint vertexArray); + + // Program binding manipulation + void setProgram(Program *newProgram); + Program *getProgram() const; + + // Transform feedback object (not buffer) binding manipulation + void setTransformFeedbackBinding(TransformFeedback *transformFeedback); + TransformFeedback *getCurrentTransformFeedback() const; + bool isTransformFeedbackActiveUnpaused() const; + void detachTransformFeedback(GLuint transformFeedback); + + // Query binding manipulation + bool isQueryActive() const; + void setActiveQuery(GLenum target, Query *query); + GLuint getActiveQueryId(GLenum target) const; + Query *getActiveQuery(GLenum target) const; + + //// Typed buffer binding point manipulation //// + // GL_ARRAY_BUFFER + void setArrayBufferBinding(Buffer *buffer); + GLuint getArrayBufferId() const; + bool removeArrayBufferBinding(GLuint buffer); + + // GL_UNIFORM_BUFFER - Both indexed and generic targets + void setGenericUniformBufferBinding(Buffer *buffer); + void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); + GLuint getIndexedUniformBufferId(GLuint index) const; + Buffer *getIndexedUniformBuffer(GLuint index) const; + GLintptr getIndexedUniformBufferOffset(GLuint index) const; + GLsizeiptr getIndexedUniformBufferSize(GLuint index) const; + + // GL_TRANSFORM_FEEDBACK_BUFFER - Both indexed and generic targets + void setGenericTransformFeedbackBufferBinding(Buffer *buffer); + void setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); + GLuint getIndexedTransformFeedbackBufferId(GLuint index) const; + Buffer *getIndexedTransformFeedbackBuffer(GLuint index) const; + GLuint getIndexedTransformFeedbackBufferOffset(GLuint index) const; + size_t getTransformFeedbackBufferIndexRange() const; + + // GL_COPY_[READ/WRITE]_BUFFER + void setCopyReadBufferBinding(Buffer *buffer); + void setCopyWriteBufferBinding(Buffer *buffer); + + // GL_PIXEL[PACK/UNPACK]_BUFFER + void setPixelPackBufferBinding(Buffer *buffer); + void setPixelUnpackBufferBinding(Buffer *buffer); + + // Retrieve typed buffer by target (non-indexed) + Buffer *getTargetBuffer(GLenum target) const; + + // Vertex attrib manipulation + void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); + void setVertexAttribf(GLuint index, const GLfloat values[4]); + void setVertexAttribu(GLuint index, const GLuint values[4]); + void setVertexAttribi(GLuint index, const GLint values[4]); + void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer); + const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const; + const void *getVertexAttribPointer(unsigned int attribNum) const; + + // Pixel pack state manipulation + void setPackAlignment(GLint alignment); + GLint getPackAlignment() const; + void setPackReverseRowOrder(bool reverseRowOrder); + bool getPackReverseRowOrder() const; + const PixelPackState &getPackState() const; + PixelPackState &getPackState(); + + // Pixel unpack state manipulation + void setUnpackAlignment(GLint alignment); + GLint getUnpackAlignment() const; + void setUnpackRowLength(GLint rowLength); + GLint getUnpackRowLength() const; + const PixelUnpackState &getUnpackState() const; + PixelUnpackState &getUnpackState(); + + // State query functions + void getBooleanv(GLenum pname, GLboolean *params); + void getFloatv(GLenum pname, GLfloat *params); + void getIntegerv(const gl::Data &data, GLenum pname, GLint *params); + bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); + bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); + + bool hasMappedBuffer(GLenum target) const; + + private: + // Cached values from Context's caps + GLuint mMaxDrawBuffers; + GLuint mMaxCombinedTextureImageUnits; + + ColorF mColorClearValue; + GLclampf mDepthClearValue; + int mStencilClearValue; + + RasterizerState mRasterizer; + bool mScissorTest; + Rectangle mScissor; + + BlendState mBlend; + ColorF mBlendColor; + bool mSampleCoverage; + GLclampf mSampleCoverageValue; + bool mSampleCoverageInvert; + + DepthStencilState mDepthStencil; + GLint mStencilRef; + GLint mStencilBackRef; + + GLfloat mLineWidth; + + GLenum mGenerateMipmapHint; + GLenum mFragmentShaderDerivativeHint; + + Rectangle mViewport; + float mNearZ; + float mFarZ; + + BindingPointer mArrayBuffer; + Framebuffer *mReadFramebuffer; + Framebuffer *mDrawFramebuffer; + BindingPointer mRenderbuffer; + Program *mProgram; + + typedef std::vector VertexAttribVector; + VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib + VertexArray *mVertexArray; + + // Texture and sampler bindings + size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 + + typedef std::vector< BindingPointer > TextureBindingVector; + typedef std::map TextureBindingMap; + TextureBindingMap mSamplerTextures; + + typedef std::vector< BindingPointer > SamplerBindingVector; + SamplerBindingVector mSamplers; + + typedef std::map< GLenum, BindingPointer > ActiveQueryMap; + ActiveQueryMap mActiveQueries; + + BindingPointer mGenericUniformBuffer; + typedef std::vector< OffsetBindingPointer > BufferVector; + BufferVector mUniformBuffers; + + BindingPointer mTransformFeedback; + BindingPointer mGenericTransformFeedbackBuffer; + BufferVector mTransformFeedbackBuffers; + + BindingPointer mCopyReadBuffer; + BindingPointer mCopyWriteBuffer; + + PixelUnpackState mUnpack; + PixelPackState mPack; + + bool mPrimitiveRestart; +}; + +} + +#endif // LIBANGLE_STATE_H_ + diff --git a/src/3rdparty/angle/src/libANGLE/Surface.cpp b/src/3rdparty/angle/src/libANGLE/Surface.cpp new file mode 100644 index 0000000000..ac455f3905 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Surface.cpp @@ -0,0 +1,166 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/Surface.h" + +#include "libANGLE/Config.h" +#include "libANGLE/Texture.h" +#include "libANGLE/renderer/SurfaceImpl.h" + +#include + +namespace egl +{ + +Surface::Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes) + : RefCountObject(0), // id unused + mImplementation(impl), + mType(surfaceType), + mConfig(config), + mPostSubBufferRequested(false), + mFixedSize(false), + mFixedWidth(0), + mFixedHeight(0), + mTextureFormat(EGL_NO_TEXTURE), + mTextureTarget(EGL_NO_TEXTURE), + // FIXME: Determine actual pixel aspect ratio + mPixelAspectRatio(static_cast(1.0 * EGL_DISPLAY_SCALING)), + mRenderBuffer(EGL_BACK_BUFFER), + mSwapBehavior(EGL_BUFFER_PRESERVED), + mTexture(NULL) +{ + addRef(); + + mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE); + + mFixedSize = (attributes.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE) == EGL_TRUE); + if (mFixedSize) + { + mFixedWidth = attributes.get(EGL_WIDTH, 0); + mFixedHeight = attributes.get(EGL_HEIGHT, 0); + } + + if (mType != EGL_WINDOW_BIT) + { + mTextureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + mTextureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + } +} + +Surface::~Surface() +{ + if (mTexture) + { + if (mImplementation) + { + mImplementation->releaseTexImage(mTexture->id()); + } + mTexture->releaseTexImage(); + mTexture = NULL; + } + + SafeDelete(mImplementation); +} + +EGLint Surface::getType() const +{ + return mType; +} + +Error Surface::swap() +{ + return mImplementation->swap(); +} + +Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + return mImplementation->postSubBuffer(x, y, width, height); +} + +Error Surface::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + return mImplementation->querySurfacePointerANGLE(attribute, value); +} + +EGLint Surface::isPostSubBufferSupported() const +{ + return mPostSubBufferRequested && mImplementation->isPostSubBufferSupported(); +} + +void Surface::setSwapInterval(EGLint interval) +{ + mImplementation->setSwapInterval(interval); +} + +const Config *Surface::getConfig() const +{ + return mConfig; +} + +EGLint Surface::getPixelAspectRatio() const +{ + return mPixelAspectRatio; +} + +EGLenum Surface::getRenderBuffer() const +{ + return mRenderBuffer; +} + +EGLenum Surface::getSwapBehavior() const +{ + return mSwapBehavior; +} + +EGLenum Surface::getTextureFormat() const +{ + return mTextureFormat; +} + +EGLenum Surface::getTextureTarget() const +{ + return mTextureTarget; +} + +EGLint Surface::isFixedSize() const +{ + return mFixedSize; +} + +EGLint Surface::getWidth() const +{ + return mFixedSize ? mFixedWidth : mImplementation->getWidth(); +} + +EGLint Surface::getHeight() const +{ + return mFixedSize ? mFixedHeight : mImplementation->getHeight(); +} + +Error Surface::bindTexImage(gl::Texture *texture, EGLint buffer) +{ + ASSERT(!mTexture); + + texture->bindTexImage(this); + mTexture = texture; + return mImplementation->bindTexImage(buffer); +} + +Error Surface::releaseTexImage(EGLint buffer) +{ + ASSERT(mTexture); + gl::Texture *boundTexture = mTexture; + mTexture = NULL; + + boundTexture->releaseTexImage(); + return mImplementation->releaseTexImage(buffer); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Surface.h b/src/3rdparty/angle/src/libANGLE/Surface.h new file mode 100644 index 0000000000..430bf0195d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Surface.h @@ -0,0 +1,98 @@ +// +// Copyright (c) 2002-2014 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 LIBANGLE_SURFACE_H_ +#define LIBANGLE_SURFACE_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/RefCountObject.h" + +namespace gl +{ +class Texture; +} + +namespace rx +{ +class SurfaceImpl; +} + +namespace egl +{ +class AttributeMap; +class Display; +struct Config; + +class Surface final : public RefCountObject +{ + public: + Surface(rx::SurfaceImpl *impl, EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes); + + rx::SurfaceImpl *getImplementation() { return mImplementation; } + const rx::SurfaceImpl *getImplementation() const { return mImplementation; } + + EGLint getType() const; + + Error swap(); + Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); + Error querySurfacePointerANGLE(EGLint attribute, void **value); + Error bindTexImage(gl::Texture *texture, EGLint buffer); + Error releaseTexImage(EGLint buffer); + + EGLint isPostSubBufferSupported() const; + + void setSwapInterval(EGLint interval); + + const Config *getConfig() const; + + // width and height can change with client window resizing + EGLint getWidth() const; + EGLint getHeight() const; + EGLint getPixelAspectRatio() const; + EGLenum getRenderBuffer() const; + EGLenum getSwapBehavior() const; + EGLenum getTextureFormat() const; + EGLenum getTextureTarget() const; + + gl::Texture *getBoundTexture() const { return mTexture; } + + EGLint isFixedSize() const; + + private: + virtual ~Surface(); + + rx::SurfaceImpl *mImplementation; + + EGLint mType; + + const egl::Config *mConfig; + + bool mPostSubBufferRequested; + + bool mFixedSize; + size_t mFixedWidth; + size_t mFixedHeight; + + EGLenum mTextureFormat; + EGLenum mTextureTarget; + + EGLint mPixelAspectRatio; // Display aspect ratio + EGLenum mRenderBuffer; // Render buffer + EGLenum mSwapBehavior; // Buffer swap behavior + + gl::Texture *mTexture; +}; + +} + +#endif // LIBANGLE_SURFACE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp new file mode 100644 index 0000000000..cd4584f694 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp @@ -0,0 +1,573 @@ +// +// Copyright (c) 2002-2014 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. [OpenGL ES 2.0.24] section 3.7 page 63. + +#include "libANGLE/Texture.h" +#include "libANGLE/Data.h" +#include "libANGLE/formatutils.h" + +#include "libANGLE/Config.h" +#include "libANGLE/Surface.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +bool IsMipmapFiltered(const gl::SamplerState &samplerState) +{ + switch (samplerState.minFilter) + { + case GL_NEAREST: + case GL_LINEAR: + return false; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + return true; + default: UNREACHABLE(); + return false; + } +} + +bool IsPointSampled(const gl::SamplerState &samplerState) +{ + return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); +} + +static size_t GetImageDescIndex(GLenum target, size_t level) +{ + return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target)) : level; +} + +unsigned int Texture::mCurrentTextureSerial = 1; + +Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target) + : RefCountObject(id), + mTexture(impl), + mTextureSerial(issueTextureSerial()), + mUsage(GL_NONE), + mImmutableLevelCount(0), + mTarget(target), + mImageDescs(IMPLEMENTATION_MAX_TEXTURE_LEVELS * (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)), + mCompletenessCache(), + mBoundSurface(NULL) +{ +} + +Texture::~Texture() +{ + if (mBoundSurface) + { + mBoundSurface->releaseTexImage(EGL_BACK_BUFFER); + mBoundSurface = NULL; + } + SafeDelete(mTexture); +} + +GLenum Texture::getTarget() const +{ + return mTarget; +} + +void Texture::setUsage(GLenum usage) +{ + mUsage = usage; + getImplementation()->setUsage(usage); +} + +GLenum Texture::getUsage() const +{ + return mUsage; +} + +size_t Texture::getWidth(GLenum target, size_t level) const +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return getImageDesc(target, level).size.width; +} + +size_t Texture::getHeight(GLenum target, size_t level) const +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return getImageDesc(target, level).size.height; +} + +size_t Texture::getDepth(GLenum target, size_t level) const +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return getImageDesc(target, level).size.depth; +} + +GLenum Texture::getInternalFormat(GLenum target, size_t level) const +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + return getImageDesc(target, level).internalFormat; +} + +bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &data) const +{ + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel); + const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat); + if (!mCompletenessCache.cacheValid || + mCompletenessCache.samplerState != samplerState || + mCompletenessCache.filterable != textureCaps.filterable || + mCompletenessCache.clientVersion != data.clientVersion || + mCompletenessCache.supportsNPOT != data.extensions->textureNPOT) + { + mCompletenessCache.cacheValid = true; + mCompletenessCache.samplerState = samplerState; + mCompletenessCache.filterable = textureCaps.filterable; + mCompletenessCache.clientVersion = data.clientVersion; + mCompletenessCache.supportsNPOT = data.extensions->textureNPOT; + mCompletenessCache.samplerComplete = computeSamplerCompleteness(samplerState, data); + } + return mCompletenessCache.samplerComplete; +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool Texture::isCubeComplete() const +{ + ASSERT(mTarget == GL_TEXTURE_CUBE_MAP); + + const ImageDesc &baseImageDesc = getImageDesc(FirstCubeMapTextureTarget, 0); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height) + { + return false; + } + + for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++) + { + const ImageDesc &faceImageDesc = getImageDesc(face, 0); + if (faceImageDesc.size.width != baseImageDesc.size.width || + faceImageDesc.size.height != baseImageDesc.size.height || + faceImageDesc.internalFormat != baseImageDesc.internalFormat) + { + return false; + } + } + + return true; +} + +unsigned int Texture::getTextureSerial() const +{ + return mTextureSerial; +} + +unsigned int Texture::issueTextureSerial() +{ + return mCurrentTextureSerial++; +} + +bool Texture::isImmutable() const +{ + return (mImmutableLevelCount > 0); +} + +int Texture::immutableLevelCount() +{ + return mImmutableLevelCount; +} + +Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type, + const PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type))); + + return Error(GL_NO_ERROR); +} + +Error Texture::setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type, + const PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + return mTexture->setSubImage(target, level, area, format, type, unpack, pixels); +} + +Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, + const PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); + + return Error(GL_NO_ERROR); +} + +Error Texture::setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format, + const PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + return mTexture->setCompressedSubImage(target, level, area, format, unpack, pixels); +} + +Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat, + const Framebuffer *source) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1), + GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE))); + + return Error(GL_NO_ERROR); +} + +Error Texture::copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea, + const Framebuffer *source) +{ + ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target))); + + return mTexture->copySubImage(target, level, destOffset, sourceArea, source); +} + +Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size) +{ + ASSERT(target == mTarget); + + Error error = mTexture->setStorage(target, levels, internalFormat, size); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + mImmutableLevelCount = levels; + clearImageDescs(); + setImageDescChain(levels, size, internalFormat); + + return Error(GL_NO_ERROR); +} + + +Error Texture::generateMipmaps() +{ + Error error = mTexture->generateMipmaps(); + if (error.isError()) + { + return error; + } + + releaseTexImage(); + + const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0); + size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1; + setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat); + + return Error(GL_NO_ERROR); +} + +void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat) +{ + for (size_t level = 0; level < levels; level++) + { + Extents levelSize(std::max(baseSize.width >> level, 1), + std::max(baseSize.height >> level, 1), + (mTarget == GL_TEXTURE_2D_ARRAY) ? baseSize.depth : std::max(baseSize.depth >> level, 1)); + ImageDesc levelInfo(levelSize, sizedInternalFormat); + + if (mTarget == GL_TEXTURE_CUBE_MAP) + { + for (size_t face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) + { + setImageDesc(face, level, levelInfo); + } + } + else + { + setImageDesc(mTarget, level, levelInfo); + } + } +} + +Texture::ImageDesc::ImageDesc() + : size(0, 0, 0), internalFormat(GL_NONE) +{ +} + +Texture::ImageDesc::ImageDesc(const Extents &size, GLenum internalFormat) + : size(size), + internalFormat(internalFormat) +{ +} + +const Texture::ImageDesc &Texture::getImageDesc(GLenum target, size_t level) const +{ + size_t descIndex = GetImageDescIndex(target, level); + ASSERT(descIndex < mImageDescs.size()); + return mImageDescs[descIndex]; +} + +void Texture::setImageDesc(GLenum target, size_t level, const ImageDesc &desc) +{ + size_t descIndex = GetImageDescIndex(target, level); + ASSERT(descIndex < mImageDescs.size()); + mImageDescs[descIndex] = desc; + mCompletenessCache.cacheValid = false; +} + +void Texture::clearImageDesc(GLenum target, size_t level) +{ + setImageDesc(target, level, ImageDesc()); +} + +void Texture::clearImageDescs() +{ + for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++) + { + mImageDescs[descIndex] = ImageDesc(); + } + mCompletenessCache.cacheValid = false; +} + +void Texture::bindTexImage(egl::Surface *surface) +{ + ASSERT(surface); + + releaseTexImage(); + mTexture->bindTexImage(surface); + mBoundSurface = surface; + + // Set the image info to the size and format of the surface + ASSERT(mTarget == GL_TEXTURE_2D); + Extents size(surface->getWidth(), surface->getHeight(), 1); + ImageDesc desc(size, surface->getConfig()->renderTargetFormat); + setImageDesc(mTarget, 0, desc); +} + +void Texture::releaseTexImage() +{ + if (mBoundSurface) + { + mBoundSurface = NULL; + mTexture->releaseTexImage(); + + // Erase the image info for level 0 + ASSERT(mTarget == GL_TEXTURE_2D); + clearImageDesc(mTarget, 0); + } +} + +GLenum Texture::getBaseImageTarget() const +{ + return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget; +} + +size_t Texture::getExpectedMipLevels() const +{ + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0); + if (mTarget == GL_TEXTURE_3D) + { + return log2(std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), baseImageDesc.size.depth)) + 1; + } + else + { + return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1; + } +} + +bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const +{ + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) + { + return false; + } + + if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height) + { + return false; + } + + const TextureCaps &textureCaps = data.textureCaps->get(baseImageDesc.internalFormat); + if (!textureCaps.filterable && !IsPointSampled(samplerState)) + { + return false; + } + + bool npotSupport = data.extensions->textureNPOT || data.clientVersion >= 3; + if (!npotSupport) + { + if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.width)) || + (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(baseImageDesc.size.height))) + { + return false; + } + } + + if (IsMipmapFiltered(samplerState)) + { + if (!npotSupport) + { + if (!gl::isPow2(baseImageDesc.size.width) || !gl::isPow2(baseImageDesc.size.height)) + { + return false; + } + } + + if (!computeMipmapCompleteness(samplerState)) + { + return false; + } + } + else + { + if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete()) + { + return false; + } + } + + // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: + // The internalformat specified for the texture arrays is a sized internal depth or + // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- + // MODE is NONE, and either the magnification filter is not NEAREST or the mini- + // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(baseImageDesc.internalFormat); + if (formatInfo.depthBits > 0 && data.clientVersion > 2) + { + if (samplerState.compareMode == GL_NONE) + { + if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || + samplerState.magFilter != GL_NEAREST) + { + return false; + } + } + } + + return true; +} + +bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const +{ + size_t expectedMipLevels = getExpectedMipLevels(); + + size_t maxLevel = std::min(expectedMipLevels, samplerState.maxLevel + 1); + + for (size_t level = samplerState.baseLevel; level < maxLevel; level++) + { + if (mTarget == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++) + { + if (!computeLevelCompleteness(face, level, samplerState)) + { + return false; + } + } + } + else + { + if (!computeLevelCompleteness(mTarget, level, samplerState)) + { + return false; + } + } + } + + return true; +} + + +bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const +{ + ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (isImmutable()) + { + return true; + } + + const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), samplerState.baseLevel); + if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 || baseImageDesc.size.depth == 0) + { + return false; + } + + // The base image level is complete if the width and height are positive + if (level == 0) + { + return true; + } + + const ImageDesc &levelImageDesc = getImageDesc(target, level); + if (levelImageDesc.internalFormat != baseImageDesc.internalFormat) + { + return false; + } + + if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> level)) + { + return false; + } + + if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> level)) + { + return false; + } + + if (mTarget == GL_TEXTURE_3D) + { + if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> level)) + { + return false; + } + } + else if (mTarget == GL_TEXTURE_2D_ARRAY) + { + if (levelImageDesc.size.depth != baseImageDesc.size.depth) + { + return false; + } + } + + return true; +} + +Texture::SamplerCompletenessCache::SamplerCompletenessCache() + : cacheValid(false), + samplerState(), + filterable(false), + clientVersion(0), + supportsNPOT(false), + samplerComplete(false) +{ +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Texture.h b/src/3rdparty/angle/src/libANGLE/Texture.h new file mode 100644 index 0000000000..b5a0717713 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Texture.h @@ -0,0 +1,156 @@ +// +// Copyright (c) 2002-2013 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 gl::Texture class [OpenGL ES 2.0.24] section 3.7 page 63. + +#ifndef LIBANGLE_TEXTURE_H_ +#define LIBANGLE_TEXTURE_H_ + +#include "common/debug.h" +#include "libANGLE/RefCountObject.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Constants.h" +#include "libANGLE/renderer/TextureImpl.h" +#include "libANGLE/Caps.h" + +#include "angle_gl.h" + +#include +#include + +namespace egl +{ +class Surface; +} + +namespace gl +{ +class Framebuffer; +struct Data; + +bool IsMipmapFiltered(const gl::SamplerState &samplerState); + +class Texture final : public RefCountObject +{ + public: + Texture(rx::TextureImpl *impl, GLuint id, GLenum target); + + virtual ~Texture(); + + GLenum getTarget() const; + + const SamplerState &getSamplerState() const { return mSamplerState; } + SamplerState &getSamplerState() { return mSamplerState; } + + void setUsage(GLenum usage); + GLenum getUsage() const; + + size_t getWidth(GLenum target, size_t level) const; + size_t getHeight(GLenum target, size_t level) const; + size_t getDepth(GLenum target, size_t level) const; + GLenum getInternalFormat(GLenum target, size_t level) const; + + bool isSamplerComplete(const SamplerState &samplerState, const Data &data) const; + bool isCubeComplete() const; + + virtual Error setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type, + const PixelUnpackState &unpack, const uint8_t *pixels); + virtual Error setSubImage(GLenum target, size_t level, const Box &area, GLenum format, GLenum type, + const PixelUnpackState &unpack, const uint8_t *pixels); + + virtual Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, + const PixelUnpackState &unpack, const uint8_t *pixels); + virtual Error setCompressedSubImage(GLenum target, size_t level, const Box &area, GLenum format, + const PixelUnpackState &unpack, const uint8_t *pixels); + + virtual Error copyImage(GLenum target, size_t level, const Rectangle &sourceArea, GLenum internalFormat, + const Framebuffer *source); + virtual Error copySubImage(GLenum target, size_t level, const Offset &destOffset, const Rectangle &sourceArea, + const Framebuffer *source); + + virtual Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size); + + virtual Error generateMipmaps(); + + // Texture serials provide a unique way of identifying a Texture that isn't a raw pointer. + // "id" is not good enough, as Textures can be deleted, then re-allocated with the same id. + unsigned int getTextureSerial() const; + + bool isImmutable() const; + GLsizei immutableLevelCount(); + + void bindTexImage(egl::Surface *surface); + void releaseTexImage(); + + rx::TextureImpl *getImplementation() { return mTexture; } + const rx::TextureImpl *getImplementation() const { return mTexture; } + + 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. + + private: + static unsigned int issueTextureSerial(); + + rx::TextureImpl *mTexture; + + SamplerState mSamplerState; + GLenum mUsage; + + GLsizei mImmutableLevelCount; + + GLenum mTarget; + + + struct ImageDesc + { + Extents size; + GLenum internalFormat; + + ImageDesc(); + ImageDesc(const Extents &size, GLenum internalFormat); + }; + + const unsigned int mTextureSerial; + static unsigned int mCurrentTextureSerial; + + GLenum getBaseImageTarget() const; + size_t getExpectedMipLevels() const; + + bool computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const; + bool computeMipmapCompleteness(const gl::SamplerState &samplerState) const; + bool computeLevelCompleteness(GLenum target, size_t level, const gl::SamplerState &samplerState) const; + + const ImageDesc &getImageDesc(GLenum target, size_t level) const; + void setImageDesc(GLenum target, size_t level, const ImageDesc &desc); + void setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat); + void clearImageDesc(GLenum target, size_t level); + void clearImageDescs(); + + std::vector mImageDescs; + + struct SamplerCompletenessCache + { + SamplerCompletenessCache(); + + bool cacheValid; + + // All values that affect sampler completeness that are not stored within + // the texture itself + SamplerState samplerState; + bool filterable; + GLint clientVersion; + bool supportsNPOT; + + // Result of the sampler completeness with the above parameters + bool samplerComplete; + }; + mutable SamplerCompletenessCache mCompletenessCache; + + egl::Surface *mBoundSurface; +}; + +} + +#endif // LIBANGLE_TEXTURE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp new file mode 100644 index 0000000000..6effaca976 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.cpp @@ -0,0 +1,71 @@ +// +// Copyright (c) 2014 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 "libANGLE/TransformFeedback.h" +#include "libANGLE/renderer/TransformFeedbackImpl.h" + +namespace gl +{ + +TransformFeedback::TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id) + : RefCountObject(id), + mTransformFeedback(impl), + mStarted(GL_FALSE), + mPrimitiveMode(GL_NONE), + mPaused(GL_FALSE) +{ + ASSERT(impl != NULL); +} + +TransformFeedback::~TransformFeedback() +{ + SafeDelete(mTransformFeedback); +} + +void TransformFeedback::start(GLenum primitiveMode) +{ + mStarted = GL_TRUE; + mPrimitiveMode = primitiveMode; + mPaused = GL_FALSE; + mTransformFeedback->begin(primitiveMode); +} + +void TransformFeedback::stop() +{ + mStarted = GL_FALSE; + mPrimitiveMode = GL_NONE; + mPaused = GL_FALSE; + mTransformFeedback->end(); +} + +GLboolean TransformFeedback::isStarted() const +{ + return mStarted; +} + +GLenum TransformFeedback::getDrawMode() const +{ + return mPrimitiveMode; +} + +void TransformFeedback::pause() +{ + mPaused = GL_TRUE; + mTransformFeedback->pause(); +} + +void TransformFeedback::resume() +{ + mPaused = GL_FALSE; + mTransformFeedback->resume(); +} + +GLboolean TransformFeedback::isPaused() const +{ + return mPaused; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/TransformFeedback.h b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h new file mode 100644 index 0000000000..7673db93ff --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/TransformFeedback.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2014 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 LIBANGLE_TRANSFORM_FEEDBACK_H_ +#define LIBANGLE_TRANSFORM_FEEDBACK_H_ + +#include "libANGLE/RefCountObject.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ +class TransformFeedbackImpl; +} + +namespace gl +{ + +class TransformFeedback : public RefCountObject +{ + public: + TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id); + virtual ~TransformFeedback(); + + void start(GLenum primitiveMode); + void stop(); + GLboolean isStarted() const; + + GLenum getDrawMode() const; + + void pause(); + void resume(); + GLboolean isPaused() const; + + private: + rx::TransformFeedbackImpl* mTransformFeedback; + + GLboolean mStarted; + GLenum mPrimitiveMode; + GLboolean mPaused; +}; + +} + +#endif // LIBANGLE_TRANSFORM_FEEDBACK_H_ diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.cpp b/src/3rdparty/angle/src/libANGLE/Uniform.cpp new file mode 100644 index 0000000000..f161b9d6bd --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Uniform.cpp @@ -0,0 +1,107 @@ +// +// Copyright (c) 2010-2013 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 "libANGLE/Uniform.h" + +#include "common/utilities.h" + +#include + +namespace gl +{ + +LinkedUniform::LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, + const int blockIndex, const sh::BlockMemberInfo &blockInfo) + : type(type), + precision(precision), + name(name), + arraySize(arraySize), + blockIndex(blockIndex), + blockInfo(blockInfo), + data(NULL), + dirty(true), + psRegisterIndex(GL_INVALID_INDEX), + vsRegisterIndex(GL_INVALID_INDEX), + registerCount(0), + registerElement(0) +{ + // We use data storage for default block uniforms to cache values that are sent to D3D during rendering + // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only) + if (isInDefaultBlock()) + { + size_t bytes = dataSize(); + data = new unsigned char[bytes]; + memset(data, 0, bytes); + registerCount = VariableRowCount(type) * elementCount(); + } +} + +LinkedUniform::~LinkedUniform() +{ + delete[] data; +} + +bool LinkedUniform::isArray() const +{ + return arraySize > 0; +} + +unsigned int LinkedUniform::elementCount() const +{ + return arraySize > 0 ? arraySize : 1; +} + +bool LinkedUniform::isReferencedByVertexShader() const +{ + return vsRegisterIndex != GL_INVALID_INDEX; +} + +bool LinkedUniform::isReferencedByFragmentShader() const +{ + return psRegisterIndex != GL_INVALID_INDEX; +} + +bool LinkedUniform::isInDefaultBlock() const +{ + return blockIndex == -1; +} + +size_t LinkedUniform::dataSize() const +{ + ASSERT(type != GL_STRUCT_ANGLEX); + return VariableInternalSize(type) * elementCount(); +} + +bool LinkedUniform::isSampler() const +{ + return IsSamplerType(type); +} + +UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize) + : name(name), + elementIndex(elementIndex), + dataSize(dataSize), + psRegisterIndex(GL_INVALID_INDEX), + vsRegisterIndex(GL_INVALID_INDEX) +{ +} + +bool UniformBlock::isArrayElement() const +{ + return elementIndex != GL_INVALID_INDEX; +} + +bool UniformBlock::isReferencedByVertexShader() const +{ + return vsRegisterIndex != GL_INVALID_INDEX; +} + +bool UniformBlock::isReferencedByFragmentShader() const +{ + return psRegisterIndex != GL_INVALID_INDEX; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/Uniform.h b/src/3rdparty/angle/src/libANGLE/Uniform.h new file mode 100644 index 0000000000..dcf30f23cc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/Uniform.h @@ -0,0 +1,77 @@ +// +// Copyright (c) 2010-2013 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 LIBANGLE_UNIFORM_H_ +#define LIBANGLE_UNIFORM_H_ + +#include +#include + +#include "angle_gl.h" +#include "common/debug.h" +#include "compiler/translator/blocklayout.h" +#include "libANGLE/angletypes.h" + +namespace gl +{ + +// Helper struct representing a single shader uniform +struct LinkedUniform : angle::NonCopyable +{ + LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo); + + ~LinkedUniform(); + + bool isArray() const; + unsigned int elementCount() const; + bool isReferencedByVertexShader() const; + bool isReferencedByFragmentShader() const; + bool isInDefaultBlock() const; + size_t dataSize() const; + bool isSampler() const; + + const GLenum type; + const GLenum precision; + const std::string name; + const unsigned int arraySize; + const int blockIndex; + const sh::BlockMemberInfo blockInfo; + + unsigned char *data; + bool dirty; + + unsigned int psRegisterIndex; + unsigned int vsRegisterIndex; + unsigned int registerCount; + + // Register "elements" are used for uniform structs in ES3, to appropriately identify single uniforms + // inside aggregate types, which are packed according C-like structure rules. + unsigned int registerElement; +}; + +// Helper struct representing a single shader uniform block +struct UniformBlock : angle::NonCopyable +{ + // use GL_INVALID_INDEX for non-array elements + UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize); + + bool isArrayElement() const; + bool isReferencedByVertexShader() const; + bool isReferencedByFragmentShader() const; + + const std::string name; + const unsigned int elementIndex; + const unsigned int dataSize; + + std::vector memberUniformIndexes; + + unsigned int psRegisterIndex; + unsigned int vsRegisterIndex; +}; + +} + +#endif // LIBANGLE_UNIFORM_H_ diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.cpp b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp new file mode 100644 index 0000000000..f0aded905d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VertexArray.cpp @@ -0,0 +1,101 @@ +// +// Copyright (c) 2013 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. +// +// Implementation of the state class for mananging GLES 3 Vertex Array Objects. +// + +#include "libANGLE/VertexArray.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/renderer/VertexArrayImpl.h" + +namespace gl +{ + +VertexArray::VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs) + : mId(id), + mVertexArray(impl), + mVertexAttributes(maxAttribs) +{ + ASSERT(impl != NULL); +} + +VertexArray::~VertexArray() +{ + SafeDelete(mVertexArray); + + for (size_t i = 0; i < getMaxAttribs(); i++) + { + mVertexAttributes[i].buffer.set(NULL); + } + mElementArrayBuffer.set(NULL); +} + +GLuint VertexArray::id() const +{ + return mId; +} + +void VertexArray::detachBuffer(GLuint bufferName) +{ + for (size_t attribute = 0; attribute < getMaxAttribs(); attribute++) + { + if (mVertexAttributes[attribute].buffer.id() == bufferName) + { + mVertexAttributes[attribute].buffer.set(NULL); + } + } + + if (mElementArrayBuffer.id() == bufferName) + { + mElementArrayBuffer.set(NULL); + } +} + +const VertexAttribute& VertexArray::getVertexAttribute(size_t attributeIndex) const +{ + ASSERT(attributeIndex < getMaxAttribs()); + return mVertexAttributes[attributeIndex]; +} + +const std::vector &VertexArray::getVertexAttributes() const +{ + return mVertexAttributes; +} + +void VertexArray::setVertexAttribDivisor(GLuint index, GLuint divisor) +{ + ASSERT(index < getMaxAttribs()); + mVertexAttributes[index].divisor = divisor; + mVertexArray->setAttributeDivisor(index, divisor); +} + +void VertexArray::enableAttribute(unsigned int attributeIndex, bool enabledState) +{ + ASSERT(attributeIndex < getMaxAttribs()); + mVertexAttributes[attributeIndex].enabled = enabledState; + mVertexArray->enableAttribute(attributeIndex, enabledState); +} + +void VertexArray::setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer) +{ + ASSERT(attributeIndex < getMaxAttribs()); + mVertexAttributes[attributeIndex].buffer.set(boundBuffer); + mVertexAttributes[attributeIndex].size = size; + mVertexAttributes[attributeIndex].type = type; + mVertexAttributes[attributeIndex].normalized = normalized; + mVertexAttributes[attributeIndex].pureInteger = pureInteger; + mVertexAttributes[attributeIndex].stride = stride; + mVertexAttributes[attributeIndex].pointer = pointer; + mVertexArray->setAttribute(attributeIndex, mVertexAttributes[attributeIndex]); +} + +void VertexArray::setElementArrayBuffer(Buffer *buffer) +{ + mElementArrayBuffer.set(buffer); + mVertexArray->setElementArrayBuffer(buffer); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/VertexArray.h b/src/3rdparty/angle/src/libANGLE/VertexArray.h new file mode 100644 index 0000000000..5c79b9953d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VertexArray.h @@ -0,0 +1,66 @@ +// +// Copyright (c) 2013 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 class contains prototypes for representing GLES 3 Vertex Array Objects: +// +// The buffer objects that are to be used by the vertex stage of the GL are collected +// together to form a vertex array object. All state related to the definition of data used +// by the vertex processor is encapsulated in a vertex array object. +// + +#ifndef LIBANGLE_VERTEXARRAY_H_ +#define LIBANGLE_VERTEXARRAY_H_ + +#include "libANGLE/RefCountObject.h" +#include "libANGLE/Constants.h" +#include "libANGLE/VertexAttribute.h" + +#include + +namespace rx +{ +class VertexArrayImpl; +} + +namespace gl +{ +class Buffer; + +class VertexArray +{ + public: + VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs); + ~VertexArray(); + + GLuint id() const; + + const VertexAttribute& getVertexAttribute(size_t attributeIndex) const; + const std::vector &getVertexAttributes() const; + + void detachBuffer(GLuint bufferName); + void setVertexAttribDivisor(GLuint index, GLuint divisor); + void enableAttribute(unsigned int attributeIndex, bool enabledState); + void setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, + bool normalized, bool pureInteger, GLsizei stride, const void *pointer); + + Buffer *getElementArrayBuffer() const { return mElementArrayBuffer.get(); } + void setElementArrayBuffer(Buffer *buffer); + GLuint getElementArrayBufferId() const { return mElementArrayBuffer.id(); } + size_t getMaxAttribs() const { return mVertexAttributes.size(); } + + rx::VertexArrayImpl *getImplementation() { return mVertexArray; } + const rx::VertexArrayImpl *getImplementation() const { return mVertexArray; } + + private: + GLuint mId; + + rx::VertexArrayImpl *mVertexArray; + std::vector mVertexAttributes; + BindingPointer mElementArrayBuffer; +}; + +} + +#endif // LIBANGLE_VERTEXARRAY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp new file mode 100644 index 0000000000..19934e7fac --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.cpp @@ -0,0 +1,73 @@ +// +// Copyright 2014 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. +// +// Implementation of the state class for mananging GLES 3 Vertex Array Objects. +// + +#include "libANGLE/VertexAttribute.h" + +namespace gl +{ + +VertexAttribute::VertexAttribute() + : enabled(false), + type(GL_FLOAT), + size(4), + normalized(false), + pureInteger(false), + stride(0), + pointer(NULL), + divisor(0) +{ +} + +bool operator==(const VertexAttribute &a, const VertexAttribute &b) +{ + return a.enabled == b.enabled && + a.type == b.type && + a.size == b.size && + a.normalized == b.normalized && + a.pureInteger == b.pureInteger && + a.stride == b.stride && + a.pointer == b.pointer && + a.buffer.get() == b.buffer.get() && + a.divisor == b.divisor; +} + +bool operator!=(const VertexAttribute &a, const VertexAttribute &b) +{ + return !(a == b); +} + +size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib) +{ + GLuint size = attrib.size; + switch (attrib.type) + { + case GL_BYTE: return size * sizeof(GLbyte); + case GL_UNSIGNED_BYTE: return size * sizeof(GLubyte); + case GL_SHORT: return size * sizeof(GLshort); + case GL_UNSIGNED_SHORT: return size * sizeof(GLushort); + case GL_INT: return size * sizeof(GLint); + case GL_UNSIGNED_INT: return size * sizeof(GLuint); + case GL_INT_2_10_10_10_REV: return 4; + case GL_UNSIGNED_INT_2_10_10_10_REV: return 4; + case GL_FIXED: return size * sizeof(GLfixed); + case GL_HALF_FLOAT: return size * sizeof(GLhalf); + case GL_FLOAT: return size * sizeof(GLfloat); + default: UNREACHABLE(); return size * sizeof(GLfloat); + } +} + +size_t ComputeVertexAttributeStride(const VertexAttribute& attrib) +{ + if (!attrib.enabled) + { + return 16; + } + return attrib.stride ? attrib.stride : ComputeVertexAttributeTypeSize(attrib); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/VertexAttribute.h b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h new file mode 100644 index 0000000000..bdffe97466 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/VertexAttribute.h @@ -0,0 +1,122 @@ +// +// Copyright (c) 2013 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. +// +// Helper structure describing a single vertex attribute +// + +#ifndef LIBANGLE_VERTEXATTRIBUTE_H_ +#define LIBANGLE_VERTEXATTRIBUTE_H_ + +#include "libANGLE/Buffer.h" + +namespace gl +{ + +struct VertexAttribute +{ + bool enabled; // From glEnable/DisableVertexAttribArray + + GLenum type; + GLuint size; + bool normalized; + bool pureInteger; + GLuint stride; // 0 means natural stride + + union + { + const GLvoid *pointer; + GLintptr offset; + }; + BindingPointer buffer; // Captured when glVertexAttribPointer is called. + + GLuint divisor; + + VertexAttribute(); +}; + +bool operator==(const VertexAttribute &a, const VertexAttribute &b); +bool operator!=(const VertexAttribute &a, const VertexAttribute &b); + +template +T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + return static_cast(attrib.enabled ? GL_TRUE : GL_FALSE); + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + return static_cast(attrib.size); + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + return static_cast(attrib.stride); + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + return static_cast(attrib.type); + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + return static_cast(attrib.normalized ? GL_TRUE : GL_FALSE); + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + return static_cast(attrib.buffer.id()); + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + return static_cast(attrib.divisor); + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + return static_cast(attrib.pureInteger ? GL_TRUE : GL_FALSE); + default: + UNREACHABLE(); + return static_cast(0); + } +} + +size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib); +size_t ComputeVertexAttributeStride(const VertexAttribute& attrib); + +struct VertexAttribCurrentValueData +{ + union + { + GLfloat FloatValues[4]; + GLint IntValues[4]; + GLuint UnsignedIntValues[4]; + }; + GLenum Type; + + void setFloatValues(const GLfloat floatValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + FloatValues[valueIndex] = floatValues[valueIndex]; + } + Type = GL_FLOAT; + } + + void setIntValues(const GLint intValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + IntValues[valueIndex] = intValues[valueIndex]; + } + Type = GL_INT; + } + + void setUnsignedIntValues(const GLuint unsignedIntValues[4]) + { + for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) + { + UnsignedIntValues[valueIndex] = unsignedIntValues[valueIndex]; + } + Type = GL_UNSIGNED_INT; + } + + bool operator==(const VertexAttribCurrentValueData &other) + { + return (Type == other.Type && memcmp(FloatValues, other.FloatValues, sizeof(float) * 4) == 0); + } + + bool operator!=(const VertexAttribCurrentValueData &other) + { + return !(*this == other); + } +}; + +} + +#endif // LIBANGLE_VERTEXATTRIBUTE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.cpp b/src/3rdparty/angle/src/libANGLE/angletypes.cpp new file mode 100644 index 0000000000..16879f8041 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/angletypes.cpp @@ -0,0 +1,246 @@ +// +// Copyright (c) 2013 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. +// + +// angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2 + +#include "libANGLE/angletypes.h" +#include "libANGLE/Program.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexArray.h" + +namespace gl +{ + +bool operator==(const Rectangle &a, const Rectangle &b) +{ + return a.x == b.x && + a.y == b.y && + a.width == b.width && + a.height == b.height; +} + +bool operator!=(const Rectangle &a, const Rectangle &b) +{ + return !(a == b); +} + +SamplerState::SamplerState() + : minFilter(GL_NEAREST_MIPMAP_LINEAR), + magFilter(GL_LINEAR), + wrapS(GL_REPEAT), + wrapT(GL_REPEAT), + wrapR(GL_REPEAT), + maxAnisotropy(1.0f), + baseLevel(0), + maxLevel(1000), + minLod(-1000.0f), + maxLod(1000.0f), + compareMode(GL_NONE), + compareFunc(GL_LEQUAL), + swizzleRed(GL_RED), + swizzleGreen(GL_GREEN), + swizzleBlue(GL_BLUE), + swizzleAlpha(GL_ALPHA) +{} + +bool SamplerState::swizzleRequired() const +{ + return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || + swizzleBlue != GL_BLUE || swizzleAlpha != GL_ALPHA; +} + +bool SamplerState::operator==(const SamplerState &other) const +{ + return minFilter == other.minFilter && + magFilter == other.magFilter && + wrapS == other.wrapS && + wrapT == other.wrapT && + wrapR == other.wrapR && + maxAnisotropy == other.maxAnisotropy && + baseLevel == other.baseLevel && + maxLevel == other.maxLevel && + minLod == other.minLod && + maxLod == other.maxLod && + compareMode == other.compareMode && + compareFunc == other.compareFunc && + swizzleRed == other.swizzleRed && + swizzleGreen == other.swizzleGreen && + swizzleBlue == other.swizzleBlue && + swizzleAlpha == other.swizzleAlpha; +} + +bool SamplerState::operator!=(const SamplerState &other) const +{ + return !(*this == other); +} + +static void MinMax(int a, int b, int *minimum, int *maximum) +{ + if (a < b) + { + *minimum = a; + *maximum = b; + } + else + { + *minimum = b; + *maximum = a; + } +} + +bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection) +{ + int minSourceX, maxSourceX, minSourceY, maxSourceY; + MinMax(source.x, source.x + source.width, &minSourceX, &maxSourceX); + MinMax(source.y, source.y + source.height, &minSourceY, &maxSourceY); + + int minClipX, maxClipX, minClipY, maxClipY; + MinMax(clip.x, clip.x + clip.width, &minClipX, &maxClipX); + MinMax(clip.y, clip.y + clip.height, &minClipY, &maxClipY); + + if (minSourceX >= maxClipX || maxSourceX <= minClipX || minSourceY >= maxClipY || maxSourceY <= minClipY) + { + if (intersection) + { + intersection->x = minSourceX; + intersection->y = maxSourceY; + intersection->width = maxSourceX - minSourceX; + intersection->height = maxSourceY - minSourceY; + } + + return false; + } + else + { + if (intersection) + { + intersection->x = std::max(minSourceX, minClipX); + intersection->y = std::max(minSourceY, minClipY); + intersection->width = std::min(maxSourceX, maxClipX) - std::max(minSourceX, minClipX); + intersection->height = std::min(maxSourceY, maxClipY) - std::max(minSourceY, minClipY); + } + + return true; + } +} + +VertexFormat::VertexFormat() + : mType(GL_NONE), + mNormalized(GL_FALSE), + mComponents(0), + mPureInteger(false) +{} + +VertexFormat::VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger) + : mType(type), + mNormalized(normalized), + mComponents(components), + mPureInteger(pureInteger) +{ + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +VertexFormat::VertexFormat(const VertexAttribute &attrib) + : mType(attrib.type), + mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE), + mComponents(attrib.size), + mPureInteger(attrib.pureInteger) +{ + // Ensure we aren't initializing a vertex format which should be using + // the current-value type + ASSERT(attrib.enabled); + + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +VertexFormat::VertexFormat(const VertexAttribute &attrib, GLenum currentValueType) + : mType(attrib.type), + mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE), + mComponents(attrib.size), + mPureInteger(attrib.pureInteger) +{ + if (!attrib.enabled) + { + mType = currentValueType; + mNormalized = GL_FALSE; + mComponents = 4; + mPureInteger = (currentValueType != GL_FLOAT); + } + + // Float data can not be normalized, so ignore the user setting + if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) + { + mNormalized = GL_FALSE; + } +} + +void VertexFormat::GetInputLayout(VertexFormat *inputLayout, + Program *program, + const State &state) +{ + const std::vector &vertexAttributes = state.getVertexArray()->getVertexAttributes(); + for (unsigned int attributeIndex = 0; attributeIndex < vertexAttributes.size(); attributeIndex++) + { + int semanticIndex = program->getSemanticIndex(attributeIndex); + + if (semanticIndex != -1) + { + inputLayout[semanticIndex] = VertexFormat(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex).Type); + } + } +} + +bool VertexFormat::operator==(const VertexFormat &other) const +{ + return (mType == other.mType && + mComponents == other.mComponents && + mNormalized == other.mNormalized && + mPureInteger == other.mPureInteger ); +} + +bool VertexFormat::operator!=(const VertexFormat &other) const +{ + return !(*this == other); +} + +bool VertexFormat::operator<(const VertexFormat& other) const +{ + if (mType != other.mType) + { + return mType < other.mType; + } + if (mNormalized != other.mNormalized) + { + return mNormalized < other.mNormalized; + } + if (mComponents != other.mComponents) + { + return mComponents < other.mComponents; + } + return mPureInteger < other.mPureInteger; +} + +bool Box::operator==(const Box &other) const +{ + return (x == other.x && y == other.y && z == other.z && + width == other.width && height == other.height && depth == other.depth); +} + +bool Box::operator!=(const Box &other) const +{ + return !(*this == other); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.h b/src/3rdparty/angle/src/libANGLE/angletypes.h new file mode 100644 index 0000000000..e4e08b5512 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/angletypes.h @@ -0,0 +1,323 @@ +// +// Copyright (c) 2012-2013 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. +// + +// angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2 + +#ifndef LIBANGLE_ANGLETYPES_H_ +#define LIBANGLE_ANGLETYPES_H_ + +#include "libANGLE/Constants.h" +#include "libANGLE/RefCountObject.h" + +#include +#include + +namespace gl +{ +class Buffer; +class State; +class Program; +struct VertexAttribute; +struct VertexAttribCurrentValueData; + +enum SamplerType +{ + SAMPLER_PIXEL, + SAMPLER_VERTEX +}; + +template +struct Color +{ + T red; + T green; + T blue; + T alpha; + + Color() : red(0), green(0), blue(0), alpha(0) { } + Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a) { } +}; + +template +bool operator==(const Color &a, const Color &b) +{ + return a.red == b.red && + a.green == b.green && + a.blue == b.blue && + a.alpha == b.alpha; +} + +template +bool operator!=(const Color &a, const Color &b) +{ + return !(a == b); +} + +typedef Color ColorF; +typedef Color ColorI; +typedef Color ColorUI; + +struct Rectangle +{ + int x; + int y; + int width; + int height; + + Rectangle() : x(0), y(0), width(0), height(0) { } + Rectangle(int x_in, int y_in, int width_in, int height_in) : x(x_in), y(y_in), width(width_in), height(height_in) { } +}; + +bool operator==(const Rectangle &a, const Rectangle &b); +bool operator!=(const Rectangle &a, const Rectangle &b); + +bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection); + +struct Offset +{ + int x; + int y; + int z; + + Offset() : x(0), y(0), z(0) { } + Offset(int x_in, int y_in, int z_in) : x(x_in), y(y_in), z(z_in) { } +}; + +struct Extents +{ + int width; + int height; + int depth; + + Extents() : width(0), height(0), depth(0) { } + Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { } + + bool empty() const { return (width * height * depth) == 0; } +}; + +struct Box +{ + int x; + int y; + int z; + int width; + int height; + int depth; + + Box() : x(0), y(0), z(0), width(0), height(0), depth(0) { } + Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in) : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in) { } + Box(const Offset &offset, const Extents &size) : x(offset.x), y(offset.y), z(offset.z), width(size.width), height(size.height), depth(size.depth) { } + bool operator==(const Box &other) const; + bool operator!=(const Box &other) const; +}; + + +struct RasterizerState +{ + bool cullFace; + GLenum cullMode; + GLenum frontFace; + + bool polygonOffsetFill; + GLfloat polygonOffsetFactor; + GLfloat polygonOffsetUnits; + + bool pointDrawMode; + bool multiSample; + + bool rasterizerDiscard; +}; + +struct BlendState +{ + bool blend; + GLenum sourceBlendRGB; + GLenum destBlendRGB; + GLenum sourceBlendAlpha; + GLenum destBlendAlpha; + GLenum blendEquationRGB; + GLenum blendEquationAlpha; + + bool colorMaskRed; + bool colorMaskGreen; + bool colorMaskBlue; + bool colorMaskAlpha; + + bool sampleAlphaToCoverage; + + bool dither; +}; + +struct DepthStencilState +{ + bool depthTest; + GLenum depthFunc; + bool depthMask; + + bool stencilTest; + GLenum stencilFunc; + GLuint stencilMask; + GLenum stencilFail; + GLenum stencilPassDepthFail; + GLenum stencilPassDepthPass; + GLuint stencilWritemask; + GLenum stencilBackFunc; + GLuint stencilBackMask; + GLenum stencilBackFail; + GLenum stencilBackPassDepthFail; + GLenum stencilBackPassDepthPass; + GLuint stencilBackWritemask; +}; + +struct SamplerState +{ + SamplerState(); + + GLenum minFilter; + GLenum magFilter; + GLenum wrapS; + GLenum wrapT; + GLenum wrapR; + float maxAnisotropy; + + GLint baseLevel; + GLint maxLevel; + GLfloat minLod; + GLfloat maxLod; + + GLenum compareMode; + GLenum compareFunc; + + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; + + bool swizzleRequired() const; + + bool operator==(const SamplerState &other) const; + bool operator!=(const SamplerState &other) const; +}; + +struct PixelUnpackState +{ + BindingPointer pixelBuffer; + GLint alignment; + GLint rowLength; + GLint skipRows; + GLint skipPixels; + GLint imageHeight; + GLint skipImages; + + PixelUnpackState() + : alignment(4), + rowLength(0), + skipRows(0), + skipPixels(0), + imageHeight(0), + skipImages(0) + {} + + PixelUnpackState(GLint alignmentIn, GLint rowLengthIn) + : alignment(alignmentIn), + rowLength(rowLengthIn), + skipRows(0), + skipPixels(0), + imageHeight(0), + skipImages(0) + {} +}; + +struct PixelPackState +{ + BindingPointer pixelBuffer; + GLint alignment; + bool reverseRowOrder; + GLint rowLength; + GLint skipRows; + GLint skipPixels; + + PixelPackState() + : alignment(4), + reverseRowOrder(false), + rowLength(0), + skipRows(0), + skipPixels(0) + {} + + explicit PixelPackState(GLint alignmentIn, bool reverseRowOrderIn) + : alignment(alignmentIn), + reverseRowOrder(reverseRowOrderIn), + rowLength(0), + skipRows(0), + skipPixels(0) + {} +}; + +struct VertexFormat +{ + GLenum mType; + GLboolean mNormalized; + GLuint mComponents; + bool mPureInteger; + + VertexFormat(); + VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger); + explicit VertexFormat(const VertexAttribute &attribute); + VertexFormat(const VertexAttribute &attribute, GLenum currentValueType); + + static void GetInputLayout(VertexFormat *inputLayout, + Program *program, + const State& currentValues); + + bool operator==(const VertexFormat &other) const; + bool operator!=(const VertexFormat &other) const; + bool operator<(const VertexFormat& other) const; +}; + +} + +namespace rx +{ + +enum VendorID : uint32_t +{ + VENDOR_ID_AMD = 0x1002, + VENDOR_ID_INTEL = 0x8086, + VENDOR_ID_NVIDIA = 0x10DE, +}; + +// Downcast a base implementation object (EG TextureImpl to TextureD3D) +template +inline DestT *GetAs(SrcT *src) +{ + ASSERT(HAS_DYNAMIC_TYPE(DestT*, src)); + return static_cast(src); +} + +template +inline const DestT *GetAs(const SrcT *src) +{ + ASSERT(HAS_DYNAMIC_TYPE(const DestT*, src)); + return static_cast(src); +} + +// Downcast a GL object to an Impl (EG gl::Texture to rx::TextureD3D) +template +inline DestT *GetImplAs(SrcT *src) +{ + return GetAs(src->getImplementation()); +} + +template +inline const DestT *GetImplAs(const SrcT *src) +{ + return GetAs(src->getImplementation()); +} + +} + +#endif // LIBANGLE_ANGLETYPES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/features.h b/src/3rdparty/angle/src/libANGLE/features.h new file mode 100644 index 0000000000..fbe013f47d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/features.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2014 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 LIBANGLE_FEATURES_H_ +#define LIBANGLE_FEATURES_H_ + +#define ANGLE_DISABLED 0 +#define ANGLE_ENABLED 1 + +// Feature defaults + +// Direct3D9EX +// 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_D3D9EX=0" in your project file. +#if !defined(ANGLE_D3D9EX) +#define ANGLE_D3D9EX ANGLE_ENABLED +#endif + +// Vsync +// ENABLED allows Vsync to be configured at runtime +// DISABLED disallows Vsync +#if !defined(ANGLE_VSYNC) +#define ANGLE_VSYNC ANGLE_ENABLED +#endif + +// Program binary loading +#if !defined(ANGLE_PROGRAM_BINARY_LOAD) +#define ANGLE_PROGRAM_BINARY_LOAD ANGLE_ENABLED +#endif + +// Shader debug info +#if !defined(ANGLE_SHADER_DEBUG_INFO) +#define ANGLE_SHADER_DEBUG_INFO ANGLE_DISABLED +#endif + +#endif // LIBANGLE_FEATURES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.cpp b/src/3rdparty/angle/src/libANGLE/formatutils.cpp new file mode 100644 index 0000000000..51e6a5a65d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/formatutils.cpp @@ -0,0 +1,650 @@ +// +// Copyright (c) 2013-2014 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. +// + +// formatutils.cpp: Queries for GL image formats. + +#include "common/mathutil.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Context.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/renderer/Renderer.h" + +namespace gl +{ + +// ES2 requires that format is equal to internal format at all glTex*Image2D entry points and the implementation +// can decide the true, sized, internal format. The ES2FormatMap determines the internal format for all valid +// format and type combinations. + +typedef std::pair FormatTypePair; +typedef std::pair FormatPair; +typedef std::map FormatMap; + +// A helper function to insert data into the format map with fewer characters. +static inline void InsertFormatMapping(FormatMap *map, GLenum format, GLenum type, GLenum internalFormat) +{ + map->insert(FormatPair(FormatTypePair(format, type), internalFormat)); +} + +FormatMap BuildFormatMap() +{ + FormatMap map; + + // | Format | Type | Internal format | + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8); + InsertFormatMapping(&map, GL_RGBA, GL_BYTE, GL_RGBA8_SNORM); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA4); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGB5_A1); + InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2); + InsertFormatMapping(&map, GL_RGBA, GL_FLOAT, GL_RGBA32F); + InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F); + InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, GL_RGBA16F); + + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_RGBA8UI); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_BYTE, GL_RGBA8I); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_RGBA16UI); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_SHORT, GL_RGBA16I); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_INT, GL_RGBA32I); + InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2UI); + + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8); + InsertFormatMapping(&map, GL_RGB, GL_BYTE, GL_RGB8_SNORM); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB565); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_R11F_G11F_B10F); + InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_RGB9_E5); + InsertFormatMapping(&map, GL_RGB, GL_FLOAT, GL_RGB32F); + InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT, GL_RGB16F); + InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, GL_RGB16F); + + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_RGB8UI); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_BYTE, GL_RGB8I); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_RGB16UI); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_SHORT, GL_RGB16I); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_RGB32UI); + InsertFormatMapping(&map, GL_RGB_INTEGER, GL_INT, GL_RGB32I); + + InsertFormatMapping(&map, GL_RG, GL_UNSIGNED_BYTE, GL_RG8); + InsertFormatMapping(&map, GL_RG, GL_BYTE, GL_RG8_SNORM); + InsertFormatMapping(&map, GL_RG, GL_FLOAT, GL_RG32F); + InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT, GL_RG16F); + InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT_OES, GL_RG16F); + + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_RG8UI); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_BYTE, GL_RG8I); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_RG16UI); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_SHORT, GL_RG16I); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_RG32UI); + InsertFormatMapping(&map, GL_RG_INTEGER, GL_INT, GL_RG32I); + + InsertFormatMapping(&map, GL_RED, GL_UNSIGNED_BYTE, GL_R8); + InsertFormatMapping(&map, GL_RED, GL_BYTE, GL_R8_SNORM); + InsertFormatMapping(&map, GL_RED, GL_FLOAT, GL_R32F); + InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT, GL_R16F); + InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT_OES, GL_R16F); + + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_R8UI); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_BYTE, GL_R8I); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_R16UI); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_SHORT, GL_R16I); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_R32UI); + InsertFormatMapping(&map, GL_RED_INTEGER, GL_INT, GL_R32I); + + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE8_ALPHA8_EXT); + InsertFormatMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE8_EXT); + InsertFormatMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA8_EXT); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA32F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE32F_EXT); + InsertFormatMapping(&map, GL_ALPHA, GL_FLOAT, GL_ALPHA32F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA16F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_LUMINANCE_ALPHA16F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE16F_EXT); + InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_LUMINANCE16F_EXT); + InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT, GL_ALPHA16F_EXT); + InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, GL_ALPHA16F_EXT); + + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_BGRA8_EXT); + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_BGRA4_ANGLEX); + InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_BGR5_A1_ANGLEX); + + InsertFormatMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, GL_SRGB8); + InsertFormatMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, GL_SRGB8_ALPHA8); + + InsertFormatMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16); + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT32_OES); + InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F); + + InsertFormatMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, GL_STENCIL_INDEX8); + + InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH24_STENCIL8); + InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_DEPTH32F_STENCIL8); + + return map; +} + +Type::Type() + : bytes(0), + bytesShift(0), + specialInterpretation(false) +{ +} + +static Type GenTypeInfo(GLuint bytes, bool specialInterpretation) +{ + Type info; + info.bytes = bytes; + GLuint i = 0; + while ((1u << i) < bytes) + { + ++i; + } + info.bytesShift = i; + ASSERT((1u << info.bytesShift) == bytes); + info.specialInterpretation = specialInterpretation; + return info; +} + +bool operator<(const Type& a, const Type& b) +{ + return memcmp(&a, &b, sizeof(Type)) < 0; +} + +// Information about internal formats +static bool AlwaysSupported(GLuint, const Extensions &) +{ + return true; +} + +static bool UnimplementedSupport(GLuint, const Extensions &) +{ + return false; +} + +static bool NeverSupported(GLuint, const Extensions &) +{ + return false; +} + +template +static bool RequireES(GLuint clientVersion, const Extensions &) +{ + return clientVersion >= minCoreGLVersion; +} + +// Pointer to a boolean memeber of the Extensions struct +typedef bool(Extensions::*ExtensionBool); + +// Check support for a single extension +template +static bool RequireExt(GLuint, const Extensions & extensions) +{ + return extensions.*bool1; +} + +// Check for a minimum client version or a single extension +template +static bool RequireESOrExt(GLuint clientVersion, const Extensions &extensions) +{ + return clientVersion >= minCoreGLVersion || extensions.*bool1; +} + +// Check for a minimum client version or two extensions +template +static bool RequireESOrExtAndExt(GLuint clientVersion, const Extensions &extensions) +{ + return clientVersion >= minCoreGLVersion || (extensions.*bool1 && extensions.*bool2); +} + +// Check for a minimum client version or at least one of two extensions +template +static bool RequireESOrExtOrExt(GLuint clientVersion, const Extensions &extensions) +{ + return clientVersion >= minCoreGLVersion || extensions.*bool1 || extensions.*bool2; +} + +// Check support for two extensions +template +static bool RequireExtAndExt(GLuint, const Extensions &extensions) +{ + return extensions.*bool1 && extensions.*bool2; +} + +InternalFormat::InternalFormat() + : redBits(0), + greenBits(0), + blueBits(0), + luminanceBits(0), + alphaBits(0), + sharedBits(0), + depthBits(0), + stencilBits(0), + pixelBytes(0), + componentCount(0), + compressedBlockWidth(0), + compressedBlockHeight(0), + format(GL_NONE), + type(GL_NONE), + componentType(GL_NONE), + colorEncoding(GL_NONE), + compressed(false), + textureSupport(NeverSupported), + renderSupport(NeverSupported), + filterSupport(NeverSupported) +{ +} + +static InternalFormat UnsizedFormat(GLenum format, InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.format = format; + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +static InternalFormat RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint alpha, GLuint shared, + GLenum format, GLenum type, GLenum componentType, bool srgb, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.redBits = red; + formatInfo.greenBits = green; + formatInfo.blueBits = blue; + formatInfo.alphaBits = alpha; + formatInfo.sharedBits = shared; + formatInfo.pixelBytes = (red + green + blue + alpha + shared) / 8; + formatInfo.componentCount = ((red > 0) ? 1 : 0) + ((green > 0) ? 1 : 0) + ((blue > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); + formatInfo.format = format; + formatInfo.type = type; + formatInfo.componentType = componentType; + formatInfo.colorEncoding = (srgb ? GL_SRGB : GL_LINEAR); + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +static InternalFormat LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, GLenum type, GLenum componentType, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.luminanceBits = luminance; + formatInfo.alphaBits = alpha; + formatInfo.pixelBytes = (luminance + alpha) / 8; + formatInfo.componentCount = ((luminance > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); + formatInfo.format = format; + formatInfo.type = type; + formatInfo.componentType = componentType; + formatInfo.colorEncoding = GL_LINEAR; + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +static InternalFormat DepthStencilFormat(GLuint depthBits, GLuint stencilBits, GLuint unusedBits, GLenum format, + GLenum type, GLenum componentType, InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.depthBits = depthBits; + formatInfo.stencilBits = stencilBits; + formatInfo.pixelBytes = (depthBits + stencilBits + unusedBits) / 8; + formatInfo.componentCount = ((depthBits > 0) ? 1 : 0) + ((stencilBits > 0) ? 1 : 0); + formatInfo.format = format; + formatInfo.type = type; + formatInfo.componentType = componentType; + formatInfo.colorEncoding = GL_LINEAR; + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +static InternalFormat CompressedFormat(GLuint compressedBlockWidth, GLuint compressedBlockHeight, GLuint compressedBlockSize, + GLuint componentCount, GLenum format, GLenum type, bool srgb, + InternalFormat::SupportCheckFunction textureSupport, + InternalFormat::SupportCheckFunction renderSupport, + InternalFormat::SupportCheckFunction filterSupport) +{ + InternalFormat formatInfo; + formatInfo.compressedBlockWidth = compressedBlockWidth; + formatInfo.compressedBlockHeight = compressedBlockHeight; + formatInfo.pixelBytes = compressedBlockSize / 8; + formatInfo.componentCount = componentCount; + formatInfo.format = format; + formatInfo.type = type; + formatInfo.componentType = GL_UNSIGNED_NORMALIZED; + formatInfo.colorEncoding = (srgb ? GL_SRGB : GL_LINEAR); + formatInfo.compressed = true; + formatInfo.textureSupport = textureSupport; + formatInfo.renderSupport = renderSupport; + formatInfo.filterSupport = filterSupport; + return formatInfo; +} + +typedef std::pair InternalFormatInfoPair; +typedef std::map InternalFormatInfoMap; + +static InternalFormatInfoMap BuildInternalFormatInfoMap() +{ + InternalFormatInfoMap map; + + // From ES 3.0.1 spec, table 3.12 + map.insert(InternalFormatInfoPair(GL_NONE, InternalFormat())); + + // | Internal format | | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_R8, RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::textureRG>, RequireESOrExt<3, &Extensions::textureRG>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R8_SNORM, RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG8, RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::textureRG>, RequireESOrExt<3, &Extensions::textureRG>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG8_SNORM, RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::rgb8rgba8>, RequireESOrExt<3, &Extensions::rgb8rgba8>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8_SNORM, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB565, RGBAFormat( 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA4, RGBAFormat( 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB5_A1, RGBAFormat( 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::rgb8rgba8>, RequireESOrExt<3, &Extensions::rgb8rgba8>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8_SNORM, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB10_A2, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireES<3>, RequireES<3>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB10_A2UI, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB8, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB8_ALPHA8, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R11F_G11F_B10F, RGBAFormat(11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, RequireES<3>, RequireExt<&Extensions::colorBufferFloat>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB9_E5, RGBAFormat( 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, RequireES<3>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_R8I, RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R8UI, RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R16I, RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R16UI, RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R32I, RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_R32UI, RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG8I, RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG8UI, RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG16I, RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG16UI, RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG32I, RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RG32UI, RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8I, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB8UI, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB16I, RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB16UI, RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB32I, RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGB32UI, RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8I, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA8UI, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA16I, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA16UI, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA32I, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA32UI, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); + + map.insert(InternalFormatInfoPair(GL_BGRA8_EXT, RGBAFormat( 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_BGRA4_ANGLEX, RGBAFormat( 4, 4, 4, 4, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_BGR5_A1_ANGLEX, RGBAFormat( 5, 5, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); + + // Floating point renderability and filtering is provided by OES_texture_float and OES_texture_half_float + // | Internal format | | D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable | + // | | | | | | | type | | | | | + map.insert(InternalFormatInfoPair(GL_R16F, RGBAFormat(16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RG16F, RGBAFormat(16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RGB16F, RGBAFormat(16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_RGBA16F, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>))); + map.insert(InternalFormatInfoPair(GL_R32F, RGBAFormat(32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RG32F, RGBAFormat(32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RGB32F, RGBAFormat(32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureFloat>, RequireESOrExt<3, &Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear> ))); + map.insert(InternalFormatInfoPair(GL_RGBA32F, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureFloat>, RequireESOrExt<3, &Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear> ))); + + // Depth stencil formats + // | Internal format | | D |S | X | Format | Type | Component type | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT16, DepthStencilFormat(16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, RequireESOrExt<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT24, DepthStencilFormat(24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireES<3>, RequireES<3>, RequireESOrExt<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32F, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireES<3>, RequireES<3>, RequireESOrExt<3, &Extensions::depthTextures>))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32_OES, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::depthTextures>, RequireExt<&Extensions::depthTextures>, AlwaysSupported ))); + map.insert(InternalFormatInfoPair(GL_DEPTH24_STENCIL8, DepthStencilFormat(24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESOrExt<3, &Extensions::depthTextures>, RequireESOrExtOrExt<3, &Extensions::depthTextures, &Extensions::packedDepthStencil>, AlwaysSupported ))); + map.insert(InternalFormatInfoPair(GL_DEPTH32F_STENCIL8, DepthStencilFormat(32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireES<3>, RequireES<3>, AlwaysSupported ))); + // STENCIL_INDEX8 is special-cased, see around the bottom of the list. + + // Luminance alpha formats + // | Internal format | | L | A | Format | Type | Component type | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_ALPHA8_EXT, LUMAFormat( 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE8_EXT, LUMAFormat( 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_ALPHA32F_EXT, LUMAFormat( 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE32F_EXT, LUMAFormat(32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_ALPHA16F_EXT, LUMAFormat( 0, 16, GL_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE16F_EXT, LUMAFormat(16, 0, GL_LUMINANCE, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE8_ALPHA8_EXT, LUMAFormat( 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA32F_EXT, LUMAFormat(32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA16F_EXT, LUMAFormat(16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); + + // Unsized formats + // | Internal format | | Format | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_ALPHA, UnsizedFormat(GL_ALPHA, RequireES<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE, UnsizedFormat(GL_LUMINANCE, RequireES<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA, UnsizedFormat(GL_LUMINANCE_ALPHA, RequireES<2>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RED, UnsizedFormat(GL_RED, RequireESOrExt<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RG, UnsizedFormat(GL_RG, RequireESOrExt<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGB, UnsizedFormat(GL_RGB, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RGBA, UnsizedFormat(GL_RGBA, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_RED_INTEGER, UnsizedFormat(GL_RED_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RG_INTEGER, UnsizedFormat(GL_RG_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RGB_INTEGER, UnsizedFormat(GL_RGB_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_RGBA_INTEGER, UnsizedFormat(GL_RGBA_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); + map.insert(InternalFormatInfoPair(GL_BGRA_EXT, UnsizedFormat(GL_BGRA_EXT, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT, UnsizedFormat(GL_DEPTH_COMPONENT, RequireES<2>, RequireES<2>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_DEPTH_STENCIL, UnsizedFormat(GL_DEPTH_STENCIL, RequireESOrExt<3, &Extensions::packedDepthStencil>, RequireESOrExt<3, &Extensions::packedDepthStencil>, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB_EXT, UnsizedFormat(GL_RGB, RequireESOrExt<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_SRGB_ALPHA_EXT, UnsizedFormat(GL_RGBA, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported))); + + // Compressed formats, From ES 3.0.1 spec, table 3.16 + // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_COMPRESSED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); + + // From GL_EXT_texture_compression_dxt1 + // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported))); + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported))); + + // From GL_ANGLE_texture_compression_dxt3 + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported))); + + // From GL_ANGLE_texture_compression_dxt5 + map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported))); + + // For STENCIL_INDEX8 we chose a normalized component type for the following reasons: + // - Multisampled buffer are disallowed for non-normalized integer component types and we want to support it for STENCIL_INDEX8 + // - All other stencil formats (all depth-stencil) are either float or normalized + // - It affects only validation of internalformat in RenderbufferStorageMultisample. + // | Internal format | |D |S |X | Format | Type | Component type | Supported | Renderable | Filterable | + map.insert(InternalFormatInfoPair(GL_STENCIL_INDEX8, DepthStencilFormat(0, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, NeverSupported))); + + return map; +} + +static const InternalFormatInfoMap &GetInternalFormatMap() +{ + static const InternalFormatInfoMap formatMap = BuildInternalFormatInfoMap(); + return formatMap; +} + +static FormatSet BuildAllSizedInternalFormatSet() +{ + FormatSet result; + + const InternalFormatInfoMap &formats = GetInternalFormatMap(); + for (InternalFormatInfoMap::const_iterator i = formats.begin(); i != formats.end(); i++) + { + if (i->second.pixelBytes > 0) + { + result.insert(i->first); + } + } + + return result; +} + +const Type &GetTypeInfo(GLenum type) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + { + static const Type info = GenTypeInfo(1, false); + return info; + } + case GL_UNSIGNED_SHORT: + case GL_SHORT: + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + { + static const Type info = GenTypeInfo(2, false); + return info; + } + case GL_UNSIGNED_INT: + case GL_INT: + case GL_FLOAT: + { + static const Type info = GenTypeInfo(4, false); + return info; + } + 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_4_4_4_4_REV_EXT: + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: + { + static const Type info = GenTypeInfo(2, true); + return info; + } + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_24_8: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + { + ASSERT(GL_UNSIGNED_INT_24_8_OES == GL_UNSIGNED_INT_24_8); + static const Type info = GenTypeInfo(4, true); + return info; + } + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + { + static const Type info = GenTypeInfo(8, true); + return info; + } + default: + { + static const Type defaultInfo; + return defaultInfo; + } + } +} + +const InternalFormat &GetInternalFormatInfo(GLenum internalFormat) +{ + const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); + InternalFormatInfoMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + static const InternalFormat defaultInternalFormat; + return defaultInternalFormat; + } +} + +GLuint InternalFormat::computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength) const +{ + ASSERT(alignment > 0 && isPow2(alignment)); + GLuint rowBytes; + if (rowLength > 0) + { + ASSERT(!compressed); + rowBytes = pixelBytes * rowLength; + } + else + { + rowBytes = computeBlockSize(formatType, width, 1); + } + return rx::roundUp(rowBytes, static_cast(alignment)); +} + +GLuint InternalFormat::computeDepthPitch(GLenum formatType, GLsizei width, GLsizei height, GLint alignment, GLint rowLength) const +{ + return computeRowPitch(formatType, width, alignment, rowLength) * height; +} + +GLuint InternalFormat::computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const +{ + if (compressed) + { + GLsizei numBlocksWide = (width + compressedBlockWidth - 1) / compressedBlockWidth; + GLsizei numBlocksHight = (height + compressedBlockHeight - 1) / compressedBlockHeight; + return (pixelBytes * numBlocksWide * numBlocksHight); + } + else + { + const Type &typeInfo = GetTypeInfo(formatType); + if (typeInfo.specialInterpretation) + { + return typeInfo.bytes * width * height; + } + else + { + return componentCount * typeInfo.bytes * width * height; + } + } +} + +GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type) +{ + const InternalFormat& formatInfo = GetInternalFormatInfo(internalFormat); + if (formatInfo.pixelBytes > 0) + { + return internalFormat; + } + else + { + static const FormatMap formatMap = BuildFormatMap(); + FormatMap::const_iterator iter = formatMap.find(FormatTypePair(internalFormat, type)); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + return GL_NONE; + } + } +} + +const FormatSet &GetAllSizedInternalFormats() +{ + static FormatSet formatSet = BuildAllSizedInternalFormatSet(); + return formatSet; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/formatutils.h b/src/3rdparty/angle/src/libANGLE/formatutils.h new file mode 100644 index 0000000000..37d4a8f8ef --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/formatutils.h @@ -0,0 +1,81 @@ +// +// Copyright (c) 2013 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. +// + +// formatutils.h: Queries for GL image formats. + +#ifndef LIBANGLE_FORMATUTILS_H_ +#define LIBANGLE_FORMATUTILS_H_ + +#include "libANGLE/Caps.h" +#include "libANGLE/angletypes.h" + +#include "angle_gl.h" + +#include +#include + +namespace gl +{ + +struct Type +{ + Type(); + + GLuint bytes; + GLuint bytesShift; // Bit shift by this value to effectively divide/multiply by "bytes" in a more optimal way + bool specialInterpretation; +}; +const Type &GetTypeInfo(GLenum type); + +struct InternalFormat +{ + InternalFormat(); + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + + GLuint luminanceBits; + + GLuint alphaBits; + GLuint sharedBits; + + GLuint depthBits; + GLuint stencilBits; + + GLuint pixelBytes; + + GLuint componentCount; + + bool compressed; + GLuint compressedBlockWidth; + GLuint compressedBlockHeight; + + GLenum format; + GLenum type; + + GLenum componentType; + GLenum colorEncoding; + + typedef bool (*SupportCheckFunction)(GLuint, const Extensions &); + SupportCheckFunction textureSupport; + SupportCheckFunction renderSupport; + SupportCheckFunction filterSupport; + + GLuint computeRowPitch(GLenum formatType, GLsizei width, GLint alignment, GLint rowLength) const; + GLuint computeDepthPitch(GLenum formatType, GLsizei width, GLsizei height, GLint alignment, GLint rowLength) const; + GLuint computeBlockSize(GLenum formatType, GLsizei width, GLsizei height) const; +}; +const InternalFormat &GetInternalFormatInfo(GLenum internalFormat); + +GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type); + +typedef std::set FormatSet; +const FormatSet &GetAllSizedInternalFormats(); + +} + +#endif // LIBANGLE_FORMATUTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.cpp b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp new file mode 100644 index 0000000000..460e346eac --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/queryconversions.cpp @@ -0,0 +1,147 @@ +// +// Copyright (c) 2014 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. +// + +// queryconversions.cpp: Implementation of state query cast conversions + +#include "libANGLE/Context.h" +#include "common/utilities.h" + +namespace gl +{ + +// Helper class for converting a GL type to a GLenum: +// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap. +// We restrict our use to CastStateValue, where it eliminates duplicate parameters. + +template +struct CastStateValueEnum { static GLenum mEnumForType; }; + +template <> GLenum CastStateValueEnum::mEnumForType = GL_INT; +template <> GLenum CastStateValueEnum::mEnumForType = GL_UNSIGNED_INT; +template <> GLenum CastStateValueEnum::mEnumForType = GL_BOOL; +template <> GLenum CastStateValueEnum::mEnumForType = GL_INT_64_ANGLEX; +template <> GLenum CastStateValueEnum::mEnumForType = GL_FLOAT; + +template +QueryT CastStateValueToInt(GLenum pname, NativeT value) +{ + GLenum queryType = CastStateValueEnum::mEnumForType; + GLenum nativeType = CastStateValueEnum::mEnumForType; + + if (nativeType == GL_FLOAT) + { + // RGBA color values and DepthRangeF values are converted to integer using Equation 2.4 from Table 4.5 + if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR) + { + return static_cast((static_cast(0xFFFFFFFF) * value - 1.0f) / 2.0f); + } + else + { + return gl::iround(value); + } + } + + // Clamp 64-bit int values when casting to int + if (nativeType == GL_INT_64_ANGLEX && queryType == GL_INT) + { + GLint64 minIntValue = static_cast(std::numeric_limits::min()); + GLint64 maxIntValue = static_cast(std::numeric_limits::max()); + GLint64 clampedValue = std::max(std::min(static_cast(value), maxIntValue), minIntValue); + return static_cast(clampedValue); + } + + return static_cast(value); +} + +template +QueryT CastStateValue(GLenum pname, NativeT value) +{ + GLenum queryType = CastStateValueEnum::mEnumForType; + + switch (queryType) + { + case GL_INT: return CastStateValueToInt(pname, value); + case GL_INT_64_ANGLEX: return CastStateValueToInt(pname, value); + case GL_FLOAT: return static_cast(value); + case GL_BOOL: return (value == static_cast(0) ? GL_FALSE : GL_TRUE); + default: UNREACHABLE(); return 0; + } +} + +template +void CastStateValues(Context *context, GLenum nativeType, GLenum pname, + unsigned int numParams, QueryT *outParams) +{ + if (nativeType == GL_INT) + { + GLint *intParams = NULL; + intParams = new GLint[numParams]; + + context->getIntegerv(pname, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastStateValue(pname, intParams[i]); + } + + delete [] intParams; + } + else if (nativeType == GL_BOOL) + { + GLboolean *boolParams = NULL; + boolParams = new GLboolean[numParams]; + + context->getBooleanv(pname, boolParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = (boolParams[i] == GL_FALSE ? static_cast(0) : static_cast(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) + { + outParams[i] = CastStateValue(pname, floatParams[i]); + } + + delete [] floatParams; + } + else if (nativeType == GL_INT_64_ANGLEX) + { + GLint64 *int64Params = NULL; + int64Params = new GLint64[numParams]; + + context->getInteger64v(pname, int64Params); + + for (unsigned int i = 0; i < numParams; ++i) + { + outParams[i] = CastStateValue(pname, int64Params[i]); + } + + delete [] int64Params; + } + else UNREACHABLE(); +} + +// Explicit template instantiation (how we export template functions in different files) +// The calls below will make CastStateValues successfully link with the GL state query types +// The GL state query API types are: bool, int, uint, float, int64 + +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLboolean *); +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint *); +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLuint *); +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLfloat *); +template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint64 *); + +} diff --git a/src/3rdparty/angle/src/libANGLE/queryconversions.h b/src/3rdparty/angle/src/libANGLE/queryconversions.h new file mode 100644 index 0000000000..da7047f730 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/queryconversions.h @@ -0,0 +1,17 @@ +// +// Copyright (c) 2014 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. +// + +// queryconversions.h: Declaration of state query cast conversions + +namespace gl +{ + +// The GL state query API types are: bool, int, uint, float, int64 +template +void CastStateValues(Context *context, GLenum nativeType, GLenum pname, + unsigned int numParams, QueryT *outParams); + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h new file mode 100644 index 0000000000..9bc5eaff58 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/BufferImpl.h @@ -0,0 +1,38 @@ +// +// Copyright 2014 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. +// + +// BufferImpl.h: Defines the abstract rx::BufferImpl class. + +#ifndef LIBANGLE_RENDERER_BUFFERIMPL_H_ +#define LIBANGLE_RENDERER_BUFFERIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Buffer.h" + +#include + +namespace rx +{ + +class BufferImpl : angle::NonCopyable +{ + public: + virtual ~BufferImpl() { } + + virtual gl::Error setData(const void* data, size_t size, GLenum usage) = 0; + virtual gl::Error setSubData(const void* data, size_t size, size_t offset) = 0; + virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) = 0; + virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) = 0; + virtual gl::Error unmap() = 0; + + // This method may not have a corresponding GL-backed function. It is necessary + // for validation, for certain indexed draw calls. + virtual gl::Error getData(const uint8_t **outData) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_BUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h new file mode 100644 index 0000000000..ccc78d8c2a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/CompilerImpl.h @@ -0,0 +1,30 @@ +// +// Copyright (c) 2014 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. +// + +// CompilerImpl.h: Defines the rx::CompilerImpl class, an implementation interface +// for the gl::Compiler object. + +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +#ifndef LIBANGLE_RENDERER_COMPILERIMPL_H_ +#define LIBANGLE_RENDERER_COMPILERIMPL_H_ + +namespace rx +{ + +class CompilerImpl : angle::NonCopyable +{ + public: + CompilerImpl() {} + virtual ~CompilerImpl() {} + + virtual gl::Error release() = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_COMPILERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp new file mode 100644 index 0000000000..7713ee2d6d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2014 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. +// + +// DisplayImpl.cpp: Implementation methods of egl::Display + +#include "libANGLE/renderer/DisplayImpl.h" + +#include "libANGLE/Surface.h" + +namespace rx +{ + +DisplayImpl::DisplayImpl() + : mExtensionsInitialized(false), + mCapsInitialized(false) +{ +} + +DisplayImpl::~DisplayImpl() +{ + while (!mSurfaceSet.empty()) + { + destroySurface(*mSurfaceSet.begin()); + } +} + +void DisplayImpl::destroySurface(egl::Surface *surface) +{ + mSurfaceSet.erase(surface); + surface->release(); +} + +const egl::DisplayExtensions &DisplayImpl::getExtensions() const +{ + if (!mExtensionsInitialized) + { + generateExtensions(&mExtensions); + mExtensionsInitialized = true; + } + + return mExtensions; +} + +const egl::Caps &DisplayImpl::getCaps() const +{ + if (!mCapsInitialized) + { + generateCaps(&mCaps); + mCapsInitialized = true; + } + + return mCaps; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h new file mode 100644 index 0000000000..381fa67f71 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/DisplayImpl.h @@ -0,0 +1,99 @@ +// +// Copyright (c) 2014 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. +// + +// DisplayImpl.h: Implementation methods of egl::Display + +#ifndef LIBANGLE_RENDERER_DISPLAYIMPL_H_ +#define LIBANGLE_RENDERER_DISPLAYIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Config.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/Renderer.h" + +#include +#include + +namespace egl +{ +class AttributeMap; +class Display; +struct Config; +class Surface; +} + +namespace gl +{ +class Context; +} + +namespace rx +{ +class SurfaceImpl; +struct ConfigDesc; + +class DisplayImpl : angle::NonCopyable +{ + public: + DisplayImpl(); + virtual ~DisplayImpl(); + + virtual egl::Error initialize(egl::Display *display) = 0; + virtual void terminate() = 0; + + virtual egl::Error createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) = 0; + virtual egl::Error createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) = 0; + virtual egl::Error createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) = 0; + virtual egl::Error createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) = 0; + virtual egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs, + gl::Context **outContext) = 0; + + virtual egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) = 0; + + virtual egl::ConfigSet generateConfigs() const = 0; + + virtual bool isDeviceLost() const = 0; + virtual bool testDeviceLost() = 0; + virtual egl::Error restoreLostDevice() = 0; + + virtual bool isValidNativeWindow(EGLNativeWindowType window) const = 0; + + virtual std::string getVendorString() const = 0; + + const egl::Caps &getCaps() const; + + typedef std::set SurfaceSet; + const SurfaceSet &getSurfaceSet() const { return mSurfaceSet; } + SurfaceSet &getSurfaceSet() { return mSurfaceSet; } + + void destroySurface(egl::Surface *surface); + + const egl::DisplayExtensions &getExtensions() const; + + protected: + // Place the surface set here so it can be accessible for handling + // context loss events. (It is shared between the Display and Impl.) + SurfaceSet mSurfaceSet; + + private: + virtual void generateExtensions(egl::DisplayExtensions *outExtensions) const = 0; + virtual void generateCaps(egl::Caps *outCaps) const = 0; + + mutable bool mExtensionsInitialized; + mutable egl::DisplayExtensions mExtensions; + + mutable bool mCapsInitialized; + mutable egl::Caps mCaps; +}; + +} + +#endif // LIBANGLE_RENDERER_DISPLAYIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h new file mode 100644 index 0000000000..3463921d6e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/FenceNVImpl.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2015 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. +// + +// FenceNVImpl.h: Defines the rx::FenceNVImpl class. + +#ifndef LIBANGLE_RENDERER_FENCENVIMPL_H_ +#define LIBANGLE_RENDERER_FENCENVIMPL_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ + +class FenceNVImpl : angle::NonCopyable +{ + public: + FenceNVImpl() { }; + virtual ~FenceNVImpl() { }; + + virtual gl::Error set() = 0; + virtual gl::Error test(bool flushCommandBuffer, GLboolean *outFinished) = 0; + virtual gl::Error finishFence(GLboolean *outFinished) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_FENCENVIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h new file mode 100644 index 0000000000..321964113f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/FenceSyncImpl.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2015 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. +// + +// FenceSyncImpl.h: Defines the rx::FenceSyncImpl class. + +#ifndef LIBANGLE_RENDERER_FENCESYNCIMPL_H_ +#define LIBANGLE_RENDERER_FENCESYNCIMPL_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +namespace rx +{ + +class FenceSyncImpl : angle::NonCopyable +{ + public: + FenceSyncImpl() { }; + virtual ~FenceSyncImpl() { }; + + virtual gl::Error set() = 0; + virtual gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) = 0; + virtual gl::Error serverWait(GLbitfield flags, GLuint64 timeout) = 0; + virtual gl::Error getStatus(GLint *outResult) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_FENCESYNCIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h new file mode 100644 index 0000000000..728f949a0f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/FramebufferImpl.h @@ -0,0 +1,68 @@ +// +// Copyright 2014 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. +// + +// FramebufferImpl.h: Defines the abstract rx::FramebufferImpl class. + +#ifndef LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ +#define LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ + +#include "angle_gl.h" +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/Framebuffer.h" + +namespace gl +{ +class State; +class Framebuffer; +class FramebufferAttachment; +struct Rectangle; +} + +namespace rx +{ + +class FramebufferImpl : angle::NonCopyable +{ + public: + explicit FramebufferImpl(const gl::Framebuffer::Data &data) : mData(data) { } + virtual ~FramebufferImpl() { } + + virtual void setColorAttachment(size_t index, const gl::FramebufferAttachment *attachment) = 0; + virtual void setDepthAttachment(const gl::FramebufferAttachment *attachment) = 0; + virtual void setStencilAttachment(const gl::FramebufferAttachment *attachment) = 0; + virtual void setDepthStencilAttachment(const gl::FramebufferAttachment *attachment) = 0; + + virtual void setDrawBuffers(size_t count, const GLenum *buffers) = 0; + virtual void setReadBuffer(GLenum buffer) = 0; + + virtual gl::Error invalidate(size_t count, const GLenum *attachments) = 0; + virtual gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) = 0; + + virtual gl::Error clear(const gl::Data &data, GLbitfield mask) = 0; + virtual gl::Error clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) = 0; + virtual gl::Error clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) = 0; + virtual gl::Error clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) = 0; + virtual gl::Error clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) = 0; + + virtual GLenum getImplementationColorReadFormat() const = 0; + virtual GLenum getImplementationColorReadType() const = 0; + virtual gl::Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const = 0; + + virtual gl::Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) = 0; + + virtual GLenum checkStatus() const = 0; + + const gl::Framebuffer::Data &getData() const { return mData; } + + protected: + const gl::Framebuffer::Data &mData; +}; + +} + +#endif // LIBANGLE_RENDERER_FRAMEBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Image.h b/src/3rdparty/angle/src/libANGLE/renderer/Image.h new file mode 100644 index 0000000000..62d854c9b6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Image.h @@ -0,0 +1,77 @@ +// +// 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. +// + +// Image.h: Defines the rx::Image class, an abstract base class for the +// renderer-specific classes which will define the interface to the underlying +// surfaces or resources. + +#ifndef LIBANGLE_RENDERER_IMAGE_H_ +#define LIBANGLE_RENDERER_IMAGE_H_ + +#include "common/debug.h" +#include "libANGLE/Error.h" + +#include + +namespace gl +{ +class Framebuffer; +struct Rectangle; +struct Extents; +struct Box; +struct Offset; +struct ImageIndex; +} + +namespace rx +{ +class RendererD3D; +class RenderTarget; +class TextureStorage; + +class Image +{ + public: + Image(); + virtual ~Image() {}; + + GLsizei getWidth() const { return mWidth; } + GLsizei getHeight() const { return mHeight; } + GLsizei getDepth() const { return mDepth; } + GLenum getInternalFormat() const { return mInternalFormat; } + GLenum getTarget() const { return mTarget; } + bool isRenderableFormat() const { return mRenderable; } + + void markDirty() {mDirty = true;} + void markClean() {mDirty = false;} + virtual bool isDirty() const = 0; + + virtual bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) = 0; + + virtual gl::Error loadData(const gl::Box &area, GLint unpackAlignment, GLenum type, const void *input) = 0; + virtual gl::Error loadCompressedData(const gl::Box &area, const void *input) = 0; + + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) = 0; + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; + + protected: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + bool mRenderable; + GLenum mTarget; + + bool mDirty; + + private: + DISALLOW_COPY_AND_ASSIGN(Image); +}; + +} + +#endif // LIBANGLE_RENDERER_IMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h b/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h new file mode 100644 index 0000000000..d77e59f7df --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ImplFactory.h @@ -0,0 +1,68 @@ +// +// Copyright 2015 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. +// +// ImplFactory.h: +// Factory interface for Impl objects. +// + +#ifndef LIBANGLE_RENDERER_IMPLFACTORY_H_ +#define LIBANGLE_RENDERER_IMPLFACTORY_H_ + +#include "libANGLE/Framebuffer.h" + +namespace rx +{ +class BufferImpl; +class CompilerImpl; +class FenceNVImpl; +class FenceSyncImpl; +class FramebufferImpl; +class ProgramImpl; +class QueryImpl; +class RenderbufferImpl; +class ShaderImpl; +class TextureImpl; +class TransformFeedbackImpl; +class VertexArrayImpl; + +class ImplFactory : angle::NonCopyable +{ + public: + ImplFactory() {} + virtual ~ImplFactory() {} + + // Shader creation + virtual CompilerImpl *createCompiler(const gl::Data &data) = 0; + virtual ShaderImpl *createShader(GLenum type) = 0; + virtual ProgramImpl *createProgram() = 0; + + // Framebuffer creation + virtual FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) = 0; + virtual FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) = 0; + + // Texture creation + virtual TextureImpl *createTexture(GLenum target) = 0; + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer() = 0; + + // Buffer creation + virtual BufferImpl *createBuffer() = 0; + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray() = 0; + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type) = 0; + virtual FenceNVImpl *createFenceNV() = 0; + virtual FenceSyncImpl *createFenceSync() = 0; + + // Transform Feedback creation + virtual TransformFeedbackImpl *createTransformFeedback() = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_IMPLFACTORY_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp new file mode 100644 index 0000000000..4a71cf4b45 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.cpp @@ -0,0 +1,114 @@ +// +// Copyright (c) 2013 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. +// + +// IndexRangeCache.cpp: Defines the rx::IndexRangeCache class which stores information about +// ranges of indices. + +#include "libANGLE/renderer/IndexRangeCache.h" +#include "libANGLE/formatutils.h" + +#include "common/debug.h" + +namespace rx +{ + +template +static RangeUI ComputeTypedRange(const IndexType *indices, GLsizei count) +{ + unsigned int minIndex = indices[0]; + unsigned int maxIndex = indices[0]; + + for (GLsizei i = 1; i < count; i++) + { + if (minIndex > indices[i]) minIndex = indices[i]; + if (maxIndex < indices[i]) maxIndex = indices[i]; + } + + return RangeUI(minIndex, maxIndex); +} + +RangeUI IndexRangeCache::ComputeRange(GLenum type, const GLvoid *indices, GLsizei count) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + return ComputeTypedRange(static_cast(indices), count); + case GL_UNSIGNED_INT: + return ComputeTypedRange(static_cast(indices), count); + case GL_UNSIGNED_SHORT: + return ComputeTypedRange(static_cast(indices), count); + default: + UNREACHABLE(); + return RangeUI(); + } +} + +void IndexRangeCache::addRange(GLenum type, unsigned int offset, GLsizei count, const RangeUI &range) +{ + mIndexRangeCache[IndexRange(type, offset, count)] = range; +} + +void IndexRangeCache::invalidateRange(unsigned int offset, unsigned int size) +{ + unsigned int invalidateStart = offset; + unsigned int invalidateEnd = offset + size; + + IndexRangeMap::iterator i = mIndexRangeCache.begin(); + while (i != mIndexRangeCache.end()) + { + unsigned int rangeStart = i->first.offset; + unsigned int rangeEnd = i->first.offset + (gl::GetTypeInfo(i->first.type).bytes * i->first.count); + + if (invalidateEnd < rangeStart || invalidateStart > rangeEnd) + { + ++i; + } + else + { + mIndexRangeCache.erase(i++); + } + } +} + +bool IndexRangeCache::findRange(GLenum type, unsigned int offset, GLsizei count, + RangeUI *outRange) const +{ + IndexRangeMap::const_iterator i = mIndexRangeCache.find(IndexRange(type, offset, count)); + if (i != mIndexRangeCache.end()) + { + if (outRange) *outRange = i->second; + return true; + } + else + { + if (outRange) *outRange = RangeUI(0, 0); + return false; + } +} + +void IndexRangeCache::clear() +{ + mIndexRangeCache.clear(); +} + +IndexRangeCache::IndexRange::IndexRange() + : type(GL_NONE), offset(0), count(0) +{ +} + +IndexRangeCache::IndexRange::IndexRange(GLenum typ, intptr_t off, GLsizei c) + : type(typ), offset(off), count(c) +{ +} + +bool IndexRangeCache::IndexRange::operator<(const IndexRange& rhs) const +{ + if (type != rhs.type) return type < rhs.type; + if (offset != rhs.offset) return offset < rhs.offset; + return count < rhs.count; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h new file mode 100644 index 0000000000..77249f5ff6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/IndexRangeCache.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2013 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. +// + +// IndexRangeCache.h: Defines the rx::IndexRangeCache class which stores information about +// ranges of indices. + +#ifndef LIBANGLE_RENDERER_INDEXRANGECACHE_H_ +#define LIBANGLE_RENDERER_INDEXRANGECACHE_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" + +#include "angle_gl.h" + +#include + +namespace rx +{ + +class IndexRangeCache +{ + public: + void addRange(GLenum type, unsigned int offset, GLsizei count, const RangeUI &range); + bool findRange(GLenum type, unsigned int offset, GLsizei count, RangeUI *rangeOut) const; + + void invalidateRange(unsigned int offset, unsigned int size); + void clear(); + + static RangeUI ComputeRange(GLenum type, const GLvoid *indices, GLsizei count); + + private: + struct IndexRange + { + GLenum type; + unsigned int offset; + GLsizei count; + + IndexRange(); + IndexRange(GLenum type, intptr_t offset, GLsizei count); + + bool operator<(const IndexRange& rhs) const; + }; + + typedef std::map IndexRangeMap; + IndexRangeMap mIndexRangeCache; +}; + +} + +#endif // LIBANGLE_RENDERER_INDEXRANGECACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp new file mode 100644 index 0000000000..8fbc53768f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.cpp @@ -0,0 +1,152 @@ +// +// Copyright (c) 2014 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. +// + +// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. + +#include "libANGLE/renderer/ProgramImpl.h" + +#include "common/utilities.h" + +namespace rx +{ + +namespace +{ + +unsigned int ParseAndStripArrayIndex(std::string* name) +{ + unsigned int subscript = GL_INVALID_INDEX; + + // 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); + } + + return subscript; +} + +} + +LinkResult::LinkResult(bool linkSuccess, const gl::Error &error) + : linkSuccess(linkSuccess), + error(error) +{ +} + +ProgramImpl::~ProgramImpl() +{ + // Ensure that reset was called by the inherited class during destruction + ASSERT(mUniformIndex.size() == 0); +} + +gl::LinkedUniform *ProgramImpl::getUniformByLocation(GLint location) const +{ + ASSERT(location >= 0 && static_cast(location) < mUniformIndex.size()); + return mUniforms[mUniformIndex[location].index]; +} + +gl::LinkedUniform *ProgramImpl::getUniformByName(const std::string &name) const +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + if (mUniforms[uniformIndex]->name == name) + { + return mUniforms[uniformIndex]; + } + } + + return NULL; +} + +gl::UniformBlock *ProgramImpl::getUniformBlockByIndex(GLuint blockIndex) const +{ + ASSERT(blockIndex < mUniformBlocks.size()); + return mUniformBlocks[blockIndex]; +} + +GLint ProgramImpl::getUniformLocation(std::string name) +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + unsigned int numUniforms = mUniformIndex.size(); + for (unsigned int location = 0; location < numUniforms; location++) + { + if (mUniformIndex[location].name == name) + { + const int index = mUniformIndex[location].index; + const bool isArray = mUniforms[index]->isArray(); + + if ((isArray && mUniformIndex[location].element == subscript) || + (subscript == GL_INVALID_INDEX)) + { + return location; + } + } + } + + return -1; +} + +GLuint ProgramImpl::getUniformIndex(std::string name) +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + // The app is not allowed to specify array indices other than 0 for arrays of basic types + if (subscript != 0 && subscript != GL_INVALID_INDEX) + { + return GL_INVALID_INDEX; + } + + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + if (mUniforms[index]->name == name) + { + if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX) + { + return index; + } + } + } + + return GL_INVALID_INDEX; +} + +GLuint ProgramImpl::getUniformBlockIndex(std::string name) const +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + unsigned int numUniformBlocks = mUniformBlocks.size(); + for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) + { + const gl::UniformBlock &uniformBlock = *mUniformBlocks[blockIndex]; + if (uniformBlock.name == name) + { + const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0); + if (subscript == uniformBlock.elementIndex || arrayElementZero) + { + return blockIndex; + } + } + } + + return GL_INVALID_INDEX; +} + +void ProgramImpl::reset() +{ + std::fill(mSemanticIndex, mSemanticIndex + ArraySize(mSemanticIndex), -1); + SafeDeleteContainer(mUniforms); + mUniformIndex.clear(); + SafeDeleteContainer(mUniformBlocks); + mTransformFeedbackLinkedVaryings.clear(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h new file mode 100644 index 0000000000..1128ab6741 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ProgramImpl.h @@ -0,0 +1,137 @@ +// +// Copyright 2014 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. +// + +// ProgramImpl.h: Defines the abstract rx::ProgramImpl class. + +#ifndef LIBANGLE_RENDERER_PROGRAMIMPL_H_ +#define LIBANGLE_RENDERER_PROGRAMIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/BinaryStream.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Program.h" +#include "libANGLE/Shader.h" +#include "libANGLE/renderer/Renderer.h" + +#include + +namespace rx +{ + +struct LinkResult +{ + bool linkSuccess; + gl::Error error; + LinkResult(bool linkSuccess, const gl::Error &error); +}; + +class ProgramImpl : angle::NonCopyable +{ + public: + typedef int SemanticIndexArray[gl::MAX_VERTEX_ATTRIBS]; + + ProgramImpl() { } + virtual ~ProgramImpl(); + + virtual bool usesPointSize() const = 0; + virtual int getShaderVersion() const = 0; + virtual GLenum getTransformFeedbackBufferMode() const = 0; + + virtual GLenum getBinaryFormat() = 0; + virtual LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; + virtual gl::Error save(gl::BinaryOutputStream *stream) = 0; + + virtual LinkResult link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables) = 0; + + virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform1iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform2iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform3iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform4iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + + virtual void getUniformfv(GLint location, GLfloat *params) = 0; + virtual void getUniformiv(GLint location, GLint *params) = 0; + virtual void getUniformuiv(GLint location, GLuint *params) = 0; + + // TODO: The following functions are possibly only applicable to D3D backends. The should be carefully evaluated to + // determine if they can be removed from this interface. + virtual GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const = 0; + virtual GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const = 0; + virtual GLint getUsedSamplerRange(gl::SamplerType type) const = 0; + virtual void updateSamplerMapping() = 0; + virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0; + + virtual LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers) = 0; + + virtual bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps) = 0; + virtual bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, + const gl::Caps &caps) = 0; + + virtual gl::Error applyUniforms() = 0; + virtual gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) = 0; + virtual bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps) = 0; + + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getUniformIndices() const { return mUniformIndex; } + const std::vector &getUniformBlocks() const { return mUniformBlocks; } + const std::vector &getTransformFeedbackLinkedVaryings() const { return mTransformFeedbackLinkedVaryings; } + const sh::Attribute *getShaderAttributes() const { return mShaderAttributes; } + const SemanticIndexArray &getSemanticIndexes() const { return mSemanticIndex; } + + std::vector &getUniforms() { return mUniforms; } + std::vector &getUniformIndices() { return mUniformIndex; } + std::vector &getUniformBlocks() { return mUniformBlocks; } + std::vector &getTransformFeedbackLinkedVaryings() { return mTransformFeedbackLinkedVaryings; } + sh::Attribute *getShaderAttributes() { return mShaderAttributes; } + SemanticIndexArray &getSemanticIndexes() { return mSemanticIndex; } + + gl::LinkedUniform *getUniformByLocation(GLint location) const; + gl::LinkedUniform *getUniformByName(const std::string &name) const; + gl::UniformBlock *getUniformBlockByIndex(GLuint blockIndex) const; + + GLint getUniformLocation(std::string name); + GLuint getUniformIndex(std::string name); + GLuint getUniformBlockIndex(std::string name) const; + + virtual void reset(); + + protected: + std::vector mUniforms; + std::vector mUniformIndex; + std::vector mUniformBlocks; + std::vector mTransformFeedbackLinkedVaryings; + + SemanticIndexArray mSemanticIndex; + sh::Attribute mShaderAttributes[gl::MAX_VERTEX_ATTRIBS]; +}; + +} + +#endif // LIBANGLE_RENDERER_PROGRAMIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h new file mode 100644 index 0000000000..bed63ea1b0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/QueryImpl.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2013 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. +// + +// QueryImpl.h: Defines the abstract rx::QueryImpl class. + +#ifndef LIBANGLE_RENDERER_QUERYIMPL_H_ +#define LIBANGLE_RENDERER_QUERYIMPL_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +#include + +namespace rx +{ + +class QueryImpl : angle::NonCopyable +{ + public: + explicit QueryImpl(GLenum type) { mType = type; } + virtual ~QueryImpl() { } + + virtual gl::Error begin() = 0; + virtual gl::Error end() = 0; + virtual gl::Error getResult(GLuint *params) = 0; + virtual gl::Error isResultAvailable(GLuint *available) = 0; + + GLenum getType() const { return mType; } + + private: + GLenum mType; +}; + +} + +#endif // LIBANGLE_RENDERER_QUERYIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp new file mode 100644 index 0000000000..ea5a40a21a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.cpp @@ -0,0 +1,21 @@ +// +// Copyright (c) 2014 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. +// + +// RenderbufferImpl.h: Implements the shared methods of the abstract class gl::RenderbufferImpl + +#include "libANGLE/renderer/RenderbufferImpl.h" + +namespace rx +{ +RenderbufferImpl::RenderbufferImpl() +{ +} + +RenderbufferImpl::~RenderbufferImpl() +{ +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h new file mode 100644 index 0000000000..8ce257c833 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/RenderbufferImpl.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2014 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. +// + +// RenderbufferImpl.h: Defines the abstract class gl::RenderbufferImpl + +#ifndef LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ +#define LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ + +#include "angle_gl.h" + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" + +namespace rx +{ + +class RenderbufferImpl : angle::NonCopyable +{ + public: + RenderbufferImpl(); + virtual ~RenderbufferImpl() = 0; + + virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) = 0; + virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_RENDERBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp new file mode 100644 index 0000000000..fbc2ad5d1c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.cpp @@ -0,0 +1,72 @@ +// +// Copyright (c) 2012-2014 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. +// + +// Renderer.cpp: Implements EGL dependencies for creating and destroying Renderer instances. + +#include "common/utilities.h" +#include "libANGLE/AttributeMap.h" +#include "libANGLE/renderer/Renderer.h" + +#include + +namespace rx +{ + +Renderer::Renderer() + : mCapsInitialized(false), + mWorkaroundsInitialized(false) +{ +} + +Renderer::~Renderer() +{ +} + +const gl::Caps &Renderer::getRendererCaps() const +{ + if (!mCapsInitialized) + { + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; + } + + return mCaps; +} + +const gl::TextureCapsMap &Renderer::getRendererTextureCaps() const +{ + if (!mCapsInitialized) + { + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; + } + + return mTextureCaps; +} + +const gl::Extensions &Renderer::getRendererExtensions() const +{ + if (!mCapsInitialized) + { + generateCaps(&mCaps, &mTextureCaps, &mExtensions); + mCapsInitialized = true; + } + + return mExtensions; +} + +const Workarounds &Renderer::getWorkarounds() const +{ + if (!mWorkaroundsInitialized) + { + mWorkarounds = generateWorkarounds(); + mWorkaroundsInitialized = true; + } + + return mWorkarounds; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h new file mode 100644 index 0000000000..b607fe5613 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Renderer.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2012-2014 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. +// + +// Renderer.h: Defines a back-end specific class that hides the details of the +// implementation-specific renderer. + +#ifndef LIBANGLE_RENDERER_RENDERER_H_ +#define LIBANGLE_RENDERER_RENDERER_H_ + +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/ImplFactory.h" +#include "libANGLE/renderer/Workarounds.h" +#include "common/mathutil.h" + +#include + +#include + +namespace egl +{ +class AttributeMap; +class Display; +class Surface; +} + +namespace gl +{ +class Buffer; +struct Data; +} + +namespace rx +{ +struct TranslatedIndexData; +struct Workarounds; +class DisplayImpl; + +class Renderer : public ImplFactory +{ + public: + Renderer(); + virtual ~Renderer(); + + virtual gl::Error flush() = 0; + virtual gl::Error finish() = 0; + + virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, + GLint first, GLsizei count, GLsizei instances) = 0; + virtual gl::Error drawElements(const gl::Data &data, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) = 0; + + // lost device + //TODO(jmadill): investigate if this stuff is necessary in GL + virtual void notifyDeviceLost() = 0; + virtual bool isDeviceLost() const = 0; + virtual bool testDeviceLost() = 0; + virtual bool testDeviceResettable() = 0; + + virtual VendorID getVendorId() const = 0; + virtual std::string getVendorString() const = 0; + virtual std::string getRendererDescription() const = 0; + + // Renderer capabilities + const gl::Caps &getRendererCaps() const; + const gl::TextureCapsMap &getRendererTextureCaps() const; + const gl::Extensions &getRendererExtensions() const; + const Workarounds &getWorkarounds() const; + + private: + virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const = 0; + virtual Workarounds generateWorkarounds() const = 0; + + mutable bool mCapsInitialized; + mutable gl::Caps mCaps; + mutable gl::TextureCapsMap mTextureCaps; + mutable gl::Extensions mExtensions; + + mutable bool mWorkaroundsInitialized; + mutable Workarounds mWorkarounds; +}; + +} +#endif // LIBANGLE_RENDERER_RENDERER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h new file mode 100644 index 0000000000..3011bc57f8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/ShaderImpl.h @@ -0,0 +1,57 @@ +// +// Copyright 2014 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. +// + +// ShaderImpl.h: Defines the abstract rx::ShaderImpl class. + +#ifndef LIBANGLE_RENDERER_SHADERIMPL_H_ +#define LIBANGLE_RENDERER_SHADERIMPL_H_ + +#include + +#include "common/angleutils.h" +#include "libANGLE/Shader.h" + +namespace rx +{ + +class ShaderImpl : angle::NonCopyable +{ + public: + ShaderImpl() { } + virtual ~ShaderImpl() { } + + virtual bool compile(gl::Compiler *compiler, const std::string &source) = 0; + virtual std::string getDebugInfo() const = 0; + + virtual const std::string &getInfoLog() const { return mInfoLog; } + virtual const std::string &getTranslatedSource() const { return mTranslatedSource; } + + const std::vector &getVaryings() const { return mVaryings; } + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getInterfaceBlocks() const { return mInterfaceBlocks; } + const std::vector &getActiveAttributes() const { return mActiveAttributes; } + const std::vector &getActiveOutputVariables() const { return mActiveOutputVariables; } + + std::vector &getVaryings() { return mVaryings; } + std::vector &getUniforms() { return mUniforms; } + std::vector &getInterfaceBlocks() { return mInterfaceBlocks; } + std::vector &getActiveAttributes() { return mActiveAttributes; } + std::vector &getActiveOutputVariables() { return mActiveOutputVariables; } + + protected: + std::string mInfoLog; + std::string mTranslatedSource; + + std::vector mVaryings; + std::vector mUniforms; + std::vector mInterfaceBlocks; + std::vector mActiveAttributes; + std::vector mActiveOutputVariables; +}; + +} + +#endif // LIBANGLE_RENDERER_SHADERIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp new file mode 100644 index 0000000000..36f5fdca3f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.cpp @@ -0,0 +1,22 @@ +// +// Copyright (c) 2002-2014 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. +// + +// SurfaceImpl.cpp: Implementation of Surface stub method class + +#include "libANGLE/renderer/SurfaceImpl.h" + +namespace rx +{ + +SurfaceImpl::SurfaceImpl() +{ +} + +SurfaceImpl::~SurfaceImpl() +{ +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h new file mode 100644 index 0000000000..ca04a42bd1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/SurfaceImpl.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2014 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. +// + +// SurfaceImpl.h: Implementation methods of egl::Surface + +#ifndef LIBANGLE_RENDERER_SURFACEIMPL_H_ +#define LIBANGLE_RENDERER_SURFACEIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +namespace egl +{ +class Display; +struct Config; +} + +namespace rx +{ + +class SurfaceImpl : angle::NonCopyable +{ + public: + SurfaceImpl(); + virtual ~SurfaceImpl(); + + virtual egl::Error initialize() = 0; + virtual egl::Error swap() = 0; + virtual egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) = 0; + virtual egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) = 0; + virtual egl::Error bindTexImage(EGLint buffer) = 0; + virtual egl::Error releaseTexImage(EGLint buffer) = 0; + virtual void setSwapInterval(EGLint interval) = 0; + + // width and height can change with client window resizing + virtual EGLint getWidth() const = 0; + virtual EGLint getHeight() const = 0; + + virtual EGLint isPostSubBufferSupported() const = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_SURFACEIMPL_H_ + diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h new file mode 100644 index 0000000000..d628906116 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/TextureImpl.h @@ -0,0 +1,72 @@ +// +// Copyright 2014 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. +// + +// TextureImpl.h: Defines the abstract rx::TextureImpl classes. + +#ifndef LIBANGLE_RENDERER_TEXTUREIMPL_H_ +#define LIBANGLE_RENDERER_TEXTUREIMPL_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/ImageIndex.h" + +#include "common/angleutils.h" + +#include "angle_gl.h" + +#include + +namespace egl +{ +class Surface; +} + +namespace gl +{ +struct Box; +struct Extents; +struct Offset; +struct Rectangle; +class Framebuffer; +struct PixelUnpackState; +struct SamplerState; +} + +namespace rx +{ + +class TextureImpl : angle::NonCopyable +{ + public: + virtual ~TextureImpl() {}; + + virtual void setUsage(GLenum usage) = 0; + + virtual gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; + virtual gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; + + virtual gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; + virtual gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) = 0; + + virtual gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) = 0; + virtual gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) = 0; + + virtual gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) = 0; + + virtual gl::Error generateMipmaps() = 0; + + virtual void bindTexImage(egl::Surface *surface) = 0; + virtual void releaseTexImage() = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_TEXTUREIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h new file mode 100644 index 0000000000..8f9133cfe5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/TransformFeedbackImpl.h @@ -0,0 +1,31 @@ +// +// Copyright 2014 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. +// + +// TransformFeedbackImpl.h: Defines the abstract rx::TransformFeedbackImpl class. + +#ifndef LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPL_H_ +#define LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/TransformFeedback.h" + +namespace rx +{ + +class TransformFeedbackImpl : angle::NonCopyable +{ + public: + virtual ~TransformFeedbackImpl() { } + + virtual void begin(GLenum primitiveMode) = 0; + virtual void end() = 0; + virtual void pause() = 0; + virtual void resume() = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_TRANSFORMFEEDBACKIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h new file mode 100644 index 0000000000..0e25f952c2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/VertexArrayImpl.h @@ -0,0 +1,32 @@ +// +// Copyright 2014 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. +// + +// VertexAttribImpl.h: Defines the abstract rx::VertexAttribImpl class. + +#ifndef LIBANGLE_RENDERER_VERTEXARRAYIMPL_H_ +#define LIBANGLE_RENDERER_VERTEXARRAYIMPL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/VertexAttribute.h" + +namespace rx +{ + +class VertexArrayImpl : angle::NonCopyable +{ + public: + virtual ~VertexArrayImpl() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) = 0; + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) = 0; + virtual void setAttributeDivisor(size_t idx, GLuint divisor) = 0; + virtual void enableAttribute(size_t idx, bool enabledState) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_VERTEXARRAYIMPL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h b/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h new file mode 100644 index 0000000000..b73f4a5472 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/Workarounds.h @@ -0,0 +1,74 @@ +// +// Copyright (c) 2014 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. +// + +// angletypes.h: Workarounds for driver bugs and other issues. + +#ifndef LIBANGLE_RENDERER_WORKAROUNDS_H_ +#define LIBANGLE_RENDERER_WORKAROUNDS_H_ + +// TODO(jmadill,zmo,geofflang): make a workarounds library that can operate +// independent of ANGLE's renderer. Workarounds should also be accessible +// outside of the Renderer. + +namespace rx +{ + +struct D3DCompilerWorkarounds : angle::NonCopyable +{ + D3DCompilerWorkarounds() + : skipOptimization(false), + useMaxOptimization(false), + enableIEEEStrictness(false) + {} + + void reset() + { + skipOptimization = false; + useMaxOptimization = false; + enableIEEEStrictness = false; + } + + bool skipOptimization; + bool useMaxOptimization; + + // IEEE strictness needs to be enabled for NANs to work. + bool enableIEEEStrictness; +}; + +struct Workarounds +{ + Workarounds() + : mrtPerfWorkaround(false), + setDataFasterThanImageUpload(false), + zeroMaxLodWorkaround(false), + useInstancedPointSpriteEmulation(false) + {} + + // On some systems, having extra rendertargets than necessary slows down the shader. + // We can fix this by optimizing those out of the shader. At the same time, we can + // work around a bug on some nVidia drivers that they ignore "null" render targets + // in D3D11, by compacting the active color attachments list to omit null entries. + bool mrtPerfWorkaround; + + bool setDataFasterThanImageUpload; + + // Some renderers can't disable mipmaps on a mipmapped texture (i.e. solely sample from level zero, and ignore the other levels). + // D3D11 Feature Level 10+ does this by setting MaxLOD to 0.0f in the Sampler state. D3D9 sets D3DSAMP_MIPFILTER to D3DTEXF_NONE. + // There is no equivalent to this in D3D11 Feature Level 9_3. + // This causes problems when (for example) an application creates a mipmapped texture2D, but sets GL_TEXTURE_MIN_FILTER to GL_NEAREST (i.e disables mipmaps). + // To work around this, D3D11 FL9_3 has to create two copies of the texture. The textures' level zeros are identical, but only one texture has mips. + bool zeroMaxLodWorkaround; + + // Some renderers do not support Geometry Shaders so the Geometry Shader-based + // PointSprite emulation will not work. + // To work around this, D3D11 FL9_3 has to use a different pointsprite + // emulation that is implemented using instanced quads. + bool useInstancedPointSpriteEmulation; +}; + +} + +#endif // LIBANGLE_RENDERER_WORKAROUNDS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp new file mode 100644 index 0000000000..1af8794356 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.cpp @@ -0,0 +1,80 @@ +// +// Copyright 2014 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. +// + +// BufferD3D.cpp Defines common functionality between the Buffer9 and Buffer11 classes. + +#include "libANGLE/renderer/d3d/BufferD3D.h" + +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/VertexBuffer.h" + +namespace rx +{ + +unsigned int BufferD3D::mNextSerial = 1; + +BufferD3D::BufferD3D(BufferFactoryD3D *factory) + : BufferImpl(), + mFactory(factory), + mStaticVertexBuffer(nullptr), + mStaticIndexBuffer(nullptr), + mUnmodifiedDataUse(0) +{ + updateSerial(); +} + +BufferD3D::~BufferD3D() +{ + SafeDelete(mStaticVertexBuffer); + SafeDelete(mStaticIndexBuffer); +} + +void BufferD3D::updateSerial() +{ + mSerial = mNextSerial++; +} + +void BufferD3D::initializeStaticData() +{ + if (!mStaticVertexBuffer) + { + mStaticVertexBuffer = new StaticVertexBufferInterface(mFactory); + } + if (!mStaticIndexBuffer) + { + mStaticIndexBuffer = new StaticIndexBufferInterface(mFactory); + } +} + +void BufferD3D::invalidateStaticData() +{ + if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0)) + { + SafeDelete(mStaticVertexBuffer); + SafeDelete(mStaticIndexBuffer); + + // Re-init static data to track that we're in a static buffer + initializeStaticData(); + } + + mUnmodifiedDataUse = 0; +} + +// Creates static buffers if sufficient used data has been left unmodified +void BufferD3D::promoteStaticUsage(int dataSize) +{ + if (!mStaticVertexBuffer && !mStaticIndexBuffer) + { + mUnmodifiedDataUse += dataSize; + + if (mUnmodifiedDataUse > 3 * getSize()) + { + initializeStaticData(); + } + } +} + +} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h new file mode 100644 index 0000000000..a46398f911 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/BufferD3D.h @@ -0,0 +1,56 @@ +// +// Copyright 2014 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. +// + +// BufferD3D.h: Defines the rx::BufferD3D class, an implementation of BufferImpl. + +#ifndef LIBANGLE_RENDERER_D3D_BUFFERD3D_H_ +#define LIBANGLE_RENDERER_D3D_BUFFERD3D_H_ + +#include "libANGLE/renderer/BufferImpl.h" +#include "libANGLE/angletypes.h" + +#include + +namespace rx +{ +class BufferFactoryD3D; +class StaticIndexBufferInterface; +class StaticVertexBufferInterface; + +class BufferD3D : public BufferImpl +{ + public: + BufferD3D(BufferFactoryD3D *factory); + virtual ~BufferD3D(); + + unsigned int getSerial() const { return mSerial; } + + virtual size_t getSize() const = 0; + virtual bool supportsDirectBinding() const = 0; + virtual void markTransformFeedbackUsage() = 0; + + StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; } + StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; } + + void initializeStaticData(); + void invalidateStaticData(); + void promoteStaticUsage(int dataSize); + + protected: + void updateSerial(); + + BufferFactoryD3D *mFactory; + unsigned int mSerial; + static unsigned int mNextSerial; + + StaticVertexBufferInterface *mStaticVertexBuffer; + StaticIndexBufferInterface *mStaticIndexBuffer; + unsigned int mUnmodifiedDataUse; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_BUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp new file mode 100644 index 0000000000..a22757cf9f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.cpp @@ -0,0 +1,128 @@ +// +// Copyright (c) 2014 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. +// + +// CompilerD3D.cpp: Implementation of the rx::CompilerD3D class. + +#include "libANGLE/renderer/d3d/CompilerD3D.h" + +#include "libANGLE/Caps.h" +#include "libANGLE/Data.h" + +#include "common/debug.h" + +namespace rx +{ + +// Global count of active shader compiler handles. Needed to know when to call ShInitialize and ShFinalize. +static size_t activeCompilerHandles = 0; + +CompilerD3D::CompilerD3D(const gl::Data &data, ShShaderOutput outputType) + : mSpec(data.clientVersion > 2 ? SH_GLES3_SPEC : SH_GLES2_SPEC), + mOutputType(outputType), + mResources(), + mFragmentCompiler(NULL), + mVertexCompiler(NULL) +{ + ASSERT(data.clientVersion == 2 || data.clientVersion == 3); + + const gl::Caps &caps = *data.caps; + const gl::Extensions &extensions = *data.extensions; + + ShInitBuiltInResources(&mResources); + mResources.MaxVertexAttribs = caps.maxVertexAttributes; + mResources.MaxVertexUniformVectors = caps.maxVertexUniformVectors; + mResources.MaxVaryingVectors = caps.maxVaryingVectors; + mResources.MaxVertexTextureImageUnits = caps.maxVertexTextureImageUnits; + mResources.MaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; + mResources.MaxTextureImageUnits = caps.maxTextureImageUnits; + mResources.MaxFragmentUniformVectors = caps.maxFragmentUniformVectors; + mResources.MaxDrawBuffers = caps.maxDrawBuffers; + mResources.OES_standard_derivatives = extensions.standardDerivatives; + mResources.EXT_draw_buffers = extensions.drawBuffers; + mResources.EXT_shader_texture_lod = 1; + // resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported. + mResources.FragmentPrecisionHigh = 1; // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp + mResources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output + + // GLSL ES 3.0 constants + mResources.MaxVertexOutputVectors = caps.maxVertexOutputComponents / 4; + mResources.MaxFragmentInputVectors = caps.maxFragmentInputComponents / 4; + mResources.MinProgramTexelOffset = caps.minProgramTexelOffset; + mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset; +} + +CompilerD3D::~CompilerD3D() +{ + release(); +} + +CompilerD3D *CompilerD3D::makeCompilerD3D(CompilerImpl *compiler) +{ + ASSERT(HAS_DYNAMIC_TYPE(CompilerD3D*, compiler)); + return static_cast(compiler); +} + +gl::Error CompilerD3D::release() +{ + if (mFragmentCompiler) + { + ShDestruct(mFragmentCompiler); + mFragmentCompiler = NULL; + + ASSERT(activeCompilerHandles > 0); + activeCompilerHandles--; + } + + if (mVertexCompiler) + { + ShDestruct(mVertexCompiler); + mVertexCompiler = NULL; + + ASSERT(activeCompilerHandles > 0); + activeCompilerHandles--; + } + + if (activeCompilerHandles == 0) + { + ShFinalize(); + } + + return gl::Error(GL_NO_ERROR); +} + +ShHandle CompilerD3D::getCompilerHandle(GLenum type) +{ + ShHandle *compiler = NULL; + switch (type) + { + case GL_VERTEX_SHADER: + compiler = &mVertexCompiler; + break; + + case GL_FRAGMENT_SHADER: + compiler = &mFragmentCompiler; + break; + + default: + UNREACHABLE(); + return NULL; + } + + if (!(*compiler)) + { + if (activeCompilerHandles == 0) + { + ShInitialize(); + } + + *compiler = ShConstructCompiler(type, mSpec, mOutputType, &mResources); + activeCompilerHandles++; + } + + return *compiler; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h new file mode 100644 index 0000000000..0f83e4f8c8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/CompilerD3D.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2014 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. +// + +// CompilerD3D.h: Defines the rx::CompilerD3D class, an implementation of rx::CompilerImpl. + +#ifndef LIBANGLE_RENDERER_COMPILERD3D_H_ +#define LIBANGLE_RENDERER_COMPILERD3D_H_ + +#include "libANGLE/renderer/CompilerImpl.h" +#include "libANGLE/Caps.h" + +#include "GLSLANG/ShaderLang.h" + +namespace gl +{ +struct Data; +} + +namespace rx +{ + +class CompilerD3D : public CompilerImpl +{ + public: + CompilerD3D(const gl::Data &data, ShShaderOutput outputType); + virtual ~CompilerD3D(); + + static CompilerD3D *makeCompilerD3D(CompilerImpl *compiler); + + gl::Error release() override; + + ShHandle getCompilerHandle(GLenum type); + + private: + ShShaderSpec mSpec; + ShShaderOutput mOutputType; + ShBuiltInResources mResources; + + ShHandle mFragmentCompiler; + ShHandle mVertexCompiler; +}; + +} + +#endif // LIBANGLE_RENDERER_COMPILERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp new file mode 100644 index 0000000000..add5d62fae --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp @@ -0,0 +1,357 @@ +// +// Copyright (c) 2014 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. +// + +// DisplayD3D.cpp: D3D implementation of egl::Display + +#include "libANGLE/renderer/d3d/DisplayD3D.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Config.h" +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "platform/Platform.h" + +#include + +#if defined (ANGLE_ENABLE_D3D9) +# include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#endif // ANGLE_ENABLE_D3D9 + +#if defined (ANGLE_ENABLE_D3D11) +# include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#endif // ANGLE_ENABLE_D3D11 + +#if defined (ANGLE_TEST_CONFIG) +# define ANGLE_DEFAULT_D3D11 1 +#endif + +#if !defined(ANGLE_DEFAULT_D3D11) +// Enables use of the Direct3D 11 API for a default display, when available +# define ANGLE_DEFAULT_D3D11 0 +#endif + +namespace rx +{ + +typedef RendererD3D *(*CreateRendererD3DFunction)(egl::Display*); + +template +static RendererD3D *CreateTypedRendererD3D(egl::Display *display) +{ + return new RendererType(display); +} + +egl::Error CreateRendererD3D(egl::Display *display, RendererD3D **outRenderer) +{ + ASSERT(outRenderer != nullptr); + + std::vector rendererCreationFunctions; + + const auto &attribMap = display->getAttributeMap(); + EGLNativeDisplayType nativeDisplay = display->getNativeDisplayId(); + + EGLint requestedDisplayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + +# if defined(ANGLE_ENABLE_D3D11) + if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || + nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE || + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + rendererCreationFunctions.push_back(CreateTypedRendererD3D); + } +# endif + +# if defined(ANGLE_ENABLE_D3D9) + if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE) + { + rendererCreationFunctions.push_back(CreateTypedRendererD3D); + } +# endif + + if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE && + nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE && + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) + { + // The default display is requested, try the D3D9 and D3D11 renderers, order them using + // the definition of ANGLE_DEFAULT_D3D11 +# if ANGLE_DEFAULT_D3D11 +# if defined(ANGLE_ENABLE_D3D11) + rendererCreationFunctions.push_back(CreateTypedRendererD3D); +# endif +# if defined(ANGLE_ENABLE_D3D9) + rendererCreationFunctions.push_back(CreateTypedRendererD3D); +# endif +# else +# if defined(ANGLE_ENABLE_D3D9) + rendererCreationFunctions.push_back(CreateTypedRendererD3D); +# endif +# if defined(ANGLE_ENABLE_D3D11) + rendererCreationFunctions.push_back(CreateTypedRendererD3D); +# endif +# endif + } + + egl::Error result(EGL_NOT_INITIALIZED, "No available renderers."); + for (size_t i = 0; i < rendererCreationFunctions.size(); i++) + { + RendererD3D *renderer = rendererCreationFunctions[i](display); + result = renderer->initialize(); + +# if defined(ANGLE_ENABLE_D3D11) + if (renderer->getRendererClass() == RENDERER_D3D11) + { + ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D11_INIT_ERRORS); + + angle::Platform *platform = ANGLEPlatformCurrent(); + platform->histogramEnumeration("GPU.ANGLE.D3D11InitializeResult", + result.getID(), NUM_D3D11_INIT_ERRORS); + } +# endif + +# if defined(ANGLE_ENABLE_D3D9) + if (renderer->getRendererClass() == RENDERER_D3D9) + { + ASSERT(result.getID() >= 0 && result.getID() < NUM_D3D9_INIT_ERRORS); + + angle::Platform *platform = ANGLEPlatformCurrent(); + platform->histogramEnumeration("GPU.ANGLE.D3D9InitializeResult", + result.getID(), NUM_D3D9_INIT_ERRORS); + } +# endif + + if (!result.isError()) + { + *outRenderer = renderer; + break; + } + else + { + // Failed to create the renderer, try the next + SafeDelete(renderer); + } + } + + return result; +} + +DisplayD3D::DisplayD3D() + : mRenderer(nullptr) +{ +} + +egl::Error DisplayD3D::createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) +{ + ASSERT(mRenderer != nullptr); + + EGLint width = attribs.get(EGL_WIDTH, 0); + EGLint height = attribs.get(EGL_HEIGHT, 0); + EGLint fixedSize = attribs.get(EGL_FIXED_SIZE_ANGLE, EGL_FALSE); + + if (!fixedSize) + { + width = -1; + height = -1; + } + + SurfaceD3D *surface = SurfaceD3D::createFromWindow(mRenderer, mDisplay, configuration, window, fixedSize, + width, height); + egl::Error error = surface->initialize(); + if (error.isError()) + { + SafeDelete(surface); + return error; + } + + *outSurface = surface; + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) +{ + ASSERT(mRenderer != nullptr); + + EGLint width = attribs.get(EGL_WIDTH, 0); + EGLint height = attribs.get(EGL_HEIGHT, 0); + + SurfaceD3D *surface = SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, NULL, width, height); + egl::Error error = surface->initialize(); + if (error.isError()) + { + SafeDelete(surface); + return error; + } + + *outSurface = surface; + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) +{ + ASSERT(mRenderer != nullptr); + + EGLint width = attribs.get(EGL_WIDTH, 0); + EGLint height = attribs.get(EGL_HEIGHT, 0); + + SurfaceD3D *surface = SurfaceD3D::createOffscreen(mRenderer, mDisplay, configuration, shareHandle, + width, height); + egl::Error error = surface->initialize(); + if (error.isError()) + { + SafeDelete(surface); + return error; + } + + *outSurface = surface; + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) +{ + ASSERT(mRenderer != nullptr); + + UNIMPLEMENTED(); + *outSurface = nullptr; + return egl::Error(EGL_BAD_DISPLAY); +} + +egl::Error DisplayD3D::createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs, + gl::Context **outContext) +{ + ASSERT(mRenderer != nullptr); + + EGLint clientVersion = attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1); + bool notifyResets = (attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_NO_RESET_NOTIFICATION_EXT) == EGL_LOSE_CONTEXT_ON_RESET_EXT); + bool robustAccess = (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE); + + *outContext = new gl::Context(config, clientVersion, shareContext, mRenderer, notifyResets, robustAccess); + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error DisplayD3D::initialize(egl::Display *display) +{ + ASSERT(mRenderer == nullptr && display != nullptr); + mDisplay = display; + return CreateRendererD3D(display, &mRenderer); +} + +void DisplayD3D::terminate() +{ + SafeDelete(mRenderer); +} + +egl::ConfigSet DisplayD3D::generateConfigs() const +{ + ASSERT(mRenderer != nullptr); + return mRenderer->generateConfigs(); +} + +bool DisplayD3D::isDeviceLost() const +{ + ASSERT(mRenderer != nullptr); + return mRenderer->isDeviceLost(); +} + +bool DisplayD3D::testDeviceLost() +{ + ASSERT(mRenderer != nullptr); + return mRenderer->testDeviceLost(); +} + +egl::Error DisplayD3D::restoreLostDevice() +{ + // Release surface resources to make the Reset() succeed + for (auto it = mSurfaceSet.cbegin(); it != mSurfaceSet.cend(); ++it) + { + const auto &surface = *it; + if (surface->getBoundTexture()) + { + surface->releaseTexImage(EGL_BACK_BUFFER); + } + SurfaceD3D *surfaceD3D = GetImplAs(surface); + surfaceD3D->releaseSwapChain(); + } + + if (!mRenderer->resetDevice()) + { + return egl::Error(EGL_BAD_ALLOC); + } + + // Restore any surfaces that may have been lost + for (auto it = mSurfaceSet.cbegin(); it != mSurfaceSet.cend(); ++it) + { + const auto &surface = *it; + SurfaceD3D *surfaceD3D = GetImplAs(surface); + + egl::Error error = surfaceD3D->resetSwapChain(); + if (error.isError()) + { + return error; + } + } + + return egl::Error(EGL_SUCCESS); +} + +bool DisplayD3D::isValidNativeWindow(EGLNativeWindowType window) const +{ + return NativeWindow::isValidNativeWindow(window); +} + +void DisplayD3D::generateExtensions(egl::DisplayExtensions *outExtensions) const +{ + outExtensions->createContextRobustness = true; + + // ANGLE-specific extensions + if (mRenderer->getShareHandleSupport()) + { + outExtensions->d3dShareHandleClientBuffer = true; + outExtensions->surfaceD3DTexture2DShareHandle = true; + } + + outExtensions->querySurfacePointer = true; + outExtensions->windowFixedSize = true; + + if (mRenderer->getPostSubBufferSupport()) + { + outExtensions->postSubBuffer = true; + } + + outExtensions->createContext = true; +} + +std::string DisplayD3D::getVendorString() const +{ + std::string vendorString = "Google Inc."; + if (mRenderer) + { + vendorString += " " + mRenderer->getVendorString(); + } + + return vendorString; +} + +void DisplayD3D::generateCaps(egl::Caps *outCaps) const +{ + // Display must be initialized to generate caps + ASSERT(mRenderer != nullptr); + + outCaps->textureNPOT = mRenderer->getRendererExtensions().textureNPOT; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h new file mode 100644 index 0000000000..f007ba9a19 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2014 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. +// + +// DisplayD3D.h: D3D implementation of egl::Display + +#ifndef LIBANGLE_RENDERER_D3D_DISPLAYD3D_H_ +#define LIBANGLE_RENDERER_D3D_DISPLAYD3D_H_ + +#include "libANGLE/renderer/DisplayImpl.h" + +namespace rx +{ +class RendererD3D; + +class DisplayD3D : public DisplayImpl +{ + public: + DisplayD3D(); + + egl::Error initialize(egl::Display *display) override; + virtual void terminate() override; + + egl::Error createWindowSurface(const egl::Config *configuration, EGLNativeWindowType window, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) override; + egl::Error createPbufferSurface(const egl::Config *configuration, const egl::AttributeMap &attribs, + SurfaceImpl **outSurface) override; + egl::Error createPbufferFromClientBuffer(const egl::Config *configuration, EGLClientBuffer shareHandle, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) override; + egl::Error createPixmapSurface(const egl::Config *configuration, NativePixmapType nativePixmap, + const egl::AttributeMap &attribs, SurfaceImpl **outSurface) override; + + egl::Error createContext(const egl::Config *config, const gl::Context *shareContext, const egl::AttributeMap &attribs, + gl::Context **outContext) override; + + egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override; + + egl::ConfigSet generateConfigs() const override; + + bool isDeviceLost() const override; + bool testDeviceLost() override; + egl::Error restoreLostDevice() override; + + bool isValidNativeWindow(EGLNativeWindowType window) const override; + + std::string getVendorString() const override; + + private: + void generateExtensions(egl::DisplayExtensions *outExtensions) const override; + void generateCaps(egl::Caps *outCaps) const override; + + egl::Display *mDisplay; + + rx::RendererD3D *mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_DISPLAYD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp new file mode 100644 index 0000000000..0dbc30ae36 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp @@ -0,0 +1,1265 @@ +// +// Copyright (c) 2014 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. +// +// DynamicHLSL.cpp: Implementation for link and run-time HLSL generation +// + +#include "libANGLE/renderer/d3d/DynamicHLSL.h" + +#include "common/utilities.h" +#include "compiler/translator/blocklayoutHLSL.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/Program.h" +#include "libANGLE/Shader.h" +#include "libANGLE/formatutils.h" + +// For use with ArrayString, see angleutils.h +static_assert(GL_INVALID_INDEX == UINT_MAX, "GL_INVALID_INDEX must be equal to the max unsigned int."); + +using namespace gl; + +namespace rx +{ + +namespace +{ + +std::string HLSLComponentTypeString(GLenum componentType) +{ + switch (componentType) + { + case GL_UNSIGNED_INT: return "uint"; + case GL_INT: return "int"; + case GL_UNSIGNED_NORMALIZED: + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: return "float"; + default: UNREACHABLE(); return "not-component-type"; + } +} + +std::string HLSLComponentTypeString(GLenum componentType, int componentCount) +{ + return HLSLComponentTypeString(componentType) + (componentCount > 1 ? Str(componentCount) : ""); +} + +std::string HLSLMatrixTypeString(GLenum type) +{ + switch (type) + { + case GL_FLOAT_MAT2: return "float2x2"; + case GL_FLOAT_MAT3: return "float3x3"; + case GL_FLOAT_MAT4: return "float4x4"; + case GL_FLOAT_MAT2x3: return "float2x3"; + case GL_FLOAT_MAT3x2: return "float3x2"; + case GL_FLOAT_MAT2x4: return "float2x4"; + case GL_FLOAT_MAT4x2: return "float4x2"; + case GL_FLOAT_MAT3x4: return "float3x4"; + case GL_FLOAT_MAT4x3: return "float4x3"; + default: UNREACHABLE(); return "not-matrix-type"; + } +} + +std::string HLSLTypeString(GLenum type) +{ + if (gl::IsMatrixType(type)) + { + return HLSLMatrixTypeString(type); + } + + return HLSLComponentTypeString(gl::VariableComponentType(type), gl::VariableComponentCount(type)); +} + +const PixelShaderOutputVariable *FindOutputAtLocation(const std::vector &outputVariables, + unsigned int location) +{ + for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex) + { + if (outputVariables[variableIndex].outputIndex == location) + { + return &outputVariables[variableIndex]; + } + } + + return NULL; +} + +const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; +const std::string PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; + +} + +DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) + : mRenderer(renderer) +{ +} + +static bool packVarying(PackedVarying *varying, const int maxVaryingVectors, VaryingPacking packing) +{ + // Make sure we use transposed matrix types to count registers correctly. + int registers = 0; + int elements = 0; + + if (varying->isStruct()) + { + registers = HLSLVariableRegisterCount(*varying, true) * varying->elementCount(); + elements = 4; + } + else + { + GLenum transposedType = TransposeMatrixType(varying->type); + registers = VariableRowCount(transposedType) * varying->elementCount(); + elements = VariableColumnCount(transposedType); + } + + if (elements >= 2 && elements <= 4) + { + for (int r = 0; r <= maxVaryingVectors - registers; r++) + { + bool available = true; + + for (int y = 0; y < registers && available; y++) + { + for (int x = 0; x < elements && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->registerIndex = r; + varying->columnIndex = 0; + + for (int y = 0; y < registers; y++) + { + for (int x = 0; x < elements; x++) + { + packing[r + y][x] = &*varying; + } + } + + return true; + } + } + + if (elements == 2) + { + for (int r = maxVaryingVectors - registers; r >= 0; r--) + { + bool available = true; + + for (int y = 0; y < registers && available; y++) + { + for (int x = 2; x < 4 && available; x++) + { + if (packing[r + y][x]) + { + available = false; + } + } + } + + if (available) + { + varying->registerIndex = r; + varying->columnIndex = 2; + + for (int y = 0; y < registers; y++) + { + for (int x = 2; x < 4; x++) + { + packing[r + y][x] = &*varying; + } + } + + return true; + } + } + } + } + else if (elements == 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] >= registers && (space[column] < registers || space[x] < space[column])) + { + column = x; + } + } + + if (space[column] >= registers) + { + for (int r = 0; r < maxVaryingVectors; r++) + { + if (!packing[r][column]) + { + varying->registerIndex = r; + varying->columnIndex = column; + + for (int y = r; y < r + registers; y++) + { + packing[y][column] = &*varying; + } + + break; + } + } + + return true; + } + } + else UNREACHABLE(); + + return false; +} + +// 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 DynamicHLSL::packVaryings(InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader, + ShaderD3D *vertexShader, const std::vector &transformFeedbackVaryings) +{ + // TODO (geofflang): Use context's caps + const int maxVaryingVectors = mRenderer->getRendererCaps().maxVaryingVectors; + + vertexShader->resetVaryingsRegisterAssignment(); + fragmentShader->resetVaryingsRegisterAssignment(); + + std::set packedVaryings; + + std::vector &fragmentVaryings = fragmentShader->getVaryings(); + std::vector &vertexVaryings = vertexShader->getVaryings(); + for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++) + { + PackedVarying *varying = &fragmentVaryings[varyingIndex]; + + // Do not assign registers to built-in or unreferenced varyings + if (varying->isBuiltIn() || !varying->staticUse) + { + continue; + } + + if (packVarying(varying, maxVaryingVectors, packing)) + { + packedVaryings.insert(varying->name); + } + else + { + infoLog.append("Could not pack varying %s", varying->name.c_str()); + return -1; + } + } + + for (unsigned int feedbackVaryingIndex = 0; feedbackVaryingIndex < transformFeedbackVaryings.size(); feedbackVaryingIndex++) + { + const std::string &transformFeedbackVarying = transformFeedbackVaryings[feedbackVaryingIndex]; + + if (transformFeedbackVarying == "gl_Position" || transformFeedbackVarying == "gl_PointSize") + { + // do not pack builtin XFB varyings + continue; + } + + if (packedVaryings.find(transformFeedbackVarying) == packedVaryings.end()) + { + bool found = false; + for (unsigned int varyingIndex = 0; varyingIndex < vertexVaryings.size(); varyingIndex++) + { + PackedVarying *varying = &vertexVaryings[varyingIndex]; + if (transformFeedbackVarying == varying->name) + { + if (!packVarying(varying, maxVaryingVectors, packing)) + { + infoLog.append("Could not pack varying %s", varying->name.c_str()); + return -1; + } + + found = true; + break; + } + } + + if (!found) + { + infoLog.append("Transform feedback varying %s does not exist in the vertex shader.", transformFeedbackVarying.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; +} + +std::string DynamicHLSL::generateVaryingHLSL(const ShaderD3D *shader) const +{ + std::string varyingSemantic = getVaryingSemantic(shader->mUsesPointSize); + std::string varyingHLSL; + + const std::vector &varyings = shader->getVaryings(); + + for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++) + { + const PackedVarying &varying = varyings[varyingIndex]; + if (varying.registerAssigned()) + { + ASSERT(!varying.isBuiltIn()); + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + for (int row = 0; row < variableRows; row++) + { + // TODO: Add checks to ensure D3D interpolation modifiers don't result in too many registers being used. + // For example, if there are N registers, and we have N vec3 varyings and 1 float varying, then D3D will pack them into N registers. + // If the float varying has the 'nointerpolation' modifier on it then we would need N + 1 registers, and D3D compilation will fail. + + switch (varying.interpolation) + { + case sh::INTERPOLATION_SMOOTH: varyingHLSL += " "; break; + case sh::INTERPOLATION_FLAT: varyingHLSL += " nointerpolation "; break; + case sh::INTERPOLATION_CENTROID: varyingHLSL += " centroid "; break; + default: UNREACHABLE(); + } + + unsigned int semanticIndex = elementIndex * variableRows + + varying.columnIndex * mRenderer->getRendererCaps().maxVaryingVectors + + varying.registerIndex + row; + std::string n = Str(semanticIndex); + + std::string typeString; + + if (varying.isStruct()) + { + // TODO(jmadill): pass back translated name from the shader translator + typeString = decorateVariable(varying.structName); + } + else + { + GLenum componentType = VariableComponentType(transposedType); + int columnCount = VariableColumnCount(transposedType); + typeString = HLSLComponentTypeString(componentType, columnCount); + } + varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n"; + } + } + } + } + + return varyingHLSL; +} + +std::string DynamicHLSL::generateVertexShaderForInputLayout(const std::string &sourceShader, + const VertexFormat inputLayout[], + const sh::Attribute shaderAttributes[]) const +{ + std::string structHLSL, initHLSL; + + int semanticIndex = 0; + unsigned int inputIndex = 0; + + // If gl_PointSize is used in the shader then pointsprites rendering is expected. + // If the renderer does not support Geometry shaders then Instanced PointSprite emulation + // must be used. + bool usesPointSize = sourceShader.find("GL_USES_POINT_SIZE") != std::string::npos; + bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation; + + // Instanced PointSprite emulation requires additional entries in the + // VS_INPUT structure to support the vertices that make up the quad vertices. + // These values must be in sync with the cooresponding values added during inputlayout creation + // in InputLayoutCache::applyVertexBuffers(). + // + // The additional entries must appear first in the VS_INPUT layout because + // Windows Phone 8 era devices require per vertex data to physically come + // before per instance data in the shader. + if (useInstancedPointSpriteEmulation) + { + structHLSL += " float3 spriteVertexPos : SPRITEPOSITION0;\n"; + structHLSL += " float2 spriteTexCoord : SPRITETEXCOORD0;\n"; + } + + for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const sh::Attribute &shaderAttribute = shaderAttributes[attributeIndex]; + if (!shaderAttribute.name.empty()) + { + ASSERT(inputIndex < MAX_VERTEX_ATTRIBS); + const VertexFormat &vertexFormat = inputLayout[inputIndex]; + + // HLSL code for input structure + if (IsMatrixType(shaderAttribute.type)) + { + // Matrix types are always transposed + structHLSL += " " + HLSLMatrixTypeString(TransposeMatrixType(shaderAttribute.type)); + } + else + { + GLenum componentType = mRenderer->getVertexComponentType(vertexFormat); + + if (shaderAttribute.name == "gl_InstanceID") + { + // The input type of the instance ID in HLSL (uint) differs from the one in ESSL (int). + structHLSL += " uint"; + } + else + { + structHLSL += " " + HLSLComponentTypeString(componentType, VariableComponentCount(shaderAttribute.type)); + } + } + + structHLSL += " " + decorateVariable(shaderAttribute.name) + " : "; + + if (shaderAttribute.name == "gl_InstanceID") + { + structHLSL += "SV_InstanceID"; + } + else + { + structHLSL += "TEXCOORD" + Str(semanticIndex); + semanticIndex += VariableRegisterCount(shaderAttribute.type); + } + + structHLSL += ";\n"; + + // HLSL code for initialization + initHLSL += " " + decorateVariable(shaderAttribute.name) + " = "; + + // Mismatched vertex attribute to vertex input may result in an undefined + // data reinterpretation (eg for pure integer->float, float->pure integer) + // TODO: issue warning with gl debug info extension, when supported + if (IsMatrixType(shaderAttribute.type) || + (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0) + { + initHLSL += generateAttributeConversionHLSL(vertexFormat, shaderAttribute); + } + else + { + initHLSL += "input." + decorateVariable(shaderAttribute.name); + } + + initHLSL += ";\n"; + + inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type)); + } + } + + std::string replacementHLSL = "struct VS_INPUT\n" + "{\n" + + structHLSL + + "};\n" + "\n" + "void initAttributes(VS_INPUT input)\n" + "{\n" + + initHLSL + + "}\n"; + + std::string vertexHLSL(sourceShader); + + size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING); + vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), replacementHLSL); + + return vertexHLSL; +} + +std::string DynamicHLSL::generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector &outputVariables, + bool usesFragDepth, const std::vector &outputLayout) const +{ + const int shaderModel = mRenderer->getMajorShaderModel(); + std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR"; + std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; + + std::string declarationHLSL; + std::string copyHLSL; + + for (size_t layoutIndex = 0; layoutIndex < outputLayout.size(); ++layoutIndex) + { + GLenum binding = outputLayout[layoutIndex]; + + if (binding != GL_NONE) + { + unsigned int location = (binding - GL_COLOR_ATTACHMENT0); + + const PixelShaderOutputVariable *outputVariable = FindOutputAtLocation(outputVariables, location); + + // OpenGL ES 3.0 spec $4.2.1 + // If [...] not all user-defined output variables are written, the values of fragment colors + // corresponding to unwritten variables are similarly undefined. + if (outputVariable) + { + declarationHLSL += " " + HLSLTypeString(outputVariable->type) + " " + outputVariable->name + + " : " + targetSemantic + Str(layoutIndex) + ";\n"; + + copyHLSL += " output." + outputVariable->name + " = " + outputVariable->source + ";\n"; + } + } + } + + if (usesFragDepth) + { + declarationHLSL += " float gl_Depth : " + depthSemantic + ";\n"; + copyHLSL += " output.gl_Depth = gl_Depth; \n"; + } + + std::string replacementHLSL = "struct PS_OUTPUT\n" + "{\n" + + declarationHLSL + + "};\n" + "\n" + "PS_OUTPUT generateOutput()\n" + "{\n" + " PS_OUTPUT output;\n" + + copyHLSL + + " return output;\n" + "}\n"; + + std::string pixelHLSL(sourceShader); + + size_t outputInsertionPos = pixelHLSL.find(PIXEL_OUTPUT_STUB_STRING); + pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(), replacementHLSL); + + return pixelHLSL; +} + +std::string DynamicHLSL::getVaryingSemantic(bool pointSize) const +{ + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + int shaderModel = mRenderer->getMajorShaderModel(); + return ((pointSize && shaderModel < 4) ? "COLOR" : "TEXCOORD"); +} + +struct DynamicHLSL::SemanticInfo +{ + struct BuiltinInfo + { + BuiltinInfo() + : enabled(false), + index(0), + systemValue(false) + {} + + bool enabled; + std::string semantic; + unsigned int index; + bool systemValue; + + std::string str() const + { + return (systemValue ? semantic : (semantic + Str(index))); + } + + void enableSystem(const std::string &systemValueSemantic) + { + enabled = true; + semantic = systemValueSemantic; + systemValue = true; + } + + void enable(const std::string &semanticVal, unsigned int indexVal) + { + enabled = true; + semantic = semanticVal; + index = indexVal; + } + }; + + BuiltinInfo dxPosition; + BuiltinInfo glPosition; + BuiltinInfo glFragCoord; + BuiltinInfo glPointCoord; + BuiltinInfo glPointSize; +}; + +DynamicHLSL::SemanticInfo DynamicHLSL::getSemanticInfo(int startRegisters, bool position, bool fragCoord, + bool pointCoord, bool pointSize, bool pixelShader) const +{ + SemanticInfo info; + bool hlsl4 = (mRenderer->getMajorShaderModel() >= 4); + const std::string &varyingSemantic = getVaryingSemantic(pointSize); + + int reservedRegisterIndex = startRegisters; + + if (hlsl4) + { + info.dxPosition.enableSystem("SV_Position"); + } + else if (pixelShader) + { + info.dxPosition.enableSystem("VPOS"); + } + else + { + info.dxPosition.enableSystem("POSITION"); + } + + if (position) + { + info.glPosition.enable(varyingSemantic, reservedRegisterIndex++); + } + + if (fragCoord) + { + info.glFragCoord.enable(varyingSemantic, reservedRegisterIndex++); + } + + if (pointCoord) + { + // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) + // In D3D11 we manually compute gl_PointCoord in the GS. + if (hlsl4) + { + info.glPointCoord.enable(varyingSemantic, reservedRegisterIndex++); + } + else + { + info.glPointCoord.enable("TEXCOORD", 0); + } + } + + // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders + if (pointSize && (!pixelShader || hlsl4)) + { + info.glPointSize.enableSystem("PSIZE"); + } + + return info; +} + +std::string DynamicHLSL::generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const +{ + std::string linkHLSL = "{\n"; + + ASSERT(info.dxPosition.enabled); + linkHLSL += " float4 dx_Position : " + info.dxPosition.str() + ";\n"; + + if (info.glPosition.enabled) + { + linkHLSL += " float4 gl_Position : " + info.glPosition.str() + ";\n"; + } + + if (info.glFragCoord.enabled) + { + linkHLSL += " float4 gl_FragCoord : " + info.glFragCoord.str() + ";\n"; + } + + if (info.glPointCoord.enabled) + { + linkHLSL += " float2 gl_PointCoord : " + info.glPointCoord.str() + ";\n"; + } + + if (info.glPointSize.enabled) + { + linkHLSL += " float gl_PointSize : " + info.glPointSize.str() + ";\n"; + } + + // Do this after glPointSize, to potentially combine gl_PointCoord and gl_PointSize into the same register. + linkHLSL += varyingHLSL; + + linkHLSL += "};\n"; + + return linkHLSL; +} + +void DynamicHLSL::storeBuiltinLinkedVaryings(const SemanticInfo &info, + std::vector *linkedVaryings) const +{ + if (info.glPosition.enabled) + { + linkedVaryings->push_back(LinkedVarying("gl_Position", GL_FLOAT_VEC4, 1, info.glPosition.semantic, + info.glPosition.index, 1)); + } + + if (info.glFragCoord.enabled) + { + linkedVaryings->push_back(LinkedVarying("gl_FragCoord", GL_FLOAT_VEC4, 1, info.glFragCoord.semantic, + info.glFragCoord.index, 1)); + } + + if (info.glPointSize.enabled) + { + linkedVaryings->push_back(LinkedVarying("gl_PointSize", GL_FLOAT, 1, "PSIZE", 0, 1)); + } +} + +void DynamicHLSL::storeUserLinkedVaryings(const ShaderD3D *vertexShader, + std::vector *linkedVaryings) const +{ + const std::string &varyingSemantic = getVaryingSemantic(vertexShader->mUsesPointSize); + const std::vector &varyings = vertexShader->getVaryings(); + + for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++) + { + const PackedVarying &varying = varyings[varyingIndex]; + + if (varying.registerAssigned()) + { + ASSERT(!varying.isBuiltIn()); + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + + linkedVaryings->push_back(LinkedVarying(varying.name, varying.type, varying.elementCount(), + varyingSemantic, varying.registerIndex, + variableRows * varying.elementCount())); + } + } +} + +bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog, int registers, + const VaryingPacking packing, + std::string &pixelHLSL, std::string &vertexHLSL, + ShaderD3D *fragmentShader, ShaderD3D *vertexShader, + const std::vector &transformFeedbackVaryings, + std::vector *linkedVaryings, + std::map *programOutputVars, + std::vector *outPixelShaderKey, + bool *outUsesFragDepth) const +{ + if (pixelHLSL.empty() || vertexHLSL.empty()) + { + return false; + } + + bool usesMRT = fragmentShader->mUsesMultipleRenderTargets; + bool usesFragColor = fragmentShader->mUsesFragColor; + bool usesFragData = fragmentShader->mUsesFragData; + bool usesFragCoord = fragmentShader->mUsesFragCoord; + bool usesPointCoord = fragmentShader->mUsesPointCoord; + bool usesPointSize = vertexShader->mUsesPointSize; + bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation; + + if (usesFragColor && usesFragData) + { + infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader."); + return false; + } + + // Write the HLSL input/output declarations + const int shaderModel = mRenderer->getMajorShaderModel(); + const int registersNeeded = registers + (usesFragCoord ? 1 : 0) + (usesPointCoord ? 1 : 0); + + // Two cases when writing to gl_FragColor and using ESSL 1.0: + // - with a 3.0 context, the output color is copied to channel 0 + // - with a 2.0 context, the output color is broadcast to all channels + const bool broadcast = (fragmentShader->mUsesFragColor && data.clientVersion < 3); + const unsigned int numRenderTargets = (broadcast || usesMRT ? data.caps->maxDrawBuffers : 1); + + // gl_Position only needs to be outputted from the vertex shader if transform feedback is active. + // This isn't supported on D3D11 Feature Level 9_3, so we don't output gl_Position from the vertex shader in this case. + // This saves us 1 output vector. + bool outputPositionFromVS = !(shaderModel >= 4 && mRenderer->getShaderModelSuffix() != ""); + + int shaderVersion = vertexShader->getShaderVersion(); + + if (static_cast(registersNeeded) > data.caps->maxVaryingVectors) + { + infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord"); + return false; + } + + const std::string &varyingHLSL = generateVaryingHLSL(vertexShader); + + // Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader VS_OUTPUT + // structure to ensure compatibility with the generated PS_INPUT of the pixel shader. + // GeometryShader PointSprite emulation does not require this additional entry because the + // GS_OUTPUT of the Geometry shader contains the pointCoord value and already matches the PS_INPUT of the + // generated pixel shader. + // The Geometry Shader point sprite implementation needs gl_PointSize to be in VS_OUTPUT and GS_INPUT. + // Instanced point sprites doesn't need gl_PointSize in VS_OUTPUT. + const SemanticInfo &vertexSemantics = getSemanticInfo(registers, outputPositionFromVS, + usesFragCoord, (useInstancedPointSpriteEmulation && usesPointCoord), + (!useInstancedPointSpriteEmulation && usesPointSize), false); + + storeUserLinkedVaryings(vertexShader, linkedVaryings); + storeBuiltinLinkedVaryings(vertexSemantics, linkedVaryings); + + // Instanced PointSprite emulation requires additional entries originally generated in the + // GeometryShader HLSL. These include pointsize clamp values. + if (useInstancedPointSpriteEmulation) + { + vertexHLSL += "static float minPointSize = " + Str((int)mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n" + "static float maxPointSize = " + Str((int)mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n"; + } + + // Add stub string to be replaced when shader is dynamically defined by its layout + vertexHLSL += "\n" + VERTEX_ATTRIBUTE_STUB_STRING + "\n" + "struct VS_OUTPUT\n" + generateVaryingLinkHLSL(vertexSemantics, varyingHLSL) + "\n" + "VS_OUTPUT main(VS_INPUT input)\n" + "{\n" + " initAttributes(input);\n"; + + if (vertexShader->usesDeferredInit()) + { + vertexHLSL += "\n" + " initializeDeferredGlobals();\n"; + } + + vertexHLSL += "\n" + " gl_main();\n" + "\n" + " VS_OUTPUT output;\n"; + + if (outputPositionFromVS) + { + vertexHLSL += " output.gl_Position = gl_Position;\n"; + } + + // On D3D9 or D3D11 Feature Level 9, we need to emulate large viewports using dx_ViewAdjust. + if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") + { + vertexHLSL += " output.dx_Position.x = gl_Position.x;\n" + " output.dx_Position.y = -gl_Position.y;\n" + " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.dx_Position.w = gl_Position.w;\n"; + } + else + { + vertexHLSL += " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n" + " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n" + " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.dx_Position.w = gl_Position.w;\n"; + } + + // We don't need to output gl_PointSize if we use are emulating point sprites via instancing. + if (usesPointSize && shaderModel >= 3 && !useInstancedPointSpriteEmulation) + { + vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; + } + + if (usesFragCoord) + { + vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; + } + + const std::vector &vertexVaryings = vertexShader->getVaryings(); + for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) + { + const PackedVarying &varying = vertexVaryings[vertVaryingIndex]; + if (varying.registerAssigned()) + { + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying.type))); + + for (int row = 0; row < variableRows; row++) + { + int r = varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row; + vertexHLSL += " output.v" + Str(r); + + vertexHLSL += " = _" + varying.name; + + if (varying.isArray()) + { + vertexHLSL += ArrayString(elementIndex); + } + + if (variableRows > 1) + { + vertexHLSL += ArrayString(row); + } + + vertexHLSL += ";\n"; + } + } + } + } + + // Instanced PointSprite emulation requires additional entries to calculate + // the final output vertex positions of the quad that represents each sprite. + if (useInstancedPointSpriteEmulation) + { + vertexHLSL += "\n" + " gl_PointSize = clamp(gl_PointSize, minPointSize, maxPointSize);\n" + " output.dx_Position.xyz += float3(input.spriteVertexPos.x * gl_PointSize / (dx_ViewCoords.x*2), input.spriteVertexPos.y * gl_PointSize / (dx_ViewCoords.y*2), input.spriteVertexPos.z) * output.dx_Position.w;\n"; + + if (usesPointCoord) + { + vertexHLSL += "\n" + " output.gl_PointCoord = input.spriteTexCoord;\n"; + } + } + + vertexHLSL += "\n" + " return output;\n" + "}\n"; + + const SemanticInfo &pixelSemantics = getSemanticInfo(registers, outputPositionFromVS, usesFragCoord, usesPointCoord, + (!useInstancedPointSpriteEmulation && usesPointSize), true); + + pixelHLSL += "struct PS_INPUT\n" + generateVaryingLinkHLSL(pixelSemantics, varyingHLSL) + "\n"; + + if (shaderVersion < 300) + { + for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) + { + PixelShaderOutputVariable outputKeyVariable; + outputKeyVariable.type = GL_FLOAT_VEC4; + outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex); + outputKeyVariable.source = broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]"; + outputKeyVariable.outputIndex = renderTargetIndex; + + outPixelShaderKey->push_back(outputKeyVariable); + } + + *outUsesFragDepth = fragmentShader->mUsesFragDepth; + } + else + { + defineOutputVariables(fragmentShader, programOutputVars); + + const std::vector &shaderOutputVars = fragmentShader->getActiveOutputVariables(); + for (auto locationIt = programOutputVars->begin(); locationIt != programOutputVars->end(); locationIt++) + { + const VariableLocation &outputLocation = locationIt->second; + const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index]; + const std::string &variableName = "out_" + outputLocation.name; + const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element)); + + ASSERT(outputVariable.staticUse); + + PixelShaderOutputVariable outputKeyVariable; + outputKeyVariable.type = outputVariable.type; + outputKeyVariable.name = variableName + elementString; + outputKeyVariable.source = variableName + ArrayString(outputLocation.element); + outputKeyVariable.outputIndex = locationIt->first; + + outPixelShaderKey->push_back(outputKeyVariable); + } + + *outUsesFragDepth = false; + } + + pixelHLSL += PIXEL_OUTPUT_STUB_STRING + "\n"; + + if (fragmentShader->mUsesFrontFacing) + { + if (shaderModel >= 4) + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n" + "{\n"; + } + else + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n" + "{\n"; + } + } + else + { + pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n" + "{\n"; + } + + if (usesFragCoord) + { + pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; + + // Certain Shader Models (4_0+ and 3_0) allow reading from dx_Position in the pixel shader. + // Other Shader Models (4_0_level_9_3 and 2_x) don't support this, so we emulate it using dx_ViewCoords. + if (shaderModel >= 4 && mRenderer->getShaderModelSuffix() == "") + { + pixelHLSL += " gl_FragCoord.x = input.dx_Position.x;\n" + " gl_FragCoord.y = input.dx_Position.y;\n"; + } + else if (shaderModel == 3) + { + pixelHLSL += " gl_FragCoord.x = input.dx_Position.x + 0.5;\n" + " gl_FragCoord.y = input.dx_Position.y + 0.5;\n"; + } + else + { + // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport() + pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n" + " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n"; + } + + pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n" + " gl_FragCoord.w = rhw;\n"; + } + + if (usesPointCoord && shaderModel >= 3) + { + pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; + pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; + } + + if (fragmentShader->mUsesFrontFacing) + { + if (shaderModel <= 3) + { + pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n"; + } + else + { + pixelHLSL += " gl_FrontFacing = isFrontFace;\n"; + } + } + + const std::vector &fragmentVaryings = fragmentShader->getVaryings(); + for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++) + { + const PackedVarying &varying = fragmentVaryings[varyingIndex]; + if (varying.registerAssigned()) + { + ASSERT(!varying.isBuiltIn()); + for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) + { + GLenum transposedType = TransposeMatrixType(varying.type); + int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); + for (int row = 0; row < variableRows; row++) + { + std::string n = Str(varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row); + pixelHLSL += " _" + varying.name; + + if (varying.isArray()) + { + pixelHLSL += ArrayString(elementIndex); + } + + if (variableRows > 1) + { + pixelHLSL += ArrayString(row); + } + + if (varying.isStruct()) + { + pixelHLSL += " = input.v" + n + ";\n"; break; + } + else + { + switch (VariableColumnCount(transposedType)) + { + case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break; + case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break; + case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break; + case 4: pixelHLSL += " = input.v" + n + ";\n"; break; + default: UNREACHABLE(); + } + } + } + } + } + else + { + ASSERT(varying.isBuiltIn() || !varying.staticUse); + } + } + + if (fragmentShader->usesDeferredInit()) + { + pixelHLSL += "\n" + " initializeDeferredGlobals();\n"; + } + + pixelHLSL += "\n" + " gl_main();\n" + "\n" + " return generateOutput();\n" + "}\n"; + + return true; +} + +void DynamicHLSL::defineOutputVariables(ShaderD3D *fragmentShader, std::map *programOutputVars) const +{ + const std::vector &shaderOutputVars = fragmentShader->getActiveOutputVariables(); + + for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size(); outputVariableIndex++) + { + const sh::Attribute &outputVariable = shaderOutputVars[outputVariableIndex]; + const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location; + + ASSERT(outputVariable.staticUse); + + if (outputVariable.arraySize > 0) + { + for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++) + { + const int location = baseLocation + elementIndex; + ASSERT(programOutputVars->count(location) == 0); + (*programOutputVars)[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex); + } + } + else + { + ASSERT(programOutputVars->count(baseLocation) == 0); + (*programOutputVars)[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex); + } + } +} + +std::string DynamicHLSL::generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const +{ + // for now we only handle point sprite emulation + ASSERT(vertexShader->mUsesPointSize && mRenderer->getMajorShaderModel() >= 4); + return generatePointSpriteHLSL(registers, fragmentShader, vertexShader); +} + +std::string DynamicHLSL::generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const +{ + ASSERT(registers >= 0); + ASSERT(vertexShader->mUsesPointSize); + ASSERT(mRenderer->getMajorShaderModel() >= 4); + + std::string geomHLSL; + + const SemanticInfo &inSemantics = getSemanticInfo(registers, true, fragmentShader->mUsesFragCoord, + false, true, false); + const SemanticInfo &outSemantics = getSemanticInfo(registers, true, fragmentShader->mUsesFragCoord, + fragmentShader->mUsesPointCoord, true, false); + + std::string varyingHLSL = generateVaryingHLSL(vertexShader); + std::string inLinkHLSL = generateVaryingLinkHLSL(inSemantics, varyingHLSL); + std::string outLinkHLSL = generateVaryingLinkHLSL(outSemantics, varyingHLSL); + + // TODO(geofflang): use context's caps + geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n" + "\n" + "struct GS_INPUT\n" + inLinkHLSL + "\n" + + "struct GS_OUTPUT\n" + outLinkHLSL + "\n" + + "\n" + "static float2 pointSpriteCorners[] = \n" + "{\n" + " float2( 0.5f, -0.5f),\n" + " float2( 0.5f, 0.5f),\n" + " float2(-0.5f, -0.5f),\n" + " float2(-0.5f, 0.5f)\n" + "};\n" + "\n" + "static float2 pointSpriteTexcoords[] = \n" + "{\n" + " float2(1.0f, 1.0f),\n" + " float2(1.0f, 0.0f),\n" + " float2(0.0f, 1.0f),\n" + " float2(0.0f, 0.0f)\n" + "};\n" + "\n" + "static float minPointSize = " + Str(mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n" + "static float maxPointSize = " + Str(mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n" + "\n" + "[maxvertexcount(4)]\n" + "void main(point GS_INPUT input[1], inout TriangleStream outStream)\n" + "{\n" + " GS_OUTPUT output = (GS_OUTPUT)0;\n" + " output.gl_Position = input[0].gl_Position;\n" + " output.gl_PointSize = input[0].gl_PointSize;\n"; + + for (int r = 0; r < registers; r++) + { + geomHLSL += " output.v" + Str(r) + " = input[0].v" + Str(r) + ";\n"; + } + + if (fragmentShader->mUsesFragCoord) + { + geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n"; + } + + geomHLSL += " \n" + " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n" + " float4 dx_Position = input[0].dx_Position;\n" + " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * dx_Position.w;\n"; + + for (int corner = 0; corner < 4; corner++) + { + geomHLSL += " \n" + " output.dx_Position = dx_Position + float4(pointSpriteCorners[" + Str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n"; + + if (fragmentShader->mUsesPointCoord) + { + geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + Str(corner) + "];\n"; + } + + geomHLSL += " outStream.Append(output);\n"; + } + + geomHLSL += " \n" + " outStream.RestartStrip();\n" + "}\n"; + + return geomHLSL; +} + +// This method needs to match OutputHLSL::decorate +std::string DynamicHLSL::decorateVariable(const std::string &name) +{ + if (name.compare(0, 3, "gl_") != 0) + { + return "_" + name; + } + + return name; +} + +std::string DynamicHLSL::generateAttributeConversionHLSL(const VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const +{ + std::string attribString = "input." + decorateVariable(shaderAttrib.name); + + // Matrix + if (IsMatrixType(shaderAttrib.type)) + { + return "transpose(" + attribString + ")"; + } + + GLenum shaderComponentType = VariableComponentType(shaderAttrib.type); + int shaderComponentCount = VariableComponentCount(shaderAttrib.type); + + // Perform integer to float conversion (if necessary) + bool requiresTypeConversion = (shaderComponentType == GL_FLOAT && vertexFormat.mType != GL_FLOAT); + + if (requiresTypeConversion) + { + // TODO: normalization for 32-bit integer formats + ASSERT(!vertexFormat.mNormalized && !vertexFormat.mPureInteger); + return "float" + Str(shaderComponentCount) + "(" + attribString + ")"; + } + + // No conversion necessary + return attribString; +} + +void DynamicHLSL::getInputLayoutSignature(const VertexFormat inputLayout[], GLenum signature[]) const +{ + for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++) + { + const VertexFormat &vertexFormat = inputLayout[inputIndex]; + + if (vertexFormat.mType == GL_NONE) + { + signature[inputIndex] = GL_NONE; + } + else + { + bool gpuConverted = ((mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0); + signature[inputIndex] = (gpuConverted ? GL_TRUE : GL_FALSE); + } + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h new file mode 100644 index 0000000000..26ae13b342 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DynamicHLSL.h @@ -0,0 +1,99 @@ +// +// Copyright (c) 2014 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. +// +// DynamicHLSL.h: Interface for link and run-time HLSL generation +// + +#ifndef LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_ +#define LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_ + +#include "common/angleutils.h" +#include "libANGLE/Constants.h" + +#include "angle_gl.h" + +#include +#include + +namespace sh +{ +struct Attribute; +struct ShaderVariable; +} + +namespace gl +{ +class InfoLog; +struct VariableLocation; +struct LinkedVarying; +struct VertexAttribute; +struct VertexFormat; +struct PackedVarying; +struct Data; +} + +namespace rx +{ +class RendererD3D; +class ShaderD3D; + +typedef const gl::PackedVarying *VaryingPacking[gl::IMPLEMENTATION_MAX_VARYING_VECTORS][4]; + +struct PixelShaderOutputVariable +{ + GLenum type; + std::string name; + std::string source; + size_t outputIndex; +}; + +class DynamicHLSL : angle::NonCopyable +{ + public: + explicit DynamicHLSL(RendererD3D *const renderer); + + int packVaryings(gl::InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader, + ShaderD3D *vertexShader, const std::vector& transformFeedbackVaryings); + std::string generateVertexShaderForInputLayout(const std::string &sourceShader, const gl::VertexFormat inputLayout[], + const sh::Attribute shaderAttributes[]) const; + std::string generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector &outputVariables, + bool usesFragDepth, const std::vector &outputLayout) const; + bool generateShaderLinkHLSL(const gl::Data &data, gl::InfoLog &infoLog, int registers, + const VaryingPacking packing, + std::string &pixelHLSL, std::string &vertexHLSL, + ShaderD3D *fragmentShader, ShaderD3D *vertexShader, + const std::vector &transformFeedbackVaryings, + std::vector *linkedVaryings, + std::map *programOutputVars, + std::vector *outPixelShaderKey, + bool *outUsesFragDepth) const; + + std::string generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const; + void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; + + private: + RendererD3D *const mRenderer; + + struct SemanticInfo; + + std::string getVaryingSemantic(bool pointSize) const; + SemanticInfo getSemanticInfo(int startRegisters, bool position, bool fragCoord, bool pointCoord, + bool pointSize, bool pixelShader) const; + std::string generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const; + std::string generateVaryingHLSL(const ShaderD3D *shader) const; + void storeUserLinkedVaryings(const ShaderD3D *vertexShader, std::vector *linkedVaryings) const; + void storeBuiltinLinkedVaryings(const SemanticInfo &info, std::vector *linkedVaryings) const; + void defineOutputVariables(ShaderD3D *fragmentShader, std::map *programOutputVars) const; + std::string generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const; + + // Prepend an underscore + static std::string decorateVariable(const std::string &name); + + std::string generateAttributeConversionHLSL(const gl::VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp new file mode 100644 index 0000000000..1a4734b269 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.cpp @@ -0,0 +1,463 @@ +// +// Copyright 2014 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. +// + +// FramebufferD3D.cpp: Implements the DefaultAttachmentD3D and FramebufferD3D classes. + +#include "libANGLE/renderer/d3d/FramebufferD3D.h" + +#include "libANGLE/formatutils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" + +namespace rx +{ + +namespace +{ + +ClearParameters GetClearParameters(const gl::State &state, GLbitfield mask) +{ + ClearParameters clearParams; + memset(&clearParams, 0, sizeof(ClearParameters)); + + const auto &blendState = state.getBlendState(); + + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = false; + } + clearParams.colorFClearValue = state.getColorClearValue(); + clearParams.colorClearType = GL_FLOAT; + clearParams.colorMaskRed = blendState.colorMaskRed; + clearParams.colorMaskGreen = blendState.colorMaskGreen; + clearParams.colorMaskBlue = blendState.colorMaskBlue; + clearParams.colorMaskAlpha = blendState.colorMaskAlpha; + clearParams.clearDepth = false; + clearParams.depthClearValue = state.getDepthClearValue(); + clearParams.clearStencil = false; + clearParams.stencilClearValue = state.getStencilClearValue(); + clearParams.stencilWriteMask = state.getDepthStencilState().stencilWritemask; + clearParams.scissorEnabled = state.isScissorTestEnabled(); + clearParams.scissor = state.getScissor(); + + const gl::Framebuffer *framebufferObject = state.getDrawFramebuffer(); + if (mask & GL_COLOR_BUFFER_BIT) + { + if (framebufferObject->hasEnabledColorAttachment()) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = true; + } + } + } + + if (mask & GL_DEPTH_BUFFER_BIT) + { + if (state.getDepthStencilState().depthMask && framebufferObject->getDepthbuffer() != NULL) + { + clearParams.clearDepth = true; + } + } + + if (mask & GL_STENCIL_BUFFER_BIT) + { + if (framebufferObject->getStencilbuffer() != NULL && + framebufferObject->getStencilbuffer()->getStencilSize() > 0) + { + clearParams.clearStencil = true; + } + } + + return clearParams; +} + +} + +FramebufferD3D::FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer) + : FramebufferImpl(data), + mRenderer(renderer), + mColorAttachmentsForRender(mData.mColorAttachments.size(), nullptr), + mInvalidateColorAttachmentCache(true) +{ + ASSERT(mRenderer != nullptr); +} + +FramebufferD3D::~FramebufferD3D() +{ +} + +void FramebufferD3D::setColorAttachment(size_t, const gl::FramebufferAttachment *) +{ + mInvalidateColorAttachmentCache = true; +} + +void FramebufferD3D::setDepthAttachment(const gl::FramebufferAttachment *) +{ +} + +void FramebufferD3D::setStencilAttachment(const gl::FramebufferAttachment *) +{ +} + +void FramebufferD3D::setDepthStencilAttachment(const gl::FramebufferAttachment *) +{ +} + +void FramebufferD3D::setDrawBuffers(size_t, const GLenum *) +{ + mInvalidateColorAttachmentCache = true; +} + +void FramebufferD3D::setReadBuffer(GLenum) +{ +} + +gl::Error FramebufferD3D::invalidate(size_t, const GLenum *) +{ + // No-op in D3D + return gl::Error(GL_NO_ERROR); +} + +gl::Error FramebufferD3D::invalidateSub(size_t, const GLenum *, const gl::Rectangle &) +{ + // No-op in D3D + return gl::Error(GL_NO_ERROR); +} + +gl::Error FramebufferD3D::clear(const gl::Data &data, GLbitfield mask) +{ + const gl::State &state = *data.state; + ClearParameters clearParams = GetClearParameters(state, mask); + return clear(state, clearParams); +} + +gl::Error FramebufferD3D::clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) +{ + // glClearBufferfv can be called to clear the color buffer or depth buffer + ClearParameters clearParams = GetClearParameters(state, 0); + + if (buffer == GL_COLOR) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorFClearValue = gl::ColorF(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_FLOAT; + } + + if (buffer == GL_DEPTH) + { + clearParams.clearDepth = true; + clearParams.depthClearValue = values[0]; + } + + return clear(state, clearParams); +} + +gl::Error FramebufferD3D::clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) +{ + // glClearBufferuiv can only be called to clear a color buffer + ClearParameters clearParams = GetClearParameters(state, 0); + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorUIClearValue = gl::ColorUI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_UNSIGNED_INT; + + return clear(state, clearParams); +} + +gl::Error FramebufferD3D::clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) +{ + // glClearBufferiv can be called to clear the color buffer or stencil buffer + ClearParameters clearParams = GetClearParameters(state, 0); + + if (buffer == GL_COLOR) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorIClearValue = gl::ColorI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_INT; + } + + if (buffer == GL_STENCIL) + { + clearParams.clearStencil = true; + clearParams.stencilClearValue = values[1]; + } + + return clear(state, clearParams); +} + +gl::Error FramebufferD3D::clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +{ + // glClearBufferfi can only be called to clear a depth stencil buffer + ClearParameters clearParams = GetClearParameters(state, 0); + clearParams.clearDepth = true; + clearParams.depthClearValue = depth; + clearParams.clearStencil = true; + clearParams.stencilClearValue = stencil; + + return clear(state, clearParams); +} + +GLenum FramebufferD3D::getImplementationColorReadFormat() const +{ + const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + + if (readAttachment == nullptr) + { + return GL_NONE; + } + + RenderTargetD3D *attachmentRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readAttachment, &attachmentRenderTarget); + if (error.isError()) + { + return GL_NONE; + } + + GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); + const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); + + return implementationFormatInfo.format; +} + +GLenum FramebufferD3D::getImplementationColorReadType() const +{ + const gl::FramebufferAttachment *readAttachment = mData.getReadAttachment(); + + if (readAttachment == nullptr) + { + return GL_NONE; + } + + RenderTargetD3D *attachmentRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readAttachment, &attachmentRenderTarget); + if (error.isError()) + { + return GL_NONE; + } + + GLenum implementationFormat = getRenderTargetImplementationFormat(attachmentRenderTarget); + const gl::InternalFormat &implementationFormatInfo = gl::GetInternalFormatInfo(implementationFormat); + + return implementationFormatInfo.type; +} + +gl::Error FramebufferD3D::readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const +{ + const gl::PixelPackState &packState = state.getPackState(); + + if (packState.rowLength != 0 || packState.skipRows != 0 || packState.skipPixels != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "invalid pixel store parameters in readPixels"); + } + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, type); + const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); + GLuint outputPitch = sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment, 0); + + return readPixels(area, format, type, outputPitch, packState, reinterpret_cast(pixels)); +} + +gl::Error FramebufferD3D::blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) +{ + bool blitRenderTarget = false; + if ((mask & GL_COLOR_BUFFER_BIT) && + sourceFramebuffer->getReadColorbuffer() != nullptr && + mData.getFirstColorAttachment() != nullptr) + { + blitRenderTarget = true; + } + + bool blitStencil = false; + if ((mask & GL_STENCIL_BUFFER_BIT) && + sourceFramebuffer->getStencilbuffer() != nullptr && + mData.mStencilAttachment != nullptr) + { + blitStencil = true; + } + + bool blitDepth = false; + if ((mask & GL_DEPTH_BUFFER_BIT) && + sourceFramebuffer->getDepthbuffer() != nullptr && + mData.mDepthAttachment != nullptr) + { + blitDepth = true; + } + + if (blitRenderTarget || blitDepth || blitStencil) + { + const gl::Rectangle *scissor = state.isScissorTestEnabled() ? &state.getScissor() : NULL; + gl::Error error = blit(sourceArea, destArea, scissor, blitRenderTarget, blitDepth, blitStencil, + filter, sourceFramebuffer); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum FramebufferD3D::checkStatus() const +{ + // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness + for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); colorAttachment++) + { + const gl::FramebufferAttachment *attachment = mData.mColorAttachments[colorAttachment]; + if (attachment != nullptr) + { + for (size_t prevColorAttachment = 0; prevColorAttachment < colorAttachment; prevColorAttachment++) + { + const gl::FramebufferAttachment *prevAttachment = mData.mColorAttachments[prevColorAttachment]; + if (prevAttachment != nullptr && + (attachment->id() == prevAttachment->id() && + attachment->type() == prevAttachment->type())) + { + return GL_FRAMEBUFFER_UNSUPPORTED; + } + } + } + } + + return GL_FRAMEBUFFER_COMPLETE; +} + +const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const Workarounds &workarounds) const +{ + if (!workarounds.mrtPerfWorkaround) + { + return mData.mColorAttachments; + } + + if (!mInvalidateColorAttachmentCache) + { + return mColorAttachmentsForRender; + } + + // Does not actually free memory + mColorAttachmentsForRender.clear(); + + for (size_t attachmentIndex = 0; attachmentIndex < mData.mColorAttachments.size(); ++attachmentIndex) + { + GLenum drawBufferState = mData.mDrawBufferStates[attachmentIndex]; + gl::FramebufferAttachment *colorAttachment = mData.mColorAttachments[attachmentIndex]; + + if (colorAttachment != nullptr && drawBufferState != GL_NONE) + { + ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + attachmentIndex)); + mColorAttachmentsForRender.push_back(colorAttachment); + } + } + + mInvalidateColorAttachmentCache = false; + return mColorAttachmentsForRender; +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTargetD3D **outRT) +{ + if (attachment->type() == GL_TEXTURE) + { + gl::Texture *texture = attachment->getTexture(); + ASSERT(texture); + TextureD3D *textureD3D = GetImplAs(texture); + const gl::ImageIndex *index = attachment->getTextureImageIndex(); + ASSERT(index); + return textureD3D->getRenderTarget(*index, outRT); + } + else if (attachment->type() == GL_RENDERBUFFER) + { + gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); + ASSERT(renderbuffer); + RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation()); + *outRT = renderbufferD3D->getRenderTarget(); + return gl::Error(GL_NO_ERROR); + } + else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT) + { + const gl::DefaultAttachment *defaultAttachment = static_cast(attachment); + const egl::Surface *surface = defaultAttachment->getSurface(); + ASSERT(surface); + const SurfaceD3D *surfaceD3D = GetImplAs(surface); + ASSERT(surfaceD3D); + + if (defaultAttachment->getBinding() == GL_BACK) + { + *outRT = surfaceD3D->getSwapChain()->getColorRenderTarget(); + } + else + { + *outRT = surfaceD3D->getSwapChain()->getDepthStencilRenderTarget(); + } + return gl::Error(GL_NO_ERROR); + } + else + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } +} + +// Note: RenderTarget serials should ideally be in the RenderTargets themselves. +unsigned int GetAttachmentSerial(const gl::FramebufferAttachment *attachment) +{ + if (attachment->type() == GL_TEXTURE) + { + gl::Texture *texture = attachment->getTexture(); + ASSERT(texture); + TextureD3D *textureD3D = GetImplAs(texture); + const gl::ImageIndex *index = attachment->getTextureImageIndex(); + ASSERT(index); + return textureD3D->getRenderTargetSerial(*index); + } + else if (attachment->type() == GL_RENDERBUFFER) + { + gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); + ASSERT(renderbuffer); + RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation()); + return renderbufferD3D->getRenderTargetSerial(); + } + else if (attachment->type() == GL_FRAMEBUFFER_DEFAULT) + { + const gl::DefaultAttachment *defaultAttachment = static_cast(attachment); + const egl::Surface *surface = defaultAttachment->getSurface(); + ASSERT(surface); + const SurfaceD3D *surfaceD3D = GetImplAs(surface); + ASSERT(surfaceD3D); + + if (defaultAttachment->getBinding() == GL_BACK) + { + return surfaceD3D->getSwapChain()->getColorRenderTarget()->getSerial(); + } + else + { + return surfaceD3D->getSwapChain()->getDepthStencilRenderTarget()->getSerial(); + } + } + else + { + UNREACHABLE(); + return 0; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h new file mode 100644 index 0000000000..d5d2dae8bd --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/FramebufferD3D.h @@ -0,0 +1,111 @@ +// +// Copyright 2014 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. +// + +// FramebufferD3D.h: Defines the DefaultAttachmentD3D and FramebufferD3D classes. + +#ifndef LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ +#define LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ + +#include +#include + +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/FramebufferImpl.h" + +namespace gl +{ +class FramebufferAttachment; +struct PixelPackState; +} + +namespace rx +{ +class RenderTargetD3D; +class RendererD3D; + +struct ClearParameters +{ + bool clearColor[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; + gl::ColorF colorFClearValue; + gl::ColorI colorIClearValue; + gl::ColorUI colorUIClearValue; + GLenum colorClearType; + bool colorMaskRed; + bool colorMaskGreen; + bool colorMaskBlue; + bool colorMaskAlpha; + + bool clearDepth; + float depthClearValue; + + bool clearStencil; + GLint stencilClearValue; + GLuint stencilWriteMask; + + bool scissorEnabled; + gl::Rectangle scissor; +}; + +class FramebufferD3D : public FramebufferImpl +{ + public: + FramebufferD3D(const gl::Framebuffer::Data &data, RendererD3D *renderer); + virtual ~FramebufferD3D(); + + void setColorAttachment(size_t index, const gl::FramebufferAttachment *attachment) override; + void setDepthAttachment(const gl::FramebufferAttachment *attachment) override; + void setStencilAttachment(const gl::FramebufferAttachment *attachment) override; + void setDepthStencilAttachment(const gl::FramebufferAttachment *attachment) override; + + void setDrawBuffers(size_t count, const GLenum *buffers) override; + void setReadBuffer(GLenum buffer) override; + + gl::Error invalidate(size_t count, const GLenum *attachments) override; + gl::Error invalidateSub(size_t count, const GLenum *attachments, const gl::Rectangle &area) override; + + gl::Error clear(const gl::Data &data, GLbitfield mask) override; + gl::Error clearBufferfv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLfloat *values) override; + gl::Error clearBufferuiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLuint *values) override; + gl::Error clearBufferiv(const gl::State &state, GLenum buffer, GLint drawbuffer, const GLint *values) override; + gl::Error clearBufferfi(const gl::State &state, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) override; + + GLenum getImplementationColorReadFormat() const override; + GLenum getImplementationColorReadType() const override; + gl::Error readPixels(const gl::State &state, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const override; + + gl::Error blit(const gl::State &state, const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, + GLbitfield mask, GLenum filter, const gl::Framebuffer *sourceFramebuffer) override; + + GLenum checkStatus() const override; + + const gl::AttachmentList &getColorAttachmentsForRender(const Workarounds &workarounds) const; + + protected: + // Cache variable + mutable gl::AttachmentList mColorAttachmentsForRender; + mutable bool mInvalidateColorAttachmentCache; + + private: + RendererD3D *const mRenderer; + + virtual gl::Error clear(const gl::State &state, const ClearParameters &clearParams) = 0; + + virtual gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, + const gl::PixelPackState &pack, uint8_t *pixels) const = 0; + + virtual gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) = 0; + + virtual GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const = 0; +}; + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTargetD3D **outRT); +unsigned int GetAttachmentSerial(const gl::FramebufferAttachment *attachment); + +} + +#endif // LIBANGLE_RENDERER_D3D_FRAMBUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp new file mode 100644 index 0000000000..8961a36ec5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp @@ -0,0 +1,340 @@ +// +// Copyright 2014 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 "libANGLE/renderer/d3d/HLSLCompiler.h" +#include "libANGLE/Program.h" +#include "libANGLE/features.h" + +#include "common/utilities.h" + +#include "third_party/trace_event/trace_event.h" + +#ifndef QT_D3DCOMPILER_DLL +#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL +#endif + +// Definitions local to the translation unit +namespace +{ + +#ifdef CREATE_COMPILER_FLAG_INFO + #undef CREATE_COMPILER_FLAG_INFO +#endif + +#define CREATE_COMPILER_FLAG_INFO(flag) { flag, #flag } + +#if defined(ANGLE_MINGW32_COMPAT) +#ifndef D3DCOMPILE_RESERVED16 +#define D3DCOMPILE_RESERVED16 0x10000 +#endif +#ifndef D3DCOMPILE_RESERVED17 +#define D3DCOMPILE_RESERVED17 0x20000 +#endif +#endif + +struct CompilerFlagInfo +{ + UINT mFlag; + const char *mName; +}; + +CompilerFlagInfo CompilerFlagInfos[] = +{ + // NOTE: The data below is copied from d3dcompiler.h + // If something changes there it should be changed here as well + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_DEBUG), // (1 << 0) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_VALIDATION), // (1 << 1) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_OPTIMIZATION), // (1 << 2) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_ROW_MAJOR), // (1 << 3) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR), // (1 << 4) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PARTIAL_PRECISION), // (1 << 5) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT), // (1 << 6) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT), // (1 << 7) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_NO_PRESHADER), // (1 << 8) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_AVOID_FLOW_CONTROL), // (1 << 9) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PREFER_FLOW_CONTROL), // (1 << 10) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_STRICTNESS), // (1 << 11) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY), // (1 << 12) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_IEEE_STRICTNESS), // (1 << 13) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL0), // (1 << 14) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL1), // 0 + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL2), // ((1 << 14) | (1 << 15)) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL3), // (1 << 15) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED16), // (1 << 16) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED17), // (1 << 17) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_WARNINGS_ARE_ERRORS) // (1 << 18) +}; + +#undef CREATE_COMPILER_FLAG_INFO + +bool IsCompilerFlagSet(UINT mask, UINT flag) +{ + bool isFlagSet = IsMaskFlagSet(mask, flag); + + switch(flag) + { + case D3DCOMPILE_OPTIMIZATION_LEVEL0: + return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL3)); + + case D3DCOMPILE_OPTIMIZATION_LEVEL1: + return (mask & D3DCOMPILE_OPTIMIZATION_LEVEL2) == UINT(0); + + case D3DCOMPILE_OPTIMIZATION_LEVEL3: + return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL0)); + + default: + return isFlagSet; + } +} + +const char *GetCompilerFlagName(UINT mask, size_t flagIx) +{ + const CompilerFlagInfo &flagInfo = CompilerFlagInfos[flagIx]; + if (IsCompilerFlagSet(mask, flagInfo.mFlag)) + { + return flagInfo.mName; + } + + return nullptr; +} + +} + +namespace rx +{ + +CompileConfig::CompileConfig() + : flags(0), + name() +{ +} + +CompileConfig::CompileConfig(UINT flags, const std::string &name) + : flags(flags), + name(name) +{ +} + +HLSLCompiler::HLSLCompiler() + : mD3DCompilerModule(NULL), + mD3DCompileFunc(NULL), + mD3DDisassembleFunc(NULL) +{ +} + +HLSLCompiler::~HLSLCompiler() +{ + release(); +} + +bool HLSLCompiler::initialize() +{ + TRACE_EVENT0("gpu", "initializeCompiler"); +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) + // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. + static const char *d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES; + + for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i) + { + if (GetModuleHandleExA(0, d3dCompilerNames[i], &mD3DCompilerModule)) + { + break; + } + } +#endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES + + // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL + const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); + if (!defaultCompiler) + defaultCompiler = QT_D3DCOMPILER_DLL; + + const wchar_t *compilerDlls[] = { + defaultCompiler, + L"d3dcompiler_47.dll", + L"d3dcompiler_46.dll", + L"d3dcompiler_43.dll", + 0 + }; + + // Load the first available known compiler DLL + for (int i = 0; compilerDlls[i]; ++i) + { + mD3DCompilerModule = LoadLibrary(compilerDlls[i]); + if (mD3DCompilerModule) + break; + } + + if (!mD3DCompilerModule) + { + // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. + mD3DCompilerModule = LoadLibrary(D3DCOMPILER_DLL); + } + + if (!mD3DCompilerModule) + { + ERR("No D3D compiler module found - aborting!\n"); + return false; + } + + mD3DCompileFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DCompile")); + ASSERT(mD3DCompileFunc); + + mD3DDisassembleFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DDisassemble")); + ASSERT(mD3DDisassembleFunc); + +#else + // D3D Shader compiler is linked already into this module, so the export + // can be directly assigned. + mD3DCompilerModule = NULL; + mD3DCompileFunc = reinterpret_cast(D3DCompile); + mD3DDisassembleFunc = reinterpret_cast(D3DDisassemble); +#endif + + return mD3DCompileFunc != NULL; +} + +void HLSLCompiler::release() +{ + if (mD3DCompilerModule) + { + FreeLibrary(mD3DCompilerModule); + mD3DCompilerModule = NULL; + mD3DCompileFunc = NULL; + mD3DDisassembleFunc = NULL; + } +} + +gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, + const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, + ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const +{ +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + ASSERT(mD3DCompilerModule); +#endif + ASSERT(mD3DCompileFunc); + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + if (gl::DebugAnnotationsActive()) + { + std::string sourcePath = getTempPath(); + std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str()); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } +#endif + + const D3D_SHADER_MACRO *macros = overrideMacros ? overrideMacros : NULL; + + for (size_t i = 0; i < configs.size(); ++i) + { + ID3DBlob *errorMessage = NULL; + ID3DBlob *binary = NULL; + + HRESULT result = mD3DCompileFunc(hlsl.c_str(), hlsl.length(), gl::g_fakepath, macros, NULL, "main", profile.c_str(), + configs[i].flags, 0, &binary, &errorMessage); + + if (errorMessage) + { + std::string message = reinterpret_cast(errorMessage->GetBufferPointer()); + SafeRelease(errorMessage); + + infoLog.appendSanitized(message.c_str()); + TRACE("\n%s", hlsl.c_str()); + TRACE("\n%s", message.c_str()); + + if (message.find("error X3531:") != std::string::npos || // "can't unroll loops marked with loop attribute" + message.find("error X4014:") != std::string::npos) // "cannot have gradient operations inside loops with divergent flow control", + // even though it is counter-intuitive to disable unrolling for this error, + // some very long shaders have trouble deciding which loops to unroll and + // turning off forced unrolls allows them to compile properly. + { + macros = NULL; // Disable [loop] and [flatten] + + // Retry without changing compiler flags + i--; + continue; + } + } + + if (SUCCEEDED(result)) + { + *outCompiledBlob = binary; + +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + (*outDebugInfo) += "// COMPILER INPUT HLSL BEGIN\n\n" + hlsl + "\n// COMPILER INPUT HLSL END\n"; + (*outDebugInfo) += "\n\n// ASSEMBLY BEGIN\n\n"; + (*outDebugInfo) += "// Compiler configuration: " + configs[i].name + "\n// Flags:\n"; + for (size_t fIx = 0; fIx < ArraySize(CompilerFlagInfos); ++fIx) + { + const char *flagName = GetCompilerFlagName(configs[i].flags, fIx); + if (flagName != nullptr) + { + (*outDebugInfo) += std::string("// ") + flagName + "\n"; + } + } + + (*outDebugInfo) += "// Macros:\n"; + if (macros == nullptr) + { + (*outDebugInfo) += "// - : -\n"; + } + else + { + for (const D3D_SHADER_MACRO *mIt = macros; mIt->Name != nullptr; ++mIt) + { + (*outDebugInfo) += std::string("// ") + mIt->Name + " : " + mIt->Definition + "\n"; + } + } + + (*outDebugInfo) += "\n" + disassembleBinary(binary) + "\n// ASSEMBLY END\n"; +#endif + + return gl::Error(GL_NO_ERROR); + } + else + { + if (result == E_OUTOFMEMORY) + { + *outCompiledBlob = NULL; + return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result); + } + + infoLog.append("Warning: D3D shader compilation failed with %s flags.", configs[i].name.c_str()); + + if (i + 1 < configs.size()) + { + infoLog.append(" Retrying with %s.\n", configs[i + 1].name.c_str()); + } + } + } + + // None of the configurations succeeded in compiling this shader but the compiler is still intact + *outCompiledBlob = NULL; + return gl::Error(GL_NO_ERROR); +} + +std::string HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary) const +{ + // Retrieve disassembly + UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING; + ID3DBlob *disassembly = NULL; + pD3DDisassemble disassembleFunc = reinterpret_cast(mD3DDisassembleFunc); + LPCVOID buffer = shaderBinary->GetBufferPointer(); + SIZE_T bufSize = shaderBinary->GetBufferSize(); + HRESULT result = disassembleFunc(buffer, bufSize, flags, "", &disassembly); + + std::string asmSrc; + if (SUCCEEDED(result)) + { + asmSrc = reinterpret_cast(disassembly->GetBufferPointer()); + } + + SafeRelease(disassembly); + + return asmSrc; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h new file mode 100644 index 0000000000..a824952553 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.h @@ -0,0 +1,54 @@ +#ifndef LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ +#define LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ + +#include "libANGLE/Error.h" + +#include "common/angleutils.h" +#include "common/platform.h" + +#include +#include + +namespace gl +{ +class InfoLog; +} + +namespace rx +{ + +struct CompileConfig +{ + UINT flags; + std::string name; + + CompileConfig(); + CompileConfig(UINT flags, const std::string &name); +}; + +class HLSLCompiler : angle::NonCopyable +{ + public: + HLSLCompiler(); + ~HLSLCompiler(); + + bool initialize(); + void release(); + + // Attempt to compile a HLSL shader using the supplied configurations, may output a NULL compiled blob + // even if no GL errors are returned. + gl::Error compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, + const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, + ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const; + + std::string disassembleBinary(ID3DBlob* shaderBinary) const; + + private: + HMODULE mD3DCompilerModule; + pD3DCompile mD3DCompileFunc; + pD3DDisassemble mD3DDisassembleFunc; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_HLSLCOMPILER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp new file mode 100644 index 0000000000..4e6f61150a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.cpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2002-2015 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. +// + +// Image.h: Implements the rx::Image class, an abstract base class for the +// renderer-specific classes which will define the interface to the underlying +// surfaces or resources. + +#include "libANGLE/renderer/d3d/ImageD3D.h" + +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" + +namespace rx +{ + +ImageD3D::ImageD3D() + : mWidth(0), + mHeight(0), + mDepth(0), + mInternalFormat(GL_NONE), + mTarget(GL_NONE), + mRenderable(false), + mDirty(false) +{ +} + +gl::Error ImageD3D::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source) +{ + gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); + ASSERT(colorbuffer); + + RenderTargetD3D *renderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) + { + return error; + } + + ASSERT(renderTarget); + return copy(destOffset, sourceArea, renderTarget); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h new file mode 100644 index 0000000000..0fe88a8f59 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ImageD3D.h @@ -0,0 +1,84 @@ +// +// Copyright (c) 2002-2015 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. +// + +// ImageD3D.h: Defines the rx::ImageD3D class, an abstract base class for the +// renderer-specific classes which will define the interface to the underlying +// surfaces or resources. + +#ifndef LIBANGLE_RENDERER_D3D_IMAGED3D_H_ +#define LIBANGLE_RENDERER_D3D_IMAGED3D_H_ + +#include "common/debug.h" + +#include "libANGLE/Error.h" + +namespace gl +{ +class Framebuffer; +struct ImageIndex; +struct Box; +struct Extents; +struct Offset; +struct Rectangle; +struct PixelUnpackState; +} + +namespace rx +{ +class TextureStorage; +class RendererD3D; +class RenderTargetD3D; + +class ImageD3D : angle::NonCopyable +{ + public: + ImageD3D(); + virtual ~ImageD3D() {}; + + GLsizei getWidth() const { return mWidth; } + GLsizei getHeight() const { return mHeight; } + GLsizei getDepth() const { return mDepth; } + GLenum getInternalFormat() const { return mInternalFormat; } + GLenum getTarget() const { return mTarget; } + bool isRenderableFormat() const { return mRenderable; } + + void markDirty() { mDirty = true; } + void markClean() { mDirty = false; } + virtual bool isDirty() const = 0; + + virtual bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) = 0; + + virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) = 0; + virtual gl::Error loadCompressedData(const gl::Box &area, const void *input) = 0; + + virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurface3D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurface2DArray(TextureStorage *storage, int layer, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) = 0; + + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; + + gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, const gl::Framebuffer *source); + + protected: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + bool mRenderable; + GLenum mTarget; + + bool mDirty; + + private: + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source) = 0; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_IMAGED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp new file mode 100644 index 0000000000..677b8bb240 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.cpp @@ -0,0 +1,196 @@ +// +// 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. +// + +// IndexBuffer.cpp: Defines the abstract IndexBuffer class and IndexBufferInterface +// class with derivations, classes that perform graphics API agnostic index buffer operations. + +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" + +namespace rx +{ + +unsigned int IndexBuffer::mNextSerial = 1; + +IndexBuffer::IndexBuffer() +{ + updateSerial(); +} + +IndexBuffer::~IndexBuffer() +{ +} + +unsigned int IndexBuffer::getSerial() const +{ + return mSerial; +} + +void IndexBuffer::updateSerial() +{ + mSerial = mNextSerial++; +} + + +IndexBufferInterface::IndexBufferInterface(BufferFactoryD3D *factory, bool dynamic) +{ + mIndexBuffer = factory->createIndexBuffer(); + + mDynamic = dynamic; + mWritePosition = 0; +} + +IndexBufferInterface::~IndexBufferInterface() +{ + if (mIndexBuffer) + { + delete mIndexBuffer; + } +} + +GLenum IndexBufferInterface::getIndexType() const +{ + return mIndexBuffer->getIndexType(); +} + +unsigned int IndexBufferInterface::getBufferSize() const +{ + return mIndexBuffer->getBufferSize(); +} + +unsigned int IndexBufferInterface::getSerial() const +{ + return mIndexBuffer->getSerial(); +} + +gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void **outMappedMemory, unsigned int *streamOffset) +{ + // Protect against integer overflow + if (mWritePosition + size < mWritePosition) + { + return gl::Error(GL_OUT_OF_MEMORY, "Mapping of internal index buffer would cause an integer overflow."); + } + + gl::Error error = mIndexBuffer->mapBuffer(mWritePosition, size, outMappedMemory); + if (error.isError()) + { + if (outMappedMemory) + { + *outMappedMemory = NULL; + } + return error; + } + + if (streamOffset) + { + *streamOffset = mWritePosition; + } + + mWritePosition += size; + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexBufferInterface::unmapBuffer() +{ + return mIndexBuffer->unmapBuffer(); +} + +IndexBuffer * IndexBufferInterface::getIndexBuffer() const +{ + return mIndexBuffer; +} + +unsigned int IndexBufferInterface::getWritePosition() const +{ + return mWritePosition; +} + +void IndexBufferInterface::setWritePosition(unsigned int writePosition) +{ + mWritePosition = writePosition; +} + +gl::Error IndexBufferInterface::discard() +{ + return mIndexBuffer->discard(); +} + +gl::Error IndexBufferInterface::setBufferSize(unsigned int bufferSize, GLenum indexType) +{ + if (mIndexBuffer->getBufferSize() == 0) + { + return mIndexBuffer->initialize(bufferSize, indexType, mDynamic); + } + else + { + return mIndexBuffer->setSize(bufferSize, indexType); + } +} + +StreamingIndexBufferInterface::StreamingIndexBufferInterface(BufferFactoryD3D *factory) + : IndexBufferInterface(factory, true) +{ +} + +StreamingIndexBufferInterface::~StreamingIndexBufferInterface() +{ +} + +gl::Error StreamingIndexBufferInterface::reserveBufferSpace(unsigned int size, GLenum indexType) +{ + unsigned int curBufferSize = getBufferSize(); + unsigned int writePos = getWritePosition(); + if (size > curBufferSize) + { + gl::Error error = setBufferSize(std::max(size, 2 * curBufferSize), indexType); + if (error.isError()) + { + return error; + } + setWritePosition(0); + } + else if (writePos + size > curBufferSize || writePos + size < writePos) + { + gl::Error error = discard(); + if (error.isError()) + { + return error; + } + setWritePosition(0); + } + + return gl::Error(GL_NO_ERROR); +} + + +StaticIndexBufferInterface::StaticIndexBufferInterface(BufferFactoryD3D *factory) + : IndexBufferInterface(factory, false) +{ +} + +StaticIndexBufferInterface::~StaticIndexBufferInterface() +{ +} + +gl::Error StaticIndexBufferInterface::reserveBufferSpace(unsigned int size, GLenum indexType) +{ + unsigned int curSize = getBufferSize(); + if (curSize == 0) + { + return setBufferSize(size, indexType); + } + else if (curSize >= size && indexType == getIndexType()) + { + return gl::Error(GL_NO_ERROR); + } + else + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION, "Internal static index buffers can't be resized"); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h new file mode 100644 index 0000000000..36262f1d09 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexBuffer.h @@ -0,0 +1,101 @@ +// +// 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. +// + +// IndexBuffer.h: Defines the abstract IndexBuffer class and IndexBufferInterface +// class with derivations, classes that perform graphics API agnostic index buffer operations. + +#ifndef LIBANGLE_RENDERER_D3D_INDEXBUFFER_H_ +#define LIBANGLE_RENDERER_D3D_INDEXBUFFER_H_ + +#include "common/angleutils.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/IndexRangeCache.h" + +namespace rx +{ +class BufferFactoryD3D; + +class IndexBuffer : angle::NonCopyable +{ + public: + IndexBuffer(); + virtual ~IndexBuffer(); + + virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) = 0; + + virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) = 0; + virtual gl::Error unmapBuffer() = 0; + + virtual gl::Error discard() = 0; + + virtual GLenum getIndexType() const = 0; + virtual unsigned int getBufferSize() const = 0; + virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType) = 0; + + unsigned int getSerial() const; + + protected: + void updateSerial(); + + private: + unsigned int mSerial; + static unsigned int mNextSerial; +}; + +class IndexBufferInterface : angle::NonCopyable +{ + public: + IndexBufferInterface(BufferFactoryD3D *factory, bool dynamic); + virtual ~IndexBufferInterface(); + + virtual gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) = 0; + + GLenum getIndexType() const; + unsigned int getBufferSize() const; + + unsigned int getSerial() const; + + gl::Error mapBuffer(unsigned int size, void** outMappedMemory, unsigned int *streamOffset); + gl::Error unmapBuffer(); + + IndexBuffer *getIndexBuffer() const; + + protected: + unsigned int getWritePosition() const; + void setWritePosition(unsigned int writePosition); + + gl::Error discard(); + + gl::Error setBufferSize(unsigned int bufferSize, GLenum indexType); + + private: + IndexBuffer *mIndexBuffer; + + unsigned int mWritePosition; + bool mDynamic; +}; + +class StreamingIndexBufferInterface : public IndexBufferInterface +{ + public: + explicit StreamingIndexBufferInterface(BufferFactoryD3D *factory); + ~StreamingIndexBufferInterface(); + + gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) override; +}; + +class StaticIndexBufferInterface : public IndexBufferInterface +{ + public: + explicit StaticIndexBufferInterface(BufferFactoryD3D *factory); + ~StaticIndexBufferInterface(); + + gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) override; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_INDEXBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp new file mode 100644 index 0000000000..7dad269435 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.cpp @@ -0,0 +1,267 @@ +// +// Copyright (c) 2002-2014 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 "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/IndexBuffer.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/formatutils.h" + +namespace rx +{ + +static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output) +{ + if (sourceType == GL_UNSIGNED_BYTE) + { + ASSERT(destinationType == GL_UNSIGNED_SHORT); + const GLubyte *in = static_cast(input); + GLushort *out = static_cast(output); + + for (GLsizei i = 0; i < count; i++) + { + out[i] = in[i]; + } + } + else if (sourceType == GL_UNSIGNED_INT) + { + ASSERT(destinationType == GL_UNSIGNED_INT); + memcpy(output, input, count * sizeof(GLuint)); + } + else if (sourceType == GL_UNSIGNED_SHORT) + { + if (destinationType == GL_UNSIGNED_SHORT) + { + memcpy(output, input, count * sizeof(GLushort)); + } + else if (destinationType == GL_UNSIGNED_INT) + { + const GLushort *in = static_cast(input); + GLuint *out = static_cast(output); + + for (GLsizei i = 0; i < count; i++) + { + out[i] = in[i]; + } + } + else UNREACHABLE(); + } + else UNREACHABLE(); +} + +IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass) + : mFactory(factory), + mRendererClass(rendererClass), + mStreamingBufferShort(nullptr), + mStreamingBufferInt(nullptr) +{ +} + +IndexDataManager::~IndexDataManager() +{ + SafeDelete(mStreamingBufferShort); + SafeDelete(mStreamingBufferInt); +} + +gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated) +{ + const gl::Type &typeInfo = gl::GetTypeInfo(type); + + GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + + unsigned int offset = 0; + bool alignedOffset = false; + + BufferD3D *storage = NULL; + + if (buffer != NULL) + { + offset = static_cast(reinterpret_cast(indices)); + + storage = GetImplAs(buffer); + + // We'll trust that the compiler will optimize the % below: + // the operands are unsigned and the divisor is a constant. + 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; + } + + ASSERT(typeInfo.bytes * static_cast(count) + offset <= storage->getSize()); + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; + } + + StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL; + IndexBufferInterface *indexBuffer = NULL; + bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() && + destinationIndexType == type; + unsigned int streamOffset = 0; + + if (directStorage) + { + streamOffset = offset; + } + else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) + { + indexBuffer = staticBuffer; + + // Using bit-shift here is faster than using division. + streamOffset = (offset >> typeInfo.bytesShift) << gl::GetTypeInfo(destinationIndexType).bytesShift; + } + + // Avoid D3D11's primitive restart index value + // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx + if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRendererClass == RENDERER_D3D11) + { + destinationIndexType = GL_UNSIGNED_INT; + directStorage = false; + indexBuffer = NULL; + } + + const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType); + + if (!directStorage && !indexBuffer) + { + gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer); + if (error.isError()) + { + return error; + } + + unsigned int convertCount = count; + + if (staticBuffer) + { + if (staticBuffer->getBufferSize() == 0 && alignedOffset) + { + indexBuffer = staticBuffer; + // Using bit-shift here is faster than using division. + convertCount = storage->getSize() >> typeInfo.bytesShift; + } + else + { + storage->invalidateStaticData(); + staticBuffer = NULL; + } + } + + ASSERT(indexBuffer); + + // Using bit-shift here is faster than using division. + if (convertCount > (std::numeric_limits::max() >> destTypeInfo.bytesShift)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.", + convertCount, destTypeInfo.bytes); + } + + unsigned int bufferSizeRequired = convertCount << destTypeInfo.bytesShift; + error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type); + if (error.isError()) + { + return error; + } + + void* output = NULL; + error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset); + if (error.isError()) + { + return error; + } + + const uint8_t *dataPointer = reinterpret_cast(indices); + if (staticBuffer) + { + error = storage->getData(&dataPointer); + if (error.isError()) + { + return error; + } + } + ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output); + + error = indexBuffer->unmapBuffer(); + if (error.isError()) + { + return error; + } + + if (staticBuffer) + { + // Using bit-shift here is faster than using division. + streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift; + } + } + + translated->storage = directStorage ? storage : NULL; + translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL; + translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); + // Using bit-shift here is faster than using division. + translated->startIndex = (streamOffset >> destTypeInfo.bytesShift); + translated->startOffset = streamOffset; + translated->indexType = destinationIndexType; + + if (storage) + { + storage->promoteStaticUsage(count << typeInfo.bytesShift); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer) +{ + ASSERT(outBuffer); + if (destinationIndexType == GL_UNSIGNED_INT) + { + if (!mStreamingBufferInt) + { + mStreamingBufferInt = new StreamingIndexBufferInterface(mFactory); + gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mStreamingBufferInt); + return error; + } + } + + *outBuffer = mStreamingBufferInt; + return gl::Error(GL_NO_ERROR); + } + else + { + ASSERT(destinationIndexType == GL_UNSIGNED_SHORT); + + if (!mStreamingBufferShort) + { + mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory); + gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); + if (error.isError()) + { + SafeDelete(mStreamingBufferShort); + return error; + } + } + + *outBuffer = mStreamingBufferShort; + return gl::Error(GL_NO_ERROR); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h new file mode 100644 index 0000000000..275b3720c5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/IndexDataManager.h @@ -0,0 +1,70 @@ +// +// Copyright (c) 2002-2014 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 LIBANGLE_INDEXDATAMANAGER_H_ +#define LIBANGLE_INDEXDATAMANAGER_H_ + +#include + +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" + +namespace +{ + enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) }; +} + +namespace gl +{ +class Buffer; +} + +namespace rx +{ +class IndexBufferInterface; +class StaticIndexBufferInterface; +class StreamingIndexBufferInterface; +class IndexBuffer; +class BufferD3D; +class RendererD3D; + +struct TranslatedIndexData +{ + RangeUI indexRange; + unsigned int startIndex; + unsigned int startOffset; // In bytes + + IndexBuffer *indexBuffer; + BufferD3D *storage; + GLenum indexType; + unsigned int serial; +}; + +class IndexDataManager : angle::NonCopyable +{ + public: + explicit IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass); + virtual ~IndexDataManager(); + + gl::Error prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated); + + private: + gl::Error getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer); + + BufferFactoryD3D *const mFactory; + RendererClass mRendererClass; + StreamingIndexBufferInterface *mStreamingBufferShort; + StreamingIndexBufferInterface *mStreamingBufferInt; +}; + +} + +#endif // LIBANGLE_INDEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp new file mode 100644 index 0000000000..9ce9a27cd3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.cpp @@ -0,0 +1,2005 @@ +// +// Copyright (c) 2014 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. +// + +// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. + +#include "libANGLE/renderer/d3d/ProgramD3D.h" + +#include "common/utilities.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Program.h" +#include "libANGLE/features.h" +#include "libANGLE/renderer/d3d/DynamicHLSL.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" + +namespace rx +{ + +namespace +{ + +GLenum GetTextureType(GLenum samplerType) +{ + switch (samplerType) + { + case GL_SAMPLER_2D: + case GL_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + return GL_TEXTURE_2D; + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_3D: + return GL_TEXTURE_3D; + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + return GL_TEXTURE_CUBE_MAP; + case GL_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + return GL_TEXTURE_CUBE_MAP; + case GL_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + return GL_TEXTURE_2D_ARRAY; + default: UNREACHABLE(); + } + + return GL_TEXTURE_2D; +} + +void GetDefaultInputLayoutFromShader(const std::vector &shaderAttributes, gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +{ + size_t layoutIndex = 0; + for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + ASSERT(layoutIndex < gl::MAX_VERTEX_ATTRIBS); + + const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex]; + + if (shaderAttr.type != GL_NONE) + { + GLenum transposedType = gl::TransposeMatrixType(shaderAttr.type); + + for (size_t rowIndex = 0; static_cast(rowIndex) < gl::VariableRowCount(transposedType); rowIndex++, layoutIndex++) + { + gl::VertexFormat *defaultFormat = &inputLayout[layoutIndex]; + + defaultFormat->mType = gl::VariableComponentType(transposedType); + defaultFormat->mNormalized = false; + defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool + defaultFormat->mComponents = gl::VariableColumnCount(transposedType); + } + } + } +} + +std::vector GetDefaultOutputLayoutFromShader(const std::vector &shaderOutputVars) +{ + std::vector defaultPixelOutput; + + if (!shaderOutputVars.empty()) + { + defaultPixelOutput.push_back(GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex); + } + + return defaultPixelOutput; +} + +bool IsRowMajorLayout(const sh::InterfaceBlockField &var) +{ + return var.isRowMajorLayout; +} + +bool IsRowMajorLayout(const sh::ShaderVariable &var) +{ + return false; +} + +struct AttributeSorter +{ + AttributeSorter(const ProgramImpl::SemanticIndexArray &semanticIndices) + : originalIndices(&semanticIndices) + { + } + + bool operator()(int a, int b) + { + int indexA = (*originalIndices)[a]; + int indexB = (*originalIndices)[b]; + + if (indexA == -1) return false; + if (indexB == -1) return true; + return (indexA < indexB); + } + + const ProgramImpl::SemanticIndexArray *originalIndices; +}; + +} + +ProgramD3D::VertexExecutable::VertexExecutable(const gl::VertexFormat inputLayout[], + const GLenum signature[], + ShaderExecutableD3D *shaderExecutable) + : mShaderExecutable(shaderExecutable) +{ + for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + mInputs[attributeIndex] = inputLayout[attributeIndex]; + mSignature[attributeIndex] = signature[attributeIndex]; + } +} + +ProgramD3D::VertexExecutable::~VertexExecutable() +{ + SafeDelete(mShaderExecutable); +} + +bool ProgramD3D::VertexExecutable::matchesSignature(const GLenum signature[]) const +{ + for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (mSignature[attributeIndex] != signature[attributeIndex]) + { + return false; + } + } + + return true; +} + +ProgramD3D::PixelExecutable::PixelExecutable(const std::vector &outputSignature, ShaderExecutableD3D *shaderExecutable) + : mOutputSignature(outputSignature), + mShaderExecutable(shaderExecutable) +{ +} + +ProgramD3D::PixelExecutable::~PixelExecutable() +{ + SafeDelete(mShaderExecutable); +} + +ProgramD3D::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(GL_TEXTURE_2D) +{ +} + +unsigned int ProgramD3D::mCurrentSerial = 1; + +ProgramD3D::ProgramD3D(RendererD3D *renderer) + : ProgramImpl(), + mRenderer(renderer), + mDynamicHLSL(NULL), + mGeometryExecutable(NULL), + mUsesPointSize(false), + mVertexUniformStorage(NULL), + mFragmentUniformStorage(NULL), + mUsedVertexSamplerRange(0), + mUsedPixelSamplerRange(0), + mDirtySamplerMapping(true), + mTextureUnitTypesCache(renderer->getRendererCaps().maxCombinedTextureImageUnits), + mShaderVersion(100), + mSerial(issueSerial()) +{ + mDynamicHLSL = new DynamicHLSL(renderer); +} + +ProgramD3D::~ProgramD3D() +{ + reset(); + SafeDelete(mDynamicHLSL); +} + +bool ProgramD3D::usesPointSpriteEmulation() const +{ + return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; +} + +bool ProgramD3D::usesGeometryShader() const +{ + return usesPointSpriteEmulation() && !usesInstancedPointSpriteEmulation(); +} + +bool ProgramD3D::usesInstancedPointSpriteEmulation() const +{ + return mRenderer->getWorkarounds().useInstancedPointSpriteEmulation; +} + +GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const +{ + GLint logicalTextureUnit = -1; + + switch (type) + { + case gl::SAMPLER_PIXEL: + ASSERT(samplerIndex < caps.maxTextureImageUnits); + if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active) + { + logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; + } + break; + case gl::SAMPLER_VERTEX: + ASSERT(samplerIndex < caps.maxVertexTextureImageUnits); + if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active) + { + logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; + } + break; + default: UNREACHABLE(); + } + + if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast(caps.maxCombinedTextureImageUnits)) + { + 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). +GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const +{ + switch (type) + { + case gl::SAMPLER_PIXEL: + ASSERT(samplerIndex < mSamplersPS.size()); + ASSERT(mSamplersPS[samplerIndex].active); + return mSamplersPS[samplerIndex].textureType; + case gl::SAMPLER_VERTEX: + ASSERT(samplerIndex < mSamplersVS.size()); + ASSERT(mSamplersVS[samplerIndex].active); + return mSamplersVS[samplerIndex].textureType; + default: UNREACHABLE(); + } + + return GL_TEXTURE_2D; +} + +GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const +{ + switch (type) + { + case gl::SAMPLER_PIXEL: + return mUsedPixelSamplerRange; + case gl::SAMPLER_VERTEX: + return mUsedVertexSamplerRange; + default: + UNREACHABLE(); + return 0; + } +} + +void ProgramD3D::updateSamplerMapping() +{ + if (!mDirtySamplerMapping) + { + return; + } + + mDirtySamplerMapping = false; + + // Retrieve sampler uniform values + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + gl::LinkedUniform *targetUniform = mUniforms[uniformIndex]; + + if (targetUniform->dirty) + { + if (gl::IsSamplerType(targetUniform->type)) + { + int count = targetUniform->elementCount(); + GLint (*v)[4] = reinterpret_cast(targetUniform->data); + + if (targetUniform->isReferencedByFragmentShader()) + { + unsigned int firstIndex = targetUniform->psRegisterIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < mSamplersPS.size()) + { + ASSERT(mSamplersPS[samplerIndex].active); + mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; + } + } + } + + if (targetUniform->isReferencedByVertexShader()) + { + unsigned int firstIndex = targetUniform->vsRegisterIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < mSamplersVS.size()) + { + ASSERT(mSamplersVS[samplerIndex].active); + mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; + } + } + } + } + } + } +} + +bool ProgramD3D::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) +{ + // 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. + updateSamplerMapping(); + + std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(), GL_NONE); + + for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) + { + if (mSamplersPS[i].active) + { + unsigned int unit = mSamplersPS[i].logicalTextureUnit; + + if (unit >= caps.maxCombinedTextureImageUnits) + { + if (infoLog) + { + infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits); + } + + return false; + } + + if (mTextureUnitTypesCache[unit] != GL_NONE) + { + if (mSamplersPS[i].textureType != mTextureUnitTypesCache[unit]) + { + if (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + mTextureUnitTypesCache[unit] = mSamplersPS[i].textureType; + } + } + } + + for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) + { + if (mSamplersVS[i].active) + { + unsigned int unit = mSamplersVS[i].logicalTextureUnit; + + if (unit >= caps.maxCombinedTextureImageUnits) + { + if (infoLog) + { + infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, caps.maxCombinedTextureImageUnits); + } + + return false; + } + + if (mTextureUnitTypesCache[unit] != GL_NONE) + { + if (mSamplersVS[i].textureType != mTextureUnitTypesCache[unit]) + { + if (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + mTextureUnitTypesCache[unit] = mSamplersVS[i].textureType; + } + } + } + + return true; +} + +LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) +{ + int compileFlags = stream->readInt(); + if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) + { + infoLog.append("Mismatched compilation flags."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + stream->readInt(&mShaderVersion); + + const unsigned int psSamplerCount = stream->readInt(); + for (unsigned int i = 0; i < psSamplerCount; ++i) + { + Sampler sampler; + stream->readBool(&sampler.active); + stream->readInt(&sampler.logicalTextureUnit); + stream->readInt(&sampler.textureType); + mSamplersPS.push_back(sampler); + } + const unsigned int vsSamplerCount = stream->readInt(); + for (unsigned int i = 0; i < vsSamplerCount; ++i) + { + Sampler sampler; + stream->readBool(&sampler.active); + stream->readInt(&sampler.logicalTextureUnit); + stream->readInt(&sampler.textureType); + mSamplersVS.push_back(sampler); + } + + stream->readInt(&mUsedVertexSamplerRange); + stream->readInt(&mUsedPixelSamplerRange); + + const unsigned int uniformCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniforms.resize(uniformCount); + for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) + { + GLenum type = stream->readInt(); + GLenum precision = stream->readInt(); + std::string name = stream->readString(); + unsigned int arraySize = stream->readInt(); + int blockIndex = stream->readInt(); + + int offset = stream->readInt(); + int arrayStride = stream->readInt(); + int matrixStride = stream->readInt(); + bool isRowMajorMatrix = stream->readBool(); + + const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); + + gl::LinkedUniform *uniform = new gl::LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo); + + stream->readInt(&uniform->psRegisterIndex); + stream->readInt(&uniform->vsRegisterIndex); + stream->readInt(&uniform->registerCount); + stream->readInt(&uniform->registerElement); + + mUniforms[uniformIndex] = uniform; + } + + const unsigned int uniformIndexCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniformIndex.resize(uniformIndexCount); + for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) + { + stream->readString(&mUniformIndex[uniformIndexIndex].name); + stream->readInt(&mUniformIndex[uniformIndexIndex].element); + stream->readInt(&mUniformIndex[uniformIndexIndex].index); + } + + unsigned int uniformBlockCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniformBlocks.resize(uniformBlockCount); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) + { + std::string name = stream->readString(); + unsigned int elementIndex = stream->readInt(); + unsigned int dataSize = stream->readInt(); + + gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize); + + stream->readInt(&uniformBlock->psRegisterIndex); + stream->readInt(&uniformBlock->vsRegisterIndex); + + unsigned int numMembers = stream->readInt(); + uniformBlock->memberUniformIndexes.resize(numMembers); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) + { + stream->readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]); + } + + mUniformBlocks[uniformBlockIndex] = uniformBlock; + } + + stream->readInt(&mTransformFeedbackBufferMode); + const unsigned int transformFeedbackVaryingCount = stream->readInt(); + mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); + for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) + { + gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex]; + + stream->readString(&varying.name); + stream->readInt(&varying.type); + stream->readInt(&varying.size); + stream->readString(&varying.semanticName); + stream->readInt(&varying.semanticIndex); + stream->readInt(&varying.semanticIndexCount); + } + + stream->readString(&mVertexHLSL); + stream->readBytes(reinterpret_cast(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->readString(&mPixelHLSL); + stream->readBytes(reinterpret_cast(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->readBool(&mUsesFragDepth); + stream->readBool(&mUsesPointSize); + + const size_t pixelShaderKeySize = stream->readInt(); + mPixelShaderKey.resize(pixelShaderKeySize); + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++) + { + stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].type); + stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].name); + stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].source); + stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex); + } + + const unsigned char* binary = reinterpret_cast(stream->data()); + + const unsigned int vertexShaderCount = stream->readInt(); + for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) + { + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + + for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) + { + gl::VertexFormat *vertexInput = &inputLayout[inputIndex]; + stream->readInt(&vertexInput->mType); + stream->readInt(&vertexInput->mNormalized); + stream->readInt(&vertexInput->mComponents); + stream->readBool(&vertexInput->mPureInteger); + } + + unsigned int vertexShaderSize = stream->readInt(); + const unsigned char *vertexShaderFunction = binary + stream->offset(); + + ShaderExecutableD3D *shaderExecutable = NULL; + gl::Error error = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, + SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &shaderExecutable); + if (error.isError()) + { + return LinkResult(false, error); + } + + if (!shaderExecutable) + { + infoLog.append("Could not create vertex shader."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + // generated converted input layout + GLenum signature[gl::MAX_VERTEX_ATTRIBS]; + getInputLayoutSignature(inputLayout, signature); + + // add new binary + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); + + stream->skip(vertexShaderSize); + } + + const size_t pixelShaderCount = stream->readInt(); + for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++) + { + const size_t outputCount = stream->readInt(); + std::vector outputs(outputCount); + for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++) + { + stream->readInt(&outputs[outputIndex]); + } + + const size_t pixelShaderSize = stream->readInt(); + const unsigned char *pixelShaderFunction = binary + stream->offset(); + ShaderExecutableD3D *shaderExecutable = NULL; + gl::Error error = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &shaderExecutable); + if (error.isError()) + { + return LinkResult(false, error); + } + + if (!shaderExecutable) + { + infoLog.append("Could not create pixel shader."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + // add new binary + mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); + + stream->skip(pixelShaderSize); + } + + unsigned int geometryShaderSize = stream->readInt(); + + if (geometryShaderSize > 0) + { + const unsigned char *geometryShaderFunction = binary + stream->offset(); + gl::Error error = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &mGeometryExecutable); + if (error.isError()) + { + return LinkResult(false, error); + } + + if (!mGeometryExecutable) + { + infoLog.append("Could not create geometry shader."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + stream->skip(geometryShaderSize); + } + + GUID binaryIdentifier = {0}; + stream->readBytes(reinterpret_cast(&binaryIdentifier), sizeof(GUID)); + + GUID identifier = mRenderer->getAdapterIdentifier(); + if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0) + { + infoLog.append("Invalid program binary."); + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + initializeUniformStorage(); + initAttributesByLayout(); + + return LinkResult(true, gl::Error(GL_NO_ERROR)); +} + +gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) +{ + stream->writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL); + + stream->writeInt(mShaderVersion); + + stream->writeInt(mSamplersPS.size()); + for (unsigned int i = 0; i < mSamplersPS.size(); ++i) + { + stream->writeInt(mSamplersPS[i].active); + stream->writeInt(mSamplersPS[i].logicalTextureUnit); + stream->writeInt(mSamplersPS[i].textureType); + } + + stream->writeInt(mSamplersVS.size()); + for (unsigned int i = 0; i < mSamplersVS.size(); ++i) + { + stream->writeInt(mSamplersVS[i].active); + stream->writeInt(mSamplersVS[i].logicalTextureUnit); + stream->writeInt(mSamplersVS[i].textureType); + } + + stream->writeInt(mUsedVertexSamplerRange); + stream->writeInt(mUsedPixelSamplerRange); + + stream->writeInt(mUniforms.size()); + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) + { + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; + + stream->writeInt(uniform.type); + stream->writeInt(uniform.precision); + stream->writeString(uniform.name); + stream->writeInt(uniform.arraySize); + stream->writeInt(uniform.blockIndex); + + stream->writeInt(uniform.blockInfo.offset); + stream->writeInt(uniform.blockInfo.arrayStride); + stream->writeInt(uniform.blockInfo.matrixStride); + stream->writeInt(uniform.blockInfo.isRowMajorMatrix); + + stream->writeInt(uniform.psRegisterIndex); + stream->writeInt(uniform.vsRegisterIndex); + stream->writeInt(uniform.registerCount); + stream->writeInt(uniform.registerElement); + } + + stream->writeInt(mUniformIndex.size()); + for (size_t i = 0; i < mUniformIndex.size(); ++i) + { + stream->writeString(mUniformIndex[i].name); + stream->writeInt(mUniformIndex[i].element); + stream->writeInt(mUniformIndex[i].index); + } + + stream->writeInt(mUniformBlocks.size()); + for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) + { + const gl::UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex]; + + stream->writeString(uniformBlock.name); + stream->writeInt(uniformBlock.elementIndex); + stream->writeInt(uniformBlock.dataSize); + + stream->writeInt(uniformBlock.memberUniformIndexes.size()); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + stream->writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } + + stream->writeInt(uniformBlock.psRegisterIndex); + stream->writeInt(uniformBlock.vsRegisterIndex); + } + + stream->writeInt(mTransformFeedbackBufferMode); + stream->writeInt(mTransformFeedbackLinkedVaryings.size()); + for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) + { + const gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i]; + + stream->writeString(varying.name); + stream->writeInt(varying.type); + stream->writeInt(varying.size); + stream->writeString(varying.semanticName); + stream->writeInt(varying.semanticIndex); + stream->writeInt(varying.semanticIndexCount); + } + + stream->writeString(mVertexHLSL); + stream->writeBytes(reinterpret_cast(&mVertexWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->writeString(mPixelHLSL); + stream->writeBytes(reinterpret_cast(&mPixelWorkarounds), sizeof(D3DCompilerWorkarounds)); + stream->writeInt(mUsesFragDepth); + stream->writeInt(mUsesPointSize); + + const std::vector &pixelShaderKey = mPixelShaderKey; + stream->writeInt(pixelShaderKey.size()); + for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); pixelShaderKeyIndex++) + { + const PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex]; + stream->writeInt(variable.type); + stream->writeString(variable.name); + stream->writeString(variable.source); + stream->writeInt(variable.outputIndex); + } + + stream->writeInt(mVertexExecutables.size()); + for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) + { + VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; + + for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) + { + const gl::VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex]; + stream->writeInt(vertexInput.mType); + stream->writeInt(vertexInput.mNormalized); + stream->writeInt(vertexInput.mComponents); + stream->writeInt(vertexInput.mPureInteger); + } + + size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); + stream->writeInt(vertexShaderSize); + + const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction(); + stream->writeBytes(vertexBlob, vertexShaderSize); + } + + stream->writeInt(mPixelExecutables.size()); + for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) + { + PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; + + const std::vector outputs = pixelExecutable->outputSignature(); + stream->writeInt(outputs.size()); + for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++) + { + stream->writeInt(outputs[outputIndex]); + } + + size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength(); + stream->writeInt(pixelShaderSize); + + const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction(); + stream->writeBytes(pixelBlob, pixelShaderSize); + } + + size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; + stream->writeInt(geometryShaderSize); + + if (mGeometryExecutable != NULL && geometryShaderSize > 0) + { + const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); + stream->writeBytes(geometryBlob, geometryShaderSize); + } + + GUID binaryIdentifier = mRenderer->getAdapterIdentifier(); + stream->writeBytes(reinterpret_cast(&binaryIdentifier), sizeof(GUID)); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutableD3D **outExecutable) +{ + mPixelShaderOutputFormatCache.clear(); + + const FramebufferD3D *fboD3D = GetImplAs(fbo); + const gl::AttachmentList &colorbuffers = fboD3D->getColorAttachmentsForRender(mRenderer->getWorkarounds()); + + for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) + { + const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; + + if (colorbuffer) + { + mPixelShaderOutputFormatCache.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding()); + } + else + { + mPixelShaderOutputFormatCache.push_back(GL_NONE); + } + } + + return getPixelExecutableForOutputLayout(mPixelShaderOutputFormatCache, outExecutable, nullptr); +} + +gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector &outputSignature, + ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog) +{ + for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + { + if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) + { + *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable(); + return gl::Error(GL_NO_ERROR); + } + } + + std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth, + outputSignature); + + // Generate new pixel executable + ShaderExecutableD3D *pixelExecutable = NULL; + + gl::InfoLog tempInfoLog; + gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; + + gl::Error error = mRenderer->compileToExecutable(*currentInfoLog, finalPixelHLSL, SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mPixelWorkarounds, &pixelExecutable); + if (error.isError()) + { + return error; + } + + if (pixelExecutable) + { + mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); + } + else if (!infoLog) + { + std::vector tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); + } + + *outExectuable = pixelExecutable; + return gl::Error(GL_NO_ERROR); +} + +gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], + ShaderExecutableD3D **outExectuable, + gl::InfoLog *infoLog) +{ + GLenum signature[gl::MAX_VERTEX_ATTRIBS]; + getInputLayoutSignature(inputLayout, signature); + + for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + { + if (mVertexExecutables[executableIndex]->matchesSignature(signature)) + { + *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); + return gl::Error(GL_NO_ERROR); + } + } + + // Generate new dynamic layout with attribute conversions + std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes); + + // Generate new vertex executable + ShaderExecutableD3D *vertexExecutable = NULL; + + gl::InfoLog tempInfoLog; + gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog; + + gl::Error error = mRenderer->compileToExecutable(*currentInfoLog, finalVertexHLSL, SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mVertexWorkarounds, &vertexExecutable); + if (error.isError()) + { + return error; + } + + if (vertexExecutable) + { + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); + } + else if (!infoLog) + { + std::vector tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); + } + + *outExectuable = vertexExecutable; + return gl::Error(GL_NO_ERROR); +} + +LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers) +{ + ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); + ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + + gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS]; + GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout); + ShaderExecutableD3D *defaultVertexExecutable = NULL; + gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable, &infoLog); + if (error.isError()) + { + return LinkResult(false, error); + } + + std::vector defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); + ShaderExecutableD3D *defaultPixelExecutable = NULL; + error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable, &infoLog); + if (error.isError()) + { + return LinkResult(false, error); + } + + if (usesGeometryShader()) + { + std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D); + + + error = mRenderer->compileToExecutable(infoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + D3DCompilerWorkarounds(), &mGeometryExecutable); + if (error.isError()) + { + return LinkResult(false, error); + } + } + +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + if (usesGeometryShader() && mGeometryExecutable) + { + // Geometry shaders are currently only used internally, so there is no corresponding shader object at the interface level + // For now the geometry shader debug info is pre-pended to the vertex shader, this is a bit of a clutch + vertexShaderD3D->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n"); + vertexShaderD3D->appendDebugInfo(mGeometryExecutable->getDebugInfo()); + vertexShaderD3D->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n"); + } + + if (defaultVertexExecutable) + { + vertexShaderD3D->appendDebugInfo(defaultVertexExecutable->getDebugInfo()); + } + + if (defaultPixelExecutable) + { + fragmentShaderD3D->appendDebugInfo(defaultPixelExecutable->getDebugInfo()); + } +#endif + + bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable)); + return LinkResult(linkSuccess, gl::Error(GL_NO_ERROR)); +} + +LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables) +{ + ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); + ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + + mSamplersPS.resize(data.caps->maxTextureImageUnits); + mSamplersVS.resize(data.caps->maxVertexTextureImageUnits); + + mTransformFeedbackBufferMode = transformFeedbackBufferMode; + + mPixelHLSL = fragmentShaderD3D->getTranslatedSource(); + fragmentShaderD3D->generateWorkarounds(&mPixelWorkarounds); + + mVertexHLSL = vertexShaderD3D->getTranslatedSource(); + vertexShaderD3D->generateWorkarounds(&mVertexWorkarounds); + mShaderVersion = vertexShaderD3D->getShaderVersion(); + + // Map the varyings to the register file + VaryingPacking packing = { NULL }; + *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings); + + if (*registers < 0) + { + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + if (!gl::Program::linkVaryings(infoLog, fragmentShader, vertexShader)) + { + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + if (!mDynamicHLSL->generateShaderLinkHLSL(data, infoLog, *registers, packing, mPixelHLSL, mVertexHLSL, + fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings, + linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth)) + { + return LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUsesPointSize = vertexShaderD3D->usesPointSize(); + + initAttributesByLayout(); + + return LinkResult(true, gl::Error(GL_NO_ERROR)); +} + +void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const +{ + mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); +} + +void ProgramD3D::initializeUniformStorage() +{ + // Compute total default block size + unsigned int vertexRegisters = 0; + unsigned int fragmentRegisters = 0; + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (!gl::IsSamplerType(uniform.type)) + { + if (uniform.isReferencedByVertexShader()) + { + vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount); + } + if (uniform.isReferencedByFragmentShader()) + { + fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount); + } + } + } + + mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); + mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); +} + +gl::Error ProgramD3D::applyUniforms() +{ + updateSamplerMapping(); + + gl::Error error = mRenderer->applyUniforms(*this, mUniforms); + if (error.isError()) + { + return error; + } + + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + mUniforms[uniformIndex]->dirty = false; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error ProgramD3D::applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) +{ + GLint vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + GLint fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; + + for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; ++registerIndex) + { + vertexUniformBuffers[registerIndex] = -1; + } + + for (unsigned int registerIndex = 0; registerIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; ++registerIndex) + { + fragmentUniformBuffers[registerIndex] = -1; + } + + const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); + const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); + + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++) + { + gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex]; + GLuint blockBinding = uniformBlockBindings[uniformBlockIndex]; + + ASSERT(uniformBlock); + + // Unnecessary to apply an unreferenced standard or shared UBO + if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader()) + { + continue; + } + + if (uniformBlock->isReferencedByVertexShader()) + { + unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS; + ASSERT(vertexUniformBuffers[registerIndex] == -1); + ASSERT(registerIndex < data.caps->maxVertexUniformBlocks); + vertexUniformBuffers[registerIndex] = blockBinding; + } + + if (uniformBlock->isReferencedByFragmentShader()) + { + unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS; + ASSERT(fragmentUniformBuffers[registerIndex] == -1); + ASSERT(registerIndex < data.caps->maxFragmentUniformBlocks); + fragmentUniformBuffers[registerIndex] = blockBinding; + } + } + + return mRenderer->setUniformBuffers(data, vertexUniformBuffers, fragmentUniformBuffers); +} + +bool ProgramD3D::assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps) +{ + if (shader == GL_VERTEX_SHADER) + { + uniformBlock->vsRegisterIndex = registerIndex; + if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks) + { + infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks); + return false; + } + } + else if (shader == GL_FRAGMENT_SHADER) + { + uniformBlock->psRegisterIndex = registerIndex; + if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks) + { + infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks); + return false; + } + } + else UNREACHABLE(); + + return true; +} + +void ProgramD3D::dirtyAllUniforms() +{ + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + mUniforms[index]->dirty = true; + } +} + +void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + setUniform(location, count, v, GL_FLOAT); +} + +void ProgramD3D::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC2); +} + +void ProgramD3D::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC3); +} + +void ProgramD3D::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC4); +} + +void ProgramD3D::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); +} + +void ProgramD3D::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); +} + +void ProgramD3D::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); +} + +void ProgramD3D::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); +} + +void ProgramD3D::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); +} + +void ProgramD3D::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); +} + +void ProgramD3D::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); +} + +void ProgramD3D::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); +} + +void ProgramD3D::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); +} + +void ProgramD3D::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT); +} + +void ProgramD3D::setUniform2iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC2); +} + +void ProgramD3D::setUniform3iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC3); +} + +void ProgramD3D::setUniform4iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC4); +} + +void ProgramD3D::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT); +} + +void ProgramD3D::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); +} + +void ProgramD3D::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC3); +} + +void ProgramD3D::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); +} + +void ProgramD3D::getUniformfv(GLint location, GLfloat *params) +{ + getUniformv(location, params, GL_FLOAT); +} + +void ProgramD3D::getUniformiv(GLint location, GLint *params) +{ + getUniformv(location, params, GL_INT); +} + +void ProgramD3D::getUniformuiv(GLint location, GLuint *params) +{ + getUniformv(location, params, GL_UNSIGNED_INT); +} + +bool ProgramD3D::linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps) +{ + const ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader.getImplementation()); + const ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader.getImplementation()); + + const std::vector &vertexUniforms = vertexShader.getUniforms(); + const std::vector &fragmentUniforms = fragmentShader.getUniforms(); + + // Check that uniforms defined in the vertex and fragment shaders are identical + typedef std::map UniformMap; + UniformMap linkedUniforms; + + for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++) + { + const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex]; + linkedUniforms[vertexUniform.name] = &vertexUniform; + } + + for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++) + { + const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex]; + UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name); + if (entry != linkedUniforms.end()) + { + const sh::Uniform &vertexUniform = *entry->second; + const std::string &uniformName = "uniform '" + vertexUniform.name + "'"; + if (!gl::Program::linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform)) + { + return false; + } + } + } + + for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = vertexUniforms[uniformIndex]; + + if (uniform.staticUse) + { + defineUniformBase(vertexShaderD3D, uniform, vertexShaderD3D->getUniformRegister(uniform.name)); + } + } + + for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = fragmentUniforms[uniformIndex]; + + if (uniform.staticUse) + { + defineUniformBase(fragmentShaderD3D, uniform, fragmentShaderD3D->getUniformRegister(uniform.name)); + } + } + + if (!indexUniforms(infoLog, caps)) + { + return false; + } + + initializeUniformStorage(); + + // special case for gl_DepthRange, the only built-in uniform (also a struct) + if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange()) + { + const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); + + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); + } + + return true; +} + +void ProgramD3D::defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister) +{ + ShShaderOutput outputType = shader->getCompilerOutputType(); + sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); + encoder.skipRegisters(uniformRegister); + + defineUniform(shader, uniform, uniform.name, &encoder); +} + +void ProgramD3D::defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform, + const std::string &fullName, sh::HLSLBlockEncoder *encoder) +{ + if (uniform.isStruct()) + { + for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + { + const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); + + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) + { + const sh::ShaderVariable &field = uniform.fields[fieldIndex]; + const std::string &fieldFullName = (fullName + elementString + "." + field.name); + + defineUniform(shader, field, fieldFullName, encoder); + } + + encoder->exitAggregateType(); + } + } + else // Not a struct + { + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->enterAggregateType(); + } + + gl::LinkedUniform *linkedUniform = getUniformByName(fullName); + + // Advance the uniform offset, to track registers allocation for structs + sh::BlockMemberInfo blockInfo = encoder->encodeType(uniform.type, uniform.arraySize, false); + + if (!linkedUniform) + { + linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, + -1, sh::BlockMemberInfo::getDefaultBlockInfo()); + ASSERT(linkedUniform); + linkedUniform->registerElement = sh::HLSLBlockEncoder::getBlockRegisterElement(blockInfo); + mUniforms.push_back(linkedUniform); + } + + if (shader->getShaderType() == GL_FRAGMENT_SHADER) + { + linkedUniform->psRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo); + } + else if (shader->getShaderType() == GL_VERTEX_SHADER) + { + linkedUniform->vsRegisterIndex = sh::HLSLBlockEncoder::getBlockRegister(blockInfo); + } + else UNREACHABLE(); + + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->exitAggregateType(); + } + } +} + +template +static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag) +{ + ASSERT(dest != NULL); + ASSERT(dirtyFlag != NULL); + + *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); + *dest = source; +} + +template +void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType) +{ + const int components = gl::VariableComponentCount(targetUniformType); + const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType); + + gl::LinkedUniform *targetUniform = getUniformByLocation(location); + + int elementCount = targetUniform->elementCount(); + + count = std::min(elementCount - (int)mUniformIndex[location].element, count); + + if (targetUniform->type == targetUniformType) + { + T *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + T *dest = target + (i * 4); + const T *source = v + (i * components); + + for (int c = 0; c < components; c++) + { + SetIfDirty(dest + c, source[c], &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(dest + c, T(0), &targetUniform->dirty); + } + } + } + else if (targetUniform->type == targetBoolType) + { + GLint *boolParams = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + GLint *dest = boolParams + (i * 4); + const T *source = v + (i * components); + + for (int c = 0; c < components; c++) + { + SetIfDirty(dest + c, (source[c] == static_cast(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty); + } + } + } + else if (gl::IsSamplerType(targetUniform->type)) + { + ASSERT(targetUniformType == GL_INT); + + GLint *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + bool wasDirty = targetUniform->dirty; + + for (int i = 0; i < count; i++) + { + GLint *dest = target + (i * 4); + const GLint *source = reinterpret_cast(v) + (i * components); + + SetIfDirty(dest + 0, source[0], &targetUniform->dirty); + SetIfDirty(dest + 1, 0, &targetUniform->dirty); + SetIfDirty(dest + 2, 0, &targetUniform->dirty); + SetIfDirty(dest + 3, 0, &targetUniform->dirty); + } + + if (!wasDirty && targetUniform->dirty) + { + mDirtySamplerMapping = true; + } + } + else UNREACHABLE(); +} + +template +bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) +{ + bool dirty = false; + int copyWidth = std::min(targetHeight, srcWidth); + int copyHeight = std::min(targetWidth, srcHeight); + + for (int x = 0; x < copyWidth; x++) + { + for (int y = 0; y < copyHeight; y++) + { + SetIfDirty(target + (x * targetWidth + y), static_cast(value[y * srcWidth + x]), &dirty); + } + } + // clear unfilled right side + for (int y = 0; y < copyWidth; y++) + { + for (int x = copyHeight; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + // clear unfilled bottom. + for (int y = copyWidth; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + + return dirty; +} + +template +bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) +{ + bool dirty = false; + int copyWidth = std::min(targetWidth, srcWidth); + int copyHeight = std::min(targetHeight, srcHeight); + + for (int y = 0; y < copyHeight; y++) + { + for (int x = 0; x < copyWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(value[y * srcWidth + x]), &dirty); + } + } + // clear unfilled right side + for (int y = 0; y < copyHeight; y++) + { + for (int x = copyWidth; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + // clear unfilled bottom. + for (int y = copyHeight; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + + return dirty; +} + +template +void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType) +{ + gl::LinkedUniform *targetUniform = getUniformByLocation(location); + + int elementCount = targetUniform->elementCount(); + + count = std::min(elementCount - (int)mUniformIndex[location].element, count); + const unsigned int targetMatrixStride = (4 * rows); + GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride); + + for (int i = 0; i < count; i++) + { + // Internally store matrices as transposed versions to accomodate HLSL matrix indexing + if (transpose == GL_FALSE) + { + targetUniform->dirty = transposeMatrix(target, value, 4, rows, rows, cols) || targetUniform->dirty; + } + else + { + targetUniform->dirty = expandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; + } + target += targetMatrixStride; + value += cols * rows; + } +} + +template +void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType) +{ + gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; + + if (gl::IsMatrixType(targetUniform->type)) + { + const int rows = gl::VariableRowCount(targetUniform->type); + const int cols = gl::VariableColumnCount(targetUniform->type); + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows); + } + else if (uniformType == gl::VariableComponentType(targetUniform->type)) + { + unsigned int size = gl::VariableComponentCount(targetUniform->type); + memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T), + size * sizeof(T)); + } + else + { + unsigned int size = gl::VariableComponentCount(targetUniform->type); + switch (gl::VariableComponentType(targetUniform->type)) + { + case GL_BOOL: + { + GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = (boolParams[i] == GL_FALSE) ? static_cast(0) : static_cast(1); + } + } + break; + + case GL_FLOAT: + { + GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(floatParams[i]); + } + } + break; + + case GL_INT: + { + GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(intParams[i]); + } + } + break; + + case GL_UNSIGNED_INT: + { + GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(uintParams[i]); + } + } + break; + + default: UNREACHABLE(); + } + } +} + +template +void ProgramD3D::defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, + bool inRowMajorLayout) +{ + for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++) + { + const VarT &field = fields[uniformIndex]; + const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); + + if (field.isStruct()) + { + bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); + + for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) + { + encoder->enterAggregateType(); + + const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); + defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout); + + encoder->exitAggregateType(); + } + } + else + { + bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); + + sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); + + gl::LinkedUniform *newUniform = new gl::LinkedUniform(field.type, field.precision, fieldName, field.arraySize, + blockIndex, memberInfo); + + // add to uniform list, but not index, since uniform block uniforms have no location + blockUniformIndexes->push_back(mUniforms.size()); + mUniforms.push_back(newUniform); + } + } +} + +bool ProgramD3D::defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, + const gl::Caps &caps) +{ + const ShaderD3D* shaderD3D = ShaderD3D::makeShaderD3D(shader.getImplementation()); + + // create uniform block entries if they do not exist + if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX) + { + std::vector blockUniformIndexes; + const unsigned int blockIndex = mUniformBlocks.size(); + + // define member uniforms + sh::BlockLayoutEncoder *encoder = NULL; + + if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) + { + encoder = new sh::Std140BlockEncoder; + } + else + { + encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); + } + ASSERT(encoder); + + defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout); + + size_t dataSize = encoder->getBlockSize(); + + // create all the uniform blocks + if (interfaceBlock.arraySize > 0) + { + for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++) + { + gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + else + { + gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + + if (interfaceBlock.staticUse) + { + // Assign registers to the uniform blocks + const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name); + const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize); + ASSERT(blockIndex != GL_INVALID_INDEX); + ASSERT(blockIndex + elementCount <= mUniformBlocks.size()); + + unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name); + + for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++) + { + gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement]; + ASSERT(uniformBlock->name == interfaceBlock.name); + + if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(), + interfaceBlockRegister + uniformBlockElement, caps)) + { + return false; + } + } + } + + return true; +} + +bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex, + GLenum samplerType, + unsigned int samplerCount, + std::vector &outSamplers, + GLuint *outUsedRange) +{ + unsigned int samplerIndex = startSamplerIndex; + + do + { + if (samplerIndex < outSamplers.size()) + { + Sampler& sampler = outSamplers[samplerIndex]; + sampler.active = true; + sampler.textureType = GetTextureType(samplerType); + sampler.logicalTextureUnit = 0; + *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); + } + else + { + return false; + } + + samplerIndex++; + } while (samplerIndex < startSamplerIndex + samplerCount); + + return true; +} + +bool ProgramD3D::indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps) +{ + ASSERT(gl::IsSamplerType(uniform.type)); + ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX); + + if (uniform.vsRegisterIndex != GL_INVALID_INDEX) + { + if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS, + &mUsedVertexSamplerRange)) + { + infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", + mSamplersVS.size()); + return false; + } + + unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors; + if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors) + { + infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", + caps.maxVertexUniformVectors); + return false; + } + } + + if (uniform.psRegisterIndex != GL_INVALID_INDEX) + { + if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS, + &mUsedPixelSamplerRange)) + { + infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", + mSamplersPS.size()); + return false; + } + + unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors; + if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors) + { + infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", + caps.maxFragmentUniformVectors); + return false; + } + } + + return true; +} + +bool ProgramD3D::indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (gl::IsSamplerType(uniform.type)) + { + if (!indexSamplerUniform(uniform, infoLog, caps)) + { + return false; + } + } + + for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++) + { + mUniformIndex.push_back(gl::VariableLocation(uniform.name, arrayElementIndex, uniformIndex)); + } + } + + return true; +} + +void ProgramD3D::reset() +{ + ProgramImpl::reset(); + + SafeDeleteContainer(mVertexExecutables); + SafeDeleteContainer(mPixelExecutables); + SafeDelete(mGeometryExecutable); + + mTransformFeedbackBufferMode = GL_NONE; + + mVertexHLSL.clear(); + mVertexWorkarounds.reset(); + mShaderVersion = 100; + + mPixelHLSL.clear(); + mPixelWorkarounds.reset(); + mUsesFragDepth = false; + mPixelShaderKey.clear(); + mUsesPointSize = false; + + SafeDelete(mVertexUniformStorage); + SafeDelete(mFragmentUniformStorage); + + mSamplersPS.clear(); + mSamplersVS.clear(); + + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + mDirtySamplerMapping = true; + + std::fill(mAttributesByLayout, mAttributesByLayout + ArraySize(mAttributesByLayout), -1); +} + +unsigned int ProgramD3D::getSerial() const +{ + return mSerial; +} + +unsigned int ProgramD3D::issueSerial() +{ + return mCurrentSerial++; +} + +void ProgramD3D::initAttributesByLayout() +{ + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAttributesByLayout[i] = i; + } + + std::sort(&mAttributesByLayout[0], &mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex)); +} + +void ProgramD3D::sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]) const +{ + rx::TranslatedAttribute oldTranslatedAttributes[gl::MAX_VERTEX_ATTRIBS]; + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + oldTranslatedAttributes[i] = attributes[i]; + } + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + int oldIndex = mAttributesByLayout[i]; + sortedSemanticIndices[i] = mSemanticIndex[oldIndex]; + attributes[i] = oldTranslatedAttributes[oldIndex]; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h new file mode 100644 index 0000000000..6f3eade81d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ProgramD3D.h @@ -0,0 +1,244 @@ +// +// Copyright (c) 2014 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. +// + +// ProgramD3D.h: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. + +#ifndef LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_ +#define LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_ + +#include "compiler/translator/blocklayoutHLSL.h" +#include "libANGLE/Constants.h" +#include "libANGLE/renderer/ProgramImpl.h" +#include "libANGLE/renderer/Workarounds.h" +#include "libANGLE/renderer/d3d/DynamicHLSL.h" + +#include +#include + +namespace gl +{ +struct LinkedUniform; +struct VariableLocation; +struct VertexFormat; +} + +namespace rx +{ +class RendererD3D; +class UniformStorageD3D; +class ShaderExecutableD3D; + +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +// WARNING: D3DCOMPILE_OPTIMIZATION_LEVEL3 may lead to a DX9 shader compiler hang. +// It should only be used selectively to work around specific bugs. +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1 +#endif + +class ProgramD3D : public ProgramImpl +{ + public: + ProgramD3D(RendererD3D *renderer); + virtual ~ProgramD3D(); + + const std::vector &getPixelShaderKey() { return mPixelShaderKey; } + int getShaderVersion() const { return mShaderVersion; } + GLenum getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } + + GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const; + GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const; + GLint getUsedSamplerRange(gl::SamplerType type) const; + void updateSamplerMapping(); + bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps); + + bool usesPointSize() const { return mUsesPointSize; } + bool usesPointSpriteEmulation() const; + bool usesGeometryShader() const; + bool usesInstancedPointSpriteEmulation() const; + + GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; } + LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream); + gl::Error save(gl::BinaryOutputStream *stream); + + gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutableD3D **outExectuable); + gl::Error getPixelExecutableForOutputLayout(const std::vector &outputLayout, ShaderExecutableD3D **outExectuable, gl::InfoLog *infoLog); + gl::Error getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutableD3D **outExectuable, gl::InfoLog *infoLog); + ShaderExecutableD3D *getGeometryExecutable() const { return mGeometryExecutable; } + + LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers); + + LinkResult link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables); + + void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; + + void initializeUniformStorage(); + gl::Error applyUniforms(); + gl::Error applyUniformBuffers(const gl::Data &data, GLuint uniformBlockBindings[]) override; + bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps); + void dirtyAllUniforms(); + + void setUniform1fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform1iv(GLint location, GLsizei count, const GLint *v); + void setUniform2iv(GLint location, GLsizei count, const GLint *v); + void setUniform3iv(GLint location, GLsizei count, const GLint *v); + void setUniform4iv(GLint location, GLsizei count, const GLint *v); + void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform2uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform3uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform4uiv(GLint location, GLsizei count, const GLuint *v); + void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + + void getUniformfv(GLint location, GLfloat *params); + void getUniformiv(GLint location, GLint *params); + void getUniformuiv(GLint location, GLuint *params); + + const UniformStorageD3D &getVertexUniformStorage() const { return *mVertexUniformStorage; } + const UniformStorageD3D &getFragmentUniformStorage() const { return *mFragmentUniformStorage; } + + bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps); + bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, const gl::Caps &caps); + + void reset(); + + unsigned int getSerial() const; + + void initAttributesByLayout(); + void sortAttributesByLayout(rx::TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]) const; + + private: + class VertexExecutable + { + public: + VertexExecutable(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], + const GLenum signature[gl::MAX_VERTEX_ATTRIBS], + ShaderExecutableD3D *shaderExecutable); + ~VertexExecutable(); + + bool matchesSignature(const GLenum convertedLayout[gl::MAX_VERTEX_ATTRIBS]) const; + + const gl::VertexFormat *inputs() const { return mInputs; } + const GLenum *signature() const { return mSignature; } + ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; } + + private: + gl::VertexFormat mInputs[gl::MAX_VERTEX_ATTRIBS]; + GLenum mSignature[gl::MAX_VERTEX_ATTRIBS]; + ShaderExecutableD3D *mShaderExecutable; + }; + + class PixelExecutable + { + public: + PixelExecutable(const std::vector &outputSignature, ShaderExecutableD3D *shaderExecutable); + ~PixelExecutable(); + + bool matchesSignature(const std::vector &signature) const { return mOutputSignature == signature; } + + const std::vector &outputSignature() const { return mOutputSignature; } + ShaderExecutableD3D *shaderExecutable() const { return mShaderExecutable; } + + private: + std::vector mOutputSignature; + ShaderExecutableD3D *mShaderExecutable; + }; + + struct Sampler + { + Sampler(); + + bool active; + GLint logicalTextureUnit; + GLenum textureType; + }; + + void defineUniformBase(const ShaderD3D *shader, const sh::Uniform &uniform, unsigned int uniformRegister); + void defineUniform(const ShaderD3D *shader, const sh::ShaderVariable &uniform, const std::string &fullName, + sh::HLSLBlockEncoder *encoder); + bool indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps); + bool indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps); + static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount, + std::vector &outSamplers, GLuint *outUsedRange); + + template + void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType); + + template + void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType); + + template + void getUniformv(GLint location, T *params, GLenum uniformType); + + template + void defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, + bool inRowMajorLayout); + + RendererD3D *mRenderer; + DynamicHLSL *mDynamicHLSL; + + std::vector mVertexExecutables; + std::vector mPixelExecutables; + ShaderExecutableD3D *mGeometryExecutable; + + std::string mVertexHLSL; + D3DCompilerWorkarounds mVertexWorkarounds; + + std::string mPixelHLSL; + D3DCompilerWorkarounds mPixelWorkarounds; + bool mUsesFragDepth; + std::vector mPixelShaderKey; + + bool mUsesPointSize; + + UniformStorageD3D *mVertexUniformStorage; + UniformStorageD3D *mFragmentUniformStorage; + + GLenum mTransformFeedbackBufferMode; + + std::vector mSamplersPS; + std::vector mSamplersVS; + GLuint mUsedVertexSamplerRange; + GLuint mUsedPixelSamplerRange; + bool mDirtySamplerMapping; + + // Cache for validateSamplers + std::vector mTextureUnitTypesCache; + + // Cache for getPixelExecutableForFramebuffer + std::vector mPixelShaderOutputFormatCache; + + int mShaderVersion; + + int mAttributesByLayout[gl::MAX_VERTEX_ATTRIBS]; + + unsigned int mSerial; + + static unsigned int issueSerial(); + static unsigned int mCurrentSerial; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_PROGRAMD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp new file mode 100644 index 0000000000..84b30aa106 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp @@ -0,0 +1,36 @@ +// +// Copyright (c) 2012-2015 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. +// + +// RenderTargetD3D.cpp: Implements serial handling for rx::RenderTargetD3D + +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +unsigned int RenderTargetD3D::mCurrentSerial = 1; + +RenderTargetD3D::RenderTargetD3D() + : mSerial(issueSerials(1)) +{ +} + +RenderTargetD3D::~RenderTargetD3D() +{ +} + +unsigned int RenderTargetD3D::getSerial() const +{ + return mSerial; +} + +unsigned int RenderTargetD3D::issueSerials(unsigned int count) +{ + unsigned int firstSerial = mCurrentSerial; + mCurrentSerial += count; + return firstSerial; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h new file mode 100644 index 0000000000..fe6afcecae --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderTargetD3D.h @@ -0,0 +1,42 @@ +// +// Copyright (c) 2012-2015 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. +// + +// RenderTargetD3D.h: Defines an abstract wrapper class to manage IDirect3DSurface9 +// and ID3D11View objects belonging to renderbuffers and renderable textures. + +#ifndef LIBANGLE_RENDERER_D3D_RENDERTARGETD3D_H_ +#define LIBANGLE_RENDERER_D3D_RENDERTARGETD3D_H_ + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ + +class RenderTargetD3D : angle::NonCopyable +{ + public: + RenderTargetD3D(); + virtual ~RenderTargetD3D(); + + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLsizei getDepth() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual GLsizei getSamples() const = 0; + gl::Extents getExtents() const { return gl::Extents(getWidth(), getHeight(), getDepth()); } + + virtual unsigned int getSerial() const; + static unsigned int issueSerials(unsigned int count); + + private: + const unsigned int mSerial; + static unsigned int mCurrentSerial; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_RENDERTARGETD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp new file mode 100644 index 0000000000..c91fedff06 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp @@ -0,0 +1,73 @@ +// +// Copyright (c) 2014 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. +// + +// RenderbufferD3d.cpp: Implements the RenderbufferD3D class, a specialization of RenderbufferImpl + + +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" + +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +RenderbufferD3D::RenderbufferD3D(RendererD3D *renderer) : mRenderer(renderer) +{ + mRenderTarget = NULL; +} + +RenderbufferD3D::~RenderbufferD3D() +{ + SafeDelete(mRenderTarget); +} + +RenderbufferD3D *RenderbufferD3D::makeRenderbufferD3D(RenderbufferImpl *renderbuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(RenderbufferD3D*, renderbuffer)); + return static_cast(renderbuffer); +} + +gl::Error RenderbufferD3D::setStorage(GLenum internalformat, size_t width, size_t height) +{ + return setStorageMultisample(0, internalformat, width, height); +} + +gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) +{ + // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage, but we should create depth and stencil buffers + // as DEPTH24_STENCIL8 + GLenum creationFormat = internalformat; + if (internalformat == GL_DEPTH_COMPONENT16 || internalformat == GL_STENCIL_INDEX8) + { + creationFormat = GL_DEPTH24_STENCIL8_OES; + } + + RenderTargetD3D *newRT = NULL; + gl::Error error = mRenderer->createRenderTarget(width, height, creationFormat, samples, &newRT); + if (error.isError()) + { + return error; + } + + SafeDelete(mRenderTarget); + mRenderTarget = newRT; + + return gl::Error(GL_NO_ERROR); +} + +RenderTargetD3D *RenderbufferD3D::getRenderTarget() +{ + return mRenderTarget; +} + +unsigned int RenderbufferD3D::getRenderTargetSerial() const +{ + return (mRenderTarget ? mRenderTarget->getSerial() : 0); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h new file mode 100644 index 0000000000..4c4b998683 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RenderbufferD3D.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 2014 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. +// + +// RenderbufferD3d.h: Defines the RenderbufferD3D class which implements RenderbufferImpl. + +#ifndef LIBANGLE_RENDERER_D3D_RENDERBUFFERD3D_H_ +#define LIBANGLE_RENDERER_D3D_RENDERBUFFERD3D_H_ + +#include "angle_gl.h" + +#include "common/angleutils.h" +#include "libANGLE/renderer/RenderbufferImpl.h" + +namespace rx +{ +class RendererD3D; +class RenderTargetD3D; +class SwapChainD3D; + +class RenderbufferD3D : public RenderbufferImpl +{ + public: + RenderbufferD3D(RendererD3D *renderer); + virtual ~RenderbufferD3D(); + + static RenderbufferD3D *makeRenderbufferD3D(RenderbufferImpl *renderbuffer); + + virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override; + virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) override; + + RenderTargetD3D *getRenderTarget(); + unsigned int getRenderTargetSerial() const; + + private: + RendererD3D *mRenderer; + RenderTargetD3D *mRenderTarget; +}; +} + +#endif // LIBANGLE_RENDERER_D3D_RENDERBUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp new file mode 100644 index 0000000000..2ce0ce5a1b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp @@ -0,0 +1,628 @@ +// +// Copyright (c) 2014 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. +// + +// RendererD3D.cpp: Implementation of the base D3D Renderer. + +#include "libANGLE/renderer/d3d/RendererD3D.h" + +#include "common/MemoryBuffer.h" +#include "common/utilities.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/DisplayD3D.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" + +namespace rx +{ + +namespace +{ +// If we request a scratch buffer requesting a smaller size this many times, +// release and recreate the scratch buffer. This ensures we don't have a +// degenerate case where we are stuck hogging memory. +const int ScratchMemoryBufferLifetime = 1000; +} + +RendererD3D::RendererD3D(egl::Display *display) + : mDisplay(display), + mDeviceLost(false), + mScratchMemoryBufferResetCounter(0) +{ +} + +RendererD3D::~RendererD3D() +{ + cleanup(); +} + +void RendererD3D::cleanup() +{ + mScratchMemoryBuffer.resize(0); + for (auto it = mIncompleteTextures.begin(); it != mIncompleteTextures.end(); ++it) + { + it->second.set(NULL); + } + mIncompleteTextures.clear(); +} + +// static +RendererD3D *RendererD3D::makeRendererD3D(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(RendererD3D*, renderer)); + return static_cast(renderer); +} + +gl::Error RendererD3D::drawElements(const gl::Data &data, + GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) +{ + if (data.state->isPrimitiveRestartEnabled()) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "Primitive restart not implemented"); + } + + gl::Program *program = data.state->getProgram(); + ASSERT(program != NULL); + + program->updateSamplerMapping(); + + gl::Error error = generateSwizzles(data); + if (error.isError()) + { + return error; + } + + if (!applyPrimitiveType(mode, count, program->usesPointSize())) + { + return gl::Error(GL_NO_ERROR); + } + + error = applyRenderTarget(data, mode, false); + if (error.isError()) + { + return error; + } + + error = applyState(data, mode); + if (error.isError()) + { + return error; + } + + gl::VertexArray *vao = data.state->getVertexArray(); + TranslatedIndexData indexInfo; + indexInfo.indexRange = indexRange; + error = applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); + if (error.isError()) + { + return error; + } + + applyTransformFeedbackBuffers(*data.state); + // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation + // layer. + ASSERT(!data.state->isTransformFeedbackActiveUnpaused()); + + GLsizei vertexCount = indexInfo.indexRange.length() + 1; + error = applyVertexBuffer(*data.state, mode, indexInfo.indexRange.start, vertexCount, instances); + if (error.isError()) + { + return error; + } + + error = applyShaders(data); + if (error.isError()) + { + return error; + } + + error = applyTextures(data); + if (error.isError()) + { + return error; + } + + error = program->applyUniformBuffers(data); + if (error.isError()) + { + return error; + } + + if (!skipDraw(data, mode)) + { + error = drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::drawArrays(const gl::Data &data, + GLenum mode, GLint first, + GLsizei count, GLsizei instances) +{ + gl::Program *program = data.state->getProgram(); + ASSERT(program != NULL); + + program->updateSamplerMapping(); + + gl::Error error = generateSwizzles(data); + if (error.isError()) + { + return error; + } + + if (!applyPrimitiveType(mode, count, program->usesPointSize())) + { + return gl::Error(GL_NO_ERROR); + } + + error = applyRenderTarget(data, mode, false); + if (error.isError()) + { + return error; + } + + error = applyState(data, mode); + if (error.isError()) + { + return error; + } + + applyTransformFeedbackBuffers(*data.state); + + error = applyVertexBuffer(*data.state, mode, first, count, instances); + if (error.isError()) + { + return error; + } + + error = applyShaders(data); + if (error.isError()) + { + return error; + } + + error = applyTextures(data); + if (error.isError()) + { + return error; + } + + error = program->applyUniformBuffers(data); + if (error.isError()) + { + return error; + } + + if (!skipDraw(data, mode)) + { + error = drawArrays(data, mode, count, instances, program->usesPointSize()); + if (error.isError()) + { + return error; + } + + if (data.state->isTransformFeedbackActiveUnpaused()) + { + markTransformFeedbackUsage(data); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::generateSwizzles(const gl::Data &data, gl::SamplerType type) +{ + gl::Program *program = data.state->getProgram(); + + size_t samplerRange = program->getUsedSamplerRange(type); + + for (size_t i = 0; i < samplerRange; i++) + { + GLenum textureType = program->getSamplerTextureType(type, i); + GLint textureUnit = program->getSamplerMapping(type, i, *data.caps); + if (textureUnit != -1) + { + gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); + ASSERT(texture); + if (texture->getSamplerState().swizzleRequired()) + { + gl::Error error = generateSwizzle(texture); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::generateSwizzles(const gl::Data &data) +{ + gl::Error error = generateSwizzles(data, gl::SAMPLER_VERTEX); + if (error.isError()) + { + return error; + } + + error = generateSwizzles(data, gl::SAMPLER_PIXEL); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +// Applies the render target surface, depth stencil surface, viewport rectangle and +// scissor rectangle to the renderer +gl::Error RendererD3D::applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport) +{ + const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); + ASSERT(framebufferObject && framebufferObject->checkStatus(data) == GL_FRAMEBUFFER_COMPLETE); + + gl::Error error = applyRenderTarget(framebufferObject); + if (error.isError()) + { + return error; + } + + float nearZ, farZ; + data.state->getDepthRange(&nearZ, &farZ); + setViewport(data.state->getViewport(), nearZ, farZ, drawMode, + data.state->getRasterizerState().frontFace, ignoreViewport); + + setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); + + return gl::Error(GL_NO_ERROR); +} + +// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D device +gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode) +{ + const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); + int samples = framebufferObject->getSamples(data); + + gl::RasterizerState rasterizer = data.state->getRasterizerState(); + rasterizer.pointDrawMode = (drawMode == GL_POINTS); + rasterizer.multiSample = (samples != 0); + + gl::Error error = setRasterizerState(rasterizer); + if (error.isError()) + { + return error; + } + + unsigned int mask = 0; + if (data.state->isSampleCoverageEnabled()) + { + GLclampf coverageValue; + bool coverageInvert = false; + data.state->getSampleCoverageParams(&coverageValue, &coverageInvert); + if (coverageValue != 0) + { + float threshold = 0.5f; + + for (int i = 0; i < samples; ++i) + { + mask <<= 1; + + if ((i + 1) * coverageValue >= threshold) + { + threshold += 1.0f; + mask |= 1; + } + } + } + + if (coverageInvert) + { + mask = ~mask; + } + } + else + { + mask = 0xFFFFFFFF; + } + error = setBlendState(framebufferObject, data.state->getBlendState(), data.state->getBlendColor(), mask); + if (error.isError()) + { + return error; + } + + error = setDepthStencilState(data.state->getDepthStencilState(), data.state->getStencilRef(), + data.state->getStencilBackRef(), rasterizer.frontFace == GL_CCW); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +// Applies the shaders and shader constants to the Direct3D device +gl::Error RendererD3D::applyShaders(const gl::Data &data) +{ + gl::Program *program = data.state->getProgram(); + + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + gl::VertexFormat::GetInputLayout(inputLayout, program, *data.state); + + const gl::Framebuffer *fbo = data.state->getDrawFramebuffer(); + + gl::Error error = applyShaders(program, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, data.state->isTransformFeedbackActiveUnpaused()); + if (error.isError()) + { + return error; + } + + return program->applyUniforms(); +} + +// For each Direct3D 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). +gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType, + const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount) +{ + gl::Program *program = data.state->getProgram(); + + size_t samplerRange = program->getUsedSamplerRange(shaderType); + for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + GLenum textureType = program->getSamplerTextureType(shaderType, samplerIndex); + GLint textureUnit = program->getSamplerMapping(shaderType, samplerIndex, *data.caps); + if (textureUnit != -1) + { + gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); + ASSERT(texture); + gl::SamplerState sampler = texture->getSamplerState(); + + gl::Sampler *samplerObject = data.state->getSampler(textureUnit); + if (samplerObject) + { + samplerObject->getState(&sampler); + } + + // TODO: std::binary_search may become unavailable using older versions of GCC + if (texture->isSamplerComplete(sampler, data) && + !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial())) + { + gl::Error error = setSamplerState(shaderType, samplerIndex, texture, sampler); + if (error.isError()) + { + return error; + } + + error = setTexture(shaderType, samplerIndex, texture); + if (error.isError()) + { + return error; + } + } + else + { + // Texture is not sampler complete or it is in use by the framebuffer. Bind the incomplete texture. + gl::Texture *incompleteTexture = getIncompleteTexture(textureType); + gl::Error error = setTexture(shaderType, samplerIndex, incompleteTexture); + if (error.isError()) + { + return error; + } + } + } + else + { + // No texture bound to this slot even though it is used by the shader, bind a NULL texture + gl::Error error = setTexture(shaderType, samplerIndex, NULL); + if (error.isError()) + { + return error; + } + } + } + + // Set all the remaining textures to NULL + size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits + : data.caps->maxVertexTextureImageUnits; + for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + { + gl::Error error = setTexture(shaderType, samplerIndex, NULL); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::applyTextures(const gl::Data &data) +{ + FramebufferTextureSerialArray framebufferSerials; + size_t framebufferSerialCount = getBoundFramebufferTextureSerials(data, &framebufferSerials); + + gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferSerials, framebufferSerialCount); + if (error.isError()) + { + return error; + } + + error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferSerials, framebufferSerialCount); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +bool RendererD3D::skipDraw(const gl::Data &data, 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 (!data.state->getProgram()->usesPointSize() && !data.state->isTransformFeedbackActiveUnpaused()) + { + // 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 (gl::IsTriangleMode(drawMode)) + { + if (data.state->getRasterizerState().cullFace && data.state->getRasterizerState().cullMode == GL_FRONT_AND_BACK) + { + return true; + } + } + + return false; +} + +void RendererD3D::markTransformFeedbackUsage(const gl::Data &data) +{ + for (size_t i = 0; i < data.caps->maxTransformFeedbackSeparateAttributes; i++) + { + gl::Buffer *buffer = data.state->getIndexedTransformFeedbackBuffer(i); + if (buffer) + { + BufferD3D *bufferD3D = GetImplAs(buffer); + bufferD3D->markTransformFeedbackUsage(); + } + } +} + +size_t RendererD3D::getBoundFramebufferTextureSerials(const gl::Data &data, + FramebufferTextureSerialArray *outSerialArray) +{ + size_t serialCount = 0; + + const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); + for (unsigned int i = 0; i < data.caps->maxColorAttachments; i++) + { + gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); + if (attachment && attachment->type() == GL_TEXTURE) + { + gl::Texture *texture = attachment->getTexture(); + (*outSerialArray)[serialCount++] = texture->getTextureSerial(); + } + } + + gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); + if (depthStencilAttachment && depthStencilAttachment->type() == GL_TEXTURE) + { + gl::Texture *depthStencilTexture = depthStencilAttachment->getTexture(); + (*outSerialArray)[serialCount++] = depthStencilTexture->getTextureSerial(); + } + + std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount); + + return serialCount; +} + +gl::Texture *RendererD3D::getIncompleteTexture(GLenum type) +{ + if (mIncompleteTextures.find(type) == mIncompleteTextures.end()) + { + const GLubyte color[] = { 0, 0, 0, 255 }; + const gl::Extents colorSize(1, 1, 1); + const gl::PixelUnpackState incompleteUnpackState(1, 0); + + gl::Texture* t = new gl::Texture(createTexture(type), gl::Texture::INCOMPLETE_TEXTURE_ID, type); + + if (type == GL_TEXTURE_CUBE_MAP) + { + for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++) + { + t->setImage(face, 0, GL_RGBA, colorSize, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + } + } + else + { + t->setImage(type, 0, GL_RGBA, colorSize, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + } + + mIncompleteTextures[type].set(t); + } + + return mIncompleteTextures[type].get(); +} + +bool RendererD3D::isDeviceLost() const +{ + return mDeviceLost; +} + +void RendererD3D::notifyDeviceLost() +{ + mDeviceLost = true; + mDisplay->notifyDeviceLost(); +} + +std::string RendererD3D::getVendorString() const +{ + LUID adapterLuid = { 0 }; + + if (getLUID(&adapterLuid)) + { + char adapterLuidString[64]; + sprintf_s(adapterLuidString, sizeof(adapterLuidString), "(adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); + return std::string(adapterLuidString); + } + + return std::string(""); +} + +gl::Error RendererD3D::getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut) +{ + if (mScratchMemoryBuffer.size() == requestedSize) + { + mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime; + *bufferOut = &mScratchMemoryBuffer; + return gl::Error(GL_NO_ERROR); + } + + if (mScratchMemoryBuffer.size() > requestedSize) + { + mScratchMemoryBufferResetCounter--; + } + + if (mScratchMemoryBufferResetCounter <= 0 || mScratchMemoryBuffer.size() < requestedSize) + { + mScratchMemoryBuffer.resize(0); + if (!mScratchMemoryBuffer.resize(requestedSize)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + } + mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime; + } + + ASSERT(mScratchMemoryBuffer.size() >= requestedSize); + + *bufferOut = &mScratchMemoryBuffer; + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h new file mode 100644 index 0000000000..3de6c20886 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.h @@ -0,0 +1,241 @@ + +// Copyright (c) 2014 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. +// + +// RendererD3D.h: Defines a back-end specific class for the DirectX renderer. + +#ifndef LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ +#define LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ + +#include "common/MemoryBuffer.h" +#include "libANGLE/Data.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/d3d/formatutilsD3D.h" +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +//FIXME(jmadill): std::array is currently prohibited by Chromium style guide +#include + +namespace egl +{ +class ConfigSet; +} + +namespace gl +{ +class InfoLog; +struct LinkedVarying; +class Texture; +} + +namespace rx +{ +class ImageD3D; +class IndexBuffer; +class RenderTargetD3D; +class ShaderExecutableD3D; +class SwapChainD3D; +class TextureStorage; +class UniformStorageD3D; +class VertexBuffer; + +enum ShaderType +{ + SHADER_VERTEX, + SHADER_PIXEL, + SHADER_GEOMETRY +}; + +enum RendererClass +{ + RENDERER_D3D11, + RENDERER_D3D9, +}; + +// Useful for unit testing +class BufferFactoryD3D +{ + public: + BufferFactoryD3D() {} + virtual ~BufferFactoryD3D() {} + + virtual VertexBuffer *createVertexBuffer() = 0; + virtual IndexBuffer *createIndexBuffer() = 0; + + // TODO(jmadill): add VertexFormatCaps + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const = 0; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const = 0; +}; + +class RendererD3D : public Renderer, public BufferFactoryD3D +{ + public: + explicit RendererD3D(egl::Display *display); + virtual ~RendererD3D(); + + virtual egl::Error initialize() = 0; + + static RendererD3D *makeRendererD3D(Renderer *renderer); + + virtual egl::ConfigSet generateConfigs() const = 0; + + gl::Error drawArrays(const gl::Data &data, + GLenum mode, GLint first, + GLsizei count, GLsizei instances) override; + + gl::Error drawElements(const gl::Data &data, + GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) override; + + bool isDeviceLost() const override; + std::string getVendorString() const override; + + virtual int getMinorShaderModel() const = 0; + virtual std::string getShaderModelSuffix() const = 0; + + // Direct3D Specific methods + virtual GUID getAdapterIdentifier() const = 0; + + virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0; + + virtual gl::Error generateSwizzle(gl::Texture *texture) = 0; + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler) = 0; + virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0; + + virtual gl::Error setUniformBuffers(const gl::Data &data, + const GLint vertexUniformBuffers[], + const GLint fragmentUniformBuffers[]) = 0; + + virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState) = 0; + virtual gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) = 0; + virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW) = 0; + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled) = 0; + virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) = 0; + + virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 0; + virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) = 0; + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) = 0; + virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize) = 0; + virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances) = 0; + virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0; + virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0; + + virtual void markAllStateDirty() = 0; + + virtual unsigned int getReservedVertexUniformVectors() const = 0; + virtual unsigned int getReservedFragmentUniformVectors() const = 0; + virtual unsigned int getReservedVertexUniformBuffers() const = 0; + virtual unsigned int getReservedFragmentUniformBuffers() const = 0; + virtual bool getShareHandleSupport() const = 0; + virtual bool getPostSubBufferSupport() const = 0; + + virtual int getMajorShaderModel() const = 0; + + // Pixel operations + virtual gl::Error copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0; + virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) = 0; + virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0; + virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) = 0; + + // RenderTarget creation + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) = 0; + + // Shader operations + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) = 0; + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable) = 0; + virtual UniformStorageD3D *createUniformStorage(size_t storageSize) = 0; + + // Image operations + virtual ImageD3D *createImage() = 0; + virtual gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) = 0; + virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) = 0; + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) = 0; + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) = 0; + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const = 0; + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) = 0; + + // Device lost + void notifyDeviceLost() override; + virtual bool resetDevice() = 0; + + virtual RendererClass getRendererClass() const = 0; + + gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut); + + protected: + virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) = 0; + virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0; + + virtual bool getLUID(LUID *adapterLuid) const = 0; + + void cleanup(); + + egl::Display *mDisplay; + bool mDeviceLost; + + private: + //FIXME(jmadill): std::array is currently prohibited by Chromium style guide + typedef std::array FramebufferTextureSerialArray; + + gl::Error generateSwizzles(const gl::Data &data, gl::SamplerType type); + gl::Error generateSwizzles(const gl::Data &data); + + gl::Error applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport); + gl::Error applyState(const gl::Data &data, GLenum drawMode); + gl::Error applyShaders(const gl::Data &data); + gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType, + const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount); + gl::Error applyTextures(const gl::Data &data); + + bool skipDraw(const gl::Data &data, GLenum drawMode); + void markTransformFeedbackUsage(const gl::Data &data); + + size_t getBoundFramebufferTextureSerials(const gl::Data &data, + FramebufferTextureSerialArray *outSerialArray); + gl::Texture *getIncompleteTexture(GLenum type); + + gl::TextureMap mIncompleteTextures; + MemoryBuffer mScratchMemoryBuffer; + unsigned int mScratchMemoryBufferResetCounter; +}; + +struct dx_VertexConstants +{ + float depthRange[4]; + float viewAdjust[4]; + float viewCoords[4]; +}; + +struct dx_PixelConstants +{ + float depthRange[4]; + float viewCoords[4]; + float depthFront[4]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_RENDERERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp new file mode 100644 index 0000000000..7d522a95d4 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.cpp @@ -0,0 +1,388 @@ +// +// Copyright (c) 2014 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. +// + +// ShaderD3D.cpp: Defines the rx::ShaderD3D class which implements rx::ShaderImpl. + +#include "libANGLE/Shader.h" +#include "libANGLE/Compiler.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/features.h" + +#include "common/utilities.h" + +// Definitions local to the translation unit +namespace +{ + +const char *GetShaderTypeString(GLenum type) +{ + switch (type) + { + case GL_VERTEX_SHADER: + return "VERTEX"; + + case GL_FRAGMENT_SHADER: + return "FRAGMENT"; + + default: + UNREACHABLE(); + return ""; + } +} + +} + +namespace rx +{ + +template +void FilterInactiveVariables(std::vector *variableList) +{ + ASSERT(variableList); + + for (size_t varIndex = 0; varIndex < variableList->size();) + { + if (!(*variableList)[varIndex].staticUse) + { + variableList->erase(variableList->begin() + varIndex); + } + else + { + varIndex++; + } + } +} + +template +const std::vector *GetShaderVariables(const std::vector *variableList) +{ + ASSERT(variableList); + return variableList; +} + +ShaderD3D::ShaderD3D(GLenum type) + : mShaderType(type), + mShaderVersion(100) +{ + uncompile(); +} + +ShaderD3D::~ShaderD3D() +{ +} + +ShaderD3D *ShaderD3D::makeShaderD3D(ShaderImpl *impl) +{ + ASSERT(HAS_DYNAMIC_TYPE(ShaderD3D*, impl)); + return static_cast(impl); +} + +const ShaderD3D *ShaderD3D::makeShaderD3D(const ShaderImpl *impl) +{ + ASSERT(HAS_DYNAMIC_TYPE(const ShaderD3D*, impl)); + return static_cast(impl); +} + +std::string ShaderD3D::getDebugInfo() const +{ + return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mShaderType) + " SHADER END\n"; +} + + +void ShaderD3D::parseVaryings(ShHandle compiler) +{ + if (!mTranslatedSource.empty()) + { + const std::vector *varyings = ShGetVaryings(compiler); + ASSERT(varyings); + + for (size_t varyingIndex = 0; varyingIndex < varyings->size(); varyingIndex++) + { + mVaryings.push_back(gl::PackedVarying((*varyings)[varyingIndex])); + } + + mUsesMultipleRenderTargets = mTranslatedSource.find("GL_USES_MRT") != std::string::npos; + mUsesFragColor = mTranslatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos; + mUsesFragData = mTranslatedSource.find("GL_USES_FRAG_DATA") != std::string::npos; + mUsesFragCoord = mTranslatedSource.find("GL_USES_FRAG_COORD") != std::string::npos; + mUsesFrontFacing = mTranslatedSource.find("GL_USES_FRONT_FACING") != std::string::npos; + mUsesPointSize = mTranslatedSource.find("GL_USES_POINT_SIZE") != std::string::npos; + mUsesPointCoord = mTranslatedSource.find("GL_USES_POINT_COORD") != std::string::npos; + mUsesDepthRange = mTranslatedSource.find("GL_USES_DEPTH_RANGE") != std::string::npos; + mUsesFragDepth = mTranslatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos; + mUsesDiscardRewriting = mTranslatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; + mUsesNestedBreak = mTranslatedSource.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; + mUsesDeferredInit = mTranslatedSource.find("ANGLE_USES_DEFERRED_INIT") != std::string::npos; + mRequiresIEEEStrictCompiling = mTranslatedSource.find("ANGLE_REQUIRES_IEEE_STRICT_COMPILING") != std::string::npos; + } +} + +void ShaderD3D::resetVaryingsRegisterAssignment() +{ + for (size_t varyingIndex = 0; varyingIndex < mVaryings.size(); varyingIndex++) + { + mVaryings[varyingIndex].resetRegisterAssignment(); + } +} + +// initialize/clean up previous state +void ShaderD3D::uncompile() +{ + // set by compileToHLSL + mCompilerOutputType = SH_ESSL_OUTPUT; + mTranslatedSource.clear(); + mInfoLog.clear(); + + mUsesMultipleRenderTargets = false; + mUsesFragColor = false; + mUsesFragData = false; + mUsesFragCoord = false; + mUsesFrontFacing = false; + mUsesPointSize = false; + mUsesPointCoord = false; + mUsesDepthRange = false; + mUsesFragDepth = false; + mShaderVersion = 100; + mUsesDiscardRewriting = false; + mUsesNestedBreak = false; + mUsesDeferredInit = false; + mRequiresIEEEStrictCompiling = false; + + mVaryings.clear(); + mUniforms.clear(); + mInterfaceBlocks.clear(); + mActiveAttributes.clear(); + mActiveOutputVariables.clear(); + mDebugInfo.clear(); +} + +void ShaderD3D::compileToHLSL(ShHandle compiler, const std::string &source) +{ + int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES); + std::string sourcePath; + +#if !defined (ANGLE_ENABLE_WINDOWS_STORE) + if (gl::DebugAnnotationsActive()) + { + sourcePath = getTempPath(); + writeFile(sourcePath.c_str(), source.c_str(), source.length()); + compileOptions |= SH_LINE_DIRECTIVES; + } +#endif + + int result; + if (sourcePath.empty()) + { + const char* sourceStrings[] = + { + source.c_str(), + }; + + result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions); + } + else + { + const char* sourceStrings[] = + { + sourcePath.c_str(), + source.c_str(), + }; + + result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions | SH_SOURCE_PATH); + } + + mShaderVersion = ShGetShaderVersion(compiler); + + if (result) + { + mTranslatedSource = ShGetObjectCode(compiler); + +#ifdef _DEBUG + // Prefix hlsl shader with commented out glsl shader + // Useful in diagnostics tools like pix which capture the hlsl shaders + std::ostringstream hlslStream; + hlslStream << "// GLSL\n"; + hlslStream << "//\n"; + + size_t curPos = 0; + while (curPos != std::string::npos) + { + size_t nextLine = source.find("\n", curPos); + size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1); + + hlslStream << "// " << source.substr(curPos, len); + + curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); + } + hlslStream << "\n\n"; + hlslStream << mTranslatedSource; + mTranslatedSource = hlslStream.str(); +#endif + + mUniforms = *GetShaderVariables(ShGetUniforms(compiler)); + + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = mUniforms[uniformIndex]; + + if (uniform.staticUse) + { + unsigned int index = static_cast(-1); + bool getUniformRegisterResult = ShGetUniformRegister(compiler, uniform.name, &index); + UNUSED_ASSERTION_VARIABLE(getUniformRegisterResult); + ASSERT(getUniformRegisterResult); + + mUniformRegisterMap[uniform.name] = index; + } + } + + mInterfaceBlocks = *GetShaderVariables(ShGetInterfaceBlocks(compiler)); + + for (size_t blockIndex = 0; blockIndex < mInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = mInterfaceBlocks[blockIndex]; + + if (interfaceBlock.staticUse) + { + unsigned int index = static_cast(-1); + bool blockRegisterResult = ShGetInterfaceBlockRegister(compiler, interfaceBlock.name, &index); + UNUSED_ASSERTION_VARIABLE(blockRegisterResult); + ASSERT(blockRegisterResult); + + mInterfaceBlockRegisterMap[interfaceBlock.name] = index; + } + } + } + else + { + mInfoLog = ShGetInfoLog(compiler); + + TRACE("\n%s", mInfoLog.c_str()); + } +} + +void ShaderD3D::generateWorkarounds(D3DCompilerWorkarounds *workarounds) const +{ + if (mUsesDiscardRewriting) + { + // ANGLE issue 486: + // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization + workarounds->skipOptimization = true; + } + else if (mUsesNestedBreak) + { + // ANGLE issue 603: + // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop, by maximizing optimization + // We want to keep the use of ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes precedence + workarounds->useMaxOptimization = true; + } + + if (mRequiresIEEEStrictCompiling) + { + // IEEE Strictness for D3D compiler needs to be enabled for NaNs to work. + workarounds->enableIEEEStrictness = true; + } +} + +// true if varying x has a higher priority in packing than y +bool ShaderD3D::compareVarying(const gl::PackedVarying &x, const gl::PackedVarying &y) +{ + if (x.type == y.type) + { + return x.arraySize > y.arraySize; + } + + // Special case for handling structs: we sort these to the end of the list + if (x.type == GL_STRUCT_ANGLEX) + { + return false; + } + + if (y.type == GL_STRUCT_ANGLEX) + { + return true; + } + + return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type); +} + +unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const +{ + ASSERT(mUniformRegisterMap.count(uniformName) > 0); + return mUniformRegisterMap.find(uniformName)->second; +} + +unsigned int ShaderD3D::getInterfaceBlockRegister(const std::string &blockName) const +{ + ASSERT(mInterfaceBlockRegisterMap.count(blockName) > 0); + return mInterfaceBlockRegisterMap.find(blockName)->second; +} + +GLenum ShaderD3D::getShaderType() const +{ + return mShaderType; +} + +ShShaderOutput ShaderD3D::getCompilerOutputType() const +{ + return mCompilerOutputType; +} + +bool ShaderD3D::compile(gl::Compiler *compiler, const std::string &source) +{ + uncompile(); + + CompilerD3D *compilerD3D = CompilerD3D::makeCompilerD3D(compiler->getImplementation()); + ShHandle compilerHandle = compilerD3D->getCompilerHandle(mShaderType); + + mCompilerOutputType = ShGetShaderOutputType(compilerHandle); + + compileToHLSL(compilerHandle, source); + + if (mShaderType == GL_VERTEX_SHADER) + { + parseAttributes(compilerHandle); + } + + parseVaryings(compilerHandle); + + if (mShaderType == GL_FRAGMENT_SHADER) + { + std::sort(mVaryings.begin(), mVaryings.end(), compareVarying); + + const std::string &hlsl = getTranslatedSource(); + if (!hlsl.empty()) + { + mActiveOutputVariables = *GetShaderVariables(ShGetOutputVariables(compilerHandle)); + FilterInactiveVariables(&mActiveOutputVariables); + } + } + +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + mDebugInfo += std::string("// ") + GetShaderTypeString(mShaderType) + " SHADER BEGIN\n"; + mDebugInfo += "\n// GLSL BEGIN\n\n" + source + "\n\n// GLSL END\n\n\n"; + mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + getTranslatedSource() + "\n// INITIAL HLSL END\n\n\n"; + // Successive steps will append more info +#else + mDebugInfo += getTranslatedSource(); +#endif + + return !getTranslatedSource().empty(); +} + +void ShaderD3D::parseAttributes(ShHandle compiler) +{ + const std::string &hlsl = getTranslatedSource(); + if (!hlsl.empty()) + { + mActiveAttributes = *GetShaderVariables(ShGetAttributes(compiler)); + FilterInactiveVariables(&mActiveAttributes); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h new file mode 100644 index 0000000000..d0237b5985 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderD3D.h @@ -0,0 +1,89 @@ +// +// Copyright (c) 2014 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. +// + +// ShaderD3D.h: Defines the rx::ShaderD3D class which implements rx::ShaderImpl. + +#ifndef LIBANGLE_RENDERER_D3D_SHADERD3D_H_ +#define LIBANGLE_RENDERER_D3D_SHADERD3D_H_ + +#include "libANGLE/renderer/ShaderImpl.h" +#include "libANGLE/renderer/Workarounds.h" +#include "libANGLE/Shader.h" + +#include + +namespace rx +{ +class DynamicHLSL; +class RendererD3D; + +class ShaderD3D : public ShaderImpl +{ + friend class DynamicHLSL; + + public: + ShaderD3D(GLenum type); + virtual ~ShaderD3D(); + + static ShaderD3D *makeShaderD3D(ShaderImpl *impl); + static const ShaderD3D *makeShaderD3D(const ShaderImpl *impl); + + // ShaderImpl implementation + virtual std::string getDebugInfo() const; + + // D3D-specific methods + virtual void uncompile(); + void resetVaryingsRegisterAssignment(); + unsigned int getUniformRegister(const std::string &uniformName) const; + unsigned int getInterfaceBlockRegister(const std::string &blockName) const; + void appendDebugInfo(const std::string &info) { mDebugInfo += info; } + + void generateWorkarounds(D3DCompilerWorkarounds *workarounds) const; + int getShaderVersion() const { return mShaderVersion; } + bool usesDepthRange() const { return mUsesDepthRange; } + bool usesPointSize() const { return mUsesPointSize; } + bool usesDeferredInit() const { return mUsesDeferredInit; } + + GLenum getShaderType() const; + ShShaderOutput getCompilerOutputType() const; + + virtual bool compile(gl::Compiler *compiler, const std::string &source); + + private: + void compileToHLSL(ShHandle compiler, const std::string &source); + void parseVaryings(ShHandle compiler); + + void parseAttributes(ShHandle compiler); + + static bool compareVarying(const gl::PackedVarying &x, const gl::PackedVarying &y); + + GLenum mShaderType; + + int mShaderVersion; + + bool mUsesMultipleRenderTargets; + bool mUsesFragColor; + bool mUsesFragData; + bool mUsesFragCoord; + bool mUsesFrontFacing; + bool mUsesPointSize; + bool mUsesPointCoord; + bool mUsesDepthRange; + bool mUsesFragDepth; + bool mUsesDiscardRewriting; + bool mUsesNestedBreak; + bool mUsesDeferredInit; + bool mRequiresIEEEStrictCompiling; + + ShShaderOutput mCompilerOutputType; + std::string mDebugInfo; + std::map mUniformRegisterMap; + std::map mInterfaceBlockRegisterMap; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_SHADERD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp new file mode 100644 index 0000000000..97ffdf5094 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp @@ -0,0 +1,61 @@ +// +// Copyright (c) 2012-2015 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. +// + +// ShaderExecutable.cpp: Implements a class to contain D3D shader executable +// implementation details. + +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" + +#include "common/angleutils.h" + +namespace rx +{ + +ShaderExecutableD3D::ShaderExecutableD3D(const void *function, size_t length) + : mFunctionBuffer(length) +{ + memcpy(mFunctionBuffer.data(), function, length); +} + +ShaderExecutableD3D::~ShaderExecutableD3D() +{ +} + +const uint8_t *ShaderExecutableD3D::getFunction() const +{ + return mFunctionBuffer.data(); +} + +size_t ShaderExecutableD3D::getLength() const +{ + return mFunctionBuffer.size(); +} + +const std::string &ShaderExecutableD3D::getDebugInfo() const +{ + return mDebugInfo; +} + +void ShaderExecutableD3D::appendDebugInfo(const std::string &info) +{ + mDebugInfo += info; +} + + +UniformStorageD3D::UniformStorageD3D(size_t initialSize) : mSize(initialSize) +{ +} + +UniformStorageD3D::~UniformStorageD3D() +{ +} + +size_t UniformStorageD3D::size() const +{ + return mSize; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h new file mode 100644 index 0000000000..71b83b7954 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h @@ -0,0 +1,54 @@ +// +// Copyright (c) 2012-2015 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. +// + +// ShaderExecutable.h: Defines a class to contain D3D shader executable +// implementation details. + +#ifndef LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ +#define LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ + +#include "common/debug.h" + +#include +#include + +namespace rx +{ + +class ShaderExecutableD3D : angle::NonCopyable +{ + public: + ShaderExecutableD3D(const void *function, size_t length); + virtual ~ShaderExecutableD3D(); + + const uint8_t *getFunction() const; + + size_t getLength() const; + + const std::string &getDebugInfo() const; + + void appendDebugInfo(const std::string &info); + + private: + std::vector mFunctionBuffer; + std::string mDebugInfo; +}; + +class UniformStorageD3D : angle::NonCopyable +{ + public: + UniformStorageD3D(size_t initialSize); + virtual ~UniformStorageD3D(); + + size_t size() const; + + private: + size_t mSize; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_SHADEREXECUTABLED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp new file mode 100644 index 0000000000..4fde295443 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp @@ -0,0 +1,396 @@ +// +// Copyright (c) 2014 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. +// + +// SurfaceD3D.cpp: D3D implementation of an EGL surface + +#include "libANGLE/renderer/d3d/SurfaceD3D.h" + +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" + +#include +#include +#include + +namespace rx +{ + +SurfaceD3D *SurfaceD3D::createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLClientBuffer shareHandle, + EGLint width, EGLint height) +{ + return new SurfaceD3D(renderer, display, config, width, height, EGL_TRUE, shareHandle, NULL); +} + +SurfaceD3D *SurfaceD3D::createFromWindow(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLNativeWindowType window, + EGLint fixedSize, EGLint width, EGLint height) +{ + return new SurfaceD3D(renderer, display, config, width, height, fixedSize, static_cast(0), window); +} + +SurfaceD3D::SurfaceD3D(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLint width, EGLint height, EGLint fixedSize, + EGLClientBuffer shareHandle, EGLNativeWindowType window) + : SurfaceImpl(), + mRenderer(renderer), + mDisplay(display), + mFixedSize(fixedSize == EGL_TRUE), + mRenderTargetFormat(config->renderTargetFormat), + mDepthStencilFormat(config->depthStencilFormat), + mSwapChain(nullptr), + mSwapIntervalDirty(true), + mWindowSubclassed(false), + mNativeWindow(window), + mWidth(width), + mHeight(height), + mSwapInterval(1), + mShareHandle(reinterpret_cast(shareHandle)) +{ + subclassWindow(); +} + +SurfaceD3D::~SurfaceD3D() +{ + unsubclassWindow(); + releaseSwapChain(); +} + +void SurfaceD3D::releaseSwapChain() +{ + SafeDelete(mSwapChain); +} + +egl::Error SurfaceD3D::initialize() +{ + if (mNativeWindow.getNativeWindow()) + { + if (!mNativeWindow.initialize()) + { + return egl::Error(EGL_BAD_SURFACE); + } + } + + egl::Error error = resetSwapChain(); + if (error.isError()) + { + return error; + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::bindTexImage(EGLint) +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::releaseTexImage(EGLint) +{ + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::resetSwapChain() +{ + ASSERT(!mSwapChain); + + int width; + int height; + + if (!mFixedSize) + { + RECT windowRect; + if (!mNativeWindow.getClientRect(&windowRect)) + { + ASSERT(false); + + return egl::Error(EGL_BAD_SURFACE, "Could not retrieve the window dimensions"); + } + + width = windowRect.right - windowRect.left; + height = windowRect.bottom - windowRect.top; + } + else + { + // non-window surface - size is determined at creation + width = mWidth; + height = mHeight; + } + + mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mRenderTargetFormat, mDepthStencilFormat); + if (!mSwapChain) + { + return egl::Error(EGL_BAD_ALLOC); + } + + egl::Error error = resetSwapChain(width, height); + if (error.isError()) + { + SafeDelete(mSwapChain); + return error; + } + + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::resizeSwapChain(int backbufferWidth, int backbufferHeight) +{ + ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); + ASSERT(mSwapChain); + + EGLint status = mSwapChain->resize(std::max(1, backbufferWidth), std::max(1, backbufferHeight)); + + if (status == EGL_CONTEXT_LOST) + { + mDisplay->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::resetSwapChain(int backbufferWidth, int backbufferHeight) +{ + ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); + ASSERT(mSwapChain); + + EGLint status = mSwapChain->reset(std::max(1, backbufferWidth), std::max(1, backbufferHeight), mSwapInterval); + + if (status == EGL_CONTEXT_LOST) + { + mRenderer->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + mSwapIntervalDirty = false; + + return egl::Error(EGL_SUCCESS); +} + +egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return egl::Error(EGL_SUCCESS); + } + + if (x + width > mWidth) + { + width = mWidth - x; + } + + if (y + height > mHeight) + { + height = mHeight - y; + } + + if (width == 0 || height == 0) + { + return egl::Error(EGL_SUCCESS); + } + + EGLint status = mSwapChain->swapRect(x, y, width, height); + + if (status == EGL_CONTEXT_LOST) + { + mRenderer->notifyDeviceLost(); + return egl::Error(status); + } + else if (status != EGL_SUCCESS) + { + return egl::Error(status); + } + + checkForOutOfDateSwapChain(); + + return egl::Error(EGL_SUCCESS); +} + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +#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) + { + SurfaceD3D* surf = reinterpret_cast(GetProp(hwnd, kSurfaceProperty)); + if(surf) + { + surf->checkForOutOfDateSwapChain(); + } + } + WNDPROC prevWndFunc = reinterpret_cast(GetProp(hwnd, kParentWndProc)); + return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam); +} +#endif + +void SurfaceD3D::subclassWindow() +{ +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + HWND window = mNativeWindow.getNativeWindow(); + if (!window) + { + return; + } + + DWORD processId; + DWORD threadId = GetWindowThreadProcessId(window, &processId); + if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId()) + { + return; + } + + SetLastError(0); + LONG_PTR oldWndProc = SetWindowLongPtr(window, GWLP_WNDPROC, reinterpret_cast(SurfaceWindowProc)); + if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) + { + mWindowSubclassed = false; + return; + } + + SetProp(window, kSurfaceProperty, reinterpret_cast(this)); + SetProp(window, kParentWndProc, reinterpret_cast(oldWndProc)); + mWindowSubclassed = true; +#endif +} + +void SurfaceD3D::unsubclassWindow() +{ + if (!mWindowSubclassed) + { + return; + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + HWND window = mNativeWindow.getNativeWindow(); + if (!window) + { + return; + } + + // un-subclass + LONG_PTR parentWndFunc = reinterpret_cast(GetProp(window, 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(window, GWLP_WNDPROC, parentWndFunc); + UNUSED_ASSERTION_VARIABLE(prevWndFunc); + ASSERT(prevWndFunc == reinterpret_cast(SurfaceWindowProc)); + } + + RemoveProp(window, kSurfaceProperty); + RemoveProp(window, kParentWndProc); +#endif + mWindowSubclassed = false; +} + +bool SurfaceD3D::checkForOutOfDateSwapChain() +{ + RECT client; + int clientWidth = getWidth(); + int clientHeight = getHeight(); + bool sizeDirty = false; + if (!mFixedSize && !mNativeWindow.isIconic()) + { + // The window is automatically resized to 150x22 when it's minimized, but the swapchain shouldn't be resized + // because that's not a useful size to render to. + if (!mNativeWindow.getClientRect(&client)) + { + ASSERT(false); + return false; + } + + // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. + clientWidth = client.right - client.left; + clientHeight = client.bottom - client.top; + sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); + } + + bool wasDirty = (mSwapIntervalDirty || sizeDirty); + + if (mSwapIntervalDirty) + { + resetSwapChain(clientWidth, clientHeight); + } + else if (sizeDirty) + { + resizeSwapChain(clientWidth, clientHeight); + } + + return wasDirty; +} + +egl::Error SurfaceD3D::swap() +{ + return swapRect(0, 0, mWidth, mHeight); +} + +egl::Error SurfaceD3D::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +{ + return swapRect(x, y, width, height); +} + +rx::SwapChainD3D *SurfaceD3D::getSwapChain() const +{ + return mSwapChain; +} + +void SurfaceD3D::setSwapInterval(EGLint interval) +{ + if (mSwapInterval == interval) + { + return; + } + + mSwapInterval = interval; + mSwapIntervalDirty = true; +} + +EGLint SurfaceD3D::getWidth() const +{ + return mWidth; +} + +EGLint SurfaceD3D::getHeight() const +{ + return mHeight; +} + +EGLint SurfaceD3D::isPostSubBufferSupported() const +{ + // post sub buffer is always possible on D3D surfaces + return EGL_TRUE; +} + +egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value) +{ + ASSERT(attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || attribute == EGL_DEVICE_EXT); + if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) + *value = mSwapChain->getShareHandle(); + else if (attribute == EGL_DEVICE_EXT) + *value = mSwapChain->getDevice(); + return egl::Error(EGL_SUCCESS); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h new file mode 100644 index 0000000000..070b7cdbc4 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h @@ -0,0 +1,92 @@ +// +// Copyright (c) 2014 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. +// + +// SurfaceD3D.h: D3D implementation of an EGL surface + +#ifndef LIBANGLE_RENDERER_D3D_SURFACED3D_H_ +#define LIBANGLE_RENDERER_D3D_SURFACED3D_H_ + +#include "libANGLE/renderer/SurfaceImpl.h" +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +namespace egl +{ +class Surface; +} + +namespace rx +{ +class SwapChainD3D; +class RendererD3D; + +class SurfaceD3D : public SurfaceImpl +{ + public: + static SurfaceD3D *createFromWindow(RendererD3D *renderer, egl::Display *display, const egl::Config *config, + EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height); + static SurfaceD3D *createOffscreen(RendererD3D *renderer, egl::Display *display, const egl::Config *config, + EGLClientBuffer shareHandle, EGLint width, EGLint height); + ~SurfaceD3D() override; + void releaseSwapChain(); + + egl::Error initialize() override; + + egl::Error swap() override; + egl::Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) override; + egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override; + egl::Error bindTexImage(EGLint buffer) override; + egl::Error releaseTexImage(EGLint buffer) override; + void setSwapInterval(EGLint interval) override; + + EGLint getWidth() const override; + EGLint getHeight() const override; + + EGLint isPostSubBufferSupported() const override; + + // D3D implementations + SwapChainD3D *getSwapChain() const; + + egl::Error resetSwapChain(); + + // Returns true if swapchain changed due to resize or interval update + bool checkForOutOfDateSwapChain(); + + private: + SurfaceD3D(RendererD3D *renderer, egl::Display *display, const egl::Config *config, EGLint width, EGLint height, + EGLint fixedSize, EGLClientBuffer shareHandle, EGLNativeWindowType window); + + egl::Error swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + egl::Error resetSwapChain(int backbufferWidth, int backbufferHeight); + egl::Error resizeSwapChain(int backbufferWidth, int backbufferHeight); + + void subclassWindow(); + void unsubclassWindow(); + + RendererD3D *mRenderer; + egl::Display *mDisplay; + + bool mFixedSize; + + GLenum mRenderTargetFormat; + GLenum mDepthStencilFormat; + + SwapChainD3D *mSwapChain; + bool mSwapIntervalDirty; + bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking + + NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. + EGLint mWidth; + EGLint mHeight; + + EGLint mSwapInterval; + + HANDLE mShareHandle; +}; + + +} + +#endif // LIBANGLE_RENDERER_D3D_SURFACED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h new file mode 100644 index 0000000000..da36e52ea7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h @@ -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. +// + +// SwapChainD3D.h: Defines a back-end specific class that hides the details of the +// implementation-specific swapchain. + +#ifndef LIBANGLE_RENDERER_D3D_SWAPCHAIND3D_H_ +#define LIBANGLE_RENDERER_D3D_SWAPCHAIND3D_H_ + +#include +#include + +#include "common/angleutils.h" +#include "common/platform.h" + +// TODO: move out of D3D11 +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +#if !defined(ANGLE_FORCE_VSYNC_OFF) +#define ANGLE_FORCE_VSYNC_OFF 0 +#endif + +namespace rx +{ +class RenderTargetD3D; + +class SwapChainD3D : angle::NonCopyable +{ + public: + SwapChainD3D(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) + : mNativeWindow(nativeWindow), mShareHandle(shareHandle), mBackBufferFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat) + { + } + + virtual ~SwapChainD3D() {}; + + virtual EGLint resize(EGLint backbufferWidth, EGLint backbufferSize) = 0; + virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0; + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0; + virtual void recreate() = 0; + virtual void *getDevice() { return NULL; } + + virtual RenderTargetD3D *getColorRenderTarget() = 0; + virtual RenderTargetD3D *getDepthStencilRenderTarget() = 0; + + GLenum GetBackBufferInternalFormat() const { return mBackBufferFormat; } + GLenum GetDepthBufferInternalFormat() const { return mDepthBufferFormat; } + + HANDLE getShareHandle() { return mShareHandle; } + + protected: + rx::NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. + const GLenum mBackBufferFormat; + const GLenum mDepthBufferFormat; + + HANDLE mShareHandle; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_SWAPCHAIND3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp new file mode 100644 index 0000000000..78b03f2283 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp @@ -0,0 +1,2916 @@ +// +// Copyright 2014 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. +// + +// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends. + +#include "libANGLE/renderer/d3d/TextureD3D.h" + +#include "common/mathutil.h" +#include "common/utilities.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Config.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/BufferImpl.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/ImageD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/TextureStorage.h" + +namespace rx +{ + +namespace +{ + +gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pixels, + ptrdiff_t layerOffset, const uint8_t **pointerOut) +{ + if (unpack.pixelBuffer.id() != 0) + { + // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported + gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); + ptrdiff_t offset = reinterpret_cast(pixels); + + // TODO: this is the only place outside of renderer that asks for a buffers raw data. + // This functionality should be moved into renderer and the getData method of BufferImpl removed. + BufferD3D *bufferD3D = GetImplAs(pixelBuffer); + ASSERT(bufferD3D); + const uint8_t *bufferData = NULL; + gl::Error error = bufferD3D->getData(&bufferData); + if (error.isError()) + { + return error; + } + + *pointerOut = bufferData + offset; + } + else + { + *pointerOut = pixels; + } + + // Offset the pointer for 2D array layer (if it's valid) + if (*pointerOut != nullptr) + { + *pointerOut += layerOffset; + } + + return gl::Error(GL_NO_ERROR); +} + +bool IsRenderTargetUsage(GLenum usage) +{ + return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); +} + +} + +TextureD3D::TextureD3D(RendererD3D *renderer) + : mRenderer(renderer), + mUsage(GL_NONE), + mDirtyImages(true), + mImmutable(false), + mTexStorage(NULL) +{ +} + +TextureD3D::~TextureD3D() +{ +} + +gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage) +{ + // ensure the underlying texture is created + gl::Error error = initializeStorage(false); + if (error.isError()) + { + return error; + } + + if (mTexStorage) + { + error = updateStorage(); + if (error.isError()) + { + return error; + } + } + + ASSERT(outStorage); + + *outStorage = mTexStorage; + return gl::Error(GL_NO_ERROR); +} + +GLint TextureD3D::getBaseLevelWidth() const +{ + const ImageD3D *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getWidth() : 0); +} + +GLint TextureD3D::getBaseLevelHeight() const +{ + const ImageD3D *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getHeight() : 0); +} + +GLint TextureD3D::getBaseLevelDepth() const +{ + const ImageD3D *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getDepth() : 0); +} + +// Note: "base level image" is loosely defined to be any image from the base level, +// where in the base of 2D array textures and cube maps there are several. Don't use +// the base level image for anything except querying texture format and size. +GLenum TextureD3D::getBaseLevelInternalFormat() const +{ + const ImageD3D *baseImage = getBaseLevelImage(); + return (baseImage ? baseImage->getInternalFormat() : GL_NONE); +} + +bool TextureD3D::shouldUseSetData(const ImageD3D *image) const +{ + if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload) + { + return false; + } + + gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); + + // We can only handle full updates for depth-stencil textures, so to avoid complications + // disable them entirely. + if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0) + { + return false; + } + + // TODO(jmadill): Handle compressed internal formats + return (mTexStorage && !internalFormat.compressed); +} + +gl::Error TextureD3D::setImage(const gl::ImageIndex &index, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, + ptrdiff_t layerOffset) +{ + if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state"); + } + + ImageD3D *image = getImage(index); + ASSERT(image); + + // No-op + if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) + { + return gl::Error(GL_NO_ERROR); + } + + // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. + // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); + if (error.isError()) + { + return error; + } + + if (pixelData != NULL) + { + if (shouldUseSetData(image)) + { + error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData); + } + else + { + gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + error = image->loadData(fullImageArea, unpack, type, pixelData); + } + + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D::subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset) +{ + // CPU readback & copy where direct GPU copy is not supported + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); + if (error.isError()) + { + return error; + } + + if (pixelData != NULL) + { + ImageD3D *image = getImage(index); + ASSERT(image); + + if (shouldUseSetData(image)) + { + return mTexStorage->setData(index, image, &area, type, unpack, pixelData); + } + + error = image->loadData(area, unpack, type, pixelData); + if (error.isError()) + { + return error; + } + + error = commitRegion(index, area); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D::setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, + const uint8_t *pixels, ptrdiff_t layerOffset) +{ + if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state"); + } + + // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. + // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); + if (error.isError()) + { + return error; + } + + if (pixelData != NULL) + { + ImageD3D *image = getImage(index); + ASSERT(image); + + gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + error = image->loadCompressedData(fullImageArea, pixelData); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, + ptrdiff_t layerOffset) +{ + if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state"); + } + + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, layerOffset, &pixelData); + if (error.isError()) + { + return error; + } + + if (pixelData != NULL) + { + ImageD3D *image = getImage(index); + ASSERT(image); + + error = image->loadCompressedData(area, pixelData); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) +{ + return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); +} + +gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea, + GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget) +{ + // No-op + if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) + { + return gl::Error(GL_NO_ERROR); + } + + // In order to perform the fast copy through the shader, we must have the right format, and be able + // to create a render target. + ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); + + uintptr_t offset = reinterpret_cast(pixels); + + gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const +{ + if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT) + { + // Maximum number of levels + return gl::log2(std::max(std::max(width, height), depth)) + 1; + } + else + { + // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. + return 1; + } +} + +int TextureD3D::mipLevels() const +{ + return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; +} + +TextureStorage *TextureD3D::getStorage() +{ + ASSERT(mTexStorage); + return mTexStorage; +} + +ImageD3D *TextureD3D::getBaseLevelImage() const +{ + return getImage(getImageIndex(0, 0)); +} + +gl::Error TextureD3D::generateMipmaps() +{ + GLint mipCount = mipLevels(); + + if (mipCount == 1) + { + return gl::Error(GL_NO_ERROR); // no-op + } + + if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + // Switch to using the mipmapped texture. + TextureStorage *textureStorage = NULL; + gl::Error error = getNativeTexture(&textureStorage); + if (error.isError()) + { + return error; + } + + error = textureStorage->useLevelZeroWorkaroundTexture(false); + if (error.isError()) + { + return error; + } + } + + // Set up proper mipmap chain in our Image array. + initMipmapsImages(); + + // We know that all layers have the same dimension, for the texture to be complete + GLint layerCount = static_cast(getLayerCount(0)); + + // When making mipmaps with the setData workaround enabled, the texture storage has + // the image data already. For non-render-target storage, we have to pull it out into + // an image layer. + if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage) + { + if (!mTexStorage->isRenderTarget()) + { + // Copy from the storage mip 0 to Image mip 0 + for (GLint layer = 0; layer < layerCount; ++layer) + { + gl::ImageIndex srcIndex = getImageIndex(0, layer); + + ImageD3D *image = getImage(srcIndex); + gl::Box area(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth()); + gl::Offset offset(0, 0, 0); + gl::Error error = image->copy(offset, area, srcIndex, mTexStorage); + if (error.isError()) + { + return error; + } + } + } + else + { + gl::Error error = updateStorage(); + if (error.isError()) + { + return error; + } + } + } + + // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to zeroMaxLodWorkaround. + // The restriction is because Feature Level 9_3 can't create SRVs on individual levels of the texture. + // As a result, even if the storage is a rendertarget, we can't use the GPU to generate the mipmaps without further work. + // The D3D9 renderer works around this by copying each level of the texture into its own single-layer GPU texture (in Blit9::boxFilter). + // Feature Level 9_3 could do something similar, or it could continue to use CPU-side mipmap generation, or something else. + bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() && !(mRenderer->getWorkarounds().zeroMaxLodWorkaround)); + + for (GLint layer = 0; layer < layerCount; ++layer) + { + for (GLint mip = 1; mip < mipCount; ++mip) + { + ASSERT(getLayerCount(mip) == layerCount); + + gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer); + gl::ImageIndex destIndex = getImageIndex(mip, layer); + + if (renderableStorage) + { + // GPU-side mipmapping + gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex); + if (error.isError()) + { + return error; + } + } + else + { + // CPU-side mipmapping + gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex)); + if (error.isError()) + { + return error; + } + } + } + } + + if (mTexStorage) + { + updateStorage(); + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D::isBaseImageZeroSize() const +{ + ImageD3D *baseImage = getBaseLevelImage(); + + if (!baseImage || baseImage->getWidth() <= 0) + { + return true; + } + + if (!gl::IsCubeMapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0) + { + return true; + } + + if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0) + { + return true; + } + + if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0) + { + return true; + } + + return false; +} + +gl::Error TextureD3D::ensureRenderTarget() +{ + gl::Error error = initializeStorage(true); + if (error.isError()) + { + return error; + } + + if (!isBaseImageZeroSize()) + { + ASSERT(mTexStorage); + if (!mTexStorage->isRenderTarget()) + { + TextureStorage *newRenderTargetStorage = NULL; + error = createCompleteStorage(true, &newRenderTargetStorage); + if (error.isError()) + { + return error; + } + + error = mTexStorage->copyToStorage(newRenderTargetStorage); + if (error.isError()) + { + SafeDelete(newRenderTargetStorage); + return error; + } + + error = setCompleteTexStorage(newRenderTargetStorage); + if (error.isError()) + { + SafeDelete(newRenderTargetStorage); + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const +{ + ImageD3D *image = getImage(index); + bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0))); + return (image->isRenderableFormat() && levelsComplete); +} + +gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) +{ + if (mTexStorage) + { + ASSERT(isValidIndex(index)); + ImageD3D *image = getImage(index); + gl::Error error = image->copyToStorage(mTexStorage, index, region); + if (error.isError()) + { + return error; + } + + image->markClean(); + } + + return gl::Error(GL_NO_ERROR); +} + +TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer) + : TextureD3D(renderer) +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + mImageArray[i] = renderer->createImage(); + } +} + +TextureD3D_2D::~TextureD3D_2D() +{ + // Delete the Images before the TextureStorage. + // Images might be relying on the TextureStorage for some of their data. + // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + delete mImageArray[i]; + } + + SafeDelete(mTexStorage); +} + +ImageD3D *TextureD3D_2D::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(layer == 0); + return mImageArray[level]; +} + +ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const +{ + ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(!index.hasLayer()); + ASSERT(index.type == GL_TEXTURE_2D); + return mImageArray[index.mipIndex]; +} + +GLsizei TextureD3D_2D::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return 1; +} + +GLsizei TextureD3D_2D::getWidth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getWidth(); + else + return 0; +} + +GLsizei TextureD3D_2D::getHeight(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getHeight(); + else + return 0; +} + +GLenum TextureD3D_2D::getInternalFormat(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getInternalFormat(); + else + return GL_NONE; +} + +bool TextureD3D_2D::isDepth(GLint level) const +{ + return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D && size.depth == 1); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + + bool fastUnpacked = false; + + redefineImage(level, sizedInternalFormat, size); + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + + // Attempt a fast gpu copy of the pixel data to the surface + if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) + { + // Will try to create RT storage if it does not exist + RenderTargetD3D *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + + gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); + + error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); + if (error.isError()) + { + return error; + } + + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; + } + + if (!fastUnpacked) + { + gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0); + + if (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 || unpack.skipImages != 0) + { + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "unimplemented pixel store state"); + } + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) + { + RenderTargetD3D *renderTarget = NULL; + gl::Error error = getRenderTarget(index, &renderTarget); + if (error.isError()) + { + return error; + } + + ASSERT(!mImageArray[level]->isDirty()); + + return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget); + } + else + { + return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + } +} + + +gl::Error TextureD3D_2D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D && size.depth == 1); + + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, internalFormat, size); + + return TextureD3D::setCompressedImage(gl::ImageIndex::Make2D(level), unpack, pixels, 0); +} + +gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0); + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + + return commitRegion(index, area); +} + +gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) +{ + ASSERT(target == GL_TEXTURE_2D); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); + redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1)); + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Offset destOffset(0, 0, 0); + + // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, + // so we should use the non-rendering copy path. + if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + mImageArray[level]->markClean(); + + if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level)) + { + error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0); + + // can only make our texture storage to a render target if level 0 is defined (with a width & height) and + // the current level we're copying to is defined (with appropriate format, width & height) + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + + // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, + // so we should use the non-rendering copy path. + if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (isValidLevel(level)) + { + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + + error = mRenderer->copyImage2D(source, sourceArea, + gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + destOffset, mTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +{ + ASSERT(GL_TEXTURE_2D && size.depth == 1); + + for (size_t level = 0; level < levels; level++) + { + gl::Extents levelSize(std::max(1, size.width >> level), + std::max(1, size.height >> level), + 1); + mImageArray[level]->redefine(GL_TEXTURE_2D, internalFormat, levelSize, true); + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true); + } + + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mUsage); + TextureStorage *storage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, size.height, levels, false); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + error = updateStorage(); + + if (error.isError()) + { + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_2D::bindTexImage(egl::Surface *surface) +{ + GLenum internalformat = surface->getConfig()->renderTargetFormat; + + gl::Extents size(surface->getWidth(), surface->getHeight(), 1); + mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, size, true); + + if (mTexStorage) + { + SafeDelete(mTexStorage); + } + + SurfaceD3D *surfaceD3D = GetImplAs(surface); + ASSERT(surfaceD3D); + + mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain()); + + mDirtyImages = true; +} + +void TextureD3D_2D::releaseTexImage() +{ + if (mTexStorage) + { + SafeDelete(mTexStorage); + } + + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true); + } +} + +void TextureD3D_2D::initMipmapsImages() +{ + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) + { + gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), + std::max(getBaseLevelHeight() >> level, 1), + 1); + + redefineImage(level, getBaseLevelInternalFormat(), levelSize); + } +} + +unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index) +{ + ASSERT(!index.hasLayer()); + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); +} + +gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + // ensure the underlying texture is created + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); +} + +bool TextureD3D_2D::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false); +} + +bool TextureD3D_2D::isLevelComplete(int level) const +{ + if (isImmutable()) + { + return true; + } + + const ImageD3D *baseImage = getBaseLevelImage(); + + GLsizei width = baseImage->getWidth(); + GLsizei height = baseImage->getHeight(); + + if (width <= 0 || height <= 0) + { + return false; + } + + // The base image level is complete if the width and height are positive + if (level == 0) + { + return true; + } + + ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ImageD3D *image = mImageArray[level]; + + if (image->getInternalFormat() != baseImage->getInternalFormat()) + { + return false; + } + + if (image->getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (image->getHeight() != std::max(1, height >> level)) + { + return false; + } + + return true; +} + +bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + +// Constructs a native texture resource from the texture images +gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::Error(GL_NO_ERROR); + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return gl::Error(GL_NO_ERROR); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + ASSERT(mTexStorage); + + // flush image data to the storage + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLenum internalFormat = getBaseLevelInternalFormat(); + + ASSERT(width > 0 && height > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); + + bool hintLevelZeroOnly = false; + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use the mipped texture to begin with. + // Otherwise, it should use the level-zero-only texture. + hintLevelZeroOnly = true; + for (int level = 1; level < levels && hintLevelZeroOnly; level++) + { + hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level)); + } + } + + // TODO(geofflang): Determine if the texture creation succeeded + *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels, hintLevelZeroOnly); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +{ + if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) + { + for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) + { + gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + + mDirtyImages = true; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[level]->isDirty() && isLevelComplete(level)) + { + gl::Error error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2D::updateStorageLevel(int level) +{ + ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(isLevelComplete(level)); + + if (mImageArray[level]->isDirty()) + { + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +{ + ASSERT(size.depth == 1); + + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + size.width != storageWidth || + size.height != storageHeight || + internalformat != storageFormat) // Discard mismatched storage + { + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + + SafeDelete(mTexStorage); + mDirtyImages = true; + } + } +} + +gl::ImageIndexIterator TextureD3D_2D::imageIterator() const +{ + return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); +} + +gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // "layer" does not apply to 2D Textures. + return gl::ImageIndex::Make2D(mip); +} + +bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_2D && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer) + : TextureD3D(renderer) +{ + for (int i = 0; i < 6; i++) + { + for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + { + mImageArray[i][j] = renderer->createImage(); + } + } +} + +TextureD3D_Cube::~TextureD3D_Cube() +{ + // Delete the Images before the TextureStorage. + // Images might be relying on the TextureStorage for some of their data. + // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + for (int i = 0; i < 6; i++) + { + for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) + { + SafeDelete(mImageArray[i][j]); + } + } + + SafeDelete(mTexStorage); +} + +ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(layer >= 0 && layer < 6); + return mImageArray[layer][level]; +} + +ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const +{ + ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(index.layerIndex >= 0 && index.layerIndex < 6); + return mImageArray[index.layerIndex][index.mipIndex]; +} + +GLsizei TextureD3D_Cube::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return 6; +} + +GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[layer][level]->getInternalFormat(); + else + return GL_NONE; +} + +bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const +{ + return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; +} + +gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(size.depth == 1); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + redefineImage(index.layerIndex, level, sizedInternalFormat, size); + + return TextureD3D::setImage(index, type, unpack, pixels, 0); +} + +gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(area.depth == 1 && area.z == 0); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); +} + +gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(size.depth == 1); + + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target); + + redefineImage(faceIndex, level, internalFormat, size); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + return TextureD3D::setCompressedImage(index, unpack, pixels, 0); +} + +gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(area.depth == 1 && area.z == 0); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + + return commitRegion(index, area); +} + +gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) +{ + size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target); + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE); + + gl::Extents size(sourceArea.width, sourceArea.height, 1); + redefineImage(faceIndex, level, sizedInternalFormat, size); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + gl::Offset destOffset(0, 0, 0); + + // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, + // so we should use the non-rendering copy path. + if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + mImageArray[faceIndex][level]->markClean(); + + ASSERT(size.width == size.height); + + if (size.width > 0 && isValidFaceLevel(faceIndex, level)) + { + error = mRenderer->copyImageCube(source, sourceArea, internalFormat, destOffset, mTexStorage, target, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders, + // so we should use the non-rendering copy path. + if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (isValidFaceLevel(faceIndex, level)) + { + error = updateStorageFaceLevel(faceIndex, level); + if (error.isError()) + { + return error; + } + + error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + destOffset, mTexStorage, target, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +{ + ASSERT(size.width == size.height); + ASSERT(size.depth == 1); + + for (size_t level = 0; level < levels; level++) + { + GLsizei mipSize = std::max(1, size.width >> level); + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalFormat, gl::Extents(mipSize, mipSize, 1), true); + } + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, GL_NONE, gl::Extents(0, 0, 0), true); + } + } + + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mUsage); + + TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels, false); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + error = updateStorage(); + + if (error.isError()) + { + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); +} + +// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureD3D_Cube::isCubeComplete() const +{ + int baseWidth = getBaseLevelWidth(); + int baseHeight = getBaseLevelHeight(); + GLenum baseFormat = getBaseLevelInternalFormat(); + + if (baseWidth <= 0 || baseWidth != baseHeight) + { + return false; + } + + for (int faceIndex = 1; faceIndex < 6; faceIndex++) + { + const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; + + if (faceBaseImage.getWidth() != baseWidth || + faceBaseImage.getHeight() != baseHeight || + faceBaseImage.getInternalFormat() != baseFormat ) + { + return false; + } + } + + return true; +} + +void TextureD3D_Cube::bindTexImage(egl::Surface *surface) +{ + UNREACHABLE(); +} + +void TextureD3D_Cube::releaseTexImage() +{ + UNREACHABLE(); +} + + +void TextureD3D_Cube::initMipmapsImages() +{ + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 1; level < levelCount; level++) + { + int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); + redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), + gl::Extents(faceLevelSize, faceLevelSize, 1)); + } + } +} + +unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index) +{ + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); +} + +gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(gl::IsCubeMapTextureTarget(index.type)); + + // ensure the underlying texture is created + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + error = updateStorageFaceLevel(index.layerIndex, index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); +} + +gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::Error(GL_NO_ERROR); + } + + // do not attempt to create storage for nonexistant data + if (!isFaceLevelComplete(0, 0)) + { + return gl::Error(GL_NO_ERROR); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + ASSERT(mTexStorage); + + // flush image data to the storage + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const +{ + GLsizei size = getBaseLevelWidth(); + + ASSERT(size > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1)); + + bool hintLevelZeroOnly = false; + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + // If any of the CPU images (levels >= 1) are dirty, then the textureStorage should use the mipped texture to begin with. + // Otherwise, it should use the level-zero-only texture. + hintLevelZeroOnly = true; + for (int faceIndex = 0; faceIndex < 6 && hintLevelZeroOnly; faceIndex++) + { + for (int level = 1; level < levels && hintLevelZeroOnly; level++) + { + hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() && isFaceLevelComplete(faceIndex, level)); + } + } + } + + // TODO (geofflang): detect if storage creation succeeded + *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +{ + if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) + { + for (int faceIndex = 0; faceIndex < 6; faceIndex++) + { + for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) + { + gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level); + if (error.isError()) + { + return error; + } + } + } + } + + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + + mDirtyImages = true; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_Cube::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) + { + gl::Error error = updateStorageFaceLevel(face, level); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + +bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const +{ + ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + + if (isImmutable()) + { + return true; + } + + int baseSize = getBaseLevelWidth(); + + if (baseSize <= 0) + { + return false; + } + + // "isCubeComplete" checks for base level completeness and we must call that + // to determine if any face at level 0 is complete. We omit that check here + // to avoid re-checking cube-completeness for every face at level 0. + if (level == 0) + { + return true; + } + + // Check that non-zero levels are consistent with the base level. + const ImageD3D *faceLevelImage = mImageArray[faceIndex][level]; + + if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) + { + return false; + } + + if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) + { + return false; + } + + return true; +} + +bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const +{ + return isFaceLevelComplete(index.layerIndex, index.mipIndex); +} + +gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) +{ + ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); + ImageD3D *image = mImageArray[faceIndex][level]; + + if (image->isDirty()) + { + GLenum faceTarget = gl::LayerIndexToCubeMapTextureTarget(faceIndex); + gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level); + gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + size.width != storageWidth || + size.height != storageHeight || + internalformat != storageFormat) // Discard mismatched storage + { + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) + { + for (int dirtyFace = 0; dirtyFace < 6; dirtyFace++) + { + mImageArray[dirtyFace][dirtyLevel]->markDirty(); + } + } + + SafeDelete(mTexStorage); + + mDirtyImages = true; + } + } +} + +gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const +{ + return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount()); +} + +gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const +{ + // The "layer" of the image index corresponds to the cube face + return gl::ImageIndex::MakeCube(gl::LayerIndexToCubeMapTextureTarget(layer), mip); +} + +bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && gl::IsCubeMapTextureTarget(index.type) && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer) + : TextureD3D(renderer) +{ + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + mImageArray[i] = renderer->createImage(); + } +} + +TextureD3D_3D::~TextureD3D_3D() +{ + // Delete the Images before the TextureStorage. + // Images might be relying on the TextureStorage for some of their data. + // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) + { + delete mImageArray[i]; + } + + SafeDelete(mTexStorage); +} + +ImageD3D *TextureD3D_3D::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(layer == 0); + return mImageArray[level]; +} + +ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const +{ + ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(!index.hasLayer()); + ASSERT(index.type == GL_TEXTURE_3D); + return mImageArray[index.mipIndex]; +} + +GLsizei TextureD3D_3D::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return 1; +} + +GLsizei TextureD3D_3D::getWidth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getWidth(); + else + return 0; +} + +GLsizei TextureD3D_3D::getHeight(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getHeight(); + else + return 0; +} + +GLsizei TextureD3D_3D::getDepth(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getDepth(); + else + return 0; +} + +GLenum TextureD3D_3D::getInternalFormat(GLint level) const +{ + if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + return mImageArray[level]->getInternalFormat(); + else + return GL_NONE; +} + +bool TextureD3D_3D::isDepth(GLint level) const +{ + return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_3D); + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + + redefineImage(level, sizedInternalFormat, size); + + bool fastUnpacked = false; + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + + // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer + if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty()) + { + // Will try to create RT storage if it does not exist + RenderTargetD3D *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + + gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + + error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); + if (error.isError()) + { + return error; + } + + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; + } + + if (!fastUnpacked) + { + gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_3D); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + + // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer + if (isFastUnpackable(unpack, getInternalFormat(level))) + { + RenderTargetD3D *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + + ASSERT(!mImageArray[level]->isDirty()); + + return fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget); + } + else + { + return TextureD3D::subImage(index, area, format, type, unpack, pixels, 0); + } +} + +gl::Error TextureD3D_3D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_3D); + + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, internalFormat, size); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + return TextureD3D::setCompressedImage(index, unpack, pixels, 0); +} + +gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_3D); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels, 0); + if (error.isError()) + { + return error; + } + + return commitRegion(index, area); +} + +gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented."); +} + +gl::Error TextureD3D_3D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + ASSERT(target == GL_TEXTURE_3D); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + + if (canCreateRenderTargetForImage(index)) + { + gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (isValidLevel(level)) + { + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + + error = mRenderer->copyImage3D(source, sourceArea, + gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + destOffset, mTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +{ + ASSERT(target == GL_TEXTURE_3D); + + for (size_t level = 0; level < levels; level++) + { + gl::Extents levelSize(std::max(1, size.width >> level), + std::max(1, size.height >> level), + std::max(1, size.depth >> level)); + mImageArray[level]->redefine(GL_TEXTURE_3D, internalFormat, levelSize, true); + } + + for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, gl::Extents(0, 0, 0), true); + } + + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mUsage); + TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, size.depth, levels); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + error = updateStorage(); + + if (error.isError()) + { + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_3D::bindTexImage(egl::Surface *surface) +{ + UNREACHABLE(); +} + +void TextureD3D_3D::releaseTexImage() +{ + UNREACHABLE(); +} + + +void TextureD3D_3D::initMipmapsImages() +{ + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) + { + gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1), + std::max(getBaseLevelHeight() >> level, 1), + std::max(getBaseLevelDepth() >> level, 1)); + redefineImage(level, getBaseLevelInternalFormat(), levelSize); + } +} + +unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index) +{ + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); +} + +gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + // ensure the underlying texture is created + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (index.hasLayer()) + { + error = updateStorage(); + if (error.isError()) + { + return error; + } + } + else + { + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } + } + + return mTexStorage->getRenderTarget(index, outRT); +} + +gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::Error(GL_NO_ERROR); + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return gl::Error(GL_NO_ERROR); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + ASSERT(mTexStorage); + + // flush image data to the storage + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getBaseLevelDepth(); + GLenum internalFormat = getBaseLevelInternalFormat(); + + ASSERT(width > 0 && height > 0 && depth > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); + + // TODO: Verify creation of the storage succeeded + *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +{ + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + mDirtyImages = true; + + // We do not support managed 3D storage, as that is D3D9/ES2-only + ASSERT(!mTexStorage->isManaged()); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_3D::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (mImageArray[level]->isDirty() && isLevelComplete(level)) + { + gl::Error error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D_3D::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + +bool TextureD3D_3D::isLevelComplete(int level) const +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + + if (isImmutable()) + { + return true; + } + + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getBaseLevelDepth(); + + if (width <= 0 || height <= 0 || depth <= 0) + { + return false; + } + + if (level == 0) + { + return true; + } + + ImageD3D *levelImage = mImageArray[level]; + + if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) + { + return false; + } + + if (levelImage->getWidth() != std::max(1, width >> level)) + { + return false; + } + + if (levelImage->getHeight() != std::max(1, height >> level)) + { + return false; + } + + if (levelImage->getDepth() != std::max(1, depth >> level)) + { + return false; + } + + return true; +} + +bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + +gl::Error TextureD3D_3D::updateStorageLevel(int level) +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); + ASSERT(isLevelComplete(level)); + + if (mImageArray[level]->isDirty()) + { + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageDepth = std::max(1, getBaseLevelDepth() >> level); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false); + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + size.width != storageWidth || + size.height != storageHeight || + size.depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage + { + for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mImageArray[i]->markDirty(); + } + + SafeDelete(mTexStorage); + mDirtyImages = true; + } + } +} + +gl::ImageIndexIterator TextureD3D_3D::imageIterator() const +{ + return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(), + gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL); +} + +gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // The "layer" here does not apply to 3D images. We use one Image per mip. + return gl::ImageIndex::Make3D(mip); +} + +bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_3D && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer) + : TextureD3D(renderer) +{ + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) + { + mLayerCounts[level] = 0; + mImageArray[level] = NULL; + } +} + +TextureD3D_2DArray::~TextureD3D_2DArray() +{ + // Delete the Images before the TextureStorage. + // Images might be relying on the TextureStorage for some of their data. + // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. + deleteImages(); + SafeDelete(mTexStorage); +} + +ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT((layer == 0 && mLayerCounts[level] == 0) || + layer < mLayerCounts[level]); + return (mImageArray[level] ? mImageArray[level][layer] : NULL); +} + +ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const +{ + ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) || + index.layerIndex < mLayerCounts[index.mipIndex]); + ASSERT(index.type == GL_TEXTURE_2D_ARRAY); + return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL); +} + +GLsizei TextureD3D_2DArray::getLayerCount(int level) const +{ + ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + return mLayerCounts[level]; +} + +GLsizei TextureD3D_2DArray::getWidth(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0; +} + +GLsizei TextureD3D_2DArray::getHeight(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0; +} + +GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const +{ + return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE; +} + +bool TextureD3D_2DArray::isDepth(GLint level) const +{ + return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; +} + +gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + + redefineImage(level, sizedInternalFormat, size); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment, unpack.rowLength); + + for (int i = 0; i < size.depth; i++) + { + const ptrdiff_t layerOffset = (inputDepthPitch * i); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); + gl::Error error = TextureD3D::setImage(index, type, unpack, pixels, layerOffset); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level)); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, unpack.rowLength); + + for (int i = 0; i < area.depth; i++) + { + int layer = area.z + i; + const ptrdiff_t layerOffset = (inputDepthPitch * i); + + gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, pixels, layerOffset); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly + redefineImage(level, internalFormat, size); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0); + + for (int i = 0; i < size.depth; i++) + { + const ptrdiff_t layerOffset = (inputDepthPitch * i); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); + gl::Error error = TextureD3D::setCompressedImage(index, unpack, pixels, layerOffset); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0); + + for (int i = 0; i < area.depth; i++) + { + int layer = area.z + i; + const ptrdiff_t layerOffset = (inputDepthPitch * i); + + gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, pixels, layerOffset); + if (error.isError()) + { + return error; + } + + error = commitRegion(index, layerArea); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) +{ + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented."); +} + +gl::Error TextureD3D_2DArray::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); + + if (canCreateRenderTargetForImage(index)) + { + gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0); + gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source); + if (error.isError()) + { + return error; + } + + mDirtyImages = true; + } + else + { + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + if (isValidLevel(level)) + { + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + + error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format, + destOffset, mTexStorage, level); + if (error.isError()) + { + return error; + } + } + } + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) +{ + ASSERT(target == GL_TEXTURE_2D_ARRAY); + + deleteImages(); + + for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + gl::Extents levelLayerSize(std::max(1, size.width >> level), + std::max(1, size.height >> level), + 1); + + mLayerCounts[level] = (level < levels ? size.depth : 0); + + if (mLayerCounts[level] > 0) + { + // Create new images for this level + mImageArray[level] = new ImageD3D*[mLayerCounts[level]]; + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mImageArray[level][layer] = mRenderer->createImage(); + mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalFormat, levelLayerSize, true); + } + } + } + + // TODO(geofflang): Verify storage creation had no errors + bool renderTarget = IsRenderTargetUsage(mUsage); + TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, size.height, size.depth, levels); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + error = updateStorage(); + + if (error.isError()) + { + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_2DArray::bindTexImage(egl::Surface *surface) +{ + UNREACHABLE(); +} + +void TextureD3D_2DArray::releaseTexImage() +{ + UNREACHABLE(); +} + + +void TextureD3D_2DArray::initMipmapsImages() +{ + int baseWidth = getBaseLevelWidth(); + int baseHeight = getBaseLevelHeight(); + int baseDepth = getLayerCount(0); + GLenum baseFormat = getBaseLevelInternalFormat(); + + // Purge array levels 1 through q and reset them to represent the generated mipmap levels. + int levelCount = mipLevels(); + for (int level = 1; level < levelCount; level++) + { + gl::Extents levelLayerSize(std::max(baseWidth >> level, 1), + std::max(baseHeight >> level, 1), + baseDepth); + redefineImage(level, baseFormat, levelLayerSize); + } +} + +unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index) +{ + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); +} + +gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + // ensure the underlying texture is created + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); +} + +gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) +{ + // Only initialize the first time this texture is used as a render target or shader resource + if (mTexStorage) + { + return gl::Error(GL_NO_ERROR); + } + + // do not attempt to create storage for nonexistant data + if (!isLevelComplete(0)) + { + return gl::Error(GL_NO_ERROR); + } + + bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); + + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + ASSERT(mTexStorage); + + // flush image data to the storage + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const +{ + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei depth = getLayerCount(0); + GLenum internalFormat = getBaseLevelInternalFormat(); + + ASSERT(width > 0 && height > 0 && depth > 0); + + // use existing storage level count, when previously specified by TexStorage*D + GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); + + // TODO(geofflang): Verify storage creation succeeds + *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +{ + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + mDirtyImages = true; + + // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only + ASSERT(!mTexStorage->isManaged()); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureD3D_2DArray::updateStorage() +{ + ASSERT(mTexStorage != NULL); + GLint storageLevels = mTexStorage->getLevelCount(); + for (int level = 0; level < storageLevels; level++) + { + if (isLevelComplete(level)) + { + gl::Error error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D_2DArray::isValidLevel(int level) const +{ + return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); +} + +bool TextureD3D_2DArray::isLevelComplete(int level) const +{ + ASSERT(level >= 0 && level < (int)ArraySize(mImageArray)); + + if (isImmutable()) + { + return true; + } + + GLsizei width = getBaseLevelWidth(); + GLsizei height = getBaseLevelHeight(); + GLsizei layers = getLayerCount(0); + + if (width <= 0 || height <= 0 || layers <= 0) + { + return false; + } + + if (level == 0) + { + return true; + } + + if (getInternalFormat(level) != getInternalFormat(0)) + { + return false; + } + + if (getWidth(level) != std::max(1, width >> level)) + { + return false; + } + + if (getHeight(level) != std::max(1, height >> level)) + { + return false; + } + + if (getLayerCount(level) != layers) + { + return false; + } + + return true; +} + +bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + +gl::Error TextureD3D_2DArray::updateStorageLevel(int level) +{ + ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); + ASSERT(isLevelComplete(level)); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); + if (mImageArray[level][layer]->isDirty()) + { + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureD3D_2DArray::deleteImages() +{ + for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) + { + for (int layer = 0; layer < mLayerCounts[level]; ++layer) + { + delete mImageArray[level][layer]; + } + delete[] mImageArray[level]; + mImageArray[level] = NULL; + mLayerCounts[level] = 0; + } +} + +void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size) +{ + // If there currently is a corresponding storage texture image, it has these parameters + const int storageWidth = std::max(1, getBaseLevelWidth() >> level); + const int storageHeight = std::max(1, getBaseLevelHeight() >> level); + const int storageDepth = getLayerCount(0); + const GLenum storageFormat = getBaseLevelInternalFormat(); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + delete mImageArray[level][layer]; + } + delete[] mImageArray[level]; + mImageArray[level] = NULL; + mLayerCounts[level] = size.depth; + + if (size.depth > 0) + { + mImageArray[level] = new ImageD3D*[size.depth](); + + for (int layer = 0; layer < mLayerCounts[level]; layer++) + { + mImageArray[level][layer] = mRenderer->createImage(); + mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat, + gl::Extents(size.width, size.height, 1), false); + } + } + + if (mTexStorage) + { + const int storageLevels = mTexStorage->getLevelCount(); + + if ((level >= storageLevels && storageLevels != 0) || + size.width != storageWidth || + size.height != storageHeight || + size.depth != storageDepth || + internalformat != storageFormat) // Discard mismatched storage + { + for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++) + { + for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++) + { + mImageArray[dirtyLevel][dirtyLayer]->markDirty(); + } + } + + delete mTexStorage; + mTexStorage = NULL; + mDirtyImages = true; + } + } +} + +gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const +{ + return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts); +} + +gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const +{ + return gl::ImageIndex::Make2DArray(mip, layer); +} + +bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const +{ + // Check for having a storage and the right type of index + if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY) + { + return false; + } + + // Check the mip index + if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount()) + { + return false; + } + + // Check the layer index + return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex])); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h new file mode 100644 index 0000000000..d94be49a08 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureD3D.h @@ -0,0 +1,364 @@ +// +// Copyright 2014 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. +// + +// TextureD3D.h: Implementations of the Texture interfaces shared betweeen the D3D backends. + +#ifndef LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ +#define LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ + +#include "libANGLE/renderer/TextureImpl.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Constants.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ + +class ImageD3D; +class ImageD3D; +class RendererD3D; +class RenderTargetD3D; +class TextureStorage; + +class TextureD3D : public TextureImpl +{ + public: + TextureD3D(RendererD3D *renderer); + virtual ~TextureD3D(); + + gl::Error getNativeTexture(TextureStorage **outStorage); + + virtual void setUsage(GLenum usage) { mUsage = usage; } + bool hasDirtyImages() const { return mDirtyImages; } + void resetDirty() { mDirtyImages = false; } + + virtual ImageD3D *getImage(const gl::ImageIndex &index) const = 0; + virtual GLsizei getLayerCount(int level) const = 0; + + GLint getBaseLevelWidth() const; + GLint getBaseLevelHeight() const; + GLint getBaseLevelDepth() const; + GLenum getBaseLevelInternalFormat() const; + + bool isImmutable() const { return mImmutable; } + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index) = 0; + + // Returns an iterator over all "Images" for this particular Texture. + virtual gl::ImageIndexIterator imageIterator() const = 0; + + // Returns an ImageIndex for a particular "Image". 3D Textures do not have images for + // slices of their depth texures, so 3D textures ignore the layer parameter. + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0; + virtual bool isValidIndex(const gl::ImageIndex &index) const = 0; + + virtual gl::Error generateMipmaps(); + TextureStorage *getStorage(); + ImageD3D *getBaseLevelImage() const; + + protected: + gl::Error setImage(const gl::ImageIndex &index, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, + ptrdiff_t layerOffset); + gl::Error subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset); + gl::Error setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, + const uint8_t *pixels, ptrdiff_t layerOffset); + gl::Error subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels, ptrdiff_t layerOffset); + bool isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat); + gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea, + GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget); + + GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const; + int mipLevels() const; + virtual void initMipmapsImages() = 0; + bool isBaseImageZeroSize() const; + virtual bool isImageComplete(const gl::ImageIndex &index) const = 0; + + bool canCreateRenderTargetForImage(const gl::ImageIndex &index) const; + virtual gl::Error ensureRenderTarget(); + + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const = 0; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0; + gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); + + RendererD3D *mRenderer; + + GLenum mUsage; + + bool mDirtyImages; + + bool mImmutable; + TextureStorage *mTexStorage; + + private: + virtual gl::Error initializeStorage(bool renderTarget) = 0; + + virtual gl::Error updateStorage() = 0; + + bool shouldUseSetData(const ImageD3D *image) const; +}; + +class TextureD3D_2D : public TextureD3D +{ + public: + TextureD3D_2D(RendererD3D *renderer); + virtual ~TextureD3D_2D(); + + virtual ImageD3D *getImage(int level, int layer) const; + virtual ImageD3D *getImage(const gl::ImageIndex &index) const; + virtual GLsizei getLayerCount(int level) const; + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLenum getInternalFormat(GLint level) const; + bool isDepth(GLint level) const; + + gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + + private: + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); + + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; + + gl::Error updateStorageLevel(int level); + + void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + + ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureD3D_Cube : public TextureD3D +{ + public: + TextureD3D_Cube(RendererD3D *renderer); + virtual ~TextureD3D_Cube(); + + virtual ImageD3D *getImage(int level, int layer) const; + virtual ImageD3D *getImage(const gl::ImageIndex &index) const; + virtual GLsizei getLayerCount(int level) const; + + virtual bool hasDirtyImages() const { return mDirtyImages; } + virtual void resetDirty() { mDirtyImages = false; } + virtual void setUsage(GLenum usage) { mUsage = usage; } + + GLenum getInternalFormat(GLint level, GLint layer) const; + bool isDepth(GLint level, GLint layer) const; + + gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + + private: + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); + + bool isValidFaceLevel(int faceIndex, int level) const; + bool isFaceLevelComplete(int faceIndex, int level) const; + bool isCubeComplete() const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageFaceLevel(int faceIndex, int level); + + void redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size); + + ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureD3D_3D : public TextureD3D +{ + public: + TextureD3D_3D(RendererD3D *renderer); + virtual ~TextureD3D_3D(); + + virtual ImageD3D *getImage(int level, int layer) const; + virtual ImageD3D *getImage(const gl::ImageIndex &index) const; + virtual GLsizei getLayerCount(int level) const; + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLsizei getDepth(GLint level) const; + GLenum getInternalFormat(GLint level) const; + bool isDepth(GLint level) const; + + gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + + private: + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); + + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageLevel(int level); + + void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + + ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureD3D_2DArray : public TextureD3D +{ + public: + TextureD3D_2DArray(RendererD3D *renderer); + virtual ~TextureD3D_2DArray(); + + virtual ImageD3D *getImage(int level, int layer) const; + virtual ImageD3D *getImage(const gl::ImageIndex &index) const; + virtual GLsizei getLayerCount(int level) const; + + GLsizei getWidth(GLint level) const; + GLsizei getHeight(GLint level) const; + GLenum getInternalFormat(GLint level) const; + bool isDepth(GLint level) const; + + gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + gl::Error setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, + const gl::PixelUnpackState &unpack, const uint8_t *pixels) override; + + gl::Error copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat, + const gl::Framebuffer *source) override; + gl::Error copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea, + const gl::Framebuffer *source) override; + + gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) override; + + virtual void bindTexImage(egl::Surface *surface); + virtual void releaseTexImage(); + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + + private: + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); + + bool isValidLevel(int level) const; + bool isLevelComplete(int level) const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageLevel(int level); + + void deleteImages(); + void redefineImage(GLint level, GLenum internalformat, const gl::Extents &size); + + // Storing images as an array of single depth textures since D3D11 treats each array level of a + // Texture2D object as a separate subresource. Each layer would have to be looped over + // to update all the texture layers since they cannot all be updated at once and it makes the most + // sense for the Image class to not have to worry about layer subresource as well as mip subresources. + GLsizei mLayerCounts[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_TEXTURED3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp new file mode 100644 index 0000000000..abb83a14d5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.cpp @@ -0,0 +1,39 @@ +// +// Copyright (c) 2002-2013 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. +// + +// TextureStorage.cpp: Shared members of abstract rx::TextureStorage class. + +#include "libANGLE/renderer/d3d/TextureStorage.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Texture.h" + +#include "common/debug.h" +#include "common/mathutil.h" + +namespace rx +{ + +TextureStorage::TextureStorage() + : mFirstRenderTargetSerial(0), + mRenderTargetSerialsLayerStride(0) +{} + +void TextureStorage::initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride) +{ + mFirstRenderTargetSerial = RenderTargetD3D::issueSerials(rtSerialsToReserve); + mRenderTargetSerialsLayerStride = rtSerialsLayerStride; +} + +unsigned int TextureStorage::getRenderTargetSerial(const gl::ImageIndex &index) const +{ + unsigned int layerOffset = (index.hasLayer() ? (static_cast(index.layerIndex) * mRenderTargetSerialsLayerStride) : 0); + return mFirstRenderTargetSerial + static_cast(index.mipIndex) + layerOffset; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h new file mode 100644 index 0000000000..ae2d42ca8a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TextureStorage.h @@ -0,0 +1,67 @@ +// +// Copyright (c) 2002-2013 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. +// + +// TextureStorage.h: Defines the abstract rx::TextureStorage class. + +#ifndef LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ +#define LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ + +#include "libANGLE/Error.h" + +#include "common/debug.h" +#include "libANGLE/Error.h" + +#include +#include + +namespace gl +{ +struct ImageIndex; +struct Box; +struct PixelUnpackState; +} + +namespace rx +{ +class SwapChainD3D; +class RenderTargetD3D; +class ImageD3D; + +class TextureStorage : angle::NonCopyable +{ + public: + TextureStorage(); + virtual ~TextureStorage() {}; + + virtual int getTopLevel() const = 0; + virtual bool isRenderTarget() const = 0; + virtual bool isManaged() const = 0; + virtual int getLevelCount() const = 0; + + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0; + + virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0; + virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0; + + unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const; + unsigned int getTextureSerial() const; + + // This is a no-op for most implementations of TextureStorage. Some (e.g. TextureStorage11_2D) might override it. + virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) { return gl::Error(GL_NO_ERROR); } + + protected: + void initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride); + + private: + unsigned int mFirstRenderTargetSerial; + unsigned int mRenderTargetSerialsLayerStride; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_TEXTURESTORAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp new file mode 100644 index 0000000000..5c0bfdcd5b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp @@ -0,0 +1,38 @@ +// +// Copyright 2014 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. +// + +// TransformFeedbackD3D.cpp is a no-op implementation for both the D3D9 and D3D11 renderers. + +#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" + +namespace rx +{ + +TransformFeedbackD3D::TransformFeedbackD3D() +{ +} + +TransformFeedbackD3D::~TransformFeedbackD3D() +{ +} + +void TransformFeedbackD3D::begin(GLenum primitiveMode) +{ +} + +void TransformFeedbackD3D::end() +{ +} + +void TransformFeedbackD3D::pause() +{ +} + +void TransformFeedbackD3D::resume() +{ +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h new file mode 100644 index 0000000000..6b255b4a2b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h @@ -0,0 +1,32 @@ +// +// Copyright 2014 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. +// + +// TransformFeedbackD3D.h: Implements the abstract rx::TransformFeedbackImpl class. + +#ifndef LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ +#define LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ + +#include "libANGLE/renderer/TransformFeedbackImpl.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ + +class TransformFeedbackD3D : public TransformFeedbackImpl +{ + public: + TransformFeedbackD3D(); + virtual ~TransformFeedbackD3D(); + + virtual void begin(GLenum primitiveMode); + virtual void end(); + virtual void pause(); + virtual void resume(); +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp new file mode 100644 index 0000000000..19bd548fce --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.cpp @@ -0,0 +1,311 @@ +// +// 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. +// + +// VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface +// class with derivations, classes that perform graphics API agnostic vertex buffer operations. + +#include "libANGLE/renderer/d3d/VertexBuffer.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/VertexAttribute.h" + +#include "common/mathutil.h" + +namespace rx +{ + +unsigned int VertexBuffer::mNextSerial = 1; + +VertexBuffer::VertexBuffer() +{ + updateSerial(); +} + +VertexBuffer::~VertexBuffer() +{ +} + +void VertexBuffer::updateSerial() +{ + mSerial = mNextSerial++; +} + +unsigned int VertexBuffer::getSerial() const +{ + return mSerial; +} + +VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic) + : mFactory(factory) +{ + mDynamic = dynamic; + mWritePosition = 0; + mReservedSpace = 0; + + mVertexBuffer = factory->createVertexBuffer(); +} + +VertexBufferInterface::~VertexBufferInterface() +{ + delete mVertexBuffer; +} + +unsigned int VertexBufferInterface::getSerial() const +{ + return mVertexBuffer->getSerial(); +} + +unsigned int VertexBufferInterface::getBufferSize() const +{ + return mVertexBuffer->getBufferSize(); +} + +gl::Error VertexBufferInterface::setBufferSize(unsigned int size) +{ + if (mVertexBuffer->getBufferSize() == 0) + { + return mVertexBuffer->initialize(size, mDynamic); + } + else + { + return mVertexBuffer->setBufferSize(size); + } +} + +unsigned int VertexBufferInterface::getWritePosition() const +{ + return mWritePosition; +} + +void VertexBufferInterface::setWritePosition(unsigned int writePosition) +{ + mWritePosition = writePosition; +} + +gl::Error VertexBufferInterface::discard() +{ + return mVertexBuffer->discard(); +} + +gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) +{ + gl::Error error(GL_NO_ERROR); + + unsigned int spaceRequired; + error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired); + if (error.isError()) + { + return error; + } + + if (mWritePosition + spaceRequired < mWritePosition) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow."); + } + + error = reserveSpace(mReservedSpace); + if (error.isError()) + { + return error; + } + mReservedSpace = 0; + + error = mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition); + if (error.isError()) + { + return error; + } + + if (outStreamOffset) + { + *outStreamOffset = mWritePosition; + } + + mWritePosition += spaceRequired; + + // Align to 16-byte boundary + mWritePosition = roundUp(mWritePosition, 16u); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) +{ + gl::Error error(GL_NO_ERROR); + + unsigned int requiredSpace; + error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &requiredSpace); + if (error.isError()) + { + return error; + } + + // Protect against integer overflow + if (mReservedSpace + requiredSpace < mReservedSpace) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, " + "it would result in an overflow.", requiredSpace); + } + + mReservedSpace += requiredSpace; + + // Align to 16-byte boundary + mReservedSpace = roundUp(mReservedSpace, 16u); + + return gl::Error(GL_NO_ERROR); +} + +VertexBuffer* VertexBufferInterface::getVertexBuffer() const +{ + return mVertexBuffer; +} + +bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const +{ + gl::Buffer *buffer = attrib.buffer.get(); + BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; + + if (!storage || !storage->supportsDirectBinding()) + { + return false; + } + + // Alignment restrictions: In D3D, vertex data must be aligned to + // the format stride, or to a 4-byte boundary, whichever is smaller. + // (Undocumented, and experimentally confirmed) + size_t alignment = 4; + bool requiresConversion = false; + + if (attrib.type != GL_FLOAT) + { + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + + unsigned int outputElementSize; + getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); + alignment = std::min(outputElementSize, 4); + + // TODO(jmadill): add VertexFormatCaps + requiresConversion = (mFactory->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0; + } + + bool isAligned = (static_cast(ComputeVertexAttributeStride(attrib)) % alignment == 0) && + (static_cast(attrib.offset) % alignment == 0); + + return !requiresConversion && isAligned; +} + +StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize) + : VertexBufferInterface(factory, true) +{ + setBufferSize(initialSize); +} + +StreamingVertexBufferInterface::~StreamingVertexBufferInterface() +{ +} + +gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size) +{ + unsigned int curBufferSize = getBufferSize(); + if (size > curBufferSize) + { + gl::Error error = setBufferSize(std::max(size, 3 * curBufferSize / 2)); + if (error.isError()) + { + return error; + } + setWritePosition(0); + } + else if (getWritePosition() + size > curBufferSize) + { + gl::Error error = discard(); + if (error.isError()) + { + return error; + } + setWritePosition(0); + } + + return gl::Error(GL_NO_ERROR); +} + +StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory) + : VertexBufferInterface(factory, false) +{ +} + +StaticVertexBufferInterface::~StaticVertexBufferInterface() +{ +} + +bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset) +{ + for (unsigned int element = 0; element < mCache.size(); element++) + { + if (mCache[element].type == attrib.type && + mCache[element].size == attrib.size && + mCache[element].stride == ComputeVertexAttributeStride(attrib) && + mCache[element].normalized == attrib.normalized && + mCache[element].pureInteger == attrib.pureInteger) + { + size_t offset = (static_cast(attrib.offset) % ComputeVertexAttributeStride(attrib)); + if (mCache[element].attributeOffset == offset) + { + if (outStreamOffset) + { + *outStreamOffset = mCache[element].streamOffset; + } + return true; + } + } + } + + return false; +} + +gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size) +{ + unsigned int curSize = getBufferSize(); + if (curSize == 0) + { + return setBufferSize(size); + } + else if (curSize >= size) + { + return gl::Error(GL_NO_ERROR); + } + else + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION, "Internal error, Static vertex buffers can't be resized."); + } +} + +gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) +{ + unsigned int streamOffset; + gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset); + if (error.isError()) + { + return error; + } + + size_t attributeOffset = static_cast(attrib.offset) % ComputeVertexAttributeStride(attrib); + VertexElement element = { attrib.type, attrib.size, static_cast(ComputeVertexAttributeStride(attrib)), attrib.normalized, attrib.pureInteger, attributeOffset, streamOffset }; + mCache.push_back(element); + + if (outStreamOffset) + { + *outStreamOffset = streamOffset; + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h new file mode 100644 index 0000000000..5cb03fe3a1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexBuffer.h @@ -0,0 +1,143 @@ +// +// 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. +// + +// VertexBuffer.h: Defines the abstract VertexBuffer class and VertexBufferInterface +// class with derivations, classes that perform graphics API agnostic vertex buffer operations. + +#ifndef LIBANGLE_RENDERER_D3D_VERTEXBUFFER_H_ +#define LIBANGLE_RENDERER_D3D_VERTEXBUFFER_H_ + +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +#include + +#include +#include + +namespace gl +{ +struct VertexAttribute; +struct VertexAttribCurrentValueData; +} + +namespace rx +{ +class BufferFactoryD3D; + +class VertexBuffer : angle::NonCopyable +{ + public: + VertexBuffer(); + virtual ~VertexBuffer(); + + virtual gl::Error initialize(unsigned int size, bool dynamicUsage) = 0; + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) = 0; + virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const = 0; + + virtual unsigned int getBufferSize() const = 0; + virtual gl::Error setBufferSize(unsigned int size) = 0; + virtual gl::Error discard() = 0; + + unsigned int getSerial() const; + + // This may be overridden (e.g. by VertexBuffer11) if necessary. + virtual void hintUnmapResource() { }; + + protected: + void updateSerial(); + + private: + unsigned int mSerial; + static unsigned int mNextSerial; +}; + +class VertexBufferInterface : angle::NonCopyable +{ + public: + VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic); + virtual ~VertexBufferInterface(); + + gl::Error reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances); + + unsigned int getBufferSize() const; + + unsigned int getSerial() const; + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset); + + bool directStoragePossible(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const; + + VertexBuffer* getVertexBuffer() const; + + protected: + virtual gl::Error reserveSpace(unsigned int size) = 0; + + unsigned int getWritePosition() const; + void setWritePosition(unsigned int writePosition); + + gl::Error discard(); + + gl::Error setBufferSize(unsigned int size); + + private: + BufferFactoryD3D *const mFactory; + + VertexBuffer* mVertexBuffer; + + unsigned int mWritePosition; + unsigned int mReservedSpace; + bool mDynamic; +}; + +class StreamingVertexBufferInterface : public VertexBufferInterface +{ + public: + StreamingVertexBufferInterface(BufferFactoryD3D *factory, std::size_t initialSize); + ~StreamingVertexBufferInterface(); + + protected: + gl::Error reserveSpace(unsigned int size); +}; + +class StaticVertexBufferInterface : public VertexBufferInterface +{ + public: + explicit StaticVertexBufferInterface(BufferFactoryD3D *factory); + ~StaticVertexBufferInterface(); + + gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset); + + bool lookupAttribute(const gl::VertexAttribute &attribute, unsigned int* outStreamFffset); + + protected: + gl::Error reserveSpace(unsigned int size); + + private: + struct VertexElement + { + GLenum type; + GLuint size; + GLuint stride; + bool normalized; + bool pureInteger; + size_t attributeOffset; + + unsigned int streamOffset; + }; + + std::vector mCache; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_VERTEXBUFFER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp new file mode 100644 index 0000000000..cb70b9e4ef --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.cpp @@ -0,0 +1,396 @@ +// +// 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 "libANGLE/renderer/d3d/VertexDataManager.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/Program.h" +#include "libANGLE/State.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/renderer/d3d/VertexBuffer.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 rx +{ + +static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size) +{ + // Size cannot be larger than a GLsizei + if (size > static_cast(std::numeric_limits::max())) + { + size = static_cast(std::numeric_limits::max()); + } + + GLsizei stride = ComputeVertexAttributeStride(attrib); + return (size - attrib.offset % stride + (stride - ComputeVertexAttributeTypeSize(attrib))) / stride; +} + +static int StreamingBufferElementCount(const gl::VertexAttribute &attrib, int vertexDrawCount, int instanceDrawCount) +{ + // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices. + // + // A vertex attribute with a positive divisor loads one instanced vertex for every set of + // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" instances. + if (instanceDrawCount > 0 && attrib.divisor > 0) + { + // When instanceDrawCount is not a multiple attrib.divisor, the division must round up. + // For instance, with 5 non-instanced vertices and a divisor equal to 3, we need 2 instanced vertices. + return (instanceDrawCount + attrib.divisor - 1) / attrib.divisor; + } + + return vertexDrawCount; +} + +VertexDataManager::VertexDataManager(BufferFactoryD3D *factory) + : mFactory(factory) +{ + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mCurrentValue[i].FloatValues[0] = std::numeric_limits::quiet_NaN(); + mCurrentValue[i].FloatValues[1] = std::numeric_limits::quiet_NaN(); + mCurrentValue[i].FloatValues[2] = std::numeric_limits::quiet_NaN(); + mCurrentValue[i].FloatValues[3] = std::numeric_limits::quiet_NaN(); + mCurrentValue[i].Type = GL_FLOAT; + mCurrentValueBuffer[i] = NULL; + mCurrentValueOffsets[i] = 0; + } + + mStreamingBuffer = new StreamingVertexBufferInterface(factory, INITIAL_STREAM_BUFFER_SIZE); + + if (!mStreamingBuffer) + { + ERR("Failed to allocate the streaming vertex buffer."); + } +} + +VertexDataManager::~VertexDataManager() +{ + delete mStreamingBuffer; + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + delete mCurrentValueBuffer[i]; + } +} + +void VertexDataManager::hintUnmapAllResources(const std::vector &vertexAttributes) +{ + mStreamingBuffer->getVertexBuffer()->hintUnmapResource(); + + for (size_t i = 0; i < vertexAttributes.size(); i++) + { + const gl::VertexAttribute &attrib = vertexAttributes[i]; + if (attrib.enabled) + { + gl::Buffer *buffer = attrib.buffer.get(); + BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; + StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL; + + if (staticBuffer) + { + staticBuffer->getVertexBuffer()->hintUnmapResource(); + } + } + } + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (mCurrentValueBuffer[i] != NULL) + { + mCurrentValueBuffer[i]->getVertexBuffer()->hintUnmapResource(); + } + } +} + +gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count, + TranslatedAttribute *translated, GLsizei instances) +{ + if (!mStreamingBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal streaming vertex buffer is unexpectedly NULL."); + } + + const gl::VertexArray *vertexArray = state.getVertexArray(); + const std::vector &vertexAttributes = vertexArray->getVertexAttributes(); + + // Invalidate static buffers that don't contain matching attributes + for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + translated[attributeIndex].active = (state.getProgram()->getSemanticIndex(attributeIndex) != -1); + if (translated[attributeIndex].active && vertexAttributes[attributeIndex].enabled) + { + invalidateMatchingStaticData(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex)); + } + } + + // Reserve the required space in the buffers + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (translated[i].active && vertexAttributes[i].enabled) + { + gl::Error error = reserveSpaceForAttrib(vertexAttributes[i], state.getVertexAttribCurrentValue(i), count, instances); + if (error.isError()) + { + return error; + } + } + } + + // Perform the vertex data translations + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + const gl::VertexAttribute &curAttrib = vertexAttributes[i]; + if (translated[i].active) + { + if (curAttrib.enabled) + { + gl::Error error = storeAttribute(curAttrib, state.getVertexAttribCurrentValue(i), + &translated[i], start, count, instances); + + if (error.isError()) + { + hintUnmapAllResources(vertexAttributes); + return error; + } + } + else + { + if (!mCurrentValueBuffer[i]) + { + mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mFactory, CONSTANT_VERTEX_BUFFER_SIZE); + } + + gl::Error error = storeCurrentValue(curAttrib, state.getVertexAttribCurrentValue(i), &translated[i], + &mCurrentValue[i], &mCurrentValueOffsets[i], + mCurrentValueBuffer[i]); + if (error.isError()) + { + hintUnmapAllResources(vertexAttributes); + return error; + } + } + } + } + + // Hint to unmap all the resources + hintUnmapAllResources(vertexAttributes); + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + const gl::VertexAttribute &curAttrib = vertexAttributes[i]; + if (translated[i].active && curAttrib.enabled) + { + gl::Buffer *buffer = curAttrib.buffer.get(); + + if (buffer) + { + BufferD3D *bufferImpl = GetImplAs(buffer); + bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(curAttrib)); + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +void VertexDataManager::invalidateMatchingStaticData(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const +{ + gl::Buffer *buffer = attrib.buffer.get(); + + if (buffer) + { + BufferD3D *bufferImpl = GetImplAs(buffer); + StaticVertexBufferInterface *staticBuffer = bufferImpl->getStaticVertexBuffer(); + + if (staticBuffer && + staticBuffer->getBufferSize() > 0 && + !staticBuffer->lookupAttribute(attrib, NULL) && + !staticBuffer->directStoragePossible(attrib, currentValue)) + { + bufferImpl->invalidateStaticData(); + } + } +} + +gl::Error VertexDataManager::reserveSpaceForAttrib(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + GLsizei count, + GLsizei instances) const +{ + gl::Buffer *buffer = attrib.buffer.get(); + BufferD3D *bufferImpl = buffer ? GetImplAs(buffer) : NULL; + StaticVertexBufferInterface *staticBuffer = bufferImpl ? bufferImpl->getStaticVertexBuffer() : NULL; + VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); + + if (!vertexBuffer->directStoragePossible(attrib, currentValue)) + { + if (staticBuffer) + { + if (staticBuffer->getBufferSize() == 0) + { + int totalCount = ElementsInBuffer(attrib, bufferImpl->getSize()); + gl::Error error = staticBuffer->reserveVertexSpace(attrib, totalCount, 0); + if (error.isError()) + { + return error; + } + } + } + else + { + int totalCount = StreamingBufferElementCount(attrib, count, instances); + ASSERT(!bufferImpl || ElementsInBuffer(attrib, bufferImpl->getSize()) >= totalCount); + + gl::Error error = mStreamingBuffer->reserveVertexSpace(attrib, totalCount, instances); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexDataManager::storeAttribute(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances) +{ + gl::Buffer *buffer = attrib.buffer.get(); + ASSERT(buffer || attrib.pointer); + + BufferD3D *storage = buffer ? GetImplAs(buffer) : NULL; + StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL; + VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); + bool directStorage = vertexBuffer->directStoragePossible(attrib, currentValue); + + unsigned int streamOffset = 0; + unsigned int outputElementSize = 0; + + // Instanced vertices do not apply the 'start' offset + GLint firstVertexIndex = (instances > 0 && attrib.divisor > 0 ? 0 : start); + + if (directStorage) + { + outputElementSize = ComputeVertexAttributeStride(attrib); + streamOffset = attrib.offset + outputElementSize * firstVertexIndex; + } + else if (staticBuffer) + { + gl::Error error = staticBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); + if (error.isError()) + { + return error; + } + + if (!staticBuffer->lookupAttribute(attrib, &streamOffset)) + { + // Convert the entire buffer + int totalCount = ElementsInBuffer(attrib, storage->getSize()); + int startIndex = attrib.offset / ComputeVertexAttributeStride(attrib); + + error = staticBuffer->storeVertexAttributes(attrib, currentValue, -startIndex, totalCount, + 0, &streamOffset); + if (error.isError()) + { + return error; + } + } + + unsigned int firstElementOffset = (attrib.offset / ComputeVertexAttributeStride(attrib)) * outputElementSize; + unsigned int startOffset = (instances == 0 || attrib.divisor == 0) ? firstVertexIndex * outputElementSize : 0; + if (streamOffset + firstElementOffset + startOffset < streamOffset) + { + return gl::Error(GL_OUT_OF_MEMORY); + } + + streamOffset += firstElementOffset + startOffset; + } + else + { + int totalCount = StreamingBufferElementCount(attrib, count, instances); + gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); + if (error.isError()) + { + return error; + } + + error = mStreamingBuffer->storeVertexAttributes(attrib, currentValue, firstVertexIndex, + totalCount, instances, &streamOffset); + if (error.isError()) + { + return error; + } + } + + translated->storage = directStorage ? storage : NULL; + translated->vertexBuffer = vertexBuffer->getVertexBuffer(); + translated->serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); + translated->divisor = attrib.divisor; + + translated->attribute = &attrib; + translated->currentValueType = currentValue.Type; + translated->stride = outputElementSize; + translated->offset = streamOffset; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + gl::VertexAttribCurrentValueData *cachedValue, + size_t *cachedOffset, + StreamingVertexBufferInterface *buffer) +{ + if (*cachedValue != currentValue) + { + gl::Error error = buffer->reserveVertexSpace(attrib, 1, 0); + if (error.isError()) + { + return error; + } + + unsigned int streamOffset; + error = buffer->storeVertexAttributes(attrib, currentValue, 0, 1, 0, &streamOffset); + if (error.isError()) + { + return error; + } + + *cachedValue = currentValue; + *cachedOffset = streamOffset; + } + + translated->storage = NULL; + translated->vertexBuffer = buffer->getVertexBuffer(); + translated->serial = buffer->getSerial(); + translated->divisor = 0; + + translated->attribute = &attrib; + translated->currentValueType = currentValue.Type; + translated->stride = 0; + translated->offset = *cachedOffset; + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h new file mode 100644 index 0000000000..898ed340b8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/VertexDataManager.h @@ -0,0 +1,95 @@ +// +// 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 LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ +#define LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ + +#include "libANGLE/Constants.h" +#include "libANGLE/VertexAttribute.h" +#include "common/angleutils.h" + +namespace gl +{ +class State; +struct VertexAttribute; +struct VertexAttribCurrentValueData; +} + +namespace rx +{ +class BufferD3D; +class BufferFactoryD3D; +class StreamingVertexBufferInterface; +class VertexBuffer; + +struct TranslatedAttribute +{ + TranslatedAttribute() : active(false), attribute(NULL), currentValueType(GL_NONE), + offset(0), stride(0), vertexBuffer(NULL), storage(NULL), + serial(0), divisor(0) {}; + bool active; + + const gl::VertexAttribute *attribute; + GLenum currentValueType; + unsigned int offset; + unsigned int stride; // 0 means not to advance the read pointer at all + + VertexBuffer *vertexBuffer; + BufferD3D *storage; + unsigned int serial; + unsigned int divisor; +}; + +class VertexDataManager : angle::NonCopyable +{ + public: + VertexDataManager(BufferFactoryD3D *factory); + virtual ~VertexDataManager(); + + gl::Error prepareVertexData(const gl::State &state, GLint start, GLsizei count, + TranslatedAttribute *outAttribs, GLsizei instances); + + private: + gl::Error reserveSpaceForAttrib(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + GLsizei count, + GLsizei instances) const; + + void invalidateMatchingStaticData(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue) const; + + gl::Error storeAttribute(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + GLint start, + GLsizei count, + GLsizei instances); + + gl::Error storeCurrentValue(const gl::VertexAttribute &attrib, + const gl::VertexAttribCurrentValueData ¤tValue, + TranslatedAttribute *translated, + gl::VertexAttribCurrentValueData *cachedValue, + size_t *cachedOffset, + StreamingVertexBufferInterface *buffer); + + void hintUnmapAllResources(const std::vector &vertexAttributes); + + BufferFactoryD3D *const mFactory; + + StreamingVertexBufferInterface *mStreamingBuffer; + + gl::VertexAttribCurrentValueData mCurrentValue[gl::MAX_VERTEX_ATTRIBS]; + + StreamingVertexBufferInterface *mCurrentValueBuffer[gl::MAX_VERTEX_ATTRIBS]; + std::size_t mCurrentValueOffsets[gl::MAX_VERTEX_ATTRIBS]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_VERTEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp new file mode 100644 index 0000000000..b1798454ca --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.cpp @@ -0,0 +1,22 @@ +// +// Copyright (c) 2013 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. +// + +// copyimage.cpp: Defines image copying functions + +#include "libANGLE/renderer/d3d/copyimage.h" + +namespace rx +{ + +void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest) +{ + uint32_t argb = *reinterpret_cast(source); + *reinterpret_cast(dest) = (argb & 0xFF00FF00) | // Keep alpha and green + (argb & 0x00FF0000) >> 16 | // Move red to blue + (argb & 0x000000FF) << 16; // Move blue to red +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h new file mode 100644 index 0000000000..189654ca39 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2013-2014 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. +// + +// copyimage.h: Defines image copying functions + +#ifndef LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ +#define LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ + +#include "common/mathutil.h" +#include "libANGLE/angletypes.h" + +#include + +namespace rx +{ + +template +void ReadColor(const uint8_t *source, uint8_t *dest); + +template +void WriteColor(const uint8_t *source, uint8_t *dest); + +template +void CopyPixel(const uint8_t *source, uint8_t *dest); + +void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest); + +} + +#include "copyimage.inl" + +#endif // LIBANGLE_RENDERER_D3D_COPYIMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl new file mode 100644 index 0000000000..0498cf7750 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/copyimage.inl @@ -0,0 +1,32 @@ +// +// Copyright (c) 2014 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. +// + +// copyimage.inl: Defines image copying functions + +namespace rx +{ + +template +inline void ReadColor(const uint8_t *source, uint8_t *dest) +{ + sourceType::readColor(reinterpret_cast*>(dest), reinterpret_cast(source)); +} + +template +inline void WriteColor(const uint8_t *source, uint8_t *dest) +{ + destType::writeColor(reinterpret_cast(dest), reinterpret_cast*>(source)); +} + +template +inline void CopyPixel(const uint8_t *source, uint8_t *dest) +{ + colorDataType temp; + ReadColor(source, &temp); + WriteColor(&temp, dest); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp new file mode 100644 index 0000000000..e38b61709f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp @@ -0,0 +1,1059 @@ +// +// Copyright (c) 2013 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. +// + +// Blit11.cpp: Texture copy utility class. + +#include "libANGLE/renderer/d3d/d3d11/Blit11.h" + +#include + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/formatutils.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr2di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlum2d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2d11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough3d11gs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrg3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3dui11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughr3di11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlum3d11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3d11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef3dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzlei2darrayps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui2darrayps.h" + +namespace rx +{ + +static DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource) +{ + ID3D11Texture2D *texture = d3d11::DynamicCastComObject(resource); + if (!texture) + { + return DXGI_FORMAT_UNKNOWN; + } + + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc(&desc); + + SafeRelease(texture); + + return desc.Format; +} + +static ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context, + ID3D11Resource *source, unsigned int subresource, + const gl::Extents &size, unsigned int cpuAccessFlags) +{ + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = size.width; + stagingDesc.Height = size.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = GetTextureFormat(source); + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.CPUAccessFlags = cpuAccessFlags; + stagingDesc.MiscFlags = 0; + stagingDesc.BindFlags = 0; + + ID3D11Texture2D *stagingTexture = NULL; + HRESULT result = device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture); + if (FAILED(result)) + { + ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result); + return NULL; + } + + context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, NULL); + + return stagingTexture; +} + +inline static void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + float *x1, float *y1, float *x2, float *y2, + float *u1, float *v1, float *u2, float *v2) +{ + *x1 = (destArea.x / float(destSize.width)) * 2.0f - 1.0f; + *y1 = ((destSize.height - destArea.y - destArea.height) / float(destSize.height)) * 2.0f - 1.0f; + *x2 = ((destArea.x + destArea.width) / float(destSize.width)) * 2.0f - 1.0f; + *y2 = ((destSize.height - destArea.y) / float(destSize.height)) * 2.0f - 1.0f; + + *u1 = sourceArea.x / float(sourceSize.width); + *v1 = sourceArea.y / float(sourceSize.height); + *u2 = (sourceArea.x + sourceArea.width) / float(sourceSize.width); + *v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height); +} + +static void Write2DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology) +{ + float x1, y1, x2, y2, u1, v1, u2, v2; + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + + d3d11::PositionTexCoordVertex *vertices = static_cast(outVertices); + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); + + *outStride = sizeof(d3d11::PositionTexCoordVertex); + *outVertexCount = 4; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; +} + +static void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology) +{ + ASSERT(sourceSize.depth > 0 && destSize.depth > 0); + + float x1, y1, x2, y2, u1, v1, u2, v2; + GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); + + d3d11::PositionLayerTexCoord3DVertex *vertices = static_cast(outVertices); + + for (int i = 0; i < destSize.depth; i++) + { + float readDepth = (float)i / std::max(destSize.depth - 1, 1); + + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 0], x1, y1, i, u1, v2, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 1], x1, y2, i, u1, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 2], x2, y1, i, u2, v2, readDepth); + + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 3], x1, y2, i, u1, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 4], x2, y2, i, u2, v1, readDepth); + d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 5], x2, y1, i, u2, v2, readDepth); + } + + *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); + *outVertexCount = destSize.depth * 6; + *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; +} + +Blit11::Blit11(Renderer11 *renderer) + : mRenderer(renderer), mBlitShaderMap(compareBlitParameters), mSwizzleShaderMap(compareSwizzleParameters), + mVertexBuffer(NULL), mPointSampler(NULL), mLinearSampler(NULL), mScissorEnabledRasterizerState(NULL), + mScissorDisabledRasterizerState(NULL), mDepthStencilState(NULL), + mQuad2DIL(NULL), mQuad2DVS(NULL), mDepthPS(NULL), + mQuad3DIL(NULL), mQuad3DVS(NULL), mQuad3DGS(NULL), + mSwizzleCB(NULL) +{ + HRESULT result; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex), sizeof(d3d11::PositionTexCoordVertex)) * + 6 * renderer->getRendererCaps().max3DTextureSize; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mVertexBuffer, "Blit11 vertex buffer"); + + D3D11_SAMPLER_DESC pointSamplerDesc; + pointSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; + pointSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + pointSamplerDesc.MipLODBias = 0.0f; + pointSamplerDesc.MaxAnisotropy = 0; + pointSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + pointSamplerDesc.BorderColor[0] = 0.0f; + pointSamplerDesc.BorderColor[1] = 0.0f; + pointSamplerDesc.BorderColor[2] = 0.0f; + pointSamplerDesc.BorderColor[3] = 0.0f; + pointSamplerDesc.MinLOD = 0.0f; + pointSamplerDesc.MaxLOD = FLT_MAX; + + result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPointSampler, "Blit11 point sampler"); + + D3D11_SAMPLER_DESC linearSamplerDesc; + linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + linearSamplerDesc.MipLODBias = 0.0f; + linearSamplerDesc.MaxAnisotropy = 0; + linearSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + linearSamplerDesc.BorderColor[0] = 0.0f; + linearSamplerDesc.BorderColor[1] = 0.0f; + linearSamplerDesc.BorderColor[2] = 0.0f; + linearSamplerDesc.BorderColor[3] = 0.0f; + linearSamplerDesc.MinLOD = 0.0f; + linearSamplerDesc.MaxLOD = FLT_MAX; + + result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mLinearSampler, "Blit11 linear sampler"); + + // Use a rasterizer state that will not cull so that inverted quads will not be culled + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + rasterDesc.ScissorEnable = TRUE; + result = device->CreateRasterizerState(&rasterDesc, &mScissorEnabledRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state"); + + rasterDesc.ScissorEnable = FALSE; + result = device->CreateRasterizerState(&rasterDesc, &mScissorDisabledRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mScissorDisabledRasterizerState, "Blit11 no scissoring rasterizer state"); + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = true; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + result = device->CreateDepthStencilState(&depthStencilDesc, &mDepthStencilState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state"); + + D3D11_INPUT_ELEMENT_DESC quad2DLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quad2DLayout, ArraySize(quad2DLayout), g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), &mQuad2DIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad2DIL, "Blit11 2D input layout"); + + result = device->CreateVertexShader(g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), NULL, &mQuad2DVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad2DVS, "Blit11 2D vertex shader"); + + if (renderer->isES3Capable()) + { + result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader"); + + D3D11_INPUT_ELEMENT_DESC quad3DLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout"); + + result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); + + result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader"); + } + + buildShaderMap(); + + D3D11_BUFFER_DESC swizzleBufferDesc; + swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4; + swizzleBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + swizzleBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + swizzleBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + swizzleBufferDesc.MiscFlags = 0; + swizzleBufferDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&swizzleBufferDesc, NULL, &mSwizzleCB); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mSwizzleCB, "Blit11 swizzle constant buffer"); +} + +Blit11::~Blit11() +{ + SafeRelease(mVertexBuffer); + SafeRelease(mPointSampler); + SafeRelease(mLinearSampler); + SafeRelease(mScissorEnabledRasterizerState); + SafeRelease(mScissorDisabledRasterizerState); + SafeRelease(mDepthStencilState); + + SafeRelease(mQuad2DIL); + SafeRelease(mQuad2DVS); + SafeRelease(mDepthPS); + + SafeRelease(mQuad3DIL); + SafeRelease(mQuad3DVS); + SafeRelease(mQuad3DGS); + + SafeRelease(mSwizzleCB); + + clearShaderMap(); +} + +static inline unsigned int GetSwizzleIndex(GLenum swizzle) +{ + unsigned int colorIndex = 0; + + switch (swizzle) + { + case GL_RED: colorIndex = 0; break; + case GL_GREEN: colorIndex = 1; break; + case GL_BLUE: colorIndex = 2; break; + case GL_ALPHA: colorIndex = 3; break; + case GL_ZERO: colorIndex = 4; break; + case GL_ONE: colorIndex = 5; break; + default: UNREACHABLE(); break; + } + + return colorIndex; +} + +gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, + GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + source->GetDesc(&sourceSRVDesc); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); + const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + + GLenum shaderType = GL_NONE; + switch (sourceFormatInfo.componentType) + { + case GL_UNSIGNED_NORMALIZED: + case GL_SIGNED_NORMALIZED: + case GL_FLOAT: + shaderType = GL_FLOAT; + break; + case GL_INT: + shaderType = GL_INT; + break; + case GL_UNSIGNED_INT: + shaderType = GL_UNSIGNED_INT; + break; + default: + UNREACHABLE(); + break; + } + + SwizzleParameters parameters = { 0 }; + parameters.mDestinationType = shaderType; + parameters.mViewDimension = sourceSRVDesc.ViewDimension; + + SwizzleShaderMap::const_iterator i = mSwizzleShaderMap.find(parameters); + if (i == mSwizzleShaderMap.end()) + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION, "Internal error, missing swizzle shader."); + } + + const Shader &shader = i->second; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for swizzle, HRESULT: 0x%X.", result); + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + gl::Box area(0, 0, 0, size.width, size.height, size.depth); + shader.mVertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Set constant buffer + result = deviceContext->Map(mSwizzleCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal constant buffer for swizzle, HRESULT: 0x%X.", result); + } + + unsigned int *swizzleIndices = reinterpret_cast(mappedResource.pData); + swizzleIndices[0] = GetSwizzleIndex(swizzleRed); + swizzleIndices[1] = GetSwizzleIndex(swizzleGreen); + swizzleIndices[2] = GetSwizzleIndex(swizzleBlue); + swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha); + + deviceContext->Unmap(mSwizzleCB, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply constant buffer + deviceContext->PSSetConstantBuffers(0, 1, &mSwizzleCB); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + deviceContext->RSSetState(mScissorDisabledRasterizerState); + + // Apply shaders + deviceContext->IASetInputLayout(shader.mInputLayout); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); + + deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); + deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + // Apply render target + mRenderer->setOneTimeRenderTarget(dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = size.width; + viewport.Height = size.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + + // Apply samplers + deviceContext->PSSetSamplers(0, 1, &mPointSampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Determine if the source format is a signed integer format, the destFormat will already + // be GL_XXXX_INTEGER but it does not tell us if it is signed or unsigned. + D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; + source->GetDesc(&sourceSRVDesc); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + + BlitParameters parameters = { 0 }; + parameters.mDestinationFormat = destFormat; + parameters.mSignedInteger = (internalFormatInfo.componentType == GL_INT); + parameters.m3DBlit = sourceSRVDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURE3D; + + BlitShaderMap::const_iterator i = mBlitShaderMap.find(parameters); + if (i == mBlitShaderMap.end()) + { + UNREACHABLE(); + return gl::Error(GL_OUT_OF_MEMORY, "Could not find appropriate shader for internal texture blit."); + } + + const Shader& shader = i->second; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + shader.mVertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, + &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + + if (scissor) + { + D3D11_RECT scissorRect; + scissorRect.left = scissor->x; + scissorRect.right = scissor->x + scissor->width; + scissorRect.top = scissor->y; + scissorRect.bottom = scissor->y + scissor->height; + + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->RSSetState(mScissorEnabledRasterizerState); + } + else + { + deviceContext->RSSetState(mScissorDisabledRasterizerState); + } + + // Apply shaders + deviceContext->IASetInputLayout(shader.mInputLayout); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); + + deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); + deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + // Apply render target + mRenderer->setOneTimeRenderTarget(dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + + // Apply samplers + ID3D11SamplerState *sampler = NULL; + switch (filter) + { + case GL_NEAREST: sampler = mPointSampler; break; + case GL_LINEAR: sampler = mLinearSampler; break; + + default: + UNREACHABLE(); + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, unknown blit filter mode."); + } + deviceContext->PSSetSamplers(0, 1, &sampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit11::copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, + dest, destSubresource, destArea, destSize, + scissor, true); +} + +gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + HRESULT result; + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); + } + + UINT stride = 0; + UINT startIdx = 0; + UINT drawCount = 0; + D3D11_PRIMITIVE_TOPOLOGY topology; + + Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, + &stride, &drawCount, &topology); + + deviceContext->Unmap(mVertexBuffer, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); + + // Apply state + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF); + + if (scissor) + { + D3D11_RECT scissorRect; + scissorRect.left = scissor->x; + scissorRect.right = scissor->x + scissor->width; + scissorRect.top = scissor->y; + scissorRect.bottom = scissor->y + scissor->height; + + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->RSSetState(mScissorEnabledRasterizerState); + } + else + { + deviceContext->RSSetState(mScissorDisabledRasterizerState); + } + + // Apply shaders + deviceContext->IASetInputLayout(mQuad2DIL); + deviceContext->IASetPrimitiveTopology(topology); + deviceContext->VSSetShader(mQuad2DVS, NULL, 0); + + deviceContext->PSSetShader(mDepthPS, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Unset the currently bound shader resource to avoid conflicts + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + // Apply render target + deviceContext->OMSetRenderTargets(0, NULL, dest); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); + + // Apply samplers + deviceContext->PSSetSamplers(0, 1, &mPointSampler); + + // Draw the quad + deviceContext->Draw(drawCount, 0); + + // Unbind textures and render targets and vertex buffer + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + mRenderer->unapplyRenderTargets(); + + UINT zero = 0; + ID3D11Buffer *const nullBuffer = NULL; + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + + mRenderer->markAllStateDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) +{ + return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, + dest, destSubresource, destArea, destSize, + scissor, false); +} + +gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly) +{ + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11Resource *sourceStaging = CreateStagingTexture(device, deviceContext, source, sourceSubresource, sourceSize, D3D11_CPU_ACCESS_READ); + // HACK: Create the destination staging buffer as a read/write texture so ID3D11DevicContext::UpdateSubresource can be called + // using it's mapped data as a source + ID3D11Resource *destStaging = CreateStagingTexture(device, deviceContext, dest, destSubresource, destSize, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); + + if (!sourceStaging || !destStaging) + { + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging textures for depth stencil blit."); + } + + DXGI_FORMAT format = GetTextureFormat(source); + ASSERT(format == GetTextureFormat(dest)); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); + unsigned int pixelSize = dxgiFormatInfo.pixelBytes; + unsigned int copyOffset = 0; + unsigned int copySize = pixelSize; + if (stencilOnly) + { + copyOffset = dxgiFormatInfo.depthBits / 8; + copySize = dxgiFormatInfo.stencilBits / 8; + + // It would be expensive to have non-byte sized stencil sizes since it would + // require reading from the destination, currently there aren't any though. + ASSERT(dxgiFormatInfo.stencilBits % 8 == 0 && + dxgiFormatInfo.depthBits % 8 == 0); + } + + D3D11_MAPPED_SUBRESOURCE sourceMapping; + HRESULT result = deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); + if (FAILED(result)) + { + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal source staging texture for depth stencil blit, HRESULT: 0x%X.", result); + } + + D3D11_MAPPED_SUBRESOURCE destMapping; + result = deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); + if (FAILED(result)) + { + deviceContext->Unmap(sourceStaging, 0); + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal destination staging texture for depth stencil blit, HRESULT: 0x%X.", result); + } + + gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); + + // Clip dest area to the destination size + gl::ClipRectangle(clippedDestArea, gl::Rectangle(0, 0, destSize.width, destSize.height), &clippedDestArea); + + // Clip dest area to the scissor + if (scissor) + { + gl::ClipRectangle(clippedDestArea, *scissor, &clippedDestArea); + } + + // Determine if entire rows can be copied at once instead of each individual pixel, requires that there is + // no out of bounds lookups required, the entire pixel is copied and no stretching + bool wholeRowCopy = sourceArea.width == clippedDestArea.width && + sourceArea.x >= 0 && sourceArea.x + sourceArea.width <= sourceSize.width && + copySize == pixelSize; + + for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) + { + float yPerc = static_cast(y - destArea.y) / (destArea.height - 1); + + // Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges + unsigned int readRow = gl::clamp(sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f), 0, sourceSize.height - 1); + unsigned int writeRow = y; + + if (wholeRowCopy) + { + void *sourceRow = reinterpret_cast(sourceMapping.pData) + + readRow * sourceMapping.RowPitch + + sourceArea.x * pixelSize; + + void *destRow = reinterpret_cast(destMapping.pData) + + writeRow * destMapping.RowPitch + + destArea.x * pixelSize; + + memcpy(destRow, sourceRow, pixelSize * destArea.width); + } + else + { + for (int x = clippedDestArea.x; x < clippedDestArea.x + clippedDestArea.width; x++) + { + float xPerc = static_cast(x - destArea.x) / (destArea.width - 1); + + // Interpolate the original source rectangle to determine which column to sample from while clamping to the edges + unsigned int readColumn = gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1); + unsigned int writeColumn = x; + + void *sourcePixel = reinterpret_cast(sourceMapping.pData) + + readRow * sourceMapping.RowPitch + + readColumn * pixelSize + + copyOffset; + + void *destPixel = reinterpret_cast(destMapping.pData) + + writeRow * destMapping.RowPitch + + writeColumn * pixelSize + + copyOffset; + + memcpy(destPixel, sourcePixel, copySize); + } + } + } + + // HACK: Use ID3D11DevicContext::UpdateSubresource which causes an extra copy compared to ID3D11DevicContext::CopySubresourceRegion + // according to MSDN. + deviceContext->UpdateSubresource(dest, destSubresource, NULL, destMapping.pData, destMapping.RowPitch, destMapping.DepthPitch); + + deviceContext->Unmap(sourceStaging, 0); + deviceContext->Unmap(destStaging, 0); + + // TODO: Determine why this call to ID3D11DevicContext::CopySubresourceRegion causes a TDR timeout on some + // systems when called repeatedly. + // deviceContext->CopySubresourceRegion(dest, destSubresource, 0, 0, 0, destStaging, 0, NULL); + + SafeRelease(sourceStaging); + SafeRelease(destStaging); + + return gl::Error(GL_NO_ERROR); +} + +bool Blit11::compareBlitParameters(const Blit11::BlitParameters &a, const Blit11::BlitParameters &b) +{ + return memcmp(&a, &b, sizeof(Blit11::BlitParameters)) < 0; +} + +bool Blit11::compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b) +{ + return memcmp(&a, &b, sizeof(Blit11::SwizzleParameters)) < 0; +} + +void Blit11::add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) +{ + BlitParameters params = { 0 }; + params.mDestinationFormat = destFormat; + params.mSignedInteger = signedInteger; + params.m3DBlit = false; + + ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); + ASSERT(ps); + + Shader shader; + shader.mVertexWriteFunction = Write2DVertices; + shader.mInputLayout = mQuad2DIL; + shader.mVertexShader = mQuad2DVS; + shader.mGeometryShader = NULL; + shader.mPixelShader = ps; + + mBlitShaderMap[params] = shader; +} + +void Blit11::add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) +{ + BlitParameters params = { 0 }; + params.mDestinationFormat = destFormat; + params.mSignedInteger = signedInteger; + params.m3DBlit = true; + + ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); + ASSERT(ps); + + Shader shader; + shader.mVertexWriteFunction = Write3DVertices; + shader.mInputLayout = mQuad3DIL; + shader.mVertexShader = mQuad3DVS; + shader.mGeometryShader = mQuad3DGS; + shader.mPixelShader = ps; + + mBlitShaderMap[params] = shader; +} + +void Blit11::addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps) +{ + SwizzleParameters params = { 0 }; + params.mDestinationType = destType; + params.mViewDimension = viewDimension; + + ASSERT(mSwizzleShaderMap.find(params) == mSwizzleShaderMap.end()); + ASSERT(ps); + + Shader shader; + switch (viewDimension) + { + case D3D_SRV_DIMENSION_TEXTURE2D: + shader.mVertexWriteFunction = Write2DVertices; + shader.mInputLayout = mQuad2DIL; + shader.mVertexShader = mQuad2DVS; + shader.mGeometryShader = NULL; + break; + + case D3D_SRV_DIMENSION_TEXTURE3D: + case D3D_SRV_DIMENSION_TEXTURE2DARRAY: + case D3D_SRV_DIMENSION_TEXTURECUBE: + shader.mVertexWriteFunction = Write3DVertices; + shader.mInputLayout = mQuad3DIL; + shader.mVertexShader = mQuad3DVS; + shader.mGeometryShader = mQuad3DGS; + break; + + default: + UNREACHABLE(); + break; + } + shader.mPixelShader = ps; + + mSwizzleShaderMap[params] = shader; +} + +void Blit11::buildShaderMap() +{ + ID3D11Device *device = mRenderer->getDevice(); + + // 2D shaders (OpenGL ES 2+) + add2DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader" )); + add2DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader" )); + add2DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader" )); + add2DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader" )); + add2DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader" )); + add2DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader" )); + add2DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader" )); + add2DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader")); + + // 2D shaders (OpenGL ES 3+) + if (mRenderer->isES3Capable()) + { + add2DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader" )); + add2DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader" )); + add2DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader" )); + add2DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader" )); + add2DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader" )); + add2DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader" )); + add2DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader" )); + add2DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader" )); + } + + // 3D shaders (OpenGL ES 3+) + if (mRenderer->isES3Capable()) + { + add3DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader" )); + add3DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader" )); + add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" )); + add3DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader" )); + add3DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader" )); + add3DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader" )); + add3DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader" )); + add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); + add3DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader" )); + add3DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader" )); + add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); + add3DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader" )); + add3DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader" )); + add3DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader" )); + add3DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader" )); + add3DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader")); + } + + // Swizzling shaders (OpenGL ES 3+) + if (mRenderer->isES3Capable()) + { + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Cube F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Cube UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Cube I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader" )); + + addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Array F swizzle pixel shader" )); + addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Array UI swizzle pixel shader")); + addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Array I swizzle pixel shader" )); + } +} + +void Blit11::clearShaderMap() +{ + for (BlitShaderMap::iterator i = mBlitShaderMap.begin(); i != mBlitShaderMap.end(); ++i) + { + Shader &shader = i->second; + SafeRelease(shader.mPixelShader); + } + mBlitShaderMap.clear(); + + for (SwizzleShaderMap::iterator i = mSwizzleShaderMap.begin(); i != mSwizzleShaderMap.end(); ++i) + { + Shader &shader = i->second; + SafeRelease(shader.mPixelShader); + } + mSwizzleShaderMap.clear(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h new file mode 100644 index 0000000000..d3a8c2c8a3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Blit11.h @@ -0,0 +1,121 @@ +// +// Copyright (c) 2013 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. +// + +// Blit11.cpp: Texture copy utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" + +#include + +namespace rx +{ +class Renderer11; + +class Blit11 : angle::NonCopyable +{ + public: + explicit Blit11(Renderer11 *renderer); + ~Blit11(); + + gl::Error swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, + GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + + gl::Error copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter); + + gl::Error copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + gl::Error copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + private: + Renderer11 *mRenderer; + + struct BlitParameters + { + GLenum mDestinationFormat; + bool mSignedInteger; + bool m3DBlit; + }; + + gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly); + + static bool compareBlitParameters(const BlitParameters &a, const BlitParameters &b); + + typedef void (*WriteVertexFunction)(const gl::Box &sourceArea, const gl::Extents &sourceSize, + const gl::Box &destArea, const gl::Extents &destSize, + void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, + D3D11_PRIMITIVE_TOPOLOGY *outTopology); + + struct Shader + { + WriteVertexFunction mVertexWriteFunction; + ID3D11InputLayout *mInputLayout; + ID3D11VertexShader *mVertexShader; + ID3D11GeometryShader *mGeometryShader; + ID3D11PixelShader *mPixelShader; + }; + + typedef bool (*BlitParametersComparisonFunction)(const BlitParameters&, const BlitParameters &); + typedef std::map BlitShaderMap; + BlitShaderMap mBlitShaderMap; + + void add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); + void add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); + + struct SwizzleParameters + { + GLenum mDestinationType; + D3D11_SRV_DIMENSION mViewDimension; + }; + + static bool compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b); + + typedef bool (*SwizzleParametersComparisonFunction)(const SwizzleParameters&, const SwizzleParameters &); + typedef std::map SwizzleShaderMap; + SwizzleShaderMap mSwizzleShaderMap; + + void addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps); + + void buildShaderMap(); + void clearShaderMap(); + + ID3D11Buffer *mVertexBuffer; + ID3D11SamplerState *mPointSampler; + ID3D11SamplerState *mLinearSampler; + ID3D11RasterizerState *mScissorEnabledRasterizerState; + ID3D11RasterizerState *mScissorDisabledRasterizerState; + ID3D11DepthStencilState *mDepthStencilState; + + ID3D11InputLayout *mQuad2DIL; + ID3D11VertexShader *mQuad2DVS; + ID3D11PixelShader *mDepthPS; + + ID3D11InputLayout *mQuad3DIL; + ID3D11VertexShader *mQuad3DVS; + ID3D11GeometryShader *mQuad3DGS; + + ID3D11Buffer *mSwizzleCB; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_BLIT11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp new file mode 100644 index 0000000000..d56b0ea7ad --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp @@ -0,0 +1,1070 @@ +// +// Copyright 2014 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. +// + +// Buffer11.cpp Defines the Buffer11 class. + +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" + +#include "common/MemoryBuffer.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +#if defined(ANGLE_MINGW32_COMPAT) +typedef enum D3D11_MAP_FLAG { + D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000 +} D3D11_MAP_FLAG; +#endif + +namespace rx +{ + +PackPixelsParams::PackPixelsParams() + : format(GL_NONE), + type(GL_NONE), + outputPitch(0), + packBuffer(NULL), + offset(0) +{} + +PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, GLenum formatIn, GLenum typeIn, GLuint outputPitchIn, + const gl::PixelPackState &packIn, ptrdiff_t offsetIn) + : area(areaIn), + format(formatIn), + type(typeIn), + outputPitch(outputPitchIn), + packBuffer(packIn.pixelBuffer.get()), + pack(packIn.alignment, packIn.reverseRowOrder), + offset(offsetIn) +{} + +namespace gl_d3d11 +{ + +D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) +{ + bool readBit = ((access & GL_MAP_READ_BIT) != 0); + bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); + + ASSERT(readBit || writeBit); + + // Note : we ignore the discard bit, because in D3D11, staging buffers + // don't accept the map-discard flag (discard only works for DYNAMIC usage) + + if (readBit && !writeBit) + { + return D3D11_MAP_READ; + } + else if (writeBit && !readBit) + { + return D3D11_MAP_WRITE; + } + else if (writeBit && readBit) + { + return D3D11_MAP_READ_WRITE; + } + else + { + UNREACHABLE(); + return D3D11_MAP_READ; + } +} + +} + +// Each instance of Buffer11::BufferStorage is specialized for a class of D3D binding points +// - vertex/transform feedback buffers +// - index buffers +// - pixel unpack buffers +// - uniform buffers +class Buffer11::BufferStorage : angle::NonCopyable +{ + public: + virtual ~BufferStorage() {} + + DataRevision getDataRevision() const { return mRevision; } + BufferUsage getUsage() const { return mUsage; } + size_t getSize() const { return mBufferSize; } + void setDataRevision(DataRevision rev) { mRevision = rev; } + + virtual bool isMappable() const = 0; + + virtual bool copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) = 0; + virtual gl::Error resize(size_t size, bool preserveData) = 0; + + virtual uint8_t *map(size_t offset, size_t length, GLbitfield access) = 0; + virtual void unmap() = 0; + + gl::Error setData(const uint8_t *data, size_t offset, size_t size); + + protected: + BufferStorage(Renderer11 *renderer, BufferUsage usage); + + Renderer11 *mRenderer; + DataRevision mRevision; + const BufferUsage mUsage; + size_t mBufferSize; +}; + +// A native buffer storage represents an underlying D3D11 buffer for a particular +// type of storage. +class Buffer11::NativeStorage : public Buffer11::BufferStorage +{ + public: + NativeStorage(Renderer11 *renderer, BufferUsage usage); + ~NativeStorage() override; + + bool isMappable() const override { return mUsage == BUFFER_USAGE_STAGING; } + + ID3D11Buffer *getNativeStorage() const { return mNativeStorage; } + + bool copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) override; + gl::Error resize(size_t size, bool preserveData) override; + + uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + void unmap() override; + + private: + static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize); + + ID3D11Buffer *mNativeStorage; +}; + +// Pack storage represents internal storage for pack buffers. We implement pack buffers +// as CPU memory, tied to a staging texture, for asynchronous texture readback. +class Buffer11::PackStorage : public Buffer11::BufferStorage +{ + public: + explicit PackStorage(Renderer11 *renderer); + ~PackStorage() override; + + bool isMappable() const override { return true; } + + bool copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) override; + gl::Error resize(size_t size, bool preserveData) override; + + uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + void unmap() override; + + gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); + + private: + gl::Error flushQueuedPackCommand(); + + ID3D11Texture2D *mStagingTexture; + DXGI_FORMAT mTextureFormat; + gl::Extents mTextureSize; + MemoryBuffer mMemoryBuffer; + PackPixelsParams *mQueuedPackCommand; + PackPixelsParams mPackParams; + bool mDataModified; +}; + +// System memory storage stores a CPU memory buffer with our buffer data. +// For dynamic data, it's much faster to update the CPU memory buffer than +// it is to update a D3D staging buffer and read it back later. +class Buffer11::SystemMemoryStorage : public Buffer11::BufferStorage +{ + public: + explicit SystemMemoryStorage(Renderer11 *renderer); + ~SystemMemoryStorage() override {} + + bool isMappable() const override { return true; } + + bool copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) override; + gl::Error resize(size_t size, bool preserveData) override; + + uint8_t *map(size_t offset, size_t length, GLbitfield access) override; + void unmap() override; + + MemoryBuffer *getSystemCopy() { return &mSystemCopy; } + + protected: + MemoryBuffer mSystemCopy; +}; + +Buffer11::Buffer11(Renderer11 *renderer) + : BufferD3D(renderer), + mRenderer(renderer), + mSize(0), + mMappedStorage(NULL), + mReadUsageCount(0), + mHasSystemMemoryStorage(false) +{} + +Buffer11::~Buffer11() +{ + for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) + { + SafeDelete(it->second); + } +} + +Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer)); + return static_cast(buffer); +} + +gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage) +{ + gl::Error error = setSubData(data, size, 0); + if (error.isError()) + { + return error; + } + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } + + return error; +} + +gl::Error Buffer11::getData(const uint8_t **outData) +{ + SystemMemoryStorage *systemMemoryStorage = nullptr; + gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); + + if (error.isError()) + { + *outData = nullptr; + return error; + } + + mReadUsageCount = 0; + + ASSERT(systemMemoryStorage->getSize() >= mSize); + + *outData = systemMemoryStorage->getSystemCopy()->data(); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::getSystemMemoryStorage(SystemMemoryStorage **storageOut) +{ + BufferStorage *memStorageUntyped = getBufferStorage(BUFFER_USAGE_SYSTEM_MEMORY); + + if (memStorageUntyped == nullptr) + { + // TODO(jmadill): convert all to errors + return gl::Error(GL_OUT_OF_MEMORY); + } + + *storageOut = GetAs(memStorageUntyped); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) +{ + size_t requiredSize = size + offset; + + if (data && size > 0) + { + // Use system memory storage for dynamic buffers. + + BufferStorage *writeBuffer = nullptr; + if (supportsDirectBinding()) + { + writeBuffer = getStagingStorage(); + + if (!writeBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + } + } + else + { + SystemMemoryStorage *systemMemoryStorage = nullptr; + gl::Error error = getSystemMemoryStorage(&systemMemoryStorage); + if (error.isError()) + { + return error; + } + + writeBuffer = systemMemoryStorage; + } + + ASSERT(writeBuffer); + + // Explicitly resize the staging buffer, preserving data if the new data will not + // completely fill the buffer + if (writeBuffer->getSize() < requiredSize) + { + bool preserveData = (offset > 0); + gl::Error error = writeBuffer->resize(requiredSize, preserveData); + if (error.isError()) + { + return error; + } + } + + writeBuffer->setData(static_cast(data), offset, size); + writeBuffer->setDataRevision(writeBuffer->getDataRevision() + 1); + } + + mSize = std::max(mSize, requiredSize); + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + Buffer11 *sourceBuffer = makeBuffer11(source); + ASSERT(sourceBuffer != NULL); + + BufferStorage *copyDest = getLatestBufferStorage(); + if (!copyDest) + { + copyDest = getStagingStorage(); + } + + BufferStorage *copySource = sourceBuffer->getLatestBufferStorage(); + + if (!copySource || !copyDest) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); + } + + // If copying to/from a pixel pack buffer, we must have a staging or + // pack buffer partner, because other native buffers can't be mapped + if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable()) + { + copySource = sourceBuffer->getStagingStorage(); + } + else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable()) + { + copyDest = getStagingStorage(); + } + + // D3D11 does not allow overlapped copies until 11.1, and only if the + // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap + // Get around this via a different source buffer + if (copySource == copyDest) + { + if (copySource->getUsage() == BUFFER_USAGE_STAGING) + { + copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + } + else + { + copySource = getStagingStorage(); + } + } + + copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset); + copyDest->setDataRevision(copyDest->getDataRevision() + 1); + + mSize = std::max(mSize, destOffset + size); + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +{ + ASSERT(!mMappedStorage); + + BufferStorage *latestStorage = getLatestBufferStorage(); + if (latestStorage && + (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || + latestStorage->getUsage() == BUFFER_USAGE_STAGING)) + { + // Latest storage is mappable. + mMappedStorage = latestStorage; + } + else + { + // Fall back to using the staging buffer if the latest storage does + // not exist or is not CPU-accessible. + mMappedStorage = getStagingStorage(); + } + + if (!mMappedStorage) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer."); + } + + if ((access & GL_MAP_WRITE_BIT) > 0) + { + // Update the data revision immediately, since the data might be changed at any time + mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1); + } + + uint8_t *mappedBuffer = mMappedStorage->map(offset, length, access); + if (!mappedBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); + } + + *mapPtr = static_cast(mappedBuffer); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::unmap() +{ + ASSERT(mMappedStorage); + mMappedStorage->unmap(); + mMappedStorage = NULL; + return gl::Error(GL_NO_ERROR); +} + +void Buffer11::markTransformFeedbackUsage() +{ + BufferStorage *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + if (transformFeedbackStorage) + { + transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); + } + + invalidateStaticData(); +} + +void Buffer11::markBufferUsage() +{ + mReadUsageCount++; + + // Free the system memory storage if we decide it isn't being used very often. + const unsigned int usageLimit = 5; + + if (mReadUsageCount > usageLimit && mHasSystemMemoryStorage) + { + auto systemMemoryStorageIt = mBufferStorages.find(BUFFER_USAGE_SYSTEM_MEMORY); + ASSERT(systemMemoryStorageIt != mBufferStorages.end()); + + SafeDelete(systemMemoryStorageIt->second); + mBufferStorages.erase(systemMemoryStorageIt); + mHasSystemMemoryStorage = false; + } +} + +ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) +{ + markBufferUsage(); + + BufferStorage *bufferStorage = getBufferStorage(usage); + + if (!bufferStorage) + { + // Storage out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, bufferStorage)); + + return static_cast(bufferStorage)->getNativeStorage(); +} + +ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) +{ + BufferStorage *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); + + if (!storage) + { + // Storage out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, storage)); + ID3D11Buffer *buffer = static_cast(storage)->getNativeStorage(); + + auto bufferSRVIt = mBufferResourceViews.find(srvFormat); + + if (bufferSRVIt != mBufferResourceViews.end()) + { + if (bufferSRVIt->second.first == buffer) + { + return bufferSRVIt->second.second; + } + else + { + // The underlying buffer has changed since the SRV was created: recreate the SRV. + SafeRelease(bufferSRVIt->second.second); + } + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11ShaderResourceView *bufferSRV = NULL; + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat); + + D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; + bufferSRVDesc.Buffer.ElementOffset = 0; + bufferSRVDesc.Buffer.ElementWidth = mSize / dxgiFormatInfo.pixelBytes; + bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + bufferSRVDesc.Format = srvFormat; + + HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV); + + return bufferSRV; +} + +gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams ¶ms) +{ + PackStorage *packStorage = getPackStorage(); + BufferStorage *latestStorage = getLatestBufferStorage(); + + if (packStorage) + { + gl::Error error = packStorage->packPixels(srcTexture, srcSubresource, params); + if (error.isError()) + { + return error; + } + packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); + } + + return gl::Error(GL_NO_ERROR); +} + +Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage) +{ + BufferStorage *newStorage = NULL; + auto directBufferIt = mBufferStorages.find(usage); + if (directBufferIt != mBufferStorages.end()) + { + newStorage = directBufferIt->second; + } + + if (!newStorage) + { + if (usage == BUFFER_USAGE_PIXEL_PACK) + { + newStorage = new PackStorage(mRenderer); + } + else if (usage == BUFFER_USAGE_SYSTEM_MEMORY) + { + newStorage = new SystemMemoryStorage(mRenderer); + mHasSystemMemoryStorage = true; + } + else + { + // buffer is not allocated, create it + newStorage = new NativeStorage(mRenderer, usage); + } + + mBufferStorages.insert(std::make_pair(usage, newStorage)); + } + + // resize buffer + if (newStorage->getSize() < mSize) + { + if (newStorage->resize(mSize, true).isError()) + { + // Out of memory error + return NULL; + } + } + + BufferStorage *latestBuffer = getLatestBufferStorage(); + if (latestBuffer && latestBuffer->getDataRevision() > newStorage->getDataRevision()) + { + // Copy through a staging buffer if we're copying from or to a non-staging, mappable + // buffer storage. This is because we can't map a GPU buffer, and copy CPU + // data directly. If we're already using a staging buffer we're fine. + if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING && + newStorage->getUsage() != BUFFER_USAGE_STAGING && + (!latestBuffer->isMappable() || !newStorage->isMappable())) + { + NativeStorage *stagingBuffer = getStagingStorage(); + + stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); + stagingBuffer->setDataRevision(latestBuffer->getDataRevision()); + + latestBuffer = stagingBuffer; + } + + // if copyFromStorage returns true, the D3D buffer has been recreated + // and we should update our serial + if (newStorage->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) + { + updateSerial(); + } + newStorage->setDataRevision(latestBuffer->getDataRevision()); + } + + return newStorage; +} + +Buffer11::BufferStorage *Buffer11::getLatestBufferStorage() const +{ + // Even though we iterate over all the direct buffers, it is expected that only + // 1 or 2 will be present. + BufferStorage *latestStorage = NULL; + DataRevision latestRevision = 0; + for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) + { + BufferStorage *storage = it->second; + if (!latestStorage || storage->getDataRevision() > latestRevision) + { + latestStorage = storage; + latestRevision = storage->getDataRevision(); + } + } + + // resize buffer + if (latestStorage && latestStorage->getSize() < mSize) + { + if (latestStorage->resize(mSize, true).isError()) + { + // Out of memory error + return NULL; + } + } + + return latestStorage; +} + +Buffer11::NativeStorage *Buffer11::getStagingStorage() +{ + BufferStorage *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); + + if (!stagingStorage) + { + // Out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, stagingStorage)); + return static_cast(stagingStorage); +} + +Buffer11::PackStorage *Buffer11::getPackStorage() +{ + BufferStorage *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); + + if (!packStorage) + { + // Out-of-memory + return NULL; + } + + ASSERT(HAS_DYNAMIC_TYPE(PackStorage*, packStorage)); + return static_cast(packStorage); +} + +bool Buffer11::supportsDirectBinding() const +{ + // Do not support direct buffers for dynamic data. The streaming buffer + // offers better performance for data which changes every frame. + // Check for absence of static buffer interfaces to detect dynamic data. + return (mStaticVertexBuffer && mStaticIndexBuffer); +} + +Buffer11::BufferStorage::BufferStorage(Renderer11 *renderer, BufferUsage usage) + : mRenderer(renderer), + mUsage(usage), + mRevision(0), + mBufferSize(0) +{ +} + +gl::Error Buffer11::BufferStorage::setData(const uint8_t *data, size_t offset, size_t size) +{ + ASSERT(isMappable()); + + uint8_t *writePointer = map(offset, size, GL_MAP_WRITE_BIT); + if (!writePointer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); + } + + memcpy(writePointer, data, size); + + unmap(); + + return gl::Error(GL_NO_ERROR); +} + +Buffer11::NativeStorage::NativeStorage(Renderer11 *renderer, BufferUsage usage) + : BufferStorage(renderer, usage), + mNativeStorage(NULL) +{ +} + +Buffer11::NativeStorage::~NativeStorage() +{ + SafeRelease(mNativeStorage); +} + +// Returns true if it recreates the direct buffer +bool Buffer11::NativeStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + size_t requiredSize = sourceOffset + size; + bool createBuffer = !mNativeStorage || mBufferSize < requiredSize; + + // (Re)initialize D3D buffer if needed + if (createBuffer) + { + bool preserveData = (destOffset > 0); + resize(source->getSize(), preserveData); + } + + if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK || + source->getUsage() == BUFFER_USAGE_SYSTEM_MEMORY) + { + ASSERT(source->isMappable()); + + uint8_t *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT hr = context->Map(mNativeStorage, 0, D3D11_MAP_WRITE, 0, &mappedResource); + UNUSED_ASSERTION_VARIABLE(hr); + ASSERT(SUCCEEDED(hr)); + + uint8_t *destPointer = static_cast(mappedResource.pData) + destOffset; + + // Offset bounds are validated at the API layer + ASSERT(sourceOffset + size <= destOffset + mBufferSize); + memcpy(destPointer, sourcePointer, size); + + context->Unmap(mNativeStorage, 0); + source->unmap(); + } + else + { + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, source)); + + D3D11_BOX srcBox; + srcBox.left = sourceOffset; + srcBox.right = sourceOffset + size; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + ASSERT(HAS_DYNAMIC_TYPE(NativeStorage*, source)); + ID3D11Buffer *sourceBuffer = static_cast(source)->getNativeStorage(); + + context->CopySubresourceRegion(mNativeStorage, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox); + } + + return createBuffer; +} + +gl::Error Buffer11::NativeStorage::resize(size_t size, bool preserveData) +{ + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + D3D11_BUFFER_DESC bufferDesc; + fillBufferDesc(&bufferDesc, mRenderer, mUsage, size); + + ID3D11Buffer *newBuffer; + HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", result); + } + + if (mNativeStorage && preserveData) + { + // We don't call resize if the buffer is big enough already. + ASSERT(mBufferSize <= size); + + D3D11_BOX srcBox; + srcBox.left = 0; + srcBox.right = mBufferSize; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + + context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeStorage, 0, &srcBox); + } + + // No longer need the old buffer + SafeRelease(mNativeStorage); + mNativeStorage = newBuffer; + + mBufferSize = bufferDesc.ByteWidth; + + return gl::Error(GL_NO_ERROR); +} + +void Buffer11::NativeStorage::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, + BufferUsage usage, unsigned int bufferSize) +{ + bufferDesc->ByteWidth = bufferSize; + bufferDesc->MiscFlags = 0; + bufferDesc->StructureByteStride = 0; + + switch (usage) + { + case BUFFER_USAGE_STAGING: + bufferDesc->Usage = D3D11_USAGE_STAGING; + bufferDesc->BindFlags = 0; + bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + break; + + case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; + + if (renderer->isES3Capable()) + { + bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; + } + + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_INDEX: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_PIXEL_UNPACK: + bufferDesc->Usage = D3D11_USAGE_DEFAULT; + bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; + bufferDesc->CPUAccessFlags = 0; + break; + + case BUFFER_USAGE_UNIFORM: + bufferDesc->Usage = D3D11_USAGE_DYNAMIC; + bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + // Constant buffers must be of a limited size, and aligned to 16 byte boundaries + // For our purposes we ignore any buffer data past the maximum constant buffer size + bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u); + bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, renderer->getRendererCaps().maxUniformBlockSize); + break; + + default: + UNREACHABLE(); + } +} + +uint8_t *Buffer11::NativeStorage::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(mUsage == BUFFER_USAGE_STAGING); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access); + UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); + + HRESULT result = context->Map(mNativeStorage, 0, d3dMapType, d3dMapFlag, &mappedResource); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + return static_cast(mappedResource.pData) + offset; +} + +void Buffer11::NativeStorage::unmap() +{ + ASSERT(mUsage == BUFFER_USAGE_STAGING); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->Unmap(mNativeStorage, 0); +} + +Buffer11::PackStorage::PackStorage(Renderer11 *renderer) + : BufferStorage(renderer, BUFFER_USAGE_PIXEL_PACK), + mStagingTexture(NULL), + mTextureFormat(DXGI_FORMAT_UNKNOWN), + mQueuedPackCommand(NULL), + mDataModified(false) +{ +} + +Buffer11::PackStorage::~PackStorage() +{ + SafeRelease(mStagingTexture); + SafeDelete(mQueuedPackCommand); +} + +bool Buffer11::PackStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + // We copy through a staging buffer when drawing with a pack buffer, + // or for other cases where we access the pack buffer + UNREACHABLE(); + return false; +} + +gl::Error Buffer11::PackStorage::resize(size_t size, bool preserveData) +{ + if (size != mBufferSize) + { + if (!mMemoryBuffer.resize(size)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer storage."); + } + mBufferSize = size; + } + + return gl::Error(GL_NO_ERROR); +} + +uint8_t *Buffer11::PackStorage::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(offset + length <= getSize()); + // TODO: fast path + // We might be able to optimize out one or more memcpy calls by detecting when + // and if D3D packs the staging texture memory identically to how we would fill + // the pack buffer according to the current pack state. + + gl::Error error = flushQueuedPackCommand(); + if (error.isError()) + { + return NULL; + } + + mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); + + return mMemoryBuffer.data() + offset; +} + +void Buffer11::PackStorage::unmap() +{ + // No-op +} + +gl::Error Buffer11::PackStorage::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms) +{ + gl::Error error = flushQueuedPackCommand(); + if (error.isError()) + { + return error; + } + + mQueuedPackCommand = new PackPixelsParams(params); + + D3D11_TEXTURE2D_DESC textureDesc; + srcTexure->GetDesc(&textureDesc); + + if (mStagingTexture != NULL && + (mTextureFormat != textureDesc.Format || + mTextureSize.width != params.area.width || + mTextureSize.height != params.area.height)) + { + SafeRelease(mStagingTexture); + mTextureSize.width = 0; + mTextureSize.height = 0; + mTextureFormat = DXGI_FORMAT_UNKNOWN; + } + + if (mStagingTexture == NULL) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT hr; + + mTextureSize.width = params.area.width; + mTextureSize.height = params.area.height; + mTextureFormat = textureDesc.Format; + + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = params.area.width; + stagingDesc.Height = params.area.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = mTextureFormat; + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.BindFlags = 0; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingDesc.MiscFlags = 0; + + hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture); + if (FAILED(hr)) + { + ASSERT(hr == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging texture."); + } + } + + // ReadPixels from multisampled FBOs isn't supported in current GL + ASSERT(textureDesc.SampleDesc.Count <= 1); + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + D3D11_BOX srcBox; + srcBox.left = params.area.x; + srcBox.right = params.area.x + params.area.width; + srcBox.top = params.area.y; + srcBox.bottom = params.area.y + params.area.height; + srcBox.front = 0; + srcBox.back = 1; + + // Asynchronous copy + immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer11::PackStorage::flushQueuedPackCommand() +{ + ASSERT(mMemoryBuffer.size() > 0); + + if (mQueuedPackCommand) + { + gl::Error error = mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); + SafeDelete(mQueuedPackCommand); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +Buffer11::SystemMemoryStorage::SystemMemoryStorage(Renderer11 *renderer) + : Buffer11::BufferStorage(renderer, BUFFER_USAGE_SYSTEM_MEMORY) +{} + +bool Buffer11::SystemMemoryStorage::copyFromStorage(BufferStorage *source, size_t sourceOffset, + size_t size, size_t destOffset) +{ + ASSERT(source->isMappable()); + const uint8_t *sourceData = source->map(sourceOffset, size, GL_MAP_READ_BIT); + ASSERT(destOffset + size <= mSystemCopy.size()); + memcpy(mSystemCopy.data() + destOffset, sourceData, size); + source->unmap(); + return true; +} + +gl::Error Buffer11::SystemMemoryStorage::resize(size_t size, bool preserveData) +{ + if (mSystemCopy.size() < size) + { + if (!mSystemCopy.resize(size)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize SystemMemoryStorage"); + } + mBufferSize = size; + } + + return gl::Error(GL_NO_ERROR); +} + +uint8_t *Buffer11::SystemMemoryStorage::map(size_t offset, size_t length, GLbitfield access) +{ + ASSERT(!mSystemCopy.empty() && offset + length <= mSystemCopy.size()); + return mSystemCopy.data() + offset; +} + +void Buffer11::SystemMemoryStorage::unmap() +{ + // No-op +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h new file mode 100644 index 0000000000..39bafe880e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.h @@ -0,0 +1,103 @@ +// +// Copyright 2014 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. +// + +// Buffer11.h: Defines the rx::Buffer11 class which implements rx::BufferImpl via rx::BufferD3D. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" + +namespace rx +{ +class Renderer11; + +enum BufferUsage +{ + BUFFER_USAGE_STAGING, + BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, + BUFFER_USAGE_INDEX, + BUFFER_USAGE_PIXEL_UNPACK, + BUFFER_USAGE_PIXEL_PACK, + BUFFER_USAGE_UNIFORM, + BUFFER_USAGE_SYSTEM_MEMORY, +}; + +struct PackPixelsParams +{ + PackPixelsParams(); + PackPixelsParams(const gl::Rectangle &area, GLenum format, GLenum type, GLuint outputPitch, + const gl::PixelPackState &pack, ptrdiff_t offset); + + gl::Rectangle area; + GLenum format; + GLenum type; + GLuint outputPitch; + gl::Buffer *packBuffer; + gl::PixelPackState pack; + ptrdiff_t offset; +}; + +typedef size_t DataRevision; + +class Buffer11 : public BufferD3D +{ + public: + Buffer11(Renderer11 *renderer); + virtual ~Buffer11(); + + static Buffer11 *makeBuffer11(BufferImpl *buffer); + + ID3D11Buffer *getBuffer(BufferUsage usage); + ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat); + bool isMapped() const { return mMappedStorage != NULL; } + gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); + + // BufferD3D implementation + virtual size_t getSize() const { return mSize; } + virtual bool supportsDirectBinding() const; + + // BufferImpl implementation + virtual gl::Error setData(const void* data, size_t size, GLenum usage); + gl::Error getData(const uint8_t **outData) override; + virtual gl::Error setSubData(const void* data, size_t size, size_t offset); + virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); + virtual gl::Error unmap(); + virtual void markTransformFeedbackUsage(); + + private: + class BufferStorage; + class NativeStorage; + class PackStorage; + class SystemMemoryStorage; + + Renderer11 *mRenderer; + size_t mSize; + + BufferStorage *mMappedStorage; + + std::map mBufferStorages; + + typedef std::pair BufferSRVPair; + std::map mBufferResourceViews; + + unsigned int mReadUsageCount; + bool mHasSystemMemoryStorage; + + void markBufferUsage(); + NativeStorage *getStagingStorage(); + PackStorage *getPackStorage(); + gl::Error getSystemMemoryStorage(SystemMemoryStorage **storageOut); + + BufferStorage *getBufferStorage(BufferUsage usage); + BufferStorage *getLatestBufferStorage() const; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_BUFFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp new file mode 100644 index 0000000000..057c3bed42 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp @@ -0,0 +1,614 @@ +// +// Copyright (c) 2013 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. +// + +// Clear11.cpp: Framebuffer clear utility class. + +#include "libANGLE/renderer/d3d/d3d11/Clear11.h" + +#include + +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearfloat11_fl9ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearuint11ps.h" + +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/clearsint11ps.h" + +namespace rx +{ + +template +static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangle *scissor, const gl::Color &color, float depth, void *buffer) +{ + d3d11::PositionDepthColorVertex *vertices = reinterpret_cast*>(buffer); + + float depthClear = gl::clamp01(depth); + float left = -1.0f; + float right = 1.0f; + float top = -1.0f; + float bottom = 1.0f; + + // Clip the quad coordinates to the scissor if needed + if (scissor != NULL) + { + left = std::max(left, (scissor->x / float(framebufferSize.width)) * 2.0f - 1.0f); + right = std::min(right, ((scissor->x + scissor->width) / float(framebufferSize.width)) * 2.0f - 1.0f); + top = std::max(top, ((framebufferSize.height - scissor->y - scissor->height) / float(framebufferSize.height)) * 2.0f - 1.0f); + bottom = std::min(bottom, ((framebufferSize.height - scissor->y) / float(framebufferSize.height)) * 2.0f - 1.0f); + } + + d3d11::SetPositionDepthColorVertex(vertices + 0, left, bottom, depthClear, color); + d3d11::SetPositionDepthColorVertex(vertices + 1, left, top, depthClear, color); + d3d11::SetPositionDepthColorVertex(vertices + 2, right, bottom, depthClear, color); + d3d11::SetPositionDepthColorVertex(vertices + 3, right, top, depthClear, color); +} + +template +Clear11::ClearShader Clear11::CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize]) +{ + HRESULT result; + + ClearShader shader = { 0 }; + + D3D11_INPUT_ELEMENT_DESC quadLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, colorType, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quadLayout, ArraySize(quadLayout), vsByteCode, vsSize, &shader.inputLayout); + ASSERT(SUCCEEDED(result)); + + result = device->CreateVertexShader(vsByteCode, vsSize, NULL, &shader.vertexShader); + ASSERT(SUCCEEDED(result)); + + result = device->CreatePixelShader(psByteCode, psSize, NULL, &shader.pixelShader); + ASSERT(SUCCEEDED(result)); + + return shader; +} + +Clear11::Clear11(Renderer11 *renderer) + : mRenderer(renderer), mClearBlendStates(StructLessThan), mClearDepthStencilStates(StructLessThan), + mVertexBuffer(NULL), mRasterizerState(NULL), mSupportsClearView(false) +{ + HRESULT result; + ID3D11Device *device = renderer->getDevice(); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex) * 4; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer"); + + D3D11_RASTERIZER_DESC rsDesc; + rsDesc.FillMode = D3D11_FILL_SOLID; + rsDesc.CullMode = D3D11_CULL_NONE; + rsDesc.FrontCounterClockwise = FALSE; + rsDesc.DepthBias = 0; + rsDesc.DepthBiasClamp = 0.0f; + rsDesc.SlopeScaledDepthBias = 0.0f; + rsDesc.DepthClipEnable = TRUE; + rsDesc.ScissorEnable = FALSE; + rsDesc.MultisampleEnable = FALSE; + rsDesc.AntialiasedLineEnable = FALSE; + + result = device->CreateRasterizerState(&rsDesc, &mRasterizerState); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); + + if (renderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat_FL9); + } + else + { + mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat); + } + + if (renderer->isES3Capable()) + { + mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint ); + mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); + } + +#if defined(ANGLE_ENABLE_D3D11_1) + if (renderer->getDeviceContext1IfSupported()) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; + device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + mSupportsClearView = (d3d11Options.ClearView != FALSE); + } +#endif +} + +Clear11::~Clear11() +{ + for (ClearBlendStateMap::iterator i = mClearBlendStates.begin(); i != mClearBlendStates.end(); i++) + { + SafeRelease(i->second); + } + mClearBlendStates.clear(); + + SafeRelease(mFloatClearShader.inputLayout); + SafeRelease(mFloatClearShader.vertexShader); + SafeRelease(mFloatClearShader.pixelShader); + + if (mRenderer->isES3Capable()) + { + SafeRelease(mUintClearShader.inputLayout); + SafeRelease(mUintClearShader.vertexShader); + SafeRelease(mUintClearShader.pixelShader); + + SafeRelease(mIntClearShader.inputLayout); + SafeRelease(mIntClearShader.vertexShader); + SafeRelease(mIntClearShader.pixelShader); + } + + for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++) + { + SafeRelease(i->second); + } + mClearDepthStencilStates.clear(); + + SafeRelease(mVertexBuffer); + SafeRelease(mRasterizerState); +} + +gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData) +{ + const auto &colorAttachments = fboData.mColorAttachments; + const auto &drawBufferStates = fboData.mDrawBufferStates; + const auto *depthAttachment = fboData.mDepthAttachment; + const auto *stencilAttachment = fboData.mStencilAttachment; + + ASSERT(colorAttachments.size() == drawBufferStates.size()); + + // Iterate over the color buffers which require clearing and determine if they can be + // cleared with ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView. + // This requires: + // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer + // render targets as expected but does not work the other way around) + // 2) The format of the render target has no color channels that are currently masked out. + // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work. + // + // If these conditions are met, and: + // - No scissored clear is needed, then clear using ID3D11DeviceContext::ClearRenderTargetView. + // - A scissored clear is needed then clear using ID3D11DeviceContext1::ClearView if available. + // Otherwise draw a quad. + // + // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView + // by checking if the stencil write mask covers the entire stencil. + // + // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color + // attribute. + + gl::Extents framebufferSize; + + auto iter = std::find_if(colorAttachments.begin(), colorAttachments.end(), [](const gl::FramebufferAttachment *attachment) { return attachment != nullptr; }); + if (iter != colorAttachments.end()) + { + framebufferSize.width = (*iter)->getWidth(); + framebufferSize.height = (*iter)->getHeight(); + framebufferSize.depth = 1; + } + else if (depthAttachment != nullptr) + { + framebufferSize.width = depthAttachment->getWidth(); + framebufferSize.height = depthAttachment->getHeight(); + framebufferSize.depth = 1; + } + else if (stencilAttachment != nullptr) + { + framebufferSize.width = stencilAttachment->getWidth(); + framebufferSize.height = stencilAttachment->getHeight(); + framebufferSize.depth = 1; + } + else + { + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || + clearParams.scissor.y >= framebufferSize.height || + clearParams.scissor.x + clearParams.scissor.width <= 0 || + clearParams.scissor.y + clearParams.scissor.height <= 0)) + { + // Scissor is enabled and the scissor rectangle is outside the renderbuffer + return gl::Error(GL_NO_ERROR); + } + + bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || + clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || + clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height); + + std::vector maskedClearRenderTargets; + RenderTarget11* maskedClearDepthStencil = NULL; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ID3D11DeviceContext1 *deviceContext1 = mRenderer->getDeviceContext1IfSupported(); + + for (size_t colorAttachment = 0; colorAttachment < colorAttachments.size(); colorAttachment++) + { + if (clearParams.clearColor[colorAttachment] && + colorAttachments[colorAttachment] != nullptr && + drawBufferStates[colorAttachment] != GL_NONE) + { + const gl::FramebufferAttachment *attachment = colorAttachments[colorAttachment]; + + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat()); + + if (clearParams.colorClearType == GL_FLOAT && + !(formatInfo.componentType == GL_FLOAT || formatInfo.componentType == GL_UNSIGNED_NORMALIZED || formatInfo.componentType == GL_SIGNED_NORMALIZED)) + { + ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-" + "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, + attachment->getInternalFormat()); + } + + if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) && + (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) && + (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) && + (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha)) + { + // Every channel either does not exist in the render target or is masked out + continue; + } + else if ((!mSupportsClearView && needScissoredClear) || clearParams.colorClearType != GL_FLOAT || + (formatInfo.redBits > 0 && !clearParams.colorMaskRed) || + (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) + { + // A masked clear is required, or a scissored clear is required and ID3D11DeviceContext1::ClearView is unavailable + MaskedRenderTarget maskAndRt; + bool clearColor = clearParams.clearColor[colorAttachment]; + maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed); + maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen); + maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue); + maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha); + maskAndRt.renderTarget = renderTarget; + maskedClearRenderTargets.push_back(maskAndRt); + } + else + { + // ID3D11DeviceContext::ClearRenderTargetView or ID3D11DeviceContext1::ClearView is possible + + ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); + if (!framebufferRTV) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); + } + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); + + // Check if the actual format has a channel that the internal format does not and set them to the + // default values + const float clearValues[4] = + { + ((formatInfo.redBits == 0 && dxgiFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + ((formatInfo.greenBits == 0 && dxgiFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + ((formatInfo.blueBits == 0 && dxgiFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue), + ((formatInfo.alphaBits == 0 && dxgiFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + }; + + if (needScissoredClear) + { +#if defined(ANGLE_ENABLE_D3D11_1) + // We shouldn't reach here if deviceContext1 is unavailable. + ASSERT(deviceContext1); + + D3D11_RECT rect; + rect.left = clearParams.scissor.x; + rect.right = clearParams.scissor.x + clearParams.scissor.width; + rect.top = clearParams.scissor.y; + rect.bottom = clearParams.scissor.y + clearParams.scissor.height; + + deviceContext1->ClearView(framebufferRTV, clearValues, &rect, 1); +#endif + } + else + { + deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); + } + } + } + } + + if (clearParams.clearDepth || clearParams.clearStencil) + { + const gl::FramebufferAttachment *attachment = (depthAttachment != nullptr) ? depthAttachment : stencilAttachment; + ASSERT(attachment != nullptr); + + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget->getDXGIFormat()); + + unsigned int stencilUnmasked = (stencilAttachment != nullptr) ? (1 << dxgiFormatInfo.stencilBits) - 1 : 0; + bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + if (needScissoredClear || needMaskedStencilClear) + { + maskedClearDepthStencil = renderTarget; + } + else + { + ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); + if (!framebufferDSV) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null."); + } + + UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | + (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); + FLOAT depthClear = gl::clamp01(clearParams.depthClearValue); + UINT8 stencilClear = clearParams.stencilClearValue & 0xFF; + + deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); + } + } + + if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) + { + // To clear the render targets and depth stencil in one pass: + // + // Render a quad clipped to the scissor rectangle which draws the clear color and a blend + // state that will perform the required color masking. + // + // The quad's depth is equal to the depth clear value with a depth stencil state that + // will enable or disable depth test/writes if the depth buffer should be cleared or not. + // + // The rasterizer state's stencil is set to always pass or fail based on if the stencil + // should be cleared or not with a stencil write mask of the stencil clear value. + // + // ====================================================================================== + // + // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- + // buffer that is not normalized fixed point or floating point with floating point values + // are undefined so we can just write floats to them and D3D11 will bit cast them to + // integers. + // + // Also, we don't have to worry about attempting to clear a normalized fixed/floating point + // buffer with integer values because there is no gl API call which would allow it, + // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to + // be a compatible clear type. + + // Bind all the render targets which need clearing + ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers); + std::vector rtvs(maskedClearRenderTargets.size()); + for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++) + { + RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget; + ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView(); + if (!rtv) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); + } + + rtvs[i] = rtv; + } + ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL; + + ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets); + const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + const UINT sampleMask = 0xFFFFFFFF; + + ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); + const UINT stencilClear = clearParams.stencilClearValue & 0xFF; + + // Set the vertices + UINT vertexStride = 0; + const UINT startIdx = 0; + const ClearShader* shader = NULL; + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal masked clear vertex buffer, HRESULT: 0x%X.", result); + } + + const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL; + switch (clearParams.colorClearType) + { + case GL_FLOAT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex); + shader = &mFloatClearShader; + break; + + case GL_UNSIGNED_INT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex); + shader = &mUintClearShader; + break; + + case GL_INT: + ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); + vertexStride = sizeof(d3d11::PositionDepthColorVertex); + shader = &mIntClearShader; + break; + + default: + UNREACHABLE(); + break; + } + + deviceContext->Unmap(mVertexBuffer, 0); + + // Set the viewport to be the same size as the framebuffer + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = framebufferSize.width; + viewport.Height = framebufferSize.height; + viewport.MinDepth = 0; + viewport.MaxDepth = 1; + deviceContext->RSSetViewports(1, &viewport); + + // Apply state + deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); + deviceContext->OMSetDepthStencilState(dsState, stencilClear); + deviceContext->RSSetState(mRasterizerState); + + // Apply shaders + deviceContext->IASetInputLayout(shader->inputLayout); + deviceContext->VSSetShader(shader->vertexShader, NULL, 0); + deviceContext->PSSetShader(shader->pixelShader, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Apply vertex buffer + deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx); + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // Apply render targets + deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv); + + // Draw the clear quad + deviceContext->Draw(4, 0); + + // Clean up + mRenderer->markAllStateDirty(); + } + + return gl::Error(GL_NO_ERROR); +} + +ID3D11BlendState *Clear11::getBlendState(const std::vector& rts) +{ + ClearBlendInfo blendKey = { 0 }; + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + if (i < rts.size()) + { + RenderTarget11 *rt = rts[i].renderTarget; + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(rt->getInternalFormat()); + + blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && formatInfo.redBits > 0); + blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && formatInfo.greenBits > 0); + blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && formatInfo.blueBits > 0); + blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && formatInfo.alphaBits > 0); + } + else + { + blendKey.maskChannels[i][0] = false; + blendKey.maskChannels[i][1] = false; + blendKey.maskChannels[i][2] = false; + blendKey.maskChannels[i][3] = false; + } + } + + ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey); + if (i != mClearBlendStates.end()) + { + return i->second; + } + else + { + D3D11_BLEND_DESC blendDesc = { 0 }; + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = (rts.size() > 1) ? TRUE : FALSE; + + for (unsigned int j = 0; j < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; j++) + { + blendDesc.RenderTarget[j].BlendEnable = FALSE; + blendDesc.RenderTarget[j].RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendKey.maskChannels[j][0], + blendKey.maskChannels[j][1], + blendKey.maskChannels[j][2], + blendKey.maskChannels[j][3]); + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11BlendState* blendState = NULL; + HRESULT result = device->CreateBlendState(&blendDesc, &blendState); + if (FAILED(result) || !blendState) + { + ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); + return NULL; + } + + mClearBlendStates[blendKey] = blendState; + + return blendState; + } +} + +ID3D11DepthStencilState *Clear11::getDepthStencilState(const ClearParameters &clearParams) +{ + ClearDepthStencilInfo dsKey = { 0 }; + dsKey.clearDepth = clearParams.clearDepth; + dsKey.clearStencil = clearParams.clearStencil; + dsKey.stencilWriteMask = clearParams.stencilWriteMask & 0xFF; + + ClearDepthStencilStateMap::const_iterator i = mClearDepthStencilStates.find(dsKey); + if (i != mClearDepthStencilStates.end()) + { + return i->second; + } + else + { + D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; + dsDesc.DepthEnable = dsKey.clearDepth ? TRUE : FALSE; + dsDesc.DepthWriteMask = dsKey.clearDepth ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.StencilEnable = dsKey.clearStencil ? TRUE : FALSE; + dsDesc.StencilReadMask = 0; + dsDesc.StencilWriteMask = dsKey.stencilWriteMask; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DepthStencilState* dsState = NULL; + HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState); + if (FAILED(result) || !dsState) + { + ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); + return NULL; + } + + mClearDepthStencilStates[dsKey] = dsState; + + return dsState; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h new file mode 100644 index 0000000000..4797ca1aa0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.h @@ -0,0 +1,86 @@ +// +// Copyright (c) 2013 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. +// + +// Clear11.h: Framebuffer clear utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_CLEAR11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_CLEAR11_H_ + +#include +#include + +#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" +#include "libANGLE/Framebuffer.h" + +namespace rx +{ +class Renderer11; +class RenderTarget11; +struct ClearParameters; + +class Clear11 : angle::NonCopyable +{ + public: + explicit Clear11(Renderer11 *renderer); + ~Clear11(); + + // Clears the framebuffer with the supplied clear parameters, assumes that the framebuffer is currently applied. + gl::Error clearFramebuffer(const ClearParameters &clearParams, const gl::Framebuffer::Data &fboData); + + private: + struct MaskedRenderTarget + { + bool colorMask[4]; + RenderTarget11 *renderTarget; + }; + + ID3D11BlendState *getBlendState(const std::vector &rts); + ID3D11DepthStencilState *getDepthStencilState(const ClearParameters &clearParams); + + struct ClearShader + { + ID3D11InputLayout *inputLayout; + ID3D11VertexShader *vertexShader; + ID3D11PixelShader *pixelShader; + }; + + template + static ClearShader CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE(&vsByteCode)[vsSize], const BYTE(&psByteCode)[psSize]); + + Renderer11 *mRenderer; + + struct ClearBlendInfo + { + bool maskChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; + }; + typedef bool(*ClearBlendInfoComparisonFunction)(const ClearBlendInfo&, const ClearBlendInfo &); + typedef std::map ClearBlendStateMap; + ClearBlendStateMap mClearBlendStates; + + ClearShader mFloatClearShader; + ClearShader mUintClearShader; + ClearShader mIntClearShader; + + struct ClearDepthStencilInfo + { + bool clearDepth; + bool clearStencil; + UINT8 stencilWriteMask; + }; + typedef bool (*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &); + typedef std::map ClearDepthStencilStateMap; + ClearDepthStencilStateMap mClearDepthStencilStates; + + ID3D11Buffer *mVertexBuffer; + ID3D11RasterizerState *mRasterizerState; + + bool mSupportsClearView; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_CLEAR11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp new file mode 100644 index 0000000000..f1fe2bb2c7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp @@ -0,0 +1,119 @@ +// +// Copyright 2015 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. +// +// DebugAnnotator11.cpp: D3D11 helpers for adding trace annotations. +// + +#include "libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h" + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +namespace rx +{ + +DebugAnnotator11::DebugAnnotator11() + : mInitialized(false), + mD3d11Module(nullptr), + mUserDefinedAnnotation(nullptr) +{ + // D3D11 devices can't be created during DllMain. + // We defer device creation until the object is actually used. +} + +DebugAnnotator11::~DebugAnnotator11() +{ + if (mInitialized) + { +#if defined(ANGLE_ENABLE_D3D11_1) + SafeRelease(mUserDefinedAnnotation); +#endif + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + FreeLibrary(mD3d11Module); +#endif // !ANGLE_ENABLE_WINDOWS_STORE + } +} + +void DebugAnnotator11::beginEvent(const std::wstring &eventName) +{ + initializeDevice(); + +#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->BeginEvent(eventName.c_str()); +#endif +} + +void DebugAnnotator11::endEvent() +{ + initializeDevice(); + +#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->EndEvent(); +#endif +} + +void DebugAnnotator11::setMarker(const std::wstring &markerName) +{ + initializeDevice(); + +#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->SetMarker(markerName.c_str()); +#endif +} + +bool DebugAnnotator11::getStatus() +{ + // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013. + +#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture. + // This should only be called in DEBUG mode. + // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks. + IDXGraphicsAnalysis *graphicsAnalysis; + DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis)); + bool underCapture = (graphicsAnalysis != nullptr); + SafeRelease(graphicsAnalysis); + return underCapture; +#endif // _DEBUG && !ANGLE_ENABLE_WINDOWS_STORE + + // Otherwise, we have to return true here. + return true; +} + +void DebugAnnotator11::initializeDevice() +{ + if (!mInitialized) + { +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); + ASSERT(mD3d11Module); + + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + ASSERT(D3D11CreateDevice != nullptr); +#endif // !ANGLE_ENABLE_WINDOWS_STORE + + ID3D11Device *device = nullptr; + ID3D11DeviceContext *context = nullptr; + + HRESULT hr = E_FAIL; + + // Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device. + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context); + ASSERT(SUCCEEDED(hr)); + +#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation = d3d11::DynamicCastComObject(context); + ASSERT(mUserDefinedAnnotation != nullptr); +#endif + + SafeRelease(device); + SafeRelease(context); + + mInitialized = true; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h new file mode 100644 index 0000000000..3df62b015c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h @@ -0,0 +1,39 @@ +// +// Copyright 2015 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. +// +// DebugAnnotator11.h: D3D11 helpers for adding trace annotations. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ + +#include "common/debug.h" + +struct ID3DUserDefinedAnnotation; + +namespace rx +{ + +class DebugAnnotator11 : public gl::DebugAnnotator +{ + public: + DebugAnnotator11(); + ~DebugAnnotator11() override; + void beginEvent(const std::wstring &eventName) override; + void endEvent() override; + void setMarker(const std::wstring &markerName) override; + bool getStatus() override; + + private: + void initializeDevice(); + + bool mInitialized; + HMODULE mD3d11Module; + ID3DUserDefinedAnnotation *mUserDefinedAnnotation; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_DEBUGANNOTATOR11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp new file mode 100644 index 0000000000..8552bc2beb --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp @@ -0,0 +1,231 @@ +// +// Copyright (c) 2013 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. +// + +// Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. + +#include "libANGLE/renderer/d3d/d3d11/Fence11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +#include "common/utilities.h" + +namespace rx +{ + +// +// Template helpers for set and test operations. +// + +template +gl::Error FenceSetHelper(FenceClass *fence) +{ + if (!fence->mQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); + } + } + + fence->mRenderer->getDeviceContext()->End(fence->mQuery); + return gl::Error(GL_NO_ERROR); +} + +template +gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean *outFinished) +{ + ASSERT(fence->mQuery); + + UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); + HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); + } + else if (fence->mRenderer->isDeviceLost()) + { + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); + } + + ASSERT(result == S_OK || result == S_FALSE); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return gl::Error(GL_NO_ERROR); +} + +// +// FenceNV11 +// + +FenceNV11::FenceNV11(Renderer11 *renderer) + : FenceNVImpl(), + mRenderer(renderer), + mQuery(NULL) +{ +} + +FenceNV11::~FenceNV11() +{ + SafeRelease(mQuery); +} + +gl::Error FenceNV11::set() +{ + return FenceSetHelper(this); +} + +gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished) +{ + return FenceTestHelper(this, flushCommandBuffer, outFinished); +} + +gl::Error FenceNV11::finishFence(GLboolean *outFinished) +{ + ASSERT(outFinished); + + while (*outFinished != GL_TRUE) + { + gl::Error error = test(true, outFinished); + if (error.isError()) + { + return error; + } + + ScheduleYield(); + } + + return gl::Error(GL_NO_ERROR); +} + +// +// FenceSync11 +// + +// Important note on accurate timers in Windows: +// +// QueryPerformanceCounter has a few major issues, including being 10x as expensive to call +// as timeGetTime on laptops and "jumping" during certain hardware events. +// +// See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc" +// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc +// +// We still opt to use QPC. In the present and moving forward, most newer systems will not suffer +// from buggy implementations. + +FenceSync11::FenceSync11(Renderer11 *renderer) + : FenceSyncImpl(), + mRenderer(renderer), + mQuery(NULL) +{ + LARGE_INTEGER counterFreqency = { 0 }; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + mCounterFrequency = counterFreqency.QuadPart; +} + +FenceSync11::~FenceSync11() +{ + SafeRelease(mQuery); +} + +gl::Error FenceSync11::set() +{ + return FenceSetHelper(this); +} + +gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +{ + ASSERT(outResult); + + bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); + + GLboolean result = GL_FALSE; + gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result); + if (error.isError()) + { + *outResult = GL_WAIT_FAILED; + return error; + } + + if (result == GL_TRUE) + { + *outResult = GL_ALREADY_SIGNALED; + return gl::Error(GL_NO_ERROR); + } + + if (timeout == 0) + { + *outResult = GL_TIMEOUT_EXPIRED; + return gl::Error(GL_NO_ERROR); + } + + LARGE_INTEGER currentCounter = { 0 }; + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + LONGLONG timeoutInSeconds = static_cast(timeout) * static_cast(1000000ll); + LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + + while (currentCounter.QuadPart < endCounter && !result) + { + ScheduleYield(); + success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + error = FenceTestHelper(this, flushCommandBuffer, &result); + if (error.isError()) + { + *outResult = GL_WAIT_FAILED; + return error; + } + } + + if (currentCounter.QuadPart >= endCounter) + { + *outResult = GL_TIMEOUT_EXPIRED; + } + else + { + *outResult = GL_CONDITION_SATISFIED; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout) +{ + // Because our API is currently designed to be called from a single thread, we don't need to do + // extra work for a server-side fence. GPU commands issued after the fence is created will always + // be processed after the fence is signaled. + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceSync11::getStatus(GLint *outResult) +{ + GLboolean result = GL_FALSE; + gl::Error error = FenceTestHelper(this, false, &result); + if (error.isError()) + { + // The spec does not specify any way to report errors during the status test (e.g. device lost) + // so we report the fence is unblocked in case of error or signaled. + *outResult = GL_SIGNALED; + + return error; + } + + *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED); + return gl::Error(GL_NO_ERROR); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h new file mode 100644 index 0000000000..2d87f43e76 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Fence11.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2013 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. +// + +// Fence11.h: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ + +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/FenceSyncImpl.h" + +namespace rx +{ +class Renderer11; + +class FenceNV11 : public FenceNVImpl +{ + public: + explicit FenceNV11(Renderer11 *renderer); + virtual ~FenceNV11(); + + gl::Error set(); + gl::Error test(bool flushCommandBuffer, GLboolean *outFinished); + gl::Error finishFence(GLboolean *outFinished); + + private: + template friend gl::Error FenceSetHelper(T *fence); + template friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished); + + Renderer11 *mRenderer; + ID3D11Query *mQuery; +}; + +class FenceSync11 : public FenceSyncImpl +{ + public: + explicit FenceSync11(Renderer11 *renderer); + virtual ~FenceSync11(); + + gl::Error set(); + gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult); + gl::Error serverWait(GLbitfield flags, GLuint64 timeout); + gl::Error getStatus(GLint *outResult); + + private: + template friend gl::Error FenceSetHelper(T *fence); + template friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished); + + Renderer11 *mRenderer; + ID3D11Query *mQuery; + LONGLONG mCounterFrequency; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_FENCE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp new file mode 100644 index 0000000000..da01f320c0 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp @@ -0,0 +1,270 @@ +// +// Copyright 2014 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. +// + +// Framebuffer11.cpp: Implements the Framebuffer11 class. + +#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Clear11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" + +namespace rx +{ + +Framebuffer11::Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer) + : FramebufferD3D(data, renderer), + mRenderer(renderer) +{ + ASSERT(mRenderer != nullptr); +} + +Framebuffer11::~Framebuffer11() +{ +} + +static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *attachment) +{ + if (attachment && attachment->type() == GL_TEXTURE) + { + gl::Texture *texture = attachment->getTexture(); + + TextureD3D *textureD3D = GetImplAs(texture); + + TextureStorage *texStorage = NULL; + gl::Error error = textureD3D->getNativeTexture(&texStorage); + if (error.isError()) + { + return error; + } + + if (texStorage) + { + TextureStorage11 *texStorage11 = TextureStorage11::makeTextureStorage11(texStorage); + ASSERT(texStorage11); + + texStorage11->invalidateSwizzleCacheLevel(attachment->mipLevel()); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer11::invalidateSwizzles() const +{ + for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { + gl::FramebufferAttachment *colorAttachment = *it; + gl::Error error = InvalidateAttachmentSwizzles(colorAttachment); + if (error.isError()) + { + return error; + } + } + + gl::Error error = InvalidateAttachmentSwizzles(mData.mDepthAttachment); + if (error.isError()) + { + return error; + } + + error = InvalidateAttachmentSwizzles(mData.mStencilAttachment); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer11::clear(const gl::State &state, const ClearParameters &clearParams) +{ + Clear11 *clearer = mRenderer->getClearer(); + gl::Error error = clearer->clearFramebuffer(clearParams, mData); + if (error.isError()) + { + return error; + } + + error = invalidateSwizzles(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +static gl::Error getRenderTargetResource(const gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, + ID3D11Texture2D **texture2DOut) +{ + ASSERT(colorbuffer); + + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) + { + return error; + } + + ID3D11Resource *renderTargetResource = renderTarget->getTexture(); + ASSERT(renderTargetResource); + + *subresourceIndexOut = renderTarget->getSubresourceIndex(); + *texture2DOut = d3d11::DynamicCastComObject(renderTargetResource); + + if (!(*texture2DOut)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the ID3D11Texture2D from a RenderTarget"); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer11::readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) const +{ + ID3D11Texture2D *colorBufferTexture = NULL; + unsigned int subresourceIndex = 0; + + const gl::FramebufferAttachment *colorbuffer = mData.getReadAttachment(); + ASSERT(colorbuffer); + + gl::Error error = getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture); + if (error.isError()) + { + return error; + } + + gl::Buffer *packBuffer = pack.pixelBuffer.get(); + if (packBuffer != NULL) + { + Buffer11 *packBufferStorage = Buffer11::makeBuffer11(packBuffer->getImplementation()); + PackPixelsParams packParams(area, format, type, outputPitch, pack, reinterpret_cast(pixels)); + + error = packBufferStorage->packPixels(colorBufferTexture, subresourceIndex, packParams); + if (error.isError()) + { + SafeRelease(colorBufferTexture); + return error; + } + + packBuffer->getIndexRangeCache()->clear(); + } + else + { + error = mRenderer->readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, pack, pixels); + if (error.isError()) + { + SafeRelease(colorBufferTexture); + return error; + } + } + + SafeRelease(colorBufferTexture); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer11::blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) +{ + if (blitRenderTarget) + { + const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getReadColorbuffer(); + ASSERT(readBuffer); + + RenderTargetD3D *readRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(readRenderTarget); + + for (size_t colorAttachment = 0; colorAttachment < mData.mColorAttachments.size(); colorAttachment++) + { + if (mData.mColorAttachments[colorAttachment] != nullptr && + mData.mDrawBufferStates[colorAttachment] != GL_NONE) + { + const gl::FramebufferAttachment *drawBuffer = mData.mColorAttachments[colorAttachment]; + + RenderTargetD3D *drawRenderTarget = NULL; + error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(drawRenderTarget); + + error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget, + filter, scissor, blitRenderTarget, false, false); + if (error.isError()) + { + return error; + } + } + } + } + + if (blitDepth || blitStencil) + { + gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer(); + ASSERT(readBuffer); + + RenderTargetD3D *readRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(readRenderTarget); + + const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment(); + ASSERT(drawBuffer); + + RenderTargetD3D *drawRenderTarget = NULL; + error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(drawRenderTarget); + + error = mRenderer->blitRenderbufferRect(sourceArea, destArea, readRenderTarget, drawRenderTarget, filter, scissor, + false, blitDepth, blitStencil); + if (error.isError()) + { + return error; + } + } + + gl::Error error = invalidateSwizzles(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum Framebuffer11::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +{ + RenderTarget11 *renderTarget11 = RenderTarget11::makeRenderTarget11(renderTarget); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(renderTarget11->getDXGIFormat()); + return dxgiFormatInfo.internalFormat; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h new file mode 100644 index 0000000000..07fa480fa2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h @@ -0,0 +1,45 @@ +// +// Copyright 2014 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. +// + +// Framebuffer11.h: Defines the Framebuffer11 class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_ + +#include "libANGLE/renderer/d3d/FramebufferD3D.h" + +namespace rx +{ +class Renderer11; + +class Framebuffer11 : public FramebufferD3D +{ + public: + Framebuffer11(const gl::Framebuffer::Data &data, Renderer11 *renderer); + virtual ~Framebuffer11(); + + // Invalidate the cached swizzles of all bound texture attachments. + gl::Error invalidateSwizzles() const; + + private: + gl::Error clear(const gl::State &state, const ClearParameters &clearParams) override; + + gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, + const gl::PixelPackState &pack, uint8_t *pixels) const override; + + gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) override; + + + GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; + + Renderer11 *const mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_FRAMBUFFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp new file mode 100644 index 0000000000..956b78b5a6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.cpp @@ -0,0 +1,664 @@ +// +// 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. +// + +// Image11.h: Implements the rx::Image11 class, which acts as the interface to +// the actual underlying resources of a Texture + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/Image11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/formatutils.h" + +#include "common/utilities.h" + +namespace rx +{ + +Image11::Image11(Renderer11 *renderer) + : mRenderer(renderer), + mDXGIFormat(DXGI_FORMAT_UNKNOWN), + mStagingTexture(NULL), + mStagingSubresource(0), + mRecoverFromStorage(false), + mAssociatedStorage(NULL), + mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()), + mRecoveredFromStorageCount(0) +{ + // mRenderer should remain unchanged during the lifetime of the Image11 object. + // This lets us safely use mRenderer (and its Feature Level) in Image11's methods. + mFeatureLevel = renderer->getFeatureLevel(); +} + +Image11::~Image11() +{ + disassociateStorage(); + releaseStagingTexture(); +} + +Image11 *Image11::makeImage11(ImageD3D *img) +{ + ASSERT(HAS_DYNAMIC_TYPE(Image11*, img)); + return static_cast(img); +} + +gl::Error Image11::generateMipmap(Image11 *dest, Image11 *src) +{ + ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); + ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); + ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(src->getDXGIFormat()); + ASSERT(dxgiFormatInfo.mipGenerationFunction != NULL); + + D3D11_MAPPED_SUBRESOURCE destMapped; + gl::Error error = dest->map(D3D11_MAP_WRITE, &destMapped); + if (error.isError()) + { + return error; + } + + D3D11_MAPPED_SUBRESOURCE srcMapped; + error = src->map(D3D11_MAP_READ, &srcMapped); + if (error.isError()) + { + dest->unmap(); + return error; + } + + const uint8_t *sourceData = reinterpret_cast(srcMapped.pData); + uint8_t *destData = reinterpret_cast(destMapped.pData); + + dxgiFormatInfo.mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), + sourceData, srcMapped.RowPitch, srcMapped.DepthPitch, + destData, destMapped.RowPitch, destMapped.DepthPitch); + + dest->unmap(); + src->unmap(); + + dest->markDirty(); + + return gl::Error(GL_NO_ERROR); +} + +bool Image11::isDirty() const +{ + // If mDirty is true + // AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be recovered from TextureStorage + // AND the texture doesn't require init data (i.e. a blank new texture will suffice) + // then isDirty should still return false. + if (mDirty && !mStagingTexture && !mRecoverFromStorage && !(d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL)) + { + return false; + } + + return mDirty; +} + +gl::Error Image11::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) +{ + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); + + // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times, + // then we should just keep the staging texture around to prevent the copying from impacting perf. + // We allow the Image11 to copy its data to/from TextureStorage once. + // This accounts for an app making a late call to glGenerateMipmap. + bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2); + + if (attemptToReleaseStagingTexture) + { + // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it. + gl::Error error = storage11->releaseAssociatedImage(index, this); + if (error.isError()) + { + return error; + } + } + + ID3D11Resource *stagingTexture = NULL; + unsigned int stagingSubresourceIndex = 0; + gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); + if (error.isError()) + { + return error; + } + + error = storage11->updateSubresourceLevel(stagingTexture, stagingSubresourceIndex, index, region); + if (error.isError()) + { + return error; + } + + // Once the image data has been copied into the Storage, we can release it locally. + if (attemptToReleaseStagingTexture) + { + storage11->associateImage(this, index); + releaseStagingTexture(); + mRecoverFromStorage = true; + mAssociatedStorage = storage11; + mAssociatedImageIndex = index; + } + + return gl::Error(GL_NO_ERROR); +} + +bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const +{ + return (mAssociatedStorage == textureStorage); +} + +gl::Error Image11::recoverFromAssociatedStorage() +{ + if (mRecoverFromStorage) + { + gl::Error error = createStagingTexture(); + if (error.isError()) + { + return error; + } + + bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedImageIndex, this); + + // This means that the cached TextureStorage has been modified after this Image11 released its copy of its data. + // This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten. + ASSERT(textureStorageCorrect); + + if (textureStorageCorrect) + { + // CopySubResource from the Storage to the Staging texture + gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); + error = mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region); + if (error.isError()) + { + return error; + } + + mRecoveredFromStorageCount += 1; + } + + // Reset all the recovery parameters, even if the texture storage association is broken. + disassociateStorage(); + } + + return gl::Error(GL_NO_ERROR); +} + +void Image11::disassociateStorage() +{ + if (mRecoverFromStorage) + { + // Make the texturestorage release the Image11 too + mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this); + + mRecoverFromStorage = false; + mAssociatedStorage = NULL; + mAssociatedImageIndex = gl::ImageIndex::MakeInvalid(); + } +} + +bool Image11::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) +{ + if (mWidth != size.width || + mHeight != size.height || + mInternalFormat != internalformat || + forceRelease) + { + // End the association with the TextureStorage, since that data will be out of date. + // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined. + disassociateStorage(); + mRecoveredFromStorageCount = 0; + + mWidth = size.width; + mHeight = size.height; + mDepth = size.depth; + mInternalFormat = internalformat; + mTarget = target; + + // compute the d3d format that will be used + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, mFeatureLevel); + mDXGIFormat = formatInfo.texFormat; + mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); + + releaseStagingTexture(); + mDirty = (formatInfo.dataInitializerFunction != NULL); + + return true; + } + + return false; +} + +DXGI_FORMAT Image11::getDXGIFormat() const +{ + // this should only happen if the image hasn't been redefined first + // which would be a bug by the caller + ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN); + + return mDXGIFormat; +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +gl::Error Image11::loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) +{ + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, unpack.rowLength); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); + GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; + + const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel); + LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type); + + D3D11_MAPPED_SUBRESOURCE mappedImage; + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) + { + return error; + } + + uint8_t *offsetMappedData = (reinterpret_cast(mappedImage.pData) + (area.y * mappedImage.RowPitch + area.x * outputPixelSize + area.z * mappedImage.DepthPitch)); + loadFunction(area.width, area.height, area.depth, + reinterpret_cast(input), inputRowPitch, inputDepthPitch, + offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + + unmap(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image11::loadCompressedData(const gl::Box &area, const void *input) +{ + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); + GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; + GLuint outputBlockWidth = dxgiFormatInfo.blockWidth; + GLuint outputBlockHeight = dxgiFormatInfo.blockHeight; + + ASSERT(area.x % outputBlockWidth == 0); + ASSERT(area.y % outputBlockHeight == 0); + + const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel); + LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE); + + D3D11_MAPPED_SUBRESOURCE mappedImage; + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) + { + return error; + } + + uint8_t* offsetMappedData = reinterpret_cast(mappedImage.pData) + ((area.y / outputBlockHeight) * mappedImage.RowPitch + + (area.x / outputBlockWidth) * outputPixelSize + + area.z * mappedImage.DepthPitch); + + loadFunction(area.width, area.height, area.depth, + reinterpret_cast(input), inputRowPitch, inputDepthPitch, + offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); + + unmap(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source) +{ + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source); + ASSERT(sourceRenderTarget->getTexture()); + + ID3D11Resource *resource = sourceRenderTarget->getTexture(); + UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex(); + + gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1); + gl::Error error = copy(destOffset, sourceBox, resource, subresourceIndex); + + SafeRelease(resource); + + return error; +} + +gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source) +{ + TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source); + + UINT subresourceIndex = sourceStorage11->getSubresourceIndex(sourceIndex); + ID3D11Resource *resource = NULL; + gl::Error error = sourceStorage11->getResource(&resource); + if (error.isError()) + { + return error; + } + + error = copy(destOffset, sourceArea, resource, subresourceIndex); + + SafeRelease(resource); + + return error; +} + +gl::Error Image11::copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource) +{ + D3D11_RESOURCE_DIMENSION dim; + source->GetType(&dim); + + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + gl::Extents extents; + UINT sampleCount = 0; + + ID3D11Texture2D *source2D = NULL; + + if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D) + { + D3D11_TEXTURE2D_DESC textureDesc2D; + source2D = d3d11::DynamicCastComObject(source); + ASSERT(source2D); + source2D->GetDesc(&textureDesc2D); + + format = textureDesc2D.Format; + extents = gl::Extents(textureDesc2D.Width, textureDesc2D.Height, 1); + sampleCount = textureDesc2D.SampleDesc.Count; + } + else if (dim == D3D11_RESOURCE_DIMENSION_TEXTURE3D) + { + D3D11_TEXTURE3D_DESC textureDesc3D; + ID3D11Texture3D *source3D = d3d11::DynamicCastComObject(source); + ASSERT(source3D); + source3D->GetDesc(&textureDesc3D); + + format = textureDesc3D.Format; + extents = gl::Extents(textureDesc3D.Width, textureDesc3D.Height, textureDesc3D.Depth); + sampleCount = 1; + } + else + { + UNREACHABLE(); + } + + if (format == mDXGIFormat) + { + // No conversion needed-- use copyback fastpath + ID3D11Resource *stagingTexture = NULL; + unsigned int stagingSubresourceIndex = 0; + gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + UINT subresourceAfterResolve = sourceSubResource; + + ID3D11Resource *srcTex = NULL; + + bool needResolve = (dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D && sampleCount > 1); + + if (needResolve) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = extents.width; + resolveDesc.Height = extents.height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + ID3D11Texture2D *srcTex2D = NULL; + HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex2D); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); + } + srcTex = srcTex2D; + + deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, format); + subresourceAfterResolve = 0; + } + else + { + srcTex = source; + } + + D3D11_BOX srcBox; + srcBox.left = sourceArea.x; + srcBox.right = sourceArea.x + sourceArea.width; + srcBox.top = sourceArea.y; + srcBox.bottom = sourceArea.y + sourceArea.height; + srcBox.front = sourceArea.z; + srcBox.back = sourceArea.z + sourceArea.depth; + + deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, destOffset.x, destOffset.y, + destOffset.z, srcTex, subresourceAfterResolve, &srcBox); + + if (needResolve) + { + SafeRelease(srcTex); + } + } + else + { + // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels + D3D11_MAPPED_SUBRESOURCE mappedImage; + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) + { + return error; + } + + // determine the offset coordinate into the destination buffer + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); + GLsizei rowOffset = dxgiFormatInfo.pixelBytes * destOffset.x; + uint8_t *dataOffset = static_cast(mappedImage.pData) + mappedImage.RowPitch * destOffset.y + rowOffset + destOffset.z * mappedImage.DepthPitch; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + + // Currently in ANGLE, the source data may only need to be converted if the source is the current framebuffer + // and OpenGL ES framebuffers must be 2D textures therefore we should not need to convert 3D textures between different formats. + ASSERT(dim == D3D11_RESOURCE_DIMENSION_TEXTURE2D); + ASSERT(sourceArea.z == 0 && sourceArea.depth == 1); + gl::Rectangle sourceRect(sourceArea.x, sourceArea.y, sourceArea.width, sourceArea.height); + error = mRenderer->readTextureData(source2D, sourceSubResource, sourceRect, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); + + unmap(); + + if (error.isError()) + { + return error; + } + } + + mDirty = true; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image11::getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex) +{ + gl::Error error = createStagingTexture(); + if (error.isError()) + { + return error; + } + + *outStagingTexture = mStagingTexture; + *outSubresourceIndex = mStagingSubresource; + return gl::Error(GL_NO_ERROR); +} + +void Image11::releaseStagingTexture() +{ + SafeRelease(mStagingTexture); +} + +gl::Error Image11::createStagingTexture() +{ + if (mStagingTexture) + { + return gl::Error(GL_NO_ERROR); + } + + ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0); + + const DXGI_FORMAT dxgiFormat = getDXGIFormat(); + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + int lodOffset = 1; + GLsizei width = mWidth; + GLsizei height = mHeight; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset); + + if (mTarget == GL_TEXTURE_3D) + { + ID3D11Texture3D *newTexture = NULL; + + D3D11_TEXTURE3D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.Depth = mDepth; + desc.MipLevels = lodOffset + 1; + desc.Format = dxgiFormat; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL) + { + std::vector initialData; + std::vector< std::vector > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, mFeatureLevel, width, height, mDepth, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture3D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) + { + ID3D11Texture2D *newTexture = NULL; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = lodOffset + 1; + desc.ArraySize = 1; + desc.Format = dxgiFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (d3d11::GetTextureFormatInfo(mInternalFormat, mFeatureLevel).dataInitializerFunction != NULL) + { + std::vector initialData; + std::vector< std::vector > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, mFeatureLevel, width, height, 1, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture2D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else + { + UNREACHABLE(); + } + + mDirty = false; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) +{ + // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE. + gl::Error error = recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + + ID3D11Resource *stagingTexture = NULL; + unsigned int subresourceIndex = 0; + error = getStagingTexture(&stagingTexture, &subresourceIndex); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ASSERT(mStagingTexture); + HRESULT result = deviceContext->Map(stagingTexture, subresourceIndex, mapType, 0, map); + + // this can fail if the device is removed (from TDR) + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + } + else if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map staging texture, result: 0x%X.", result); + } + + mDirty = true; + + return gl::Error(GL_NO_ERROR); +} + +void Image11::unmap() +{ + if (mStagingTexture) + { + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + deviceContext->Unmap(mStagingTexture, mStagingSubresource); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h new file mode 100644 index 0000000000..5734f73b15 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Image11.h @@ -0,0 +1,84 @@ +// +// 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. +// + +// Image11.h: Defines the rx::Image11 class, which acts as the interface to +// the actual underlying resources of a Texture + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_IMAGE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_IMAGE11_H_ + +#include "libANGLE/renderer/d3d/ImageD3D.h" +#include "libANGLE/ImageIndex.h" + +#include "common/debug.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer11; +class TextureStorage11; + +class Image11 : public ImageD3D +{ + public: + Image11(Renderer11 *renderer); + virtual ~Image11(); + + static Image11 *makeImage11(ImageD3D *img); + + static gl::Error generateMipmap(Image11 *dest, Image11 *src); + + virtual bool isDirty() const; + + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + + bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) override; + + DXGI_FORMAT getDXGIFormat() const; + + virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input); + virtual gl::Error loadCompressedData(const gl::Box &area, const void *input); + + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source); + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source); + + gl::Error recoverFromAssociatedStorage(); + bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; + void disassociateStorage(); + + protected: + gl::Error map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); + void unmap(); + + private: + gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box ®ion); + gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, ID3D11Resource *source, UINT sourceSubResource); + + gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex); + gl::Error createStagingTexture(); + void releaseStagingTexture(); + + Renderer11 *mRenderer; + D3D_FEATURE_LEVEL mFeatureLevel; + + DXGI_FORMAT mDXGIFormat; + ID3D11Resource *mStagingTexture; + unsigned int mStagingSubresource; + + bool mRecoverFromStorage; + TextureStorage11 *mAssociatedStorage; + gl::ImageIndex mAssociatedImageIndex; + unsigned int mRecoveredFromStorageCount; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_IMAGE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp new file mode 100644 index 0000000000..99c199f2b9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp @@ -0,0 +1,162 @@ +// +// 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. +// + +// IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +{ + mBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +IndexBuffer11::~IndexBuffer11() +{ + SafeRelease(mBuffer); +} + +gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) +{ + SafeRelease(mBuffer); + + updateSerial(); + + if (bufferSize > 0) + { + ID3D11Device* dxDevice = mRenderer->getDevice(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = bufferSize; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); + } + } + + mBufferSize = bufferSize; + mIndexType = indexType; + mDynamicUsage = dynamic; + + return gl::Error(GL_NO_ERROR); +} + +IndexBuffer11 *IndexBuffer11::makeIndexBuffer11(IndexBuffer *indexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer11*, indexBuffer)); + return static_cast(indexBuffer); +} + +gl::Error IndexBuffer11::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + // Check for integer overflows and out-out-bounds map requests + if (offset + size < offset || offset + size > mBufferSize) + { + return gl::Error(GL_OUT_OF_MEMORY, "Index buffer map range is not inside the buffer."); + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal index buffer, HRESULT: 0x%08x.", result); + } + + *outMappedMemory = reinterpret_cast(mappedResource.pData) + offset; + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexBuffer11::unmapBuffer() +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + dxContext->Unmap(mBuffer, 0); + return gl::Error(GL_NO_ERROR); +} + +GLenum IndexBuffer11::getIndexType() const +{ + return mIndexType; +} + +unsigned int IndexBuffer11::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error IndexBuffer11::setSize(unsigned int bufferSize, GLenum indexType) +{ + if (bufferSize > mBufferSize || indexType != mIndexType) + { + return initialize(bufferSize, indexType, mDynamicUsage); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error IndexBuffer11::discard() +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal index buffer, HRESULT: 0x%08x.", result); + } + + dxContext->Unmap(mBuffer, 0); + + return gl::Error(GL_NO_ERROR); +} + +DXGI_FORMAT IndexBuffer11::getIndexFormat() const +{ + switch (mIndexType) + { + case GL_UNSIGNED_BYTE: return DXGI_FORMAT_R16_UINT; + case GL_UNSIGNED_SHORT: return DXGI_FORMAT_R16_UINT; + case GL_UNSIGNED_INT: return DXGI_FORMAT_R32_UINT; + default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN; + } +} + +ID3D11Buffer *IndexBuffer11::getBuffer() const +{ + return mBuffer; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h new file mode 100644 index 0000000000..eadd03eb76 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h @@ -0,0 +1,51 @@ +// +// 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. +// + +// IndexBuffer11.h: Defines the D3D11 IndexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ + +#include "libANGLE/renderer/d3d/IndexBuffer.h" + +namespace rx +{ +class Renderer11; + +class IndexBuffer11 : public IndexBuffer +{ + public: + explicit IndexBuffer11(Renderer11 *const renderer); + virtual ~IndexBuffer11(); + + virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + + static IndexBuffer11 *makeIndexBuffer11(IndexBuffer *indexBuffer); + + virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); + virtual gl::Error unmapBuffer(); + + virtual GLenum getIndexType() const; + virtual unsigned int getBufferSize() const; + virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + + virtual gl::Error discard(); + + DXGI_FORMAT getIndexFormat() const; + ID3D11Buffer *getBuffer() const; + + private: + Renderer11 *const mRenderer; + + ID3D11Buffer *mBuffer; + unsigned int mBufferSize; + GLenum mIndexType; + bool mDynamicUsage; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_INDEXBUFFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp new file mode 100644 index 0000000000..242c09d6ce --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp @@ -0,0 +1,430 @@ +// +// 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. +// + +// InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches +// D3D11 input layouts. + +#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" +#include "libANGLE/Program.h" +#include "libANGLE/VertexAttribute.h" + +#include "third_party/murmurhash/MurmurHash3.h" + +namespace rx +{ + +static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS], + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +{ + for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex]; + + if (translatedAttributes[attributeIndex].active) + { + inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute, + translatedAttribute.currentValueType); + } + } +} + +const unsigned int InputLayoutCache::kMaxInputLayouts = 1024; + +InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts) +{ + mCounter = 0; + mDevice = NULL; + mDeviceContext = NULL; + mCurrentIL = NULL; + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mCurrentBuffers[i] = NULL; + mCurrentVertexStrides[i] = static_cast(-1); + mCurrentVertexOffsets[i] = static_cast(-1); + } + mPointSpriteVertexBuffer = NULL; + mPointSpriteIndexBuffer = NULL; +} + +InputLayoutCache::~InputLayoutCache() +{ + clear(); +} + +void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context) +{ + clear(); + mDevice = device; + mDeviceContext = context; + mFeatureLevel = device->GetFeatureLevel(); +} + +void InputLayoutCache::clear() +{ + for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) + { + SafeRelease(i->second.inputLayout); + } + mInputLayoutMap.clear(); + SafeRelease(mPointSpriteVertexBuffer); + SafeRelease(mPointSpriteIndexBuffer); + markDirty(); +} + +void InputLayoutCache::markDirty() +{ + mCurrentIL = NULL; + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mCurrentBuffers[i] = NULL; + mCurrentVertexStrides[i] = static_cast(-1); + mCurrentVertexOffsets[i] = static_cast(-1); + } +} + +gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + GLenum mode, gl::Program *program) +{ + ProgramD3D *programD3D = GetImplAs(program); + + int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]; + programD3D->sortAttributesByLayout(attributes, sortedSemanticIndices); + bool programUsesInstancedPointSprites = programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation(); + bool instancedPointSpritesActive = programUsesInstancedPointSprites && (mode == GL_POINTS); + + if (!mDevice || !mDeviceContext) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal input layout cache is not initialized."); + } + + InputLayoutKey ilKey = { 0 }; + + static const char* semanticName = "TEXCOORD"; + + unsigned int firstIndexedElement = gl::MAX_VERTEX_ATTRIBS; + unsigned int firstInstancedElement = gl::MAX_VERTEX_ATTRIBS; + unsigned int nextAvailableInputSlot = 0; + + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; + // If rendering points and instanced pointsprite emulation is being used, the inputClass is required to be configured as per instance data + inputClass = instancedPointSpritesActive ? D3D11_INPUT_PER_INSTANCE_DATA : inputClass; + + gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType); + const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel); + + // Record the type of the associated vertex shader vector in our key + // This will prevent mismatched vertex shaders from using the same input layout + GLint attributeSize; + program->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL); + + ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName; + ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i]; + ilKey.elements[ilKey.elementCount].desc.Format = vertexFormatInfo.nativeFormat; + ilKey.elements[ilKey.elementCount].desc.InputSlot = i; + ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; + ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass; + ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = instancedPointSpritesActive ? 1 : attributes[i].divisor; + + if (inputClass == D3D11_INPUT_PER_VERTEX_DATA && firstIndexedElement == gl::MAX_VERTEX_ATTRIBS) + { + firstIndexedElement = ilKey.elementCount; + } + else if (inputClass == D3D11_INPUT_PER_INSTANCE_DATA && firstInstancedElement == gl::MAX_VERTEX_ATTRIBS) + { + firstInstancedElement = ilKey.elementCount; + } + + ilKey.elementCount++; + nextAvailableInputSlot = i + 1; + } + } + + // Instanced PointSprite emulation requires additional entries in the + // inputlayout to support the vertices that make up the pointsprite quad. + // We do this even if mode != GL_POINTS, since the shader signature has these inputs, and the input layout must match the shader + if (programUsesInstancedPointSprites) + { + ilKey.elements[ilKey.elementCount].desc.SemanticName = "SPRITEPOSITION"; + ilKey.elements[ilKey.elementCount].desc.SemanticIndex = 0; + ilKey.elements[ilKey.elementCount].desc.Format = DXGI_FORMAT_R32G32B32_FLOAT; + ilKey.elements[ilKey.elementCount].desc.InputSlot = nextAvailableInputSlot; + ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; + ilKey.elements[ilKey.elementCount].desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = 0; + + // The new elements are D3D11_INPUT_PER_VERTEX_DATA data so the indexed element + // tracking must be applied. This ensures that the instancing specific + // buffer swapping logic continues to work. + if (firstIndexedElement == gl::MAX_VERTEX_ATTRIBS) + { + firstIndexedElement = ilKey.elementCount; + } + + ilKey.elementCount++; + + ilKey.elements[ilKey.elementCount].desc.SemanticName = "SPRITETEXCOORD"; + ilKey.elements[ilKey.elementCount].desc.SemanticIndex = 0; + ilKey.elements[ilKey.elementCount].desc.Format = DXGI_FORMAT_R32G32_FLOAT; + ilKey.elements[ilKey.elementCount].desc.InputSlot = nextAvailableInputSlot; + ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = sizeof(float) * 3; + ilKey.elements[ilKey.elementCount].desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = 0; + + ilKey.elementCount++; + } + + // On 9_3, we must ensure that slot 0 contains non-instanced data. + // If slot 0 currently contains instanced data then we swap it with a non-instanced element. + // Note that instancing is only available on 9_3 via ANGLE_instanced_arrays, since 9_3 doesn't support OpenGL ES 3.0. + // As per the spec for ANGLE_instanced_arrays, not all attributes can be instanced simultaneously, so a non-instanced element must exist. + ASSERT(!(mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && firstIndexedElement == gl::MAX_VERTEX_ATTRIBS)); + bool moveFirstIndexedIntoSlotZero = mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && firstInstancedElement == 0 && firstIndexedElement != gl::MAX_VERTEX_ATTRIBS; + + if (moveFirstIndexedIntoSlotZero) + { + ilKey.elements[firstInstancedElement].desc.InputSlot = ilKey.elements[firstIndexedElement].desc.InputSlot; + ilKey.elements[firstIndexedElement].desc.InputSlot = 0; + + // Instanced PointSprite emulation uses multiple layout entries across a single vertex buffer. + // If an index swap is performed, we need to ensure that all elements get the proper InputSlot. + if (programUsesInstancedPointSprites) + { + ilKey.elements[firstIndexedElement + 1].desc.InputSlot = 0; + } + } + + ID3D11InputLayout *inputLayout = NULL; + + InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey); + if (keyIter != mInputLayoutMap.end()) + { + inputLayout = keyIter->second.inputLayout; + keyIter->second.lastUsedTime = mCounter++; + } + else + { + gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS]; + GetInputLayout(attributes, shaderInputLayout); + + ShaderExecutableD3D *shader = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader, nullptr); + if (error.isError()) + { + return error; + } + + ShaderExecutableD3D *shader11 = ShaderExecutable11::makeShaderExecutable11(shader); + + D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS]; + for (unsigned int j = 0; j < ilKey.elementCount; ++j) + { + descs[j] = ilKey.elements[j].desc; + } + + HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader11->getFunction(), shader11->getLength(), &inputLayout); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result); + } + + if (mInputLayoutMap.size() >= kMaxInputLayouts) + { + TRACE("Overflowed the limit of %u input layouts, removing the least recently used " + "to make room.", kMaxInputLayouts); + + InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin(); + for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) + { + if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.inputLayout); + mInputLayoutMap.erase(leastRecentlyUsed); + } + + InputLayoutCounterPair inputCounterPair; + inputCounterPair.inputLayout = inputLayout; + inputCounterPair.lastUsedTime = mCounter++; + + mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair)); + } + + if (inputLayout != mCurrentIL) + { + mDeviceContext->IASetInputLayout(inputLayout); + mCurrentIL = inputLayout; + } + + bool dirtyBuffers = false; + size_t minDiff = gl::MAX_VERTEX_ATTRIBS; + size_t maxDiff = 0; + unsigned int nextAvailableIndex = 0; + + for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + ID3D11Buffer *buffer = NULL; + + if (attributes[i].active) + { + VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer); + Buffer11 *bufferStorage = attributes[i].storage ? Buffer11::makeBuffer11(attributes[i].storage) : NULL; + + buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK) + : vertexBuffer->getBuffer(); + } + + UINT vertexStride = attributes[i].stride; + UINT vertexOffset = attributes[i].offset; + + if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] || + vertexOffset != mCurrentVertexOffsets[i]) + { + dirtyBuffers = true; + minDiff = std::min(minDiff, static_cast(i)); + maxDiff = std::max(maxDiff, static_cast(i)); + + mCurrentBuffers[i] = buffer; + mCurrentVertexStrides[i] = vertexStride; + mCurrentVertexOffsets[i] = vertexOffset; + + // If a non null ID3D11Buffer is being assigned to mCurrentBuffers, + // then the next available index needs to be tracked to ensure + // that any instanced pointsprite emulation buffers will be properly packed. + if (buffer) + { + nextAvailableIndex = i + 1; + } + } + } + + // Instanced PointSprite emulation requires two additional ID3D11Buffers. + // A vertex buffer needs to be created and added to the list of current buffers, + // strides and offsets collections. This buffer contains the vertices for a single + // PointSprite quad. + // An index buffer also needs to be created and applied because rendering instanced + // data on D3D11 FL9_3 requires DrawIndexedInstanced() to be used. + if (instancedPointSpritesActive) + { + HRESULT result = S_OK; + const UINT pointSpriteVertexStride = sizeof(float) * 5; + + if (!mPointSpriteVertexBuffer) + { + static const float pointSpriteVertices[] = + { + // Position // TexCoord + -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = { pointSpriteVertices, 0, 0 }; + D3D11_BUFFER_DESC vertexBufferDesc; + vertexBufferDesc.ByteWidth = sizeof(pointSpriteVertices); + vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + vertexBufferDesc.CPUAccessFlags = 0; + vertexBufferDesc.MiscFlags = 0; + vertexBufferDesc.StructureByteStride = 0; + + result = mDevice->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &mPointSpriteVertexBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create instanced pointsprite emulation vertex buffer, HRESULT: 0x%08x", result); + } + } + + mCurrentBuffers[nextAvailableIndex] = mPointSpriteVertexBuffer; + mCurrentVertexStrides[nextAvailableIndex] = pointSpriteVertexStride; + mCurrentVertexOffsets[nextAvailableIndex] = 0; + + if (!mPointSpriteIndexBuffer) + { + // Create an index buffer and set it for pointsprite rendering + static const unsigned short pointSpriteIndices[] = + { + 0, 1, 2, 3, 4, 5, + }; + + D3D11_SUBRESOURCE_DATA indexBufferData = { pointSpriteIndices, 0, 0 }; + D3D11_BUFFER_DESC indexBufferDesc; + indexBufferDesc.ByteWidth = sizeof(pointSpriteIndices); + indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + indexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + indexBufferDesc.CPUAccessFlags = 0; + indexBufferDesc.MiscFlags = 0; + indexBufferDesc.StructureByteStride = 0; + + result = mDevice->CreateBuffer(&indexBufferDesc, &indexBufferData, &mPointSpriteIndexBuffer); + if (FAILED(result)) + { + SafeRelease(mPointSpriteVertexBuffer); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create instanced pointsprite emulation index buffer, HRESULT: 0x%08x", result); + } + } + + // The index buffer is applied here because Instanced PointSprite emulation uses + // the a non-indexed rendering path in ANGLE (DrawArrays). This means that applyIndexBuffer() + // on the renderer will not be called and setting this buffer here ensures that the rendering + // path will contain the correct index buffers. + mDeviceContext->IASetIndexBuffer(mPointSpriteIndexBuffer, DXGI_FORMAT_R16_UINT, 0); + } + + if (moveFirstIndexedIntoSlotZero) + { + // In this case, we swapped the slots of the first instanced element and the first indexed element, to ensure + // that the first slot contains non-instanced data (required by Feature Level 9_3). + // We must also swap the corresponding buffers sent to IASetVertexBuffers so that the correct data is sent to each slot. + std::swap(mCurrentBuffers[firstIndexedElement], mCurrentBuffers[firstInstancedElement]); + std::swap(mCurrentVertexStrides[firstIndexedElement], mCurrentVertexStrides[firstInstancedElement]); + std::swap(mCurrentVertexOffsets[firstIndexedElement], mCurrentVertexOffsets[firstInstancedElement]); + } + + if (dirtyBuffers) + { + ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS); + mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff, + mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff); + } + + return gl::Error(GL_NO_ERROR); +} + +std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout) +{ + static const unsigned int seed = 0xDEADBEEF; + + std::size_t hash = 0; + MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash); + return hash; +} + +bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b) +{ + if (a.elementCount != b.elementCount) + { + return false; + } + + return std::equal(a.begin(), a.end(), b.begin()); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h new file mode 100644 index 0000000000..2c94c57595 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h @@ -0,0 +1,103 @@ +// +// 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. +// + +// InputLayoutCache.h: Defines InputLayoutCache, a class that builds and caches +// D3D11 input layouts. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_ + +#include "libANGLE/Constants.h" +#include "libANGLE/Error.h" +#include "common/angleutils.h" + +#include + +#include +#include + +namespace gl +{ +class Program; +} + +namespace rx +{ +struct TranslatedAttribute; + +class InputLayoutCache : angle::NonCopyable +{ + public: + InputLayoutCache(); + virtual ~InputLayoutCache(); + + void initialize(ID3D11Device *device, ID3D11DeviceContext *context); + void clear(); + void markDirty(); + + gl::Error applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], + GLenum mode, gl::Program *program); + + private: + struct InputLayoutElement + { + D3D11_INPUT_ELEMENT_DESC desc; + GLenum glslElementType; + }; + + struct InputLayoutKey + { + unsigned int elementCount; + InputLayoutElement elements[gl::MAX_VERTEX_ATTRIBS]; + + const char *begin() const + { + return reinterpret_cast(&elementCount); + } + + const char *end() const + { + return reinterpret_cast(&elements[elementCount]); + } + }; + + struct InputLayoutCounterPair + { + ID3D11InputLayout *inputLayout; + unsigned long long lastUsedTime; + }; + + ID3D11InputLayout *mCurrentIL; + ID3D11Buffer *mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS]; + UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS]; + UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS]; + + ID3D11Buffer *mPointSpriteVertexBuffer; + ID3D11Buffer *mPointSpriteIndexBuffer; + + static std::size_t hashInputLayout(const InputLayoutKey &inputLayout); + static bool compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b); + + typedef std::size_t (*InputLayoutHashFunction)(const InputLayoutKey &); + typedef bool (*InputLayoutEqualityFunction)(const InputLayoutKey &, const InputLayoutKey &); + typedef std::unordered_map InputLayoutMap; + InputLayoutMap mInputLayoutMap; + + static const unsigned int kMaxInputLayouts; + + unsigned long long mCounter; + + ID3D11Device *mDevice; + ID3D11DeviceContext *mDeviceContext; + D3D_FEATURE_LEVEL mFeatureLevel; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_INPUTLAYOUTCACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h new file mode 100644 index 0000000000..81b9ea748d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h @@ -0,0 +1,80 @@ +// +// Copyright (c) 2014 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. +// + +// NativeWindow.h: Defines NativeWindow, a class for managing and +// performing operations on an EGLNativeWindowType. +// It is used for HWND (Desktop Windows) and IInspectable objects +//(Windows Store Applications). + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ + +#include "common/debug.h" +#include "common/platform.h" + +#include + +// DXGISwapChain and DXGIFactory are typedef'd to specific required +// types. The HWND NativeWindow implementation requires IDXGISwapChain +// and IDXGIFactory and the Windows Store NativeWindow +// implementation requires IDXGISwapChain1 and IDXGIFactory2. +#if defined(ANGLE_ENABLE_WINDOWS_STORE) +typedef IDXGISwapChain1 DXGISwapChain; +typedef IDXGIFactory2 DXGIFactory; + +#include +#include +#include +#include + +namespace rx +{ +class InspectableNativeWindow; +} + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +#else +typedef IDXGISwapChain DXGISwapChain; +typedef IDXGIFactory DXGIFactory; +#endif + +namespace rx +{ + +class NativeWindow +{ + public: + enum RotationFlags { RotateNone = 0, RotateLeft = 1, RotateRight = 2 }; + explicit NativeWindow(EGLNativeWindowType window); + + bool initialize(); + bool getClientRect(LPRECT rect); + bool isIconic(); +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + RotationFlags rotationFlags() const; +#endif + static bool isValidNativeWindow(EGLNativeWindowType window); + + HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, + DXGI_FORMAT format, UINT width, UINT height, + DXGISwapChain** swapChain); + + inline EGLNativeWindowType getNativeWindow() const { return mWindow; } + + private: + EGLNativeWindowType mWindow; + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) + std::shared_ptr mImpl; +#endif + +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_NATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp new file mode 100644 index 0000000000..5fd5237d90 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp @@ -0,0 +1,302 @@ +// +// Copyright (c) 2013 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. +// + +// PixelTransfer11.cpp: +// Implementation for buffer-to-texture and texture-to-buffer copies. +// Used to implement pixel transfers from unpack and to pack buffers. +// + +#include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" + +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_gs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4f.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4i.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4ui.h" + +namespace rx +{ + +PixelTransfer11::PixelTransfer11(Renderer11 *renderer) + : mRenderer(renderer), + mResourcesLoaded(false), + mBufferToTextureVS(NULL), + mBufferToTextureGS(NULL), + mParamsConstantBuffer(NULL), + mCopyRasterizerState(NULL), + mCopyDepthStencilState(NULL) +{ +} + +PixelTransfer11::~PixelTransfer11() +{ + for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) + { + SafeRelease(shaderMapIt->second); + } + + mBufferToTexturePSMap.clear(); + + SafeRelease(mBufferToTextureVS); + SafeRelease(mBufferToTextureGS); + SafeRelease(mParamsConstantBuffer); + SafeRelease(mCopyRasterizerState); + SafeRelease(mCopyDepthStencilState); +} + +gl::Error PixelTransfer11::loadResources() +{ + if (mResourcesLoaded) + { + return gl::Error(GL_NO_ERROR); + } + + HRESULT result = S_OK; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = 0; + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.ScissorEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + + result = device->CreateRasterizerState(&rasterDesc, &mCopyRasterizerState); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer rasterizer state, result: 0x%X.", result); + } + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = true; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + result = device->CreateDepthStencilState(&depthStencilDesc, &mCopyDepthStencilState); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer depth stencil state, result: 0x%X.", result); + } + + D3D11_BUFFER_DESC constantBufferDesc = { 0 }; + constantBufferDesc.ByteWidth = roundUp(sizeof(CopyShaderParams), 32u); + constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDesc.MiscFlags = 0; + constantBufferDesc.StructureByteStride = 0; + + result = device->CreateBuffer(&constantBufferDesc, NULL, &mParamsConstantBuffer); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer constant buffer, result: 0x%X.", result); + } + d3d11::SetDebugName(mParamsConstantBuffer, "PixelTransfer11 constant buffer"); + + // init shaders + mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); + if (!mBufferToTextureVS) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture vertex shader."); + } + + mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); + if (!mBufferToTextureGS) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); + } + + gl::Error error = buildShaderMap(); + if (error.isError()) + { + return error; + } + + StructZero(&mParamsData); + + mResourcesLoaded = true; + + return gl::Error(GL_NO_ERROR); +} + +void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, + const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut) +{ + StructZero(parametersOut); + + float texelCenterX = 0.5f / static_cast(destSize.width - 1); + float texelCenterY = 0.5f / static_cast(destSize.height - 1); + + unsigned int bytesPerPixel = gl::GetInternalFormatInfo(internalFormat).pixelBytes; + unsigned int alignmentBytes = static_cast(unpack.alignment); + unsigned int alignmentPixels = (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel); + + parametersOut->FirstPixelOffset = offset / bytesPerPixel; + parametersOut->PixelsPerRow = static_cast((unpack.rowLength > 0) ? unpack.rowLength : destArea.width); + parametersOut->RowStride = roundUp(parametersOut->PixelsPerRow, alignmentPixels); + parametersOut->RowsPerSlice = static_cast(destArea.height); + parametersOut->PositionOffset[0] = texelCenterX + (destArea.x / float(destSize.width)) * 2.0f - 1.0f; + parametersOut->PositionOffset[1] = texelCenterY + ((destSize.height - destArea.y - 1) / float(destSize.height)) * 2.0f - 1.0f; + parametersOut->PositionScale[0] = 2.0f / static_cast(destSize.width); + parametersOut->PositionScale[1] = -2.0f / static_cast(destSize.height); + parametersOut->FirstSlice = destArea.z; +} + +gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + gl::Error error = loadResources(); + if (error.isError()) + { + return error; + } + + gl::Extents destSize = destRenderTarget->getExtents(); + + ASSERT(destArea.x >= 0 && destArea.x + destArea.width <= destSize.width && + destArea.y >= 0 && destArea.y + destArea.height <= destSize.height && + destArea.z >= 0 && destArea.z + destArea.depth <= destSize.depth ); + + const gl::Buffer &sourceBuffer = *unpack.pixelBuffer.get(); + + ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); + + ID3D11PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); + ASSERT(pixelShader); + + // The SRV must be in the proper read format, which may be different from the destination format + // EG: for half float data, we can load full precision floats with implicit conversion + GLenum unsizedFormat = gl::GetInternalFormatInfo(destinationFormat).format; + GLenum sourceFormat = gl::GetSizedInternalFormat(unsizedFormat, sourcePixelsType); + + const d3d11::TextureFormat &sourceFormatInfo = d3d11::GetTextureFormatInfo(sourceFormat, mRenderer->getFeatureLevel()); + DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat; + ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); + Buffer11 *bufferStorage11 = Buffer11::makeBuffer11(sourceBuffer.getImplementation()); + ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat); + ASSERT(bufferSRV != NULL); + + ID3D11RenderTargetView *textureRTV = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(textureRTV != NULL); + + CopyShaderParams shaderParams; + setBufferToTextureCopyParams(destArea, destSize, sourceFormat, unpack, offset, &shaderParams); + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ID3D11Buffer *nullBuffer = NULL; + UINT zero = 0; + + // Are we doing a 2D or 3D copy? + ID3D11GeometryShader *geometryShader = ((destSize.depth > 1) ? mBufferToTextureGS : NULL); + + deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); + deviceContext->GSSetShader(geometryShader, NULL, 0); + deviceContext->PSSetShader(pixelShader, NULL, 0); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV); + deviceContext->IASetInputLayout(NULL); + deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + + deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); + deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); + deviceContext->OMSetDepthStencilState(mCopyDepthStencilState, 0xFFFFFFFF); + deviceContext->RSSetState(mCopyRasterizerState); + + mRenderer->setOneTimeRenderTarget(textureRTV); + + if (!StructEquals(mParamsData, shaderParams)) + { + d3d11::SetBufferData(deviceContext, mParamsConstantBuffer, shaderParams); + mParamsData = shaderParams; + } + + deviceContext->VSSetConstantBuffers(0, 1, &mParamsConstantBuffer); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = destSize.width; + viewport.Height = destSize.height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + UINT numPixels = (destArea.width * destArea.height * destArea.depth); + deviceContext->Draw(numPixels, 0); + + // Unbind textures and render targets and vertex buffer + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); + + mRenderer->markAllStateDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error PixelTransfer11::buildShaderMap() +{ + ID3D11Device *device = mRenderer->getDevice(); + + mBufferToTexturePSMap[GL_FLOAT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4F, "BufferToTexture RGBA ps"); + mBufferToTexturePSMap[GL_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4I, "BufferToTexture RGBA-I ps"); + mBufferToTexturePSMap[GL_UNSIGNED_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4UI, "BufferToTexture RGBA-UI ps"); + + // Check that all the shaders were created successfully + for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) + { + if (shaderMapIt->second == NULL) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture pixel shader."); + } + } + + return gl::Error(GL_NO_ERROR); +} + +ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const +{ + GLenum componentType = gl::GetInternalFormatInfo(internalFormat).componentType; + if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED) + { + componentType = GL_FLOAT; + } + + auto shaderMapIt = mBufferToTexturePSMap.find(componentType); + return (shaderMapIt == mBufferToTexturePSMap.end() ? NULL : shaderMapIt->second); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h new file mode 100644 index 0000000000..1672121ec7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h @@ -0,0 +1,89 @@ +// +// Copyright (c) 2013 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. +// + +// PixelTransfer11.h: +// Buffer-to-Texture and Texture-to-Buffer data transfers. +// Used to implement pixel unpack and pixel pack buffers in ES3. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ + +#include "libANGLE/Error.h" + +#include "common/platform.h" + +#include + +#include + +namespace gl +{ + +class Buffer; +struct Box; +struct Extents; +struct PixelUnpackState; + +} + +namespace rx +{ +class Renderer11; +class RenderTargetD3D; + +class PixelTransfer11 +{ + public: + explicit PixelTransfer11(Renderer11 *renderer); + ~PixelTransfer11(); + + // unpack: the source buffer is stored in the unpack state, and buffer strides + // offset: the start of the data within the unpack buffer + // destRenderTarget: individual slice/layer of a target texture + // destinationFormat/sourcePixelsType: determines shaders + shader parameters + // destArea: the sub-section of destRenderTarget to copy to + gl::Error copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + private: + + struct CopyShaderParams + { + unsigned int FirstPixelOffset; + unsigned int PixelsPerRow; + unsigned int RowStride; + unsigned int RowsPerSlice; + float PositionOffset[2]; + float PositionScale[2]; + int TexLocationOffset[2]; + int TexLocationScale[2]; + unsigned int FirstSlice; + }; + + static void setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, + const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut); + + gl::Error loadResources(); + gl::Error buildShaderMap(); + ID3D11PixelShader *findBufferToTexturePS(GLenum internalFormat) const; + + Renderer11 *mRenderer; + + bool mResourcesLoaded; + std::map mBufferToTexturePSMap; + ID3D11VertexShader *mBufferToTextureVS; + ID3D11GeometryShader *mBufferToTextureGS; + ID3D11Buffer *mParamsConstantBuffer; + CopyShaderParams mParamsData; + + ID3D11RasterizerState *mCopyRasterizerState; + ID3D11DepthStencilState *mCopyDepthStencilState; + +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_PIXELTRANSFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp new file mode 100644 index 0000000000..4979ff51a9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp @@ -0,0 +1,164 @@ +// +// Copyright (c) 2013 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. +// + +// Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl. + +#include "libANGLE/renderer/d3d/d3d11/Query11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "common/utilities.h" + +#include + +#if defined(ANGLE_MINGW32_COMPAT) +typedef struct D3D11_QUERY_DATA_SO_STATISTICS { + UINT64 NumPrimitivesWritten; + UINT64 PrimitivesStorageNeeded; +} D3D11_QUERY_DATA_SO_STATISTICS; +#endif + +namespace rx +{ + +Query11::Query11(Renderer11 *renderer, GLenum type) + : QueryImpl(type), + mResult(0), + mQueryFinished(false), + mRenderer(renderer), + mQuery(NULL) +{ +} + +Query11::~Query11() +{ + SafeRelease(mQuery); +} + +gl::Error Query11::begin() +{ + if (mQuery == NULL) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = gl_d3d11::ConvertQueryType(getType()); + queryDesc.MiscFlags = 0; + + HRESULT result = mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); + } + } + + mRenderer->getDeviceContext()->Begin(mQuery); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query11::end() +{ + ASSERT(mQuery); + mRenderer->getDeviceContext()->End(mQuery); + + mQueryFinished = false; + mResult = GL_FALSE; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query11::getResult(GLuint *params) +{ + while (!mQueryFinished) + { + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + if (!mQueryFinished) + { + ScheduleYield(); + } + } + + ASSERT(mQueryFinished); + *params = mResult; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query11::isResultAvailable(GLuint *available) +{ + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + *available = (mQueryFinished ? GL_TRUE : GL_FALSE); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query11::testQuery() +{ + if (!mQueryFinished) + { + ASSERT(mQuery); + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + switch (getType()) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + { + UINT64 numPixels = 0; + HRESULT result = context->GetData(mQuery, &numPixels, sizeof(numPixels), 0); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the data of an internal query, result: 0x%X.", result); + } + + if (result == S_OK) + { + mQueryFinished = true; + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + } + } + break; + + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + { + D3D11_QUERY_DATA_SO_STATISTICS soStats = { 0 }; + HRESULT result = context->GetData(mQuery, &soStats, sizeof(soStats), 0); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the data of an internal query, result: 0x%X.", result); + } + + if (result == S_OK) + { + mQueryFinished = true; + mResult = static_cast(soStats.NumPrimitivesWritten); + } + } + break; + + default: + UNREACHABLE(); + break; + } + + if (!mQueryFinished && mRenderer->testDeviceLost()) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + } + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h new file mode 100644 index 0000000000..bd53fed250 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.h @@ -0,0 +1,42 @@ +// +// Copyright (c) 2013 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. +// + +// Query11.h: Defines the rx::Query11 class which implements rx::QueryImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ + +#include "libANGLE/renderer/QueryImpl.h" + +namespace rx +{ +class Renderer11; + +class Query11 : public QueryImpl +{ + public: + Query11(Renderer11 *renderer, GLenum type); + virtual ~Query11(); + + virtual gl::Error begin(); + virtual gl::Error end(); + virtual gl::Error getResult(GLuint *params); + virtual gl::Error isResultAvailable(GLuint *available); + + private: + gl::Error testQuery(); + + GLuint mResult; + + bool mQueryFinished; + + Renderer11 *mRenderer; + ID3D11Query *mQuery; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_QUERY11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp new file mode 100644 index 0000000000..4990e6bc6e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp @@ -0,0 +1,452 @@ +// +// Copyright (c) 2012-2014 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. +// + +// RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render +// state objects. + +#include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h" + +#include + +#include "common/debug.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "third_party/murmurhash/MurmurHash3.h" + +namespace rx +{ + +template +static void ClearStateMap(mapType &map) +{ + for (typename mapType::iterator i = map.begin(); i != map.end(); i++) + { + SafeRelease(i->second.first); + } + map.clear(); +} + +// MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState, +// ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum +// number of unique states of each type an application can create is 4096 +const unsigned int RenderStateCache::kMaxBlendStates = 4096; +const unsigned int RenderStateCache::kMaxRasterizerStates = 4096; +const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096; +const unsigned int RenderStateCache::kMaxSamplerStates = 4096; + +RenderStateCache::RenderStateCache(Renderer11 *renderer) + : mRenderer(renderer), + mDevice(NULL), + mCounter(0), + mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), + mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), + mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), + mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates) +{ +} + +RenderStateCache::~RenderStateCache() +{ + clear(); +} + +void RenderStateCache::initialize(ID3D11Device *device) +{ + clear(); + mDevice = device; +} + +void RenderStateCache::clear() +{ + ClearStateMap(mBlendStateCache); + ClearStateMap(mRasterizerStateCache); + ClearStateMap(mDepthStencilStateCache); + ClearStateMap(mSamplerStateCache); +} + +std::size_t RenderStateCache::hashBlendState(const BlendStateKey &blendState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareBlendStates(const BlendStateKey &a, const BlendStateKey &b) +{ + return memcmp(&a, &b, sizeof(BlendStateKey)) == 0; +} + +gl::Error RenderStateCache::getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, + ID3D11BlendState **outBlendState) +{ + if (!mDevice) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + } + + bool mrt = false; + + const FramebufferD3D *framebufferD3D = GetImplAs(framebuffer); + const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(mRenderer->getWorkarounds()); + + BlendStateKey key = { 0 }; + key.blendState = blendState; + for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) + { + const gl::FramebufferAttachment *attachment = colorbuffers[colorAttachment]; + + auto rtChannels = key.rtChannels[colorAttachment]; + + if (attachment) + { + if (colorAttachment > 0) + { + mrt = true; + } + + rtChannels[0] = attachment->getRedSize() > 0; + rtChannels[1] = attachment->getGreenSize() > 0; + rtChannels[2] = attachment->getBlueSize() > 0; + rtChannels[3] = attachment->getAlphaSize() > 0; + } + } + + BlendStateMap::iterator keyIter = mBlendStateCache.find(key); + if (keyIter != mBlendStateCache.end()) + { + BlendStateCounterPair &state = keyIter->second; + state.second = mCounter++; + *outBlendState = state.first; + return gl::Error(GL_NO_ERROR); + } + else + { + if (mBlendStateCache.size() >= kMaxBlendStates) + { + TRACE("Overflowed the limit of %u blend states, removing the least recently used " + "to make room.", kMaxBlendStates); + + BlendStateMap::iterator leastRecentlyUsed = mBlendStateCache.begin(); + for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mBlendStateCache.erase(leastRecentlyUsed); + } + + // Create a new blend state and insert it into the cache + D3D11_BLEND_DESC blendDesc = { 0 }; + blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage; + blendDesc.IndependentBlendEnable = mrt ? TRUE : FALSE; + + for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) + { + D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i]; + + rtBlend.BlendEnable = blendState.blend; + if (blendState.blend) + { + rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false); + rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false); + rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB); + + rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true); + rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true); + rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha); + } + + rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(key.rtChannels[i][0] && blendState.colorMaskRed, + key.rtChannels[i][1] && blendState.colorMaskGreen, + key.rtChannels[i][2] && blendState.colorMaskBlue, + key.rtChannels[i][3] && blendState.colorMaskAlpha); + } + + ID3D11BlendState *dx11BlendState = NULL; + HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState); + if (FAILED(result) || !dx11BlendState) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); + } + + mBlendStateCache.insert(std::make_pair(key, std::make_pair(dx11BlendState, mCounter++))); + + *outBlendState = dx11BlendState; + return gl::Error(GL_NO_ERROR); + } +} + +std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash); + return hash; +} + +bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b) +{ + return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; +} + +gl::Error RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, + ID3D11RasterizerState **outRasterizerState) +{ + if (!mDevice) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + } + + RasterizerStateKey key = { 0 }; + key.rasterizerState = rasterState; + key.scissorEnabled = scissorEnabled; + + RasterizerStateMap::iterator keyIter = mRasterizerStateCache.find(key); + if (keyIter != mRasterizerStateCache.end()) + { + RasterizerStateCounterPair &state = keyIter->second; + state.second = mCounter++; + *outRasterizerState = state.first; + return gl::Error(GL_NO_ERROR); + } + else + { + if (mRasterizerStateCache.size() >= kMaxRasterizerStates) + { + TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used " + "to make room.", kMaxRasterizerStates); + + RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin(); + for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mRasterizerStateCache.erase(leastRecentlyUsed); + } + + D3D11_CULL_MODE cullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode); + + // Disable culling if drawing points + if (rasterState.pointDrawMode) + { + cullMode = D3D11_CULL_NONE; + } + + D3D11_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.CullMode = cullMode; + rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE; + rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though. + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE; + rasterDesc.MultisampleEnable = rasterState.multiSample; + rasterDesc.AntialiasedLineEnable = FALSE; + + if (rasterState.polygonOffsetFill) + { + rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; + rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits; + } + else + { + rasterDesc.SlopeScaledDepthBias = 0.0f; + rasterDesc.DepthBias = 0; + } + + ID3D11RasterizerState *dx11RasterizerState = NULL; + HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState); + if (FAILED(result) || !dx11RasterizerState) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result); + } + + mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++))); + + *outRasterizerState = dx11RasterizerState; + return gl::Error(GL_NO_ERROR); + } +} + +std::size_t RenderStateCache::hashDepthStencilState(const gl::DepthStencilState &dsState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&dsState, sizeof(gl::DepthStencilState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b) +{ + return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0; +} + +gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &dsState, ID3D11DepthStencilState **outDSState) +{ + if (!mDevice) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + } + + DepthStencilStateMap::iterator keyIter = mDepthStencilStateCache.find(dsState); + if (keyIter != mDepthStencilStateCache.end()) + { + DepthStencilStateCounterPair &state = keyIter->second; + state.second = mCounter++; + *outDSState = state.first; + return gl::Error(GL_NO_ERROR); + } + else + { + if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates) + { + TRACE("Overflowed the limit of %u depth stencil states, removing the least recently used " + "to make room.", kMaxDepthStencilStates); + + DepthStencilStateMap::iterator leastRecentlyUsed = mDepthStencilStateCache.begin(); + for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mDepthStencilStateCache.erase(leastRecentlyUsed); + } + + D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; + dsDesc.DepthEnable = dsState.depthTest ? TRUE : FALSE; + dsDesc.DepthWriteMask = gl_d3d11::ConvertDepthMask(dsState.depthMask); + dsDesc.DepthFunc = gl_d3d11::ConvertComparison(dsState.depthFunc); + dsDesc.StencilEnable = dsState.stencilTest ? TRUE : FALSE; + dsDesc.StencilReadMask = gl_d3d11::ConvertStencilMask(dsState.stencilMask); + dsDesc.StencilWriteMask = gl_d3d11::ConvertStencilMask(dsState.stencilWritemask); + dsDesc.FrontFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilFail); + dsDesc.FrontFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthFail); + dsDesc.FrontFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthPass); + dsDesc.FrontFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilFunc); + dsDesc.BackFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackFail); + dsDesc.BackFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthFail); + dsDesc.BackFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthPass); + dsDesc.BackFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilBackFunc); + + ID3D11DepthStencilState *dx11DepthStencilState = NULL; + HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState); + if (FAILED(result) || !dx11DepthStencilState) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); + } + + mDepthStencilStateCache.insert(std::make_pair(dsState, std::make_pair(dx11DepthStencilState, mCounter++))); + + *outDSState = dx11DepthStencilState; + return gl::Error(GL_NO_ERROR); + } +} + +std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState) +{ + static const unsigned int seed = 0xABCDEF98; + + std::size_t hash = 0; + MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash); + return hash; +} + +bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b) +{ + return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0; +} + +gl::Error RenderStateCache::getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState) +{ + if (!mDevice) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); + } + + SamplerStateMap::iterator keyIter = mSamplerStateCache.find(samplerState); + if (keyIter != mSamplerStateCache.end()) + { + SamplerStateCounterPair &state = keyIter->second; + state.second = mCounter++; + *outSamplerState = state.first; + return gl::Error(GL_NO_ERROR); + } + else + { + if (mSamplerStateCache.size() >= kMaxSamplerStates) + { + TRACE("Overflowed the limit of %u sampler states, removing the least recently used " + "to make room.", kMaxSamplerStates); + + SamplerStateMap::iterator leastRecentlyUsed = mSamplerStateCache.begin(); + for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++) + { + if (i->second.second < leastRecentlyUsed->second.second) + { + leastRecentlyUsed = i; + } + } + SafeRelease(leastRecentlyUsed->second.first); + mSamplerStateCache.erase(leastRecentlyUsed); + } + + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, + samplerState.maxAnisotropy, samplerState.compareMode); + samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS); + samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT); + samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR); + samplerDesc.MipLODBias = 0; + samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy; + samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc); + samplerDesc.BorderColor[0] = 0.0f; + samplerDesc.BorderColor[1] = 0.0f; + samplerDesc.BorderColor[2] = 0.0f; + samplerDesc.BorderColor[3] = 0.0f; + samplerDesc.MinLOD = samplerState.minLod; + samplerDesc.MaxLOD = samplerState.maxLod; + + if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + // Check that maxLOD is nearly FLT_MAX (1000.0f is the default), since 9_3 doesn't support anything other than FLT_MAX. + // Note that Feature Level 9_* only supports GL ES 2.0, so the consumer of ANGLE can't modify the Max LOD themselves. + ASSERT(samplerState.maxLod >= 999.9f); + + // Now just set MaxLOD to FLT_MAX. Other parts of the renderer (e.g. the non-zero max LOD workaround) should take account of this. + samplerDesc.MaxLOD = FLT_MAX; + } + + ID3D11SamplerState *dx11SamplerState = NULL; + HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState); + if (FAILED(result) || !dx11SamplerState) + { + return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11SamplerState, HRESULT: 0x%X.", result); + } + + mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++))); + + *outSamplerState = dx11SamplerState; + return gl::Error(GL_NO_ERROR); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h new file mode 100644 index 0000000000..0099b94a04 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h @@ -0,0 +1,111 @@ +// +// Copyright (c) 2012-2014 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. +// + +// RenderStateCache.h: Defines rx::RenderStateCache, a cache of Direct3D render +// state objects. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" +#include "common/angleutils.h" + +#include + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer11; + +class RenderStateCache : angle::NonCopyable +{ + public: + RenderStateCache(Renderer11 *renderer); + virtual ~RenderStateCache(); + + void initialize(ID3D11Device *device); + void clear(); + + gl::Error getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, ID3D11BlendState **outBlendState); + gl::Error getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, ID3D11RasterizerState **outRasterizerState); + gl::Error getDepthStencilState(const gl::DepthStencilState &dsState, ID3D11DepthStencilState **outDSState); + gl::Error getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState); + + private: + Renderer11 *mRenderer; + unsigned long long mCounter; + + // Blend state cache + struct BlendStateKey + { + gl::BlendState blendState; + bool rtChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; + }; + static std::size_t hashBlendState(const BlendStateKey &blendState); + static bool compareBlendStates(const BlendStateKey &a, const BlendStateKey &b); + static const unsigned int kMaxBlendStates; + + typedef std::size_t (*BlendStateHashFunction)(const BlendStateKey &); + typedef bool (*BlendStateEqualityFunction)(const BlendStateKey &, const BlendStateKey &); + typedef std::pair BlendStateCounterPair; + typedef std::unordered_map BlendStateMap; + BlendStateMap mBlendStateCache; + + // Rasterizer state cache + struct RasterizerStateKey + { + gl::RasterizerState rasterizerState; + bool scissorEnabled; + }; + static std::size_t hashRasterizerState(const RasterizerStateKey &rasterState); + static bool compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b); + static const unsigned int kMaxRasterizerStates; + + typedef std::size_t (*RasterizerStateHashFunction)(const RasterizerStateKey &); + typedef bool (*RasterizerStateEqualityFunction)(const RasterizerStateKey &, const RasterizerStateKey &); + typedef std::pair RasterizerStateCounterPair; + typedef std::unordered_map RasterizerStateMap; + RasterizerStateMap mRasterizerStateCache; + + // Depth stencil state cache + static std::size_t hashDepthStencilState(const gl::DepthStencilState &dsState); + static bool compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b); + static const unsigned int kMaxDepthStencilStates; + + typedef std::size_t (*DepthStencilStateHashFunction)(const gl::DepthStencilState &); + typedef bool (*DepthStencilStateEqualityFunction)(const gl::DepthStencilState &, const gl::DepthStencilState &); + typedef std::pair DepthStencilStateCounterPair; + typedef std::unordered_map DepthStencilStateMap; + DepthStencilStateMap mDepthStencilStateCache; + + // Sample state cache + static std::size_t hashSamplerState(const gl::SamplerState &samplerState); + static bool compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b); + static const unsigned int kMaxSamplerStates; + + typedef std::size_t (*SamplerStateHashFunction)(const gl::SamplerState &); + typedef bool (*SamplerStateEqualityFunction)(const gl::SamplerState &, const gl::SamplerState &); + typedef std::pair SamplerStateCounterPair; + typedef std::unordered_map SamplerStateMap; + SamplerStateMap mSamplerStateCache; + + ID3D11Device *mDevice; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERSTATECACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp new file mode 100644 index 0000000000..ecd9e13c90 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp @@ -0,0 +1,394 @@ +// +// 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. +// + +// RenderTarget11.cpp: Implements a DX11-specific wrapper for ID3D11View pointers +// retained by Renderbuffers. + +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +namespace rx +{ + +static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) +{ + ID3D11Texture1D *texture1D = d3d11::DynamicCastComObject(resource); + if (texture1D) + { + D3D11_TEXTURE1D_DESC texDesc; + texture1D->GetDesc(&texDesc); + SafeRelease(texture1D); + + *mipLevels = texDesc.MipLevels; + *samples = 0; + + return true; + } + + ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject(resource); + if (texture2D) + { + D3D11_TEXTURE2D_DESC texDesc; + texture2D->GetDesc(&texDesc); + SafeRelease(texture2D); + + *mipLevels = texDesc.MipLevels; + *samples = texDesc.SampleDesc.Count > 1 ? texDesc.SampleDesc.Count : 0; + + return true; + } + + ID3D11Texture3D *texture3D = d3d11::DynamicCastComObject(resource); + if (texture3D) + { + D3D11_TEXTURE3D_DESC texDesc; + texture3D->GetDesc(&texDesc); + SafeRelease(texture3D); + + *mipLevels = texDesc.MipLevels; + *samples = 0; + + return true; + } + + return false; +} + +static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) +{ + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + view->GetDesc(&rtvDesc); + + unsigned int mipSlice = 0; + unsigned int arraySlice = 0; + + switch (rtvDesc.ViewDimension) + { + case D3D11_RTV_DIMENSION_TEXTURE1D: + mipSlice = rtvDesc.Texture1D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + mipSlice = rtvDesc.Texture1DArray.MipSlice; + arraySlice = rtvDesc.Texture1DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2D: + mipSlice = rtvDesc.Texture2D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + mipSlice = rtvDesc.Texture2DArray.MipSlice; + arraySlice = rtvDesc.Texture2DArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMS: + mipSlice = 0; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: + mipSlice = 0; + arraySlice = rtvDesc.Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_RTV_DIMENSION_TEXTURE3D: + mipSlice = rtvDesc.Texture3D.MipSlice; + arraySlice = 0; + break; + + case D3D11_RTV_DIMENSION_UNKNOWN: + case D3D11_RTV_DIMENSION_BUFFER: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + break; + } + + unsigned int mipLevels, samples; + getTextureProperties(resource, &mipLevels, &samples); + + return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); +} + +static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) +{ + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + view->GetDesc(&dsvDesc); + + unsigned int mipSlice = 0; + unsigned int arraySlice = 0; + + switch (dsvDesc.ViewDimension) + { + case D3D11_DSV_DIMENSION_TEXTURE1D: + mipSlice = dsvDesc.Texture1D.MipSlice; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: + mipSlice = dsvDesc.Texture1DArray.MipSlice; + arraySlice = dsvDesc.Texture1DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2D: + mipSlice = dsvDesc.Texture2D.MipSlice; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: + mipSlice = dsvDesc.Texture2DArray.MipSlice; + arraySlice = dsvDesc.Texture2DArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMS: + mipSlice = 0; + arraySlice = 0; + break; + + case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: + mipSlice = 0; + arraySlice = dsvDesc.Texture2DMSArray.FirstArraySlice; + break; + + case D3D11_DSV_DIMENSION_UNKNOWN: + UNIMPLEMENTED(); + break; + + default: + UNREACHABLE(); + break; + } + + unsigned int mipLevels, samples; + getTextureProperties(resource, &mipLevels, &samples); + + return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); +} + +RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTargetD3D *target) +{ + ASSERT(HAS_DYNAMIC_TYPE(RenderTarget11*, target)); + return static_cast(target); +} + +TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mDXGIFormat(DXGI_FORMAT_UNKNOWN), + mSamples(samples), + mSubresourceIndex(0), + mTexture(resource), + mRenderTarget(rtv), + mDepthStencil(NULL), + mShaderResource(srv) +{ + if (mTexture) + { + mTexture->AddRef(); + } + + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + if (mShaderResource) + { + mShaderResource->AddRef(); + } + + if (mRenderTarget && mTexture) + { + mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); + + D3D11_RENDER_TARGET_VIEW_DESC desc; + mRenderTarget->GetDesc(&desc); + mDXGIFormat = desc.Format; + } +} + +TextureRenderTarget11::TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mDXGIFormat(DXGI_FORMAT_UNKNOWN), + mSamples(samples), + mSubresourceIndex(0), + mTexture(resource), + mRenderTarget(NULL), + mDepthStencil(dsv), + mShaderResource(srv) +{ + if (mTexture) + { + mTexture->AddRef(); + } + + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + if (mShaderResource) + { + mShaderResource->AddRef(); + } + + if (mDepthStencil && mTexture) + { + mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil); + + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + mDepthStencil->GetDesc(&desc); + mDXGIFormat = desc.Format; + } +} + +TextureRenderTarget11::~TextureRenderTarget11() +{ + SafeRelease(mTexture); + SafeRelease(mRenderTarget); + SafeRelease(mDepthStencil); + SafeRelease(mShaderResource); +} + +ID3D11Resource *TextureRenderTarget11::getTexture() const +{ + return mTexture; +} + +ID3D11RenderTargetView *TextureRenderTarget11::getRenderTargetView() const +{ + return mRenderTarget; +} + +ID3D11DepthStencilView *TextureRenderTarget11::getDepthStencilView() const +{ + return mDepthStencil; +} + +ID3D11ShaderResourceView *TextureRenderTarget11::getShaderResourceView() const +{ + return mShaderResource; +} + +GLsizei TextureRenderTarget11::getWidth() const +{ + return mWidth; +} + +GLsizei TextureRenderTarget11::getHeight() const +{ + return mHeight; +} + +GLsizei TextureRenderTarget11::getDepth() const +{ + return mDepth; +} + +GLenum TextureRenderTarget11::getInternalFormat() const +{ + return mInternalFormat; +} + +GLsizei TextureRenderTarget11::getSamples() const +{ + return mSamples; +} + +unsigned int TextureRenderTarget11::getSubresourceIndex() const +{ + return mSubresourceIndex; +} + +DXGI_FORMAT TextureRenderTarget11::getDXGIFormat() const +{ + return mDXGIFormat; +} + +SurfaceRenderTarget11::SurfaceRenderTarget11(SwapChain11 *swapChain, Renderer11 *renderer, bool depth) + : mSwapChain(swapChain), + mRenderer(renderer), + mDepth(depth) +{ + ASSERT(mSwapChain); +} + +SurfaceRenderTarget11::~SurfaceRenderTarget11() +{ +} + +GLsizei SurfaceRenderTarget11::getWidth() const +{ + return mSwapChain->getWidth(); +} + +GLsizei SurfaceRenderTarget11::getHeight() const +{ + return mSwapChain->getHeight(); +} + +GLsizei SurfaceRenderTarget11::getDepth() const +{ + return 1; +} + +GLenum SurfaceRenderTarget11::getInternalFormat() const +{ + return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat()); +} + +GLsizei SurfaceRenderTarget11::getSamples() const +{ + // Our EGL surfaces do not support multisampling. + return 0; +} + +ID3D11Resource *SurfaceRenderTarget11::getTexture() const +{ + return (mDepth ? mSwapChain->getDepthStencilTexture() : mSwapChain->getOffscreenTexture()); +} + +ID3D11RenderTargetView *SurfaceRenderTarget11::getRenderTargetView() const +{ + return (mDepth ? NULL : mSwapChain->getRenderTarget()); +} + +ID3D11DepthStencilView *SurfaceRenderTarget11::getDepthStencilView() const +{ + return (mDepth ? mSwapChain->getDepthStencil() : NULL); +} + +ID3D11ShaderResourceView *SurfaceRenderTarget11::getShaderResourceView() const +{ + return (mDepth ? mSwapChain->getDepthStencilShaderResource() : mSwapChain->getRenderTargetShaderResource()); +} + +unsigned int SurfaceRenderTarget11::getSubresourceIndex() const +{ + return 0; +} + +DXGI_FORMAT SurfaceRenderTarget11::getDXGIFormat() const +{ + return d3d11::GetTextureFormatInfo(getInternalFormat(), mRenderer->getFeatureLevel()).texFormat; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h new file mode 100644 index 0000000000..4472a56175 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h @@ -0,0 +1,110 @@ +// +// 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. +// + +// RenderTarget11.h: Defines a DX11-specific wrapper for ID3D11View pointers +// retained by Renderbuffers. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ + +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +class SwapChain11; +class Renderer11; + +class RenderTarget11 : public RenderTargetD3D +{ + public: + RenderTarget11() { } + virtual ~RenderTarget11() { } + + static RenderTarget11 *makeRenderTarget11(RenderTargetD3D *renderTarget); + + virtual ID3D11Resource *getTexture() const = 0; + virtual ID3D11RenderTargetView *getRenderTargetView() const = 0; + virtual ID3D11DepthStencilView *getDepthStencilView() const = 0; + virtual ID3D11ShaderResourceView *getShaderResourceView() const = 0; + + virtual unsigned int getSubresourceIndex() const = 0; + + virtual DXGI_FORMAT getDXGIFormat() const = 0; + + private: + D3D_FEATURE_LEVEL mFeatureLevel; +}; + +class TextureRenderTarget11 : public RenderTarget11 +{ + public: + // TextureRenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them + TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); + TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); + virtual ~TextureRenderTarget11(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + ID3D11Resource *getTexture() const override; + ID3D11RenderTargetView *getRenderTargetView() const override; + ID3D11DepthStencilView *getDepthStencilView() const override; + ID3D11ShaderResourceView *getShaderResourceView() const override; + + unsigned int getSubresourceIndex() const override; + + DXGI_FORMAT getDXGIFormat() const override; + + private: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + DXGI_FORMAT mDXGIFormat; + GLsizei mSamples; + + unsigned int mSubresourceIndex; + ID3D11Resource *mTexture; + ID3D11RenderTargetView *mRenderTarget; + ID3D11DepthStencilView *mDepthStencil; + ID3D11ShaderResourceView *mShaderResource; +}; + +class SurfaceRenderTarget11 : public RenderTarget11 +{ + public: + SurfaceRenderTarget11(SwapChain11 *swapChain, Renderer11 *renderer, bool depth); + virtual ~SurfaceRenderTarget11(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + ID3D11Resource *getTexture() const override; + ID3D11RenderTargetView *getRenderTargetView() const override; + ID3D11DepthStencilView *getDepthStencilView() const override; + ID3D11ShaderResourceView *getShaderResourceView() const override; + + unsigned int getSubresourceIndex() const override; + + DXGI_FORMAT getDXGIFormat() const override; + + private: + SwapChain11 *mSwapChain; + Renderer11 *mRenderer; + bool mDepth; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERTARGET11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp new file mode 100644 index 0000000000..5291a3a086 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp @@ -0,0 +1,3585 @@ +// +// Copyright (c) 2012-2014 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. +// + +// Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. + +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +#include "common/utilities.h" +#include "common/tls.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Program.h" +#include "libANGLE/State.h" +#include "libANGLE/Surface.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" +#include "libANGLE/renderer/d3d/d3d11/Blit11.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Clear11.h" +#include "libANGLE/renderer/d3d/d3d11/Fence11.h" +#include "libANGLE/renderer/d3d/d3d11/Framebuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Image11.h" +#include "libANGLE/renderer/d3d/d3d11/IndexBuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/PixelTransfer11.h" +#include "libANGLE/renderer/d3d/d3d11/Query11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" +#include "libANGLE/renderer/d3d/d3d11/Trim11.h" +#include "libANGLE/renderer/d3d/d3d11/VertexArray11.h" +#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +#include +#include + +// Enable ANGLE_SKIP_DXGI_1_2_CHECK if there is not a possibility of using cross-process +// HWNDs or the Windows 7 Platform Update (KB2670838) is expected to be installed. +#ifndef ANGLE_SKIP_DXGI_1_2_CHECK +#define ANGLE_SKIP_DXGI_1_2_CHECK 0 +#endif + +#ifdef _DEBUG +// this flag enables suppressing some spurious warnings that pop up in certain WebGL samples +// and conformance tests. to enable all warnings, remove this define. +#define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1 +#endif + +#ifndef __d3d11sdklayers_h__ +#define D3D11_MESSAGE_CATEGORY UINT +#define D3D11_MESSAGE_SEVERITY UINT +#define D3D11_MESSAGE_ID UINT +struct D3D11_MESSAGE; +typedef struct D3D11_INFO_QUEUE_FILTER_DESC +{ + UINT NumCategories; + D3D11_MESSAGE_CATEGORY *pCategoryList; + UINT NumSeverities; + D3D11_MESSAGE_SEVERITY *pSeverityList; + UINT NumIDs; + D3D11_MESSAGE_ID *pIDList; +} D3D11_INFO_QUEUE_FILTER_DESC; +typedef struct D3D11_INFO_QUEUE_FILTER +{ + D3D11_INFO_QUEUE_FILTER_DESC AllowList; + D3D11_INFO_QUEUE_FILTER_DESC DenyList; +} D3D11_INFO_QUEUE_FILTER; +static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 }; +MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown +{ +public: + virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0; + virtual void __stdcall ClearStoredMessages() = 0; + virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0; + virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0; + virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0; + virtual UINT64 __stdcall GetNumStoredMessages() = 0; + virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0; + virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0; + virtual UINT64 __stdcall GetMessageCountLimit() = 0; + virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; + virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; + virtual void __stdcall ClearStorageFilter() = 0; + virtual HRESULT __stdcall PushEmptyStorageFilter() = 0; + virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0; + virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0; + virtual void __stdcall PopStorageFilter() = 0; + virtual UINT __stdcall GetStorageFilterStackSize() = 0; + virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; + virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; + virtual void __stdcall ClearRetrievalFilter() = 0; + virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0; + virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0; + virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0; + virtual void __stdcall PopRetrievalFilter() = 0; + virtual UINT __stdcall GetRetrievalFilterStackSize() = 0; + virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0; + virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0; + virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0; + virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0; + virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0; + virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0; + virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0; + virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0; + virtual void __stdcall SetMuteDebugOutput(BOOL) = 0; + virtual BOOL __stdcall GetMuteDebugOutput() = 0; +}; +#endif + +namespace rx +{ + +namespace +{ + +enum +{ + MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 +}; + +// dirtyPointer is a special value that will make the comparison with any valid pointer fail and force the renderer to re-apply the state. +static const uintptr_t DirtyPointer = static_cast(-1); + +static bool ImageIndexConflictsWithSRV(const gl::ImageIndex *index, D3D11_SHADER_RESOURCE_VIEW_DESC desc) +{ + unsigned mipLevel = index->mipIndex; + unsigned layerIndex = index->layerIndex; + GLenum type = index->type; + + switch (desc.ViewDimension) + { + case D3D11_SRV_DIMENSION_TEXTURE2D: + { + unsigned maxSrvMip = desc.Texture2D.MipLevels + desc.Texture2D.MostDetailedMip; + maxSrvMip = (desc.Texture2D.MipLevels == -1) ? INT_MAX : maxSrvMip; + + unsigned mipMin = index->mipIndex; + unsigned mipMax = (layerIndex == -1) ? INT_MAX : layerIndex; + + return type == GL_TEXTURE_2D && RangeUI(mipMin, mipMax).intersects(RangeUI(desc.Texture2D.MostDetailedMip, maxSrvMip)); + } + + case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: + { + unsigned maxSrvMip = desc.Texture2DArray.MipLevels + desc.Texture2DArray.MostDetailedMip; + maxSrvMip = (desc.Texture2DArray.MipLevels == -1) ? INT_MAX : maxSrvMip; + + unsigned maxSlice = desc.Texture2DArray.FirstArraySlice + desc.Texture2DArray.ArraySize; + + // Cube maps can be mapped to Texture2DArray SRVs + return (type == GL_TEXTURE_2D_ARRAY || gl::IsCubeMapTextureTarget(type)) && + desc.Texture2DArray.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip && + desc.Texture2DArray.FirstArraySlice <= layerIndex && layerIndex < maxSlice; + } + + case D3D11_SRV_DIMENSION_TEXTURECUBE: + { + unsigned maxSrvMip = desc.TextureCube.MipLevels + desc.TextureCube.MostDetailedMip; + maxSrvMip = (desc.TextureCube.MipLevels == -1) ? INT_MAX : maxSrvMip; + + return gl::IsCubeMapTextureTarget(type) && + desc.TextureCube.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; + } + + case D3D11_SRV_DIMENSION_TEXTURE3D: + { + unsigned maxSrvMip = desc.Texture3D.MipLevels + desc.Texture3D.MostDetailedMip; + maxSrvMip = (desc.Texture3D.MipLevels == -1) ? INT_MAX : maxSrvMip; + + return type == GL_TEXTURE_3D && + desc.Texture3D.MostDetailedMip <= mipLevel && mipLevel < maxSrvMip; + } + default: + // We only handle the cases corresponding to valid image indexes + UNIMPLEMENTED(); + } + + return false; +} + +// Does *not* increment the resource ref count!! +ID3D11Resource *GetViewResource(ID3D11View *view) +{ + ID3D11Resource *resource = NULL; + ASSERT(view); + view->GetResource(&resource); + resource->Release(); + return resource; +} + +void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFirstConstant, UINT *outNumConstants) +{ + // The offset must be aligned to 256 bytes (should have been enforced by glBindBufferRange). + ASSERT(offset % 256 == 0); + + // firstConstant and numConstants are expressed in constants of 16-bytes. Furthermore they must be a multiple of 16 constants. + *outFirstConstant = offset / 16; + + // The GL size is not required to be aligned to a 256 bytes boundary. + // Round the size up to a 256 bytes boundary then express the results in constants of 16-bytes. + *outNumConstants = rx::roundUp(size, static_cast(256)) / 16; + + // Since the size is rounded up, firstConstant + numConstants may be bigger than the actual size of the buffer. + // This behaviour is explictly allowed according to the documentation on ID3D11DeviceContext1::PSSetConstantBuffers1 + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx +} + +} + +Renderer11::Renderer11(egl::Display *display) + : RendererD3D(display), + mStateCache(this) +{ + // Initialize global annotator + gl::InitializeDebugAnnotations(&mAnnotator); + + mVertexDataManager = NULL; + mIndexDataManager = NULL; + + mLineLoopIB = NULL; + mTriangleFanIB = NULL; + + mBlit = NULL; + mPixelTransfer = NULL; + + mClear = NULL; + + mTrim = NULL; + + mSyncQuery = NULL; + + mSupportsConstantBufferOffsets = false; + + mD3d11Module = NULL; + mDxgiModule = NULL; + + mDevice = NULL; + mDeviceContext = NULL; + mDeviceContext1 = NULL; + mDxgiAdapter = NULL; + mDxgiFactory = NULL; + + mDriverConstantBufferVS = NULL; + mDriverConstantBufferPS = NULL; + + mAppliedVertexShader = NULL; + mAppliedGeometryShader = NULL; + mAppliedPixelShader = NULL; + + mAppliedNumXFBBindings = static_cast(-1); + + const auto &attributes = mDisplay->getAttributeMap(); + + EGLint requestedMajorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE); + EGLint requestedMinorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE); + + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11) + { + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0); + } + } + + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10) + { + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1); + } + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0); + } + } + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) +#else + if (requestedMajorVersion == 9 && requestedMinorVersion == 3) +#endif + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); + } + + EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); + switch (requestedDeviceType) + { + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: + mDriverType = D3D_DRIVER_TYPE_HARDWARE; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE: + mDriverType = D3D_DRIVER_TYPE_WARP; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + mDriverType = D3D_DRIVER_TYPE_REFERENCE; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + mDriverType = D3D_DRIVER_TYPE_NULL; + break; + + default: + UNREACHABLE(); + } +} + +Renderer11::~Renderer11() +{ + release(); + + gl::UninitializeDebugAnnotations(); +} + +Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Renderer11*, renderer)); + return static_cast(renderer); +} + +#ifndef __d3d11_1_h__ +#define D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET ((D3D11_MESSAGE_ID)3146081) +#endif + +egl::Error Renderer11::initialize() +{ + if (!mCompiler.initialize()) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_COMPILER_ERROR, + "Failed to initialize compiler."); + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); + mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); + + if (mD3d11Module == NULL || mDxgiModule == NULL) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_MISSING_DEP, + "Could not load D3D11 or DXGI library."); + } + + // create the D3D11 device + ASSERT(mDevice == NULL); + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + + if (D3D11CreateDevice == NULL) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_MISSING_DEP, + "Could not retrieve D3D11CreateDevice address."); + } +#endif + + HRESULT result = S_OK; +#ifdef _DEBUG + result = D3D11CreateDevice(NULL, + mDriverType, + NULL, + D3D11_CREATE_DEVICE_DEBUG, + mAvailableFeatureLevels.data(), + mAvailableFeatureLevels.size(), + D3D11_SDK_VERSION, + &mDevice, + &mFeatureLevel, + &mDeviceContext); + + if (!mDevice || FAILED(result)) + { + ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n"); + } + + if (!mDevice || FAILED(result)) +#endif + { + result = D3D11CreateDevice(NULL, + mDriverType, + NULL, + 0, + mAvailableFeatureLevels.data(), + mAvailableFeatureLevels.size(), + D3D11_SDK_VERSION, + &mDevice, + &mFeatureLevel, + &mDeviceContext); + + if (result == E_INVALIDARG) + { + // Cleanup done by destructor through glDestroyRenderer + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_CREATEDEVICE_INVALIDARG, + "Could not create D3D11 device."); + } + + if (!mDevice || FAILED(result)) + { + // Cleanup done by destructor through glDestroyRenderer + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_CREATEDEVICE_ERROR, + "Could not create D3D11 device."); + } + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +#if !ANGLE_SKIP_DXGI_1_2_CHECK + // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. + // The easiest way to check is to query for a IDXGIDevice2. + bool requireDXGI1_2 = false; + HWND hwnd = WindowFromDC(mDisplay->getNativeDisplayId()); + if (hwnd) + { + DWORD currentProcessId = GetCurrentProcessId(); + DWORD wndProcessId; + GetWindowThreadProcessId(hwnd, &wndProcessId); + requireDXGI1_2 = (currentProcessId != wndProcessId); + } + else + { + requireDXGI1_2 = true; + } + + if (requireDXGI1_2) + { + IDXGIDevice2 *dxgiDevice2 = NULL; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2); + if (FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_INCOMPATIBLE_DXGI, + "DXGI 1.2 required to present to HWNDs owned by another process."); + } + SafeRelease(dxgiDevice2); + } +#endif +#endif + + // Cast the DeviceContext to a DeviceContext1. + // This could fail on Windows 7 without the Platform Update. + // Don't error in this case- just don't use mDeviceContext1. +#if defined(ANGLE_ENABLE_D3D11_1) + mDeviceContext1 = d3d11::DynamicCastComObject(mDeviceContext); +#endif + + IDXGIDevice *dxgiDevice = NULL; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); + + if (FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_OTHER_ERROR, + "Could not query DXGI device."); + } + + result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); + + if (FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_OTHER_ERROR, + "Could not retrieve DXGI adapter"); + } + + SafeRelease(dxgiDevice); + +#if defined(ANGLE_ENABLE_D3D11_1) + IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject(mDxgiAdapter); + + // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter" for the description string. + // If DXGI1.2 is available then IDXGIAdapter2::GetDesc2 can be used to get the actual hardware values. + if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3 && dxgiAdapter2 != NULL) + { + DXGI_ADAPTER_DESC2 adapterDesc2 = {0}; + dxgiAdapter2->GetDesc2(&adapterDesc2); + + // Copy the contents of the DXGI_ADAPTER_DESC2 into mAdapterDescription (a DXGI_ADAPTER_DESC). + memcpy(mAdapterDescription.Description, adapterDesc2.Description, sizeof(mAdapterDescription.Description)); + mAdapterDescription.VendorId = adapterDesc2.VendorId; + mAdapterDescription.DeviceId = adapterDesc2.DeviceId; + mAdapterDescription.SubSysId = adapterDesc2.SubSysId; + mAdapterDescription.Revision = adapterDesc2.Revision; + mAdapterDescription.DedicatedVideoMemory = adapterDesc2.DedicatedVideoMemory; + mAdapterDescription.DedicatedSystemMemory = adapterDesc2.DedicatedSystemMemory; + mAdapterDescription.SharedSystemMemory = adapterDesc2.SharedSystemMemory; + mAdapterDescription.AdapterLuid = adapterDesc2.AdapterLuid; + } + else + { + mDxgiAdapter->GetDesc(&mAdapterDescription); + } + + SafeRelease(dxgiAdapter2); +#endif + + memset(mDescription, 0, sizeof(mDescription)); + wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); + + result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); + + if (!mDxgiFactory || FAILED(result)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D11_INIT_OTHER_ERROR, + "Could not create DXGI factory."); + } + + // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log +#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) + ID3D11InfoQueue *infoQueue; + result = mDevice->QueryInterface(IID_ID3D11InfoQueue, (void **)&infoQueue); + + if (SUCCEEDED(result)) + { + D3D11_MESSAGE_ID hideMessages[] = + { + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET + }; + + D3D11_INFO_QUEUE_FILTER filter = {0}; + filter.DenyList.NumIDs = ArraySize(hideMessages); + filter.DenyList.pIDList = hideMessages; + + infoQueue->AddStorageFilterEntries(&filter); + SafeRelease(infoQueue); + } +#endif + + initializeDevice(); + + return egl::Error(EGL_SUCCESS); +} + +// 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 Renderer11::initializeDevice() +{ + mStateCache.initialize(mDevice); + mInputLayoutCache.initialize(mDevice, mDeviceContext); + + ASSERT(!mVertexDataManager && !mIndexDataManager); + mVertexDataManager = new VertexDataManager(this); + mIndexDataManager = new IndexDataManager(this, getRendererClass()); + + ASSERT(!mBlit); + mBlit = new Blit11(this); + + ASSERT(!mClear); + mClear = new Clear11(this); + + const auto &attributes = mDisplay->getAttributeMap(); + // If automatic trim is enabled, DXGIDevice3::Trim( ) is called for the application + // automatically when an application is suspended by the OS. This feature is currently + // only supported for Windows Store applications. + EGLint enableAutoTrim = attributes.get(EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_FALSE); + + if (enableAutoTrim == EGL_TRUE) + { + ASSERT(!mTrim); + mTrim = new Trim11(this); + } + + ASSERT(!mPixelTransfer); + mPixelTransfer = new PixelTransfer11(this); + + const gl::Caps &rendererCaps = getRendererCaps(); + +#if defined(ANGLE_ENABLE_D3D11_1) + if (getDeviceContext1IfSupported()) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; + mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + mSupportsConstantBufferOffsets = (d3d11Options.ConstantBufferOffsetting != FALSE); + } +#endif + + mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + + mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + + mCurVertexSRVs.resize(rendererCaps.maxVertexTextureImageUnits); + mCurPixelSRVs.resize(rendererCaps.maxTextureImageUnits); + + markAllStateDirty(); +} + +egl::ConfigSet Renderer11::generateConfigs() const +{ + static const GLenum colorBufferFormats[] = + { + GL_BGRA8_EXT, + GL_RGBA8_OES, + }; + + static const GLenum depthStencilBufferFormats[] = + { + GL_NONE, + GL_DEPTH24_STENCIL8_OES, + GL_DEPTH_COMPONENT16, + }; + + const gl::Caps &rendererCaps = getRendererCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + + egl::ConfigSet configs; + for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++) + { + GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex]; + const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); + if (colorBufferFormatCaps.renderable) + { + for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + { + GLenum depthStencilBufferInternalFormat = depthStencilBufferFormats[depthStencilIndex]; + const gl::TextureCaps &depthStencilBufferFormatCaps = rendererTextureCaps.get(depthStencilBufferInternalFormat); + if (depthStencilBufferFormatCaps.renderable || depthStencilBufferInternalFormat == GL_NONE) + { + const gl::InternalFormat &colorBufferFormatInfo = gl::GetInternalFormatInfo(colorBufferInternalFormat); + const gl::InternalFormat &depthStencilBufferFormatInfo = gl::GetInternalFormatInfo(depthStencilBufferInternalFormat); + + egl::Config config; + config.renderTargetFormat = colorBufferInternalFormat; + config.depthStencilFormat = depthStencilBufferInternalFormat; + config.bufferSize = colorBufferFormatInfo.pixelBytes * 8; + config.redSize = colorBufferFormatInfo.redBits; + config.greenSize = colorBufferFormatInfo.greenBits; + config.blueSize = colorBufferFormatInfo.blueBits; + config.luminanceSize = colorBufferFormatInfo.luminanceBits; + config.alphaSize = colorBufferFormatInfo.alphaBits; + config.alphaMaskSize = 0; + config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB); + config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || colorBufferFormatInfo.format == GL_BGRA_EXT); + config.colorBufferType = EGL_RGB_BUFFER; + config.configID = static_cast(configs.size() + 1); + // Can only support a conformant ES2 with feature level greater than 10.0. + config.conformant = (mFeatureLevel >= D3D_FEATURE_LEVEL_10_0) ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR) : EGL_NONE; + config.configCaveat = config.conformant == EGL_NONE ? EGL_NON_CONFORMANT_CONFIG : EGL_NONE; + config.depthSize = depthStencilBufferFormatInfo.depthBits; + config.level = 0; + config.matchNativePixmap = EGL_NONE; + config.maxPBufferWidth = rendererCaps.max2DTextureSize; + config.maxPBufferHeight = rendererCaps.max2DTextureSize; + config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize; + config.maxSwapInterval = 4; + config.minSwapInterval = 0; + config.nativeRenderable = EGL_FALSE; + config.nativeVisualID = 0; + config.nativeVisualType = EGL_NONE; + // Can't support ES3 at all without feature level 10.0 + config.renderableType = EGL_OPENGL_ES2_BIT | ((mFeatureLevel >= D3D_FEATURE_LEVEL_10_0) ? EGL_OPENGL_ES3_BIT_KHR : 0); + config.sampleBuffers = 0; // FIXME: enumerate multi-sampling + config.samples = 0; + config.stencilSize = depthStencilBufferFormatInfo.stencilBits; + config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + config.transparentType = EGL_NONE; + config.transparentRedValue = 0; + config.transparentGreenValue = 0; + config.transparentBlueValue = 0; + + configs.add(config); + } + } + } + } + + ASSERT(configs.size() > 0); + return configs; +} + +gl::Error Renderer11::flush() +{ + mDeviceContext->Flush(); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::finish() +{ + HRESULT result; + + if (!mSyncQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + result = mDevice->CreateQuery(&queryDesc, &mSyncQuery); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); + } + } + + mDeviceContext->End(mSyncQuery); + mDeviceContext->Flush(); + + do + { + result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + // Keep polling, but allow other threads to do something useful first + ScheduleYield(); + + if (testDeviceLost()) + { + mDisplay->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while waiting for sync."); + } + } + while (result == S_FALSE); + + return gl::Error(GL_NO_ERROR); +} + +SwapChainD3D *Renderer11::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +{ + return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); +} + +gl::Error Renderer11::generateSwizzle(gl::Texture *texture) +{ + if (texture) + { + TextureD3D *textureD3D = GetImplAs(texture); + ASSERT(textureD3D); + + TextureStorage *texStorage = nullptr; + gl::Error error = textureD3D->getNativeTexture(&texStorage); + if (error.isError()) + { + return error; + } + + if (texStorage) + { + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); + error = storage11->generateSwizzles(texture->getSamplerState().swizzleRed, + texture->getSamplerState().swizzleGreen, + texture->getSamplerState().swizzleBlue, + texture->getSamplerState().swizzleAlpha); + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerStateParam) +{ + // Make sure to add the level offset for our tiny compressed texture workaround + TextureD3D *textureD3D = GetImplAs(texture); + gl::SamplerState samplerStateInternal = samplerStateParam; + + TextureStorage *storage = nullptr; + gl::Error error = textureD3D->getNativeTexture(&storage); + if (error.isError()) + { + return error; + } + + // Storage should exist, texture should be complete + ASSERT(storage); + + samplerStateInternal.baseLevel += storage->getTopLevel(); + + if (type == gl::SAMPLER_PIXEL) + { + ASSERT(static_cast(index) < getRendererCaps().maxTextureImageUnits); + + if (mForceSetPixelSamplerStates[index] || memcmp(&samplerStateInternal, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = NULL; + error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); + if (error.isError()) + { + return error; + } + + ASSERT(dxSamplerState != NULL); + mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); + + mCurPixelSamplerStates[index] = samplerStateInternal; + } + + mForceSetPixelSamplerStates[index] = false; + } + else if (type == gl::SAMPLER_VERTEX) + { + ASSERT(static_cast(index) < getRendererCaps().maxVertexTextureImageUnits); + + if (mForceSetVertexSamplerStates[index] || memcmp(&samplerStateInternal, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) + { + ID3D11SamplerState *dxSamplerState = NULL; + error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); + if (error.isError()) + { + return error; + } + + ASSERT(dxSamplerState != NULL); + mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); + + mCurVertexSamplerStates[index] = samplerStateInternal; + } + + mForceSetVertexSamplerStates[index] = false; + } + else UNREACHABLE(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +{ + ID3D11ShaderResourceView *textureSRV = NULL; + + if (texture) + { + TextureD3D *textureImpl = GetImplAs(texture); + + TextureStorage *texStorage = nullptr; + gl::Error error = textureImpl->getNativeTexture(&texStorage); + if (error.isError()) + { + return error; + } + + // Texture should be complete and have a storage + ASSERT(texStorage); + + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); + + // Make sure to add the level offset for our tiny compressed texture workaround + gl::SamplerState samplerState = texture->getSamplerState(); + samplerState.baseLevel += storage11->getTopLevel(); + + error = storage11->getSRV(samplerState, &textureSRV); + if (error.isError()) + { + return error; + } + + // If we get NULL back from getSRV here, something went wrong in the texture class and we're unexpectedly + // missing the shader resource view + ASSERT(textureSRV != NULL); + + textureImpl->resetDirty(); + } + + ASSERT((type == gl::SAMPLER_PIXEL && static_cast(index) < getRendererCaps().maxTextureImageUnits) || + (type == gl::SAMPLER_VERTEX && static_cast(index) < getRendererCaps().maxVertexTextureImageUnits)); + + setShaderResource(type, index, textureSRV); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setUniformBuffers(const gl::Data &data, + const GLint vertexUniformBuffers[], + const GLint fragmentUniformBuffers[]) +{ + for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxVertexUniformBlocks; uniformBufferIndex++) + { + GLint binding = vertexUniformBuffers[uniformBufferIndex]; + + if (binding == -1) + { + continue; + } + + gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding); + GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding); + + if (uniformBuffer) + { + Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); + ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + + if (!constantBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY); + } + + if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial() || + mCurrentConstantBufferVSOffset[uniformBufferIndex] != uniformBufferOffset || + mCurrentConstantBufferVSSize[uniformBufferIndex] != uniformBufferSize) + { +#if defined(ANGLE_ENABLE_D3D11_1) + if (mSupportsConstantBufferOffsets && uniformBufferSize != 0) + { + UINT firstConstant = 0, numConstants = 0; + CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); + mDeviceContext1->VSSetConstantBuffers1(getReservedVertexUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer, &firstConstant, &numConstants); + } + else +#endif + { + ASSERT(uniformBufferOffset == 0); + mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer); + } + + mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial(); + mCurrentConstantBufferVSOffset[uniformBufferIndex] = uniformBufferOffset; + mCurrentConstantBufferVSSize[uniformBufferIndex] = uniformBufferSize; + } + } + } + + for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < data.caps->maxFragmentUniformBlocks; uniformBufferIndex++) + { + GLint binding = fragmentUniformBuffers[uniformBufferIndex]; + + if (binding == -1) + { + continue; + } + + gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(binding); + GLintptr uniformBufferOffset = data.state->getIndexedUniformBufferOffset(binding); + GLsizeiptr uniformBufferSize = data.state->getIndexedUniformBufferSize(binding); + + if (uniformBuffer) + { + Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); + ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); + + if (!constantBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY); + } + + if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial() || + mCurrentConstantBufferPSOffset[uniformBufferIndex] != uniformBufferOffset || + mCurrentConstantBufferPSSize[uniformBufferIndex] != uniformBufferSize) + { +#if defined(ANGLE_ENABLE_D3D11_1) + if (mSupportsConstantBufferOffsets && uniformBufferSize != 0) + { + UINT firstConstant = 0, numConstants = 0; + CalculateConstantBufferParams(uniformBufferOffset, uniformBufferSize, &firstConstant, &numConstants); + mDeviceContext1->PSSetConstantBuffers1(getReservedFragmentUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer, &firstConstant, &numConstants); + } + else +#endif + { + ASSERT(uniformBufferOffset == 0); + mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex, + 1, &constantBuffer); + } + + mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial(); + mCurrentConstantBufferPSOffset[uniformBufferIndex] = uniformBufferOffset; + mCurrentConstantBufferPSSize[uniformBufferIndex] = uniformBufferSize; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) +{ + if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0) + { + ID3D11RasterizerState *dxRasterState = NULL; + gl::Error error = mStateCache.getRasterizerState(rasterState, mScissorEnabled, &dxRasterState); + if (error.isError()) + { + return error; + } + + mDeviceContext->RSSetState(dxRasterState); + + mCurRasterState = rasterState; + } + + mForceSetRasterState = false; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) +{ + if (mForceSetBlendState || + memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0 || + memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0 || + sampleMask != mCurSampleMask) + { + ID3D11BlendState *dxBlendState = NULL; + gl::Error error = mStateCache.getBlendState(framebuffer, blendState, &dxBlendState); + if (error.isError()) + { + return error; + } + + ASSERT(dxBlendState != NULL); + + float blendColors[4] = {0.0f}; + if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && + blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) + { + blendColors[0] = blendColor.red; + blendColors[1] = blendColor.green; + blendColors[2] = blendColor.blue; + blendColors[3] = blendColor.alpha; + } + else + { + blendColors[0] = blendColor.alpha; + blendColors[1] = blendColor.alpha; + blendColors[2] = blendColor.alpha; + blendColors[3] = blendColor.alpha; + } + + mDeviceContext->OMSetBlendState(dxBlendState, blendColors, sampleMask); + + mCurBlendState = blendState; + mCurBlendColor = blendColor; + mCurSampleMask = sampleMask; + } + + mForceSetBlendState = false; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW) +{ + if (mForceSetDepthStencilState || + memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0 || + stencilRef != mCurStencilRef || stencilBackRef != mCurStencilBackRef) + { + ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); + ASSERT(stencilRef == stencilBackRef); + ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); + + ID3D11DepthStencilState *dxDepthStencilState = NULL; + gl::Error error = mStateCache.getDepthStencilState(depthStencilState, &dxDepthStencilState); + if (error.isError()) + { + return error; + } + + ASSERT(dxDepthStencilState); + + // Max D3D11 stencil reference value is 0xFF, corresponding to the max 8 bits in a stencil buffer + // GL specifies we should clamp the ref value to the nearest bit depth when doing stencil ops + static_assert(D3D11_DEFAULT_STENCIL_READ_MASK == 0xFF, "Unexpected value of D3D11_DEFAULT_STENCIL_READ_MASK"); + static_assert(D3D11_DEFAULT_STENCIL_WRITE_MASK == 0xFF, "Unexpected value of D3D11_DEFAULT_STENCIL_WRITE_MASK"); + UINT dxStencilRef = std::min(stencilRef, 0xFFu); + + mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef); + + mCurDepthStencilState = depthStencilState; + mCurStencilRef = stencilRef; + mCurStencilBackRef = stencilBackRef; + } + + mForceSetDepthStencilState = false; + + return gl::Error(GL_NO_ERROR); +} + +void Renderer11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) +{ + if (mForceSetScissor || memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || + enabled != mScissorEnabled) + { + if (enabled) + { + D3D11_RECT rect; + rect.left = std::max(0, scissor.x); + rect.top = std::max(0, scissor.y); + rect.right = scissor.x + std::max(0, scissor.width); + rect.bottom = scissor.y + std::max(0, scissor.height); + + mDeviceContext->RSSetScissorRects(1, &rect); + } + + if (enabled != mScissorEnabled) + { + mForceSetRasterState = true; + } + + mCurScissor = scissor; + mScissorEnabled = enabled; + } + + mForceSetScissor = false; +} + +void Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) +{ + gl::Rectangle actualViewport = viewport; + float actualZNear = gl::clamp01(zNear); + float actualZFar = gl::clamp01(zFar); + if (ignoreViewport) + { + actualViewport.x = 0; + actualViewport.y = 0; + actualViewport.width = mRenderTargetDesc.width; + actualViewport.height = mRenderTargetDesc.height; + actualZNear = 0.0f; + actualZFar = 1.0f; + } + + bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || + actualZNear != mCurNear || actualZFar != mCurFar; + + if (viewportChanged) + { + const gl::Caps& caps = getRendererCaps(); + + int dxMaxViewportBoundsX = static_cast(caps.maxViewportWidth); + int dxMaxViewportBoundsY = static_cast(caps.maxViewportHeight); + int dxMinViewportBoundsX = -dxMaxViewportBoundsX; + int dxMinViewportBoundsY = -dxMaxViewportBoundsY; + + if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3) + { + // Feature Level 9 viewports shouldn't exceed the dimensions of the rendertarget. + dxMaxViewportBoundsX = mRenderTargetDesc.width; + dxMaxViewportBoundsY = mRenderTargetDesc.height; + dxMinViewportBoundsX = 0; + dxMinViewportBoundsY = 0; + } + + int dxViewportTopLeftX = gl::clamp(actualViewport.x, dxMinViewportBoundsX, dxMaxViewportBoundsX); + int dxViewportTopLeftY = gl::clamp(actualViewport.y, dxMinViewportBoundsY, dxMaxViewportBoundsY); + int dxViewportWidth = gl::clamp(actualViewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX); + int dxViewportHeight = gl::clamp(actualViewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY); + + D3D11_VIEWPORT dxViewport; + dxViewport.TopLeftX = static_cast(dxViewportTopLeftX); + dxViewport.TopLeftY = static_cast(dxViewportTopLeftY); + dxViewport.Width = static_cast(dxViewportWidth); + dxViewport.Height = static_cast(dxViewportHeight); + dxViewport.MinDepth = actualZNear; + dxViewport.MaxDepth = actualZFar; + + mDeviceContext->RSSetViewports(1, &dxViewport); + + mCurViewport = actualViewport; + mCurNear = actualZNear; + mCurFar = actualZFar; + + // On Feature Level 9_*, we must emulate large and/or negative viewports in the shaders using viewAdjust (like the D3D9 renderer). + if (mFeatureLevel <= D3D_FEATURE_LEVEL_9_3) + { + mVertexConstants.viewAdjust[0] = static_cast((actualViewport.width - dxViewportWidth) + 2 * (actualViewport.x - dxViewportTopLeftX)) / dxViewport.Width; + mVertexConstants.viewAdjust[1] = static_cast((actualViewport.height - dxViewportHeight) + 2 * (actualViewport.y - dxViewportTopLeftY)) / dxViewport.Height; + mVertexConstants.viewAdjust[2] = static_cast(actualViewport.width) / dxViewport.Width; + mVertexConstants.viewAdjust[3] = static_cast(actualViewport.height) / dxViewport.Height; + } + + mPixelConstants.viewCoords[0] = actualViewport.width * 0.5f; + mPixelConstants.viewCoords[1] = actualViewport.height * 0.5f; + mPixelConstants.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); + mPixelConstants.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); + + // Instanced pointsprite emulation requires ViewCoords to be defined in the + // the vertex shader. + mVertexConstants.viewCoords[0] = mPixelConstants.viewCoords[0]; + mVertexConstants.viewCoords[1] = mPixelConstants.viewCoords[1]; + mVertexConstants.viewCoords[2] = mPixelConstants.viewCoords[2]; + mVertexConstants.viewCoords[3] = mPixelConstants.viewCoords[3]; + + mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f; + mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f; + + mVertexConstants.depthRange[0] = actualZNear; + mVertexConstants.depthRange[1] = actualZFar; + mVertexConstants.depthRange[2] = actualZFar - actualZNear; + + mPixelConstants.depthRange[0] = actualZNear; + mPixelConstants.depthRange[1] = actualZFar; + mPixelConstants.depthRange[2] = actualZFar - actualZNear; + } + + mForceSetViewport = false; +} + +bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize) +{ + D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + + GLsizei minCount = 0; + + switch (mode) + { + case GL_POINTS: primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; minCount = 1; break; + case GL_LINES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; minCount = 2; break; + case GL_LINE_LOOP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; + case GL_LINE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; + case GL_TRIANGLES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; + case GL_TRIANGLE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; minCount = 3; break; + // emulate fans via rewriting index buffer + case GL_TRIANGLE_FAN: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; + default: + UNREACHABLE(); + return false; + } + + // If instanced pointsprite emulation is being used and If gl_PointSize is used in the shader, + // GL_POINTS mode is expected to render pointsprites. + // Instanced PointSprite emulation requires that the topology to be D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST. + if (mode == GL_POINTS && usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation) + { + primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + } + + if (primitiveTopology != mCurrentPrimitiveTopology) + { + mDeviceContext->IASetPrimitiveTopology(primitiveTopology); + mCurrentPrimitiveTopology = primitiveTopology; + } + + return count >= minCount; +} + +void Renderer11::unsetConflictingSRVs(gl::SamplerType samplerType, uintptr_t resource, const gl::ImageIndex *index) +{ + auto ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex) + { + auto &record = currentSRVs[resourceIndex]; + + if (record.srv && record.resource == resource && ImageIndexConflictsWithSRV(index, record.desc)) + { + setShaderResource(samplerType, static_cast(resourceIndex), NULL); + } + } +} + +gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer) +{ + // Get the color render buffer and serial + // Also extract the render target dimensions and view + unsigned int renderTargetWidth = 0; + unsigned int renderTargetHeight = 0; + DXGI_FORMAT renderTargetFormat = DXGI_FORMAT_UNKNOWN; + ID3D11RenderTargetView* framebufferRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; + bool missingColorRenderTarget = true; + + const FramebufferD3D *framebufferD3D = GetImplAs(framebuffer); + const gl::AttachmentList &colorbuffers = framebufferD3D->getColorAttachmentsForRender(getWorkarounds()); + + for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) + { + gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; + + if (colorbuffer) + { + // the draw buffer must be either "none", "back" for the default buffer or the same index as this color (in order) + + // check for zero-sized default framebuffer, which is a special case. + // in this case we do not wish to modify any state and just silently return false. + // this will not report any gl error but will cause the calling method to return. + if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) + { + return gl::Error(GL_NO_ERROR); + } + + // Extract the render target dimensions and view + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget); + + framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView(); + ASSERT(framebufferRTVs[colorAttachment]); + + if (missingColorRenderTarget) + { + renderTargetWidth = renderTarget->getWidth(); + renderTargetHeight = renderTarget->getHeight(); + renderTargetFormat = renderTarget->getDXGIFormat(); + missingColorRenderTarget = false; + } + + // Unbind render target SRVs from the shader here to prevent D3D11 warnings. + if (colorbuffer->type() == GL_TEXTURE) + { + uintptr_t rtResource = reinterpret_cast(GetViewResource(framebufferRTVs[colorAttachment])); + const gl::ImageIndex *index = colorbuffer->getTextureImageIndex(); + ASSERT(index); + // The index doesn't need to be corrected for the small compressed texture workaround + // because a rendertarget is never compressed. + unsetConflictingSRVs(gl::SAMPLER_VERTEX, rtResource, index); + unsetConflictingSRVs(gl::SAMPLER_PIXEL, rtResource, index); + } + } + } + + // Get the depth stencil buffers + ID3D11DepthStencilView* framebufferDSV = NULL; + gl::FramebufferAttachment *depthStencil = framebuffer->getDepthOrStencilbuffer(); + if (depthStencil) + { + RenderTarget11 *depthStencilRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(depthStencil, &depthStencilRenderTarget); + if (error.isError()) + { + SafeRelease(framebufferRTVs); + return error; + } + ASSERT(depthStencilRenderTarget); + + framebufferDSV = depthStencilRenderTarget->getDepthStencilView(); + ASSERT(framebufferDSV); + + // If there is no render buffer, the width, height and format values come from + // the depth stencil + if (missingColorRenderTarget) + { + renderTargetWidth = depthStencilRenderTarget->getWidth(); + renderTargetHeight = depthStencilRenderTarget->getHeight(); + renderTargetFormat = depthStencilRenderTarget->getDXGIFormat(); + } + + // Unbind render target SRVs from the shader here to prevent D3D11 warnings. + if (depthStencil->type() == GL_TEXTURE) + { + uintptr_t depthStencilResource = reinterpret_cast(GetViewResource(framebufferDSV)); + const gl::ImageIndex *index = depthStencil->getTextureImageIndex(); + ASSERT(index); + // The index doesn't need to be corrected for the small compressed texture workaround + // because a rendertarget is never compressed. + unsetConflictingSRVs(gl::SAMPLER_VERTEX, depthStencilResource, index); + unsetConflictingSRVs(gl::SAMPLER_PIXEL, depthStencilResource, index); + } + } + + // Apply the render target and depth stencil + if (!mRenderTargetDescInitialized || !mDepthStencilInitialized || + memcmp(framebufferRTVs, mAppliedRTVs, sizeof(framebufferRTVs)) != 0 || + reinterpret_cast(framebufferDSV) != mAppliedDSV) + { + mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, framebufferRTVs, framebufferDSV); + + mRenderTargetDesc.width = renderTargetWidth; + mRenderTargetDesc.height = renderTargetHeight; + mRenderTargetDesc.format = renderTargetFormat; + mForceSetViewport = true; + mForceSetScissor = true; + mForceSetBlendState = true; + + if (!mDepthStencilInitialized) + { + mForceSetRasterState = true; + } + + for (size_t rtIndex = 0; rtIndex < ArraySize(framebufferRTVs); rtIndex++) + { + mAppliedRTVs[rtIndex] = reinterpret_cast(framebufferRTVs[rtIndex]); + } + mAppliedDSV = reinterpret_cast(framebufferDSV); + mRenderTargetDescInitialized = true; + mDepthStencilInitialized = true; + } + + const Framebuffer11 *framebuffer11 = GetImplAs(framebuffer); + gl::Error error = framebuffer11->invalidateSwizzles(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances) +{ + TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; + gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); + if (error.isError()) + { + return error; + } + + return mInputLayoutCache.applyVertexBuffers(attributes, mode, state.getProgram()); +} + +gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); + if (error.isError()) + { + return error; + } + + ID3D11Buffer *buffer = NULL; + DXGI_FORMAT bufferFormat = (indexInfo->indexType == GL_UNSIGNED_INT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; + + if (indexInfo->storage) + { + Buffer11 *storage = Buffer11::makeBuffer11(indexInfo->storage); + buffer = storage->getBuffer(BUFFER_USAGE_INDEX); + } + else + { + IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); + buffer = indexBuffer->getBuffer(); + } + + if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset) + { + mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); + + mAppliedIB = buffer; + mAppliedIBFormat = bufferFormat; + mAppliedIBOffset = indexInfo->startOffset; + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer11::applyTransformFeedbackBuffers(const gl::State &state) +{ + size_t numXFBBindings = 0; + bool requiresUpdate = false; + + if (state.isTransformFeedbackActiveUnpaused()) + { + numXFBBindings = state.getTransformFeedbackBufferIndexRange(); + ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + + for (size_t i = 0; i < numXFBBindings; i++) + { + gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); + GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); + ID3D11Buffer *d3dBuffer = NULL; + if (curXFBBuffer) + { + Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + } + + // TODO: mAppliedTFBuffers and friends should also be kept in a vector. + if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i]) + { + requiresUpdate = true; + } + } + } + + if (requiresUpdate || numXFBBindings != mAppliedNumXFBBindings) + { + for (size_t i = 0; i < numXFBBindings; ++i) + { + gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); + GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); + + if (curXFBBuffer) + { + Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer || mAppliedTFOffsets[i] != curXFBOffset) ? + static_cast(curXFBOffset) : -1; + mAppliedTFBuffers[i] = d3dBuffer; + } + else + { + mAppliedTFBuffers[i] = NULL; + mCurrentD3DOffsets[i] = 0; + } + mAppliedTFOffsets[i] = curXFBOffset; + } + + mAppliedNumXFBBindings = numXFBBindings; + + mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets); + } +} + +gl::Error Renderer11::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) +{ + bool useInstancedPointSpriteEmulation = usesPointSize && getWorkarounds().useInstancedPointSpriteEmulation; + if (mode == GL_POINTS && data.state->isTransformFeedbackActiveUnpaused()) + { + // Since point sprites are generated with a geometry shader, too many vertices will + // be written if transform feedback is active. To work around this, draw only the points + // with the stream out shader and no pixel shader to feed the stream out buffers and then + // draw again with the point sprite geometry shader to rasterize the point sprites. + + mDeviceContext->PSSetShader(NULL, NULL, 0); + + if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + + ProgramD3D *programD3D = GetImplAs(data.state->getProgram()); + + rx::ShaderExecutableD3D *pixelExe = NULL; + gl::Error error = programD3D->getPixelExecutableForFramebuffer(data.state->getDrawFramebuffer(), &pixelExe); + if (error.isError()) + { + return error; + } + + // Skip this step if we're doing rasterizer discard. + if (pixelExe && !data.state->getRasterizerState().rasterizerDiscard && usesPointSize) + { + ID3D11PixelShader *pixelShader = ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader(); + ASSERT(reinterpret_cast(pixelShader) == mAppliedPixelShader); + mDeviceContext->PSSetShader(pixelShader, NULL, 0); + + // Retrieve the point sprite geometry shader + rx::ShaderExecutableD3D *geometryExe = programD3D->getGeometryExecutable(); + ID3D11GeometryShader *geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); + mAppliedGeometryShader = reinterpret_cast(geometryShader); + ASSERT(geometryShader); + mDeviceContext->GSSetShader(geometryShader, NULL, 0); + + if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + } + + return gl::Error(GL_NO_ERROR); + } + else if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, GL_NONE, NULL, 0, NULL); + } + else if (mode == GL_TRIANGLE_FAN) + { + return drawTriangleFan(count, GL_NONE, NULL, 0, NULL, instances); + } + else if (instances > 0) + { + mDeviceContext->DrawInstanced(count, instances, 0, 0); + return gl::Error(GL_NO_ERROR); + } + else + { + // If gl_PointSize is used and GL_POINTS is specified, then it is expected to render pointsprites. + // If instanced pointsprite emulation is being used the topology is expexted to be + // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST and DrawIndexedInstanced must be used. + if (mode == GL_POINTS && useInstancedPointSpriteEmulation) + { + mDeviceContext->DrawIndexedInstanced(6, count, 0, 0, 0); + } + else + { + mDeviceContext->Draw(count, 0); + } + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) +{ + int minIndex = static_cast(indexInfo.indexRange.start); + + if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); + } + else if (mode == GL_TRIANGLE_FAN) + { + return drawTriangleFan(count, type, indices, minIndex, elementArrayBuffer, instances); + } + else if (instances > 0) + { + mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0); + return gl::Error(GL_NO_ERROR); + } + else + { + mDeviceContext->DrawIndexed(count, 0, -minIndex); + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; + } + + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } + } + + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + } + + const unsigned int spaceNeeded = (static_cast(count) + 1) * sizeof(unsigned int); + gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset; + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + unsigned int *data = reinterpret_cast(mappedMemory); + unsigned int indexBufferOffset = offset; + + 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(); + } + + error = mLineLoopIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + + IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); + ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + { + mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); + mAppliedIB = d3dIndexBuffer; + mAppliedIBFormat = indexFormat; + mAppliedIBOffset = indexBufferOffset; + } + + mDeviceContext->DrawIndexed(count + 1, 0, -minIndex); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; + } + + if (!mTriangleFanIB) + { + mTriangleFanIB = new StreamingIndexBufferInterface(this); + gl::Error error = mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mTriangleFanIB); + return error; + } + } + + // Checked by Renderer11::applyPrimitiveType + ASSERT(count >= 3); + + const unsigned int numTris = count - 2; + + if (numTris > (std::numeric_limits::max() / (sizeof(unsigned int) * 3))) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); + } + + const unsigned int spaceNeeded = (numTris * 3) * sizeof(unsigned int); + gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset; + error = mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + unsigned int *data = reinterpret_cast(mappedMemory); + unsigned int indexBufferOffset = offset; + + switch (type) + { + case GL_NONE: // Non-indexed draw + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = 0; + data[i*3 + 1] = i + 1; + data[i*3 + 2] = i + 2; + } + break; + case GL_UNSIGNED_BYTE: + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = static_cast(indices)[0]; + data[i*3 + 1] = static_cast(indices)[i + 1]; + data[i*3 + 2] = static_cast(indices)[i + 2]; + } + break; + case GL_UNSIGNED_SHORT: + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = static_cast(indices)[0]; + data[i*3 + 1] = static_cast(indices)[i + 1]; + data[i*3 + 2] = static_cast(indices)[i + 2]; + } + break; + case GL_UNSIGNED_INT: + for (unsigned int i = 0; i < numTris; i++) + { + data[i*3 + 0] = static_cast(indices)[0]; + data[i*3 + 1] = static_cast(indices)[i + 1]; + data[i*3 + 2] = static_cast(indices)[i + 2]; + } + break; + default: UNREACHABLE(); + } + + error = mTriangleFanIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + + IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer()); + ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); + DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); + + if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) + { + mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); + mAppliedIB = d3dIndexBuffer; + mAppliedIBFormat = indexFormat; + mAppliedIBOffset = indexBufferOffset; + } + + if (instances > 0) + { + mDeviceContext->DrawIndexedInstanced(numTris * 3, instances, 0, -minIndex, 0); + } + else + { + mDeviceContext->DrawIndexed(numTris * 3, 0, -minIndex); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) +{ + ProgramD3D *programD3D = GetImplAs(program); + + ShaderExecutableD3D *vertexExe = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); + if (error.isError()) + { + return error; + } + + ShaderExecutableD3D *pixelExe = NULL; + error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + if (error.isError()) + { + return error; + } + + ShaderExecutableD3D *geometryExe = programD3D->getGeometryExecutable(); + + ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL); + + ID3D11PixelShader *pixelShader = NULL; + // Skip pixel shader if we're doing rasterizer discard. + if (!rasterizerDiscard) + { + pixelShader = (pixelExe ? ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader() : NULL); + } + + ID3D11GeometryShader *geometryShader = NULL; + if (transformFeedbackActive) + { + geometryShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getStreamOutShader() : NULL); + } + else if (mCurRasterState.pointDrawMode) + { + geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); + } + + bool dirtyUniforms = false; + + if (reinterpret_cast(vertexShader) != mAppliedVertexShader) + { + mDeviceContext->VSSetShader(vertexShader, NULL, 0); + mAppliedVertexShader = reinterpret_cast(vertexShader); + dirtyUniforms = true; + } + + if (reinterpret_cast(geometryShader) != mAppliedGeometryShader) + { + mDeviceContext->GSSetShader(geometryShader, NULL, 0); + mAppliedGeometryShader = reinterpret_cast(geometryShader); + dirtyUniforms = true; + } + + if (reinterpret_cast(pixelShader) != mAppliedPixelShader) + { + mDeviceContext->PSSetShader(pixelShader, NULL, 0); + mAppliedPixelShader = reinterpret_cast(pixelShader); + dirtyUniforms = true; + } + + if (dirtyUniforms) + { + programD3D->dirtyAllUniforms(); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) +{ + unsigned int totalRegisterCountVS = 0; + unsigned int totalRegisterCountPS = 0; + + bool vertexUniformsDirty = false; + bool pixelUniformsDirty = false; + + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + const gl::LinkedUniform &uniform = *uniformArray[uniformIndex]; + + if (uniform.isReferencedByVertexShader() && !uniform.isSampler()) + { + totalRegisterCountVS += uniform.registerCount; + vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty); + } + + if (uniform.isReferencedByFragmentShader() && !uniform.isSampler()) + { + totalRegisterCountPS += uniform.registerCount; + pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty); + } + } + + const ProgramD3D *programD3D = GetAs(&program); + const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getVertexUniformStorage()); + const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getFragmentUniformStorage()); + ASSERT(vertexUniformStorage); + ASSERT(fragmentUniformStorage); + + ID3D11Buffer *vertexConstantBuffer = vertexUniformStorage->getConstantBuffer(); + ID3D11Buffer *pixelConstantBuffer = fragmentUniformStorage->getConstantBuffer(); + + float (*mapVS)[4] = NULL; + float (*mapPS)[4] = NULL; + + if (totalRegisterCountVS > 0 && vertexUniformsDirty) + { + D3D11_MAPPED_SUBRESOURCE map = {0}; + HRESULT result = mDeviceContext->Map(vertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + mapVS = (float(*)[4])map.pData; + } + + if (totalRegisterCountPS > 0 && pixelUniformsDirty) + { + D3D11_MAPPED_SUBRESOURCE map = {0}; + HRESULT result = mDeviceContext->Map(pixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + mapPS = (float(*)[4])map.pData; + } + + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + gl::LinkedUniform *uniform = uniformArray[uniformIndex]; + + if (!uniform->isSampler()) + { + unsigned int componentCount = (4 - uniform->registerElement); + + // we assume that uniforms from structs are arranged in struct order in our uniforms list. otherwise we would + // overwrite previously written regions of memory. + + if (uniform->isReferencedByVertexShader() && mapVS) + { + memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); + } + + if (uniform->isReferencedByFragmentShader() && mapPS) + { + memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); + } + } + } + + if (mapVS) + { + mDeviceContext->Unmap(vertexConstantBuffer, 0); + } + + if (mapPS) + { + mDeviceContext->Unmap(pixelConstantBuffer, 0); + } + + if (mCurrentVertexConstantBuffer != vertexConstantBuffer) + { + mDeviceContext->VSSetConstantBuffers(0, 1, &vertexConstantBuffer); + mCurrentVertexConstantBuffer = vertexConstantBuffer; + } + + if (mCurrentPixelConstantBuffer != pixelConstantBuffer) + { + mDeviceContext->PSSetConstantBuffers(0, 1, &pixelConstantBuffer); + mCurrentPixelConstantBuffer = pixelConstantBuffer; + } + + // Driver uniforms + if (!mDriverConstantBufferVS) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants); + constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = 0; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS); + } + + if (!mDriverConstantBufferPS) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants); + constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = 0; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + + mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS); + } + + if (memcmp(&mVertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0) + { + mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &mVertexConstants, 16, 0); + memcpy(&mAppliedVertexConstants, &mVertexConstants, sizeof(dx_VertexConstants)); + } + + if (memcmp(&mPixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0) + { + mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &mPixelConstants, 16, 0); + memcpy(&mAppliedPixelConstants, &mPixelConstants, sizeof(dx_PixelConstants)); + } + + // GSSetConstantBuffers triggers device removal on 9_3, so we should only call it if necessary + if (programD3D->usesGeometryShader()) + { + // needed for the point sprite geometry shader + if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) + { + mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); + mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer11::markAllStateDirty() +{ + for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++) + { + mAppliedRTVs[rtIndex] = DirtyPointer; + } + mAppliedDSV = DirtyPointer; + mDepthStencilInitialized = false; + mRenderTargetDescInitialized = false; + + // We reset the current SRV data because it might not be in sync with D3D's state + // anymore. For example when a currently used SRV is used as an RTV, D3D silently + // remove it from its state. + memset(mCurVertexSRVs.data(), 0, sizeof(SRVRecord) * mCurVertexSRVs.size()); + memset(mCurPixelSRVs.data(), 0, sizeof(SRVRecord) * mCurPixelSRVs.size()); + + ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexSRVs.size()); + for (size_t vsamplerId = 0; vsamplerId < mForceSetVertexSamplerStates.size(); ++vsamplerId) + { + mForceSetVertexSamplerStates[vsamplerId] = true; + } + + ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelSRVs.size()); + for (size_t fsamplerId = 0; fsamplerId < mForceSetPixelSamplerStates.size(); ++fsamplerId) + { + mForceSetPixelSamplerStates[fsamplerId] = true; + } + + mForceSetBlendState = true; + mForceSetRasterState = true; + mForceSetDepthStencilState = true; + mForceSetScissor = true; + mForceSetViewport = true; + + mAppliedIB = NULL; + mAppliedIBFormat = DXGI_FORMAT_UNKNOWN; + mAppliedIBOffset = 0; + + mAppliedVertexShader = DirtyPointer; + mAppliedGeometryShader = DirtyPointer; + mAppliedPixelShader = DirtyPointer; + + mAppliedNumXFBBindings = static_cast(-1); + + for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + { + mAppliedTFBuffers[i] = NULL; + mAppliedTFOffsets[i] = 0; + } + + memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants)); + memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants)); + + mInputLayoutCache.markDirty(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; i++) + { + mCurrentConstantBufferVS[i] = static_cast(-1); + mCurrentConstantBufferVSOffset[i] = 0; + mCurrentConstantBufferVSSize[i] = 0; + mCurrentConstantBufferPS[i] = static_cast(-1); + mCurrentConstantBufferPSOffset[i] = 0; + mCurrentConstantBufferPSSize[i] = 0; + } + + mCurrentVertexConstantBuffer = NULL; + mCurrentPixelConstantBuffer = NULL; + mCurrentGeometryConstantBuffer = NULL; + + mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; +} + +void Renderer11::releaseDeviceResources() +{ + mStateCache.clear(); + mInputLayoutCache.clear(); + + SafeDelete(mVertexDataManager); + SafeDelete(mIndexDataManager); + SafeDelete(mLineLoopIB); + SafeDelete(mTriangleFanIB); + SafeDelete(mBlit); + SafeDelete(mClear); + SafeDelete(mTrim); + SafeDelete(mPixelTransfer); + + SafeRelease(mDriverConstantBufferVS); + SafeRelease(mDriverConstantBufferPS); + SafeRelease(mSyncQuery); +} + +// set notify to true to broadcast a message to all contexts of the device loss +bool Renderer11::testDeviceLost() +{ + bool isLost = false; + + // GetRemovedReason is used to test if the device is removed + HRESULT result = mDevice->GetDeviceRemovedReason(); + isLost = d3d11::isDeviceLostError(result); + + if (isLost) + { + // Log error if this is a new device lost event + if (mDeviceLost == false) + { + ERR("The D3D11 device was removed: 0x%08X", result); + } + + // ensure we note the device loss -- + // we'll probably get this done again by notifyDeviceLost + // but best to remember it! + // Note that we don't want to clear the device loss status here + // -- this needs to be done by resetDevice + mDeviceLost = true; + } + + return isLost; +} + +bool Renderer11::testDeviceResettable() +{ + // determine if the device is resettable by creating a dummy device + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + + if (D3D11CreateDevice == NULL) + { + return false; + } + + ID3D11Device* dummyDevice; + D3D_FEATURE_LEVEL dummyFeatureLevel; + ID3D11DeviceContext* dummyContext; + + HRESULT result = D3D11CreateDevice(NULL, + mDriverType, + NULL, + #if defined(_DEBUG) + D3D11_CREATE_DEVICE_DEBUG, + #else + 0, + #endif + mAvailableFeatureLevels.data(), + mAvailableFeatureLevels.size(), + D3D11_SDK_VERSION, + &dummyDevice, + &dummyFeatureLevel, + &dummyContext); + + if (!mDevice || FAILED(result)) + { + return false; + } + + SafeRelease(dummyContext); + SafeRelease(dummyDevice); + + return true; +} + +void Renderer11::release() +{ + RendererD3D::cleanup(); + + releaseDeviceResources(); + + SafeRelease(mDxgiFactory); + SafeRelease(mDxgiAdapter); + +#if defined(ANGLE_ENABLE_D3D11_1) + SafeRelease(mDeviceContext1); +#endif + + if (mDeviceContext) + { + mDeviceContext->ClearState(); + mDeviceContext->Flush(); + SafeRelease(mDeviceContext); + } + + SafeRelease(mDevice); + + if (mD3d11Module) + { + FreeLibrary(mD3d11Module); + mD3d11Module = NULL; + } + + if (mDxgiModule) + { + FreeLibrary(mDxgiModule); + mDxgiModule = NULL; + } + + mCompiler.release(); +} + +bool Renderer11::resetDevice() +{ + // recreate everything + release(); + egl::Error result = initialize(); + + if (result.isError()) + { + ERR("Could not reinitialize D3D11 device: %08X", result.getCode()); + return false; + } + + mDeviceLost = false; + + return true; +} + +VendorID Renderer11::getVendorId() const +{ + return static_cast(mAdapterDescription.VendorId); +} + +std::string Renderer11::getRendererDescription() const +{ + std::ostringstream rendererString; + + rendererString << mDescription; + rendererString << " Direct3D11"; + + rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel() << getShaderModelSuffix(); + rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel() << getShaderModelSuffix(); + + return rendererString.str(); +} + +GUID Renderer11::getAdapterIdentifier() const +{ + // Use the adapter LUID as our adapter ID + // This number is local to a machine is only guaranteed to be unique between restarts + static_assert(sizeof(LUID) <= sizeof(GUID), "Size of GUID must be at least as large as LUID."); + GUID adapterId = {0}; + memcpy(&adapterId, &mAdapterDescription.AdapterLuid, sizeof(LUID)); + return adapterId; +} + +unsigned int Renderer11::getReservedVertexUniformVectors() const +{ + return 0; // Driver uniforms are stored in a separate constant buffer +} + +unsigned int Renderer11::getReservedFragmentUniformVectors() const +{ + return 0; // Driver uniforms are stored in a separate constant buffer +} + +unsigned int Renderer11::getReservedVertexUniformBuffers() const +{ + // we reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +unsigned int Renderer11::getReservedFragmentUniformBuffers() const +{ + // we reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +bool Renderer11::getShareHandleSupport() const +{ + // We only currently support share handles with BGRA surfaces, because + // chrome needs BGRA. Once chrome fixes this, we should always support them. + // PIX doesn't seem to support using share handles, so disable them. + // Also disable share handles on Feature Level 9_3, since it doesn't support share handles on RGBA8 textures/swapchains. + return getRendererExtensions().textureFormatBGRA8888 && !gl::DebugAnnotationsActive();// && !(mFeatureLevel <= D3D_FEATURE_LEVEL_9_3); Qt: we don't care about the 9_3 limitation +} + +bool Renderer11::getPostSubBufferSupport() const +{ + // D3D11 does not support present with dirty rectangles until D3D11.1 and DXGI 1.2. + return false; +} + +int Renderer11::getMajorShaderModel() const +{ + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 + case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MAJOR_VERSION; // 4 + case D3D_FEATURE_LEVEL_9_3: return D3D10_SHADER_MAJOR_VERSION; // 4 + default: UNREACHABLE(); return 0; + } +} + +int Renderer11::getMinorShaderModel() const +{ + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 + case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MINOR_VERSION; // 0 + case D3D_FEATURE_LEVEL_9_3: return D3D10_SHADER_MINOR_VERSION; // 0 + default: UNREACHABLE(); return 0; + } +} + +std::string Renderer11::getShaderModelSuffix() const +{ + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: return ""; + case D3D_FEATURE_LEVEL_10_1: return ""; + case D3D_FEATURE_LEVEL_10_0: return ""; + case D3D_FEATURE_LEVEL_9_3: return "_level_9_3"; + default: UNREACHABLE(); return ""; + } +} + +gl::Error Renderer11::copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + RenderTargetD3D *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(dest); + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + RenderTargetD3D *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(dest); + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::Make3D(level, destOffset.z); + RenderTargetD3D *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(dest); + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z); + RenderTargetD3D *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(dest); + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(destOffset.x, destOffset.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); +} + +void Renderer11::unapplyRenderTargets() +{ + setOneTimeRenderTarget(NULL); +} + +// When finished with this rendertarget, markAllStateDirty must be called. +void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView) +{ + ID3D11RenderTargetView *rtvArray[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; + + rtvArray[0] = renderTargetView; + + mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, rtvArray, NULL); + + // Do not preserve the serial for this one-time-use render target + for (size_t rtIndex = 0; rtIndex < ArraySize(mAppliedRTVs); rtIndex++) + { + mAppliedRTVs[rtIndex] = DirtyPointer; + } + mAppliedDSV = DirtyPointer; +} + +gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) +{ + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format, mFeatureLevel); + + const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); + + if (width > 0 && height > 0) + { + // Create texture resource + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = formatInfo.texFormat; + desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + // If a rendertarget or depthstencil format exists for this texture format, + // we'll flag it to allow binding that way. Shader resource views are a little + // more complicated. + bool bindRTV = false, bindDSV = false, bindSRV = false; + bindRTV = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); + bindDSV = (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); + if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + // Multisample targets flagged for binding as depth stencil cannot also be + // flagged for binding as SRV, so make certain not to add the SRV flag for + // these targets. + bindSRV = !(formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1); + } + + desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | + (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | + (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0); + + // The format must be either an RTV or a DSV + ASSERT(bindRTV != bindDSV); + + ID3D11Texture2D *texture = NULL; + HRESULT result = mDevice->CreateTexture2D(&desc, NULL, &texture); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target texture, result: 0x%X.", result); + } + + ID3D11ShaderResourceView *srv = NULL; + if (bindSRV) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = formatInfo.srvFormat; + srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = 1; + + result = mDevice->CreateShaderResourceView(texture, &srvDesc, &srv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target shader resource view, result: 0x%X.", result); + } + } + + if (bindDSV) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = formatInfo.dsvFormat; + dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; + dsvDesc.Texture2D.MipSlice = 0; + dsvDesc.Flags = 0; + + ID3D11DepthStencilView *dsv = NULL; + result = mDevice->CreateDepthStencilView(texture, &dsvDesc, &dsv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target depth stencil view, result: 0x%X.", result); + } + + *outRT = new TextureRenderTarget11(dsv, texture, srv, format, width, height, 1, supportedSamples); + + SafeRelease(dsv); + } + else if (bindRTV) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = formatInfo.rtvFormat; + rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; + rtvDesc.Texture2D.MipSlice = 0; + + ID3D11RenderTargetView *rtv = NULL; + result = mDevice->CreateRenderTargetView(texture, &rtvDesc, &rtv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target render target view, result: 0x%X.", result); + } + + if (formatInfo.dataInitializerFunction != NULL) + { + const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + mDeviceContext->ClearRenderTargetView(rtv, clearValues); + } + + *outRT = new TextureRenderTarget11(rtv, texture, srv, format, width, height, 1, supportedSamples); + + SafeRelease(rtv); + } + else + { + UNREACHABLE(); + } + + SafeRelease(texture); + SafeRelease(srv); + } + else + { + *outRT = new TextureRenderTarget11(reinterpret_cast(NULL), NULL, NULL, format, width, height, 1, supportedSamples); + } + + return gl::Error(GL_NO_ERROR); +} + +FramebufferImpl *Renderer11::createDefaultFramebuffer(const gl::Framebuffer::Data &data) +{ + return createFramebuffer(data); +} + +FramebufferImpl *Renderer11::createFramebuffer(const gl::Framebuffer::Data &data) +{ + return new Framebuffer11(data, this); +} + +CompilerImpl *Renderer11::createCompiler(const gl::Data &data) +{ + return new CompilerD3D(data, SH_HLSL11_OUTPUT); +} + +ShaderImpl *Renderer11::createShader(GLenum type) +{ + return new ShaderD3D(type); +} + +ProgramImpl *Renderer11::createProgram() +{ + return new ProgramD3D(this); +} + +gl::Error Renderer11::loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) +{ + switch (type) + { + case SHADER_VERTEX: + { + ID3D11VertexShader *vertexShader = NULL; + ID3D11GeometryShader *streamOutShader = NULL; + + HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result); + } + + if (transformFeedbackVaryings.size() > 0) + { + std::vector soDeclaration; + for (size_t i = 0; i < transformFeedbackVaryings.size(); i++) + { + const gl::LinkedVarying &varying = transformFeedbackVaryings[i]; + GLenum transposedType = gl::TransposeMatrixType(varying.type); + + for (size_t j = 0; j < varying.semanticIndexCount; j++) + { + D3D11_SO_DECLARATION_ENTRY entry = { 0 }; + entry.Stream = 0; + entry.SemanticName = varying.semanticName.c_str(); + entry.SemanticIndex = varying.semanticIndex + j; + entry.StartComponent = 0; + entry.ComponentCount = gl::VariableColumnCount(transposedType); + entry.OutputSlot = (separatedOutputBuffers ? i : 0); + soDeclaration.push_back(entry); + } + } + + result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(), + NULL, 0, 0, NULL, &streamOutShader); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create steam output shader, result: 0x%X.", result); + } + } + + *outExecutable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); + } + break; + case SHADER_PIXEL: + { + ID3D11PixelShader *pixelShader = NULL; + + HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.", result); + } + + *outExecutable = new ShaderExecutable11(function, length, pixelShader); + } + break; + case SHADER_GEOMETRY: + { + ID3D11GeometryShader *geometryShader = NULL; + + HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create geometry shader, result: 0x%X.", result); + } + + *outExecutable = new ShaderExecutable11(function, length, geometryShader); + } + break; + default: + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable) +{ + const char *profileType = NULL; + switch (type) + { + case SHADER_VERTEX: + profileType = "vs"; + break; + case SHADER_PIXEL: + profileType = "ps"; + break; + case SHADER_GEOMETRY: + profileType = "gs"; + break; + default: + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + std::string profile = FormatString("%s_%d_%d%s", profileType, getMajorShaderModel(), getMinorShaderModel(), getShaderModelSuffix().c_str()); + + UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2; + + if (gl::DebugAnnotationsActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + } + + if (workarounds.enableIEEEStrictness) + flags |= D3DCOMPILE_IEEE_STRICTNESS; + + // 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. + std::vector configs; + configs.push_back(CompileConfig(flags, "default" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization")); + + D3D_SHADER_MACRO loopMacros[] = { {"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0} }; + + ID3DBlob *binary = NULL; + std::string debugInfo; + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary, &debugInfo); + if (error.isError()) + { + return error; + } + + // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL + // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. + if (!binary) + { + *outExectuable = NULL; + return gl::Error(GL_NO_ERROR); + } + + error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers, outExectuable); + + SafeRelease(binary); + if (error.isError()) + { + return error; + } + + if (!debugInfo.empty()) + { + (*outExectuable)->appendDebugInfo(debugInfo); + } + + return gl::Error(GL_NO_ERROR); +} + +UniformStorageD3D *Renderer11::createUniformStorage(size_t storageSize) +{ + return new UniformStorage11(this, storageSize); +} + +VertexBuffer *Renderer11::createVertexBuffer() +{ + return new VertexBuffer11(this); +} + +IndexBuffer *Renderer11::createIndexBuffer() +{ + return new IndexBuffer11(this); +} + +BufferImpl *Renderer11::createBuffer() +{ + return new Buffer11(this); +} + +VertexArrayImpl *Renderer11::createVertexArray() +{ + return new VertexArray11(this); +} + +QueryImpl *Renderer11::createQuery(GLenum type) +{ + return new Query11(this, type); +} + +FenceNVImpl *Renderer11::createFenceNV() +{ + return new FenceNV11(this); +} + +FenceSyncImpl *Renderer11::createFenceSync() +{ + return new FenceSync11(this); +} + +TransformFeedbackImpl* Renderer11::createTransformFeedback() +{ + return new TransformFeedbackD3D(); +} + +bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const +{ + ASSERT(getRendererExtensions().pixelBufferObject); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + const d3d11::TextureFormat &d3d11FormatInfo = d3d11::GetTextureFormatInfo(internalFormat, mFeatureLevel); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11FormatInfo.texFormat); + + // sRGB formats do not work with D3D11 buffer SRVs + if (internalFormatInfo.colorEncoding == GL_SRGB) + { + return false; + } + + // We cannot support direct copies to non-color-renderable formats + if (d3d11FormatInfo.rtvFormat == DXGI_FORMAT_UNKNOWN) + { + return false; + } + + // We skip all 3-channel formats since sometimes format support is missing + if (internalFormatInfo.componentCount == 3) + { + return false; + } + + // We don't support formats which we can't represent without conversion + if (dxgiFormatInfo.internalFormat != internalFormat) + { + return false; + } + + return true; +} + +gl::Error Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + ASSERT(supportsFastCopyBufferToTexture(destinationFormat)); + return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea); +} + +ImageD3D *Renderer11::createImage() +{ + return new Image11(this); +} + +gl::Error Renderer11::generateMipmap(ImageD3D *dest, ImageD3D *src) +{ + Image11 *dest11 = Image11::makeImage11(dest); + Image11 *src11 = Image11::makeImage11(src); + return Image11::generateMipmap(dest11, src11); +} + +TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain) +{ + SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); + return new TextureStorage11_2D(this, swapChain11); +} + +TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) +{ + return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels, hintLevelZeroOnly); +} + +TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) +{ + return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly); +} + +TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, levels); +} + +TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, levels); +} + +TextureImpl *Renderer11::createTexture(GLenum target) +{ + switch(target) + { + case GL_TEXTURE_2D: return new TextureD3D_2D(this); + case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); + case GL_TEXTURE_3D: return new TextureD3D_3D(this); + case GL_TEXTURE_2D_ARRAY: return new TextureD3D_2DArray(this); + default: + UNREACHABLE(); + } + + return NULL; +} + +RenderbufferImpl *Renderer11::createRenderbuffer() +{ + RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); + return renderbuffer; +} + +gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) +{ + ASSERT(area.width >= 0); + ASSERT(area.height >= 0); + + D3D11_TEXTURE2D_DESC textureDesc; + texture->GetDesc(&textureDesc); + + // Clamp read region to the defined texture boundaries, preventing out of bounds reads + // and reads of uninitialized data. + gl::Rectangle safeArea; + safeArea.x = gl::clamp(area.x, 0, static_cast(textureDesc.Width)); + safeArea.y = gl::clamp(area.y, 0, static_cast(textureDesc.Height)); + safeArea.width = gl::clamp(area.width + std::min(area.x, 0), 0, + static_cast(textureDesc.Width) - safeArea.x); + safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0, + static_cast(textureDesc.Height) - safeArea.y); + + ASSERT(safeArea.x >= 0 && safeArea.y >= 0); + ASSERT(safeArea.x + safeArea.width <= static_cast(textureDesc.Width)); + ASSERT(safeArea.y + safeArea.height <= static_cast(textureDesc.Height)); + + if (safeArea.width == 0 || safeArea.height == 0) + { + // no work to do + return gl::Error(GL_NO_ERROR); + } + + D3D11_TEXTURE2D_DESC stagingDesc; + stagingDesc.Width = safeArea.width; + stagingDesc.Height = safeArea.height; + stagingDesc.MipLevels = 1; + stagingDesc.ArraySize = 1; + stagingDesc.Format = textureDesc.Format; + stagingDesc.SampleDesc.Count = 1; + stagingDesc.SampleDesc.Quality = 0; + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.BindFlags = 0; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingDesc.MiscFlags = 0; + + ID3D11Texture2D* stagingTex = NULL; + HRESULT result = mDevice->CreateTexture2D(&stagingDesc, NULL, &stagingTex); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging texture for ReadPixels, HRESULT: 0x%X.", result); + } + + ID3D11Texture2D* srcTex = NULL; + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + result = mDevice->CreateTexture2D(&resolveDesc, NULL, &srcTex); + if (FAILED(result)) + { + SafeRelease(stagingTex); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal resolve texture for ReadPixels, HRESULT: 0x%X.", result); + } + + mDeviceContext->ResolveSubresource(srcTex, 0, texture, subResource, textureDesc.Format); + subResource = 0; + } + else + { + srcTex = texture; + srcTex->AddRef(); + } + + D3D11_BOX srcBox; + srcBox.left = static_cast(safeArea.x); + srcBox.right = static_cast(safeArea.x + safeArea.width); + srcBox.top = static_cast(safeArea.y); + srcBox.bottom = static_cast(safeArea.y + safeArea.height); + srcBox.front = 0; + srcBox.back = 1; + + mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox); + + SafeRelease(srcTex); + + PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); + gl::Error error = packPixels(stagingTex, packParams, pixels); + + SafeRelease(stagingTex); + + return error; +} + +gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut) +{ + D3D11_TEXTURE2D_DESC textureDesc; + readTexture->GetDesc(&textureDesc); + + D3D11_MAPPED_SUBRESOURCE mapping; + HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping); + if (FAILED(hr)) + { + ASSERT(hr == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal texture for reading, result: 0x%X.", hr); + } + + uint8_t *source; + int inputPitch; + if (params.pack.reverseRowOrder) + { + source = static_cast(mapping.pData) + mapping.RowPitch * (params.area.height - 1); + inputPitch = -static_cast(mapping.RowPitch); + } + else + { + source = static_cast(mapping.pData); + inputPitch = static_cast(mapping.RowPitch); + } + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format); + const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); + if (sourceFormatInfo.format == params.format && sourceFormatInfo.type == params.type) + { + uint8_t *dest = pixelsOut + params.offset; + for (int y = 0; y < params.area.height; y++) + { + memcpy(dest + y * params.outputPitch, source + y * inputPitch, params.area.width * sourceFormatInfo.pixelBytes); + } + } + else + { + const d3d11::DXGIFormat &sourceDXGIFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format); + ColorCopyFunction fastCopyFunc = sourceDXGIFormatInfo.getFastCopyFunction(params.format, params.type); + + GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(params.format, params.type); + const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat); + + if (fastCopyFunc) + { + // Fast copy is possible through some special function + for (int y = 0; y < params.area.height; y++) + { + for (int x = 0; x < params.area.width; x++) + { + uint8_t *dest = pixelsOut + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + fastCopyFunc(src, dest); + } + } + } + else + { + ColorReadFunction colorReadFunction = sourceDXGIFormatInfo.colorReadFunction; + ColorWriteFunction colorWriteFunction = GetColorWriteFunction(params.format, params.type); + + uint8_t temp[16]; // Maximum size of any Color type used. + static_assert(sizeof(temp) >= sizeof(gl::ColorF) && + sizeof(temp) >= sizeof(gl::ColorUI) && + sizeof(temp) >= sizeof(gl::ColorI), + "Unexpected size of gl::Color struct."); + + for (int y = 0; y < params.area.height; y++) + { + for (int x = 0; x < params.area.width; x++) + { + uint8_t *dest = pixelsOut + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + colorReadFunction(src, temp); + colorWriteFunction(temp, dest); + } + } + } + } + + mDeviceContext->Unmap(readTexture, 0); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTargetD3D *readRenderTarget, + RenderTargetD3D *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, + bool colorBlit, bool depthBlit, bool stencilBlit) +{ + // Since blitRenderbufferRect is called for each render buffer that needs to be blitted, + // it should never be the case that both color and depth/stencil need to be blitted at + // at the same time. + ASSERT(colorBlit != (depthBlit || stencilBlit)); + + RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget); + if (!drawRenderTarget) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal draw render target from the draw framebuffer."); + } + + ID3D11Resource *drawTexture = drawRenderTarget11->getTexture(); + unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); + ID3D11RenderTargetView *drawRTV = drawRenderTarget11->getRenderTargetView(); + ID3D11DepthStencilView *drawDSV = drawRenderTarget11->getDepthStencilView(); + + RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget); + if (!readRenderTarget) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target from the read framebuffer."); + } + + ID3D11Resource *readTexture = NULL; + ID3D11ShaderResourceView *readSRV = NULL; + unsigned int readSubresource = 0; + if (readRenderTarget->getSamples() > 0) + { + ID3D11Resource *unresolvedResource = readRenderTarget11->getTexture(); + ID3D11Texture2D *unresolvedTexture = d3d11::DynamicCastComObject(unresolvedResource); + + if (unresolvedTexture) + { + readTexture = resolveMultisampledTexture(unresolvedTexture, readRenderTarget11->getSubresourceIndex()); + readSubresource = 0; + + SafeRelease(unresolvedTexture); + + HRESULT hresult = mDevice->CreateShaderResourceView(readTexture, NULL, &readSRV); + if (FAILED(hresult)) + { + SafeRelease(readTexture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader resource view to resolve multisampled framebuffer."); + } + } + } + else + { + readTexture = readRenderTarget11->getTexture(); + readTexture->AddRef(); + readSubresource = readRenderTarget11->getSubresourceIndex(); + readSRV = readRenderTarget11->getShaderResourceView(); + readSRV->AddRef(); + } + + if (!readTexture || !readSRV) + { + SafeRelease(readTexture); + SafeRelease(readSRV); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target view from the read render target."); + } + + gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + + bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL); + + bool wholeBufferCopy = !scissorNeeded && + readRect.x == 0 && readRect.width == readSize.width && + readRect.y == 0 && readRect.height == readSize.height && + drawRect.x == 0 && drawRect.width == drawSize.width && + drawRect.y == 0 && drawRect.height == drawSize.height; + + bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height; + + bool flipRequired = readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || drawRect.height < 0; + + bool outOfBounds = readRect.x < 0 || readRect.x + readRect.width > readSize.width || + readRect.y < 0 || readRect.y + readRect.height > readSize.height || + drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width || + drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height; + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(drawRenderTarget11->getDXGIFormat()); + bool partialDSBlit = (dxgiFormatInfo.depthBits > 0 && depthBlit) != (dxgiFormatInfo.stencilBits > 0 && stencilBlit); + + gl::Error result(GL_NO_ERROR); + + if (readRenderTarget11->getDXGIFormat() == drawRenderTarget11->getDXGIFormat() && + !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit && + (!(depthBlit || stencilBlit) || wholeBufferCopy)) + { + UINT dstX = drawRect.x; + UINT dstY = drawRect.y; + + D3D11_BOX readBox; + readBox.left = readRect.x; + readBox.right = readRect.x + readRect.width; + readBox.top = readRect.y; + readBox.bottom = readRect.y + readRect.height; + readBox.front = 0; + readBox.back = 1; + + if (scissorNeeded) + { + // drawRect is guaranteed to have positive width and height because stretchRequired is false. + ASSERT(drawRect.width >= 0 || drawRect.height >= 0); + + if (drawRect.x < scissor->x) + { + dstX = scissor->x; + readBox.left += (scissor->x - drawRect.x); + } + if (drawRect.y < scissor->y) + { + dstY = scissor->y; + readBox.top += (scissor->y - drawRect.y); + } + if (drawRect.x + drawRect.width > scissor->x + scissor->width) + { + readBox.right -= ((drawRect.x + drawRect.width) - (scissor->x + scissor->width)); + } + if (drawRect.y + drawRect.height > scissor->y + scissor->height) + { + readBox.bottom -= ((drawRect.y + drawRect.height) - (scissor->y + scissor->height)); + } + } + + // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox + // We also require complete framebuffer copies for depth-stencil blit. + D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox; + + mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0, + readTexture, readSubresource, pSrcBox); + result = gl::Error(GL_NO_ERROR); + } + else + { + gl::Box readArea(readRect.x, readRect.y, 0, readRect.width, readRect.height, 1); + gl::Box drawArea(drawRect.x, drawRect.y, 0, drawRect.width, drawRect.height, 1); + + if (depthBlit && stencilBlit) + { + result = mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor); + } + else if (depthBlit) + { + result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize, + scissor); + } + else if (stencilBlit) + { + result = mBlit->copyStencil(readTexture, readSubresource, readArea, readSize, + drawTexture, drawSubresource, drawArea, drawSize, + scissor); + } + else + { + GLenum format = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()).format; + result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize, + scissor, format, filter); + } + } + + SafeRelease(readTexture); + SafeRelease(readSRV); + + return result; +} + +bool Renderer11::isES3Capable() const +{ + return (d3d11_gl::GetMaximumClientVersion(mFeatureLevel) > 2); +}; + +ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) +{ + D3D11_TEXTURE2D_DESC textureDesc; + source->GetDesc(&textureDesc); + + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = textureDesc.Usage; + resolveDesc.BindFlags = textureDesc.BindFlags; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + ID3D11Texture2D *resolveTexture = NULL; + HRESULT result = mDevice->CreateTexture2D(&resolveDesc, NULL, &resolveTexture); + if (FAILED(result)) + { + ERR("Failed to create a multisample resolve texture, HRESULT: 0x%X.", result); + return NULL; + } + + mDeviceContext->ResolveSubresource(resolveTexture, 0, source, subresource, textureDesc.Format); + return resolveTexture; + } + else + { + source->AddRef(); + return source; + } +} + +bool Renderer11::getLUID(LUID *adapterLuid) const +{ + adapterLuid->HighPart = 0; + adapterLuid->LowPart = 0; + + if (!mDxgiAdapter) + { + return false; + } + + DXGI_ADAPTER_DESC adapterDesc; + if (FAILED(mDxgiAdapter->GetDesc(&adapterDesc))) + { + return false; + } + + *adapterLuid = adapterDesc.AdapterLuid; + return true; +} + +VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel).conversionType; +} + +GLenum Renderer11::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormat, mFeatureLevel).nativeFormat).componentType; +} + +void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +{ + d3d11_gl::GenerateCaps(mDevice, mDeviceContext, outCaps, outTextureCaps, outExtensions); +} + +Workarounds Renderer11::generateWorkarounds() const +{ + return d3d11::GenerateWorkarounds(mFeatureLevel); +} + +void Renderer11::setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv) +{ + auto ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + ASSERT(static_cast(resourceSlot) < currentSRVs.size()); + auto &record = currentSRVs[resourceSlot]; + + if (record.srv != reinterpret_cast(srv)) + { + if (shaderType == gl::SAMPLER_VERTEX) + { + mDeviceContext->VSSetShaderResources(resourceSlot, 1, &srv); + } + else + { + mDeviceContext->PSSetShaderResources(resourceSlot, 1, &srv); + } + + record.srv = reinterpret_cast(srv); + if (srv) + { + record.resource = reinterpret_cast(GetViewResource(srv)); + srv->GetDesc(&record.desc); + } + else + { + record.resource = 0; + } + } +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h new file mode 100644 index 0000000000..cc7d6c237b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h @@ -0,0 +1,400 @@ +// +// Copyright (c) 2012-2014 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. +// + +// Renderer11.h: Defines a back-end specific class for the D3D11 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/AttributeMap.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/HLSLCompiler.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h" +#include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h" + +struct ID3D11DeviceContext1; + +namespace gl +{ +class FramebufferAttachment; +struct ImageIndex; +} + +namespace rx +{ + +class VertexDataManager; +class IndexDataManager; +class StreamingIndexBufferInterface; +class Blit11; +class Clear11; +class PixelTransfer11; +class RenderTarget11; +class Trim11; +struct PackPixelsParams; + +enum +{ + MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, + MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024 +}; + +// Possible reasons RendererD3D initialize can fail +enum D3D11InitError +{ + // The renderer loaded successfully + D3D11_INIT_SUCCESS = 0, + // Failed to load the ANGLE & D3D compiler libraries + D3D11_INIT_COMPILER_ERROR, + // Failed to load a necessary DLL (non-compiler) + D3D11_INIT_MISSING_DEP, + // CreateDevice returned E_INVALIDARG + D3D11_INIT_CREATEDEVICE_INVALIDARG, + // CreateDevice failed with an error other than invalid arg + D3D11_INIT_CREATEDEVICE_ERROR, + // DXGI 1.2 required but not found + D3D11_INIT_INCOMPATIBLE_DXGI, + // Other initialization error + D3D11_INIT_OTHER_ERROR, + NUM_D3D11_INIT_ERRORS +}; + +class Renderer11 : public RendererD3D +{ + public: + explicit Renderer11(egl::Display *display); + virtual ~Renderer11(); + + static Renderer11 *makeRenderer11(Renderer *renderer); + + egl::Error initialize() override; + virtual bool resetDevice(); + + egl::ConfigSet generateConfigs() const override; + + gl::Error flush() override; + gl::Error finish() override; + + virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + + virtual gl::Error generateSwizzle(gl::Texture *texture); + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler); + virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); + + gl::Error setUniformBuffers(const gl::Data &data, + const GLint vertexUniformBuffers[], + const GLint fragmentUniformBuffers[]) override; + + virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); + gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) override; + virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW); + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport); + + virtual bool applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize); + gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; + virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray); + virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances); + virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + void applyTransformFeedbackBuffers(const gl::State &state) override; + + gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override; + virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + + virtual void markAllStateDirty(); + + // lost device + bool testDeviceLost() override; + bool testDeviceResettable() override; + + VendorID getVendorId() const override; + std::string getRendererDescription() const override; + GUID getAdapterIdentifier() const override; + + virtual unsigned int getReservedVertexUniformVectors() const; + virtual unsigned int getReservedFragmentUniformVectors() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + virtual bool getShareHandleSupport() const; + virtual bool getPostSubBufferSupport() const; + + virtual int getMajorShaderModel() const; + int getMinorShaderModel() const override; + std::string getShaderModelSuffix() const override; + + // Pixel operations + virtual gl::Error copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); + virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + + // RenderTarget creation + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT); + + // Framebuffer creation + FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override; + FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override; + + // Shader creation + virtual CompilerImpl *createCompiler(const gl::Data &data); + virtual ShaderImpl *createShader(GLenum type); + virtual ProgramImpl *createProgram(); + + // Shader operations + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable); + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable); + virtual UniformStorageD3D *createUniformStorage(size_t storageSize); + + // Image operations + virtual ImageD3D *createImage(); + gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override; + virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain); + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly); + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + + // Texture creation + virtual TextureImpl *createTexture(GLenum target); + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer(); + + // Buffer creation + virtual BufferImpl *createBuffer(); + virtual VertexBuffer *createVertexBuffer(); + virtual IndexBuffer *createIndexBuffer(); + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(); + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type); + virtual FenceNVImpl *createFenceNV(); + virtual FenceSyncImpl *createFenceSync(); + + // Transform Feedback creation + virtual TransformFeedbackImpl* createTransformFeedback(); + + // D3D11-renderer specific methods + ID3D11Device *getDevice() { return mDevice; } + ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; + ID3D11DeviceContext1 *getDeviceContext1IfSupported() { return mDeviceContext1; }; + DXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + + Blit11 *getBlitter() { return mBlit; } + Clear11 *getClearer() { return mClear; } + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + void unapplyRenderTargets(); + void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); + gl::Error packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut); + + bool getLUID(LUID *adapterLuid) const override; + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; + + gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); + + void setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv); + + gl::Error blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTargetD3D *readRenderTarget, + RenderTargetD3D *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, + bool colorBlit, bool depthBlit, bool stencilBlit); + + bool isES3Capable() const; + D3D_FEATURE_LEVEL getFeatureLevel() const { return mFeatureLevel; }; + + RendererClass getRendererClass() const override { return RENDERER_D3D11; } + + private: + void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override; + Workarounds generateWorkarounds() const override; + + gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances); + + ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); + void unsetConflictingSRVs(gl::SamplerType shaderType, uintptr_t resource, const gl::ImageIndex *index); + + HMODULE mD3d11Module; + HMODULE mDxgiModule; + std::vector mAvailableFeatureLevels; + D3D_DRIVER_TYPE mDriverType; + + HLSLCompiler mCompiler; + + void initializeDevice(); + void releaseDeviceResources(); + void release(); + + RenderStateCache mStateCache; + + // current render target states + uintptr_t mAppliedRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; + uintptr_t mAppliedDSV; + bool mDepthStencilInitialized; + bool mRenderTargetDescInitialized; + + struct RenderTargetDesc + { + size_t width; + size_t height; + DXGI_FORMAT format; + }; + RenderTargetDesc mRenderTargetDesc; + + // Currently applied sampler states + std::vector mForceSetVertexSamplerStates; + std::vector mCurVertexSamplerStates; + + std::vector mForceSetPixelSamplerStates; + std::vector mCurPixelSamplerStates; + + // Currently applied textures + struct SRVRecord + { + uintptr_t srv; + uintptr_t resource; + D3D11_SHADER_RESOURCE_VIEW_DESC desc; + }; + std::vector mCurVertexSRVs; + std::vector mCurPixelSRVs; + + // Currently applied blend state + bool mForceSetBlendState; + gl::BlendState mCurBlendState; + gl::ColorF mCurBlendColor; + unsigned int mCurSampleMask; + + // Currently applied rasterizer state + bool mForceSetRasterState; + gl::RasterizerState mCurRasterState; + + // Currently applied depth stencil state + bool mForceSetDepthStencilState; + gl::DepthStencilState mCurDepthStencilState; + int mCurStencilRef; + int mCurStencilBackRef; + + // Currently applied scissor rectangle + bool mForceSetScissor; + bool mScissorEnabled; + gl::Rectangle mCurScissor; + + // Currently applied viewport + bool mForceSetViewport; + gl::Rectangle mCurViewport; + float mCurNear; + float mCurFar; + + // Currently applied primitive topology + D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; + + // Currently applied index buffer + ID3D11Buffer *mAppliedIB; + DXGI_FORMAT mAppliedIBFormat; + unsigned int mAppliedIBOffset; + + // Currently applied transform feedback buffers + size_t mAppliedNumXFBBindings; + ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers + // in use for streamout + GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified + // buffer offsets to transform feedback + // buffers + UINT mCurrentD3DOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the D3D buffer offsets, + // which may differ from GLs, due + // to different append behavior + + // Currently applied shaders + uintptr_t mAppliedVertexShader; + uintptr_t mAppliedGeometryShader; + uintptr_t mAppliedPixelShader; + + dx_VertexConstants mVertexConstants; + dx_VertexConstants mAppliedVertexConstants; + ID3D11Buffer *mDriverConstantBufferVS; + ID3D11Buffer *mCurrentVertexConstantBuffer; + unsigned int mCurrentConstantBufferVS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + GLintptr mCurrentConstantBufferVSOffset[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + GLsizeiptr mCurrentConstantBufferVSSize[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; + + dx_PixelConstants mPixelConstants; + dx_PixelConstants mAppliedPixelConstants; + ID3D11Buffer *mDriverConstantBufferPS; + ID3D11Buffer *mCurrentPixelConstantBuffer; + unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; + GLintptr mCurrentConstantBufferPSOffset[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; + GLsizeiptr mCurrentConstantBufferPSSize[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS]; + + ID3D11Buffer *mCurrentGeometryConstantBuffer; + + // Vertex, index and input layouts + VertexDataManager *mVertexDataManager; + IndexDataManager *mIndexDataManager; + InputLayoutCache mInputLayoutCache; + + StreamingIndexBufferInterface *mLineLoopIB; + StreamingIndexBufferInterface *mTriangleFanIB; + + // Texture copy resources + Blit11 *mBlit; + PixelTransfer11 *mPixelTransfer; + + // Masked clear resources + Clear11 *mClear; + + // Perform trim for D3D resources + Trim11 *mTrim; + + // Sync query + ID3D11Query *mSyncQuery; + + // Constant buffer offset support + bool mSupportsConstantBufferOffsets; + + ID3D11Device *mDevice; + D3D_FEATURE_LEVEL mFeatureLevel; + ID3D11DeviceContext *mDeviceContext; + ID3D11DeviceContext1 *mDeviceContext1; + IDXGIAdapter *mDxgiAdapter; + DXGI_ADAPTER_DESC mAdapterDescription; + char mDescription[128]; + DXGIFactory *mDxgiFactory; + + DebugAnnotator11 mAnnotator; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp new file mode 100644 index 0000000000..7e64c3183d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp @@ -0,0 +1,110 @@ +// +// Copyright (c) 2012-2014 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. +// + +// ShaderExecutable11.cpp: Implements a D3D11-specific class to contain shader +// executable implementation details. + +#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable) + : ShaderExecutableD3D(function, length) +{ + mPixelExecutable = executable; + mVertexExecutable = NULL; + mGeometryExecutable = NULL; + mStreamOutExecutable = NULL; +} + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut) + : ShaderExecutableD3D(function, length) +{ + mVertexExecutable = executable; + mPixelExecutable = NULL; + mGeometryExecutable = NULL; + mStreamOutExecutable = streamOut; +} + +ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable) + : ShaderExecutableD3D(function, length) +{ + mGeometryExecutable = executable; + mVertexExecutable = NULL; + mPixelExecutable = NULL; + mStreamOutExecutable = NULL; +} + +ShaderExecutable11::~ShaderExecutable11() +{ + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); + SafeRelease(mGeometryExecutable); + SafeRelease(mStreamOutExecutable); +} + +ShaderExecutable11 *ShaderExecutable11::makeShaderExecutable11(ShaderExecutableD3D *executable) +{ + ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable11*, executable)); + return static_cast(executable); +} + +ID3D11VertexShader *ShaderExecutable11::getVertexShader() const +{ + return mVertexExecutable; +} + +ID3D11PixelShader *ShaderExecutable11::getPixelShader() const +{ + return mPixelExecutable; +} + +ID3D11GeometryShader *ShaderExecutable11::getGeometryShader() const +{ + return mGeometryExecutable; +} + +ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const +{ + return mStreamOutExecutable; +} + +UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize) + : UniformStorageD3D(initialSize), + mConstantBuffer(NULL) +{ + ID3D11Device *d3d11Device = renderer->getDevice(); + + if (initialSize > 0) + { + D3D11_BUFFER_DESC constantBufferDescription = {0}; + constantBufferDescription.ByteWidth = initialSize; + constantBufferDescription.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + constantBufferDescription.MiscFlags = 0; + constantBufferDescription.StructureByteStride = 0; + + HRESULT result = d3d11Device->CreateBuffer(&constantBufferDescription, NULL, &mConstantBuffer); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + } +} + +UniformStorage11::~UniformStorage11() +{ + SafeRelease(mConstantBuffer); +} + +const UniformStorage11 *UniformStorage11::makeUniformStorage11(const UniformStorageD3D *uniformStorage) +{ + ASSERT(HAS_DYNAMIC_TYPE(const UniformStorage11*, uniformStorage)); + return static_cast(uniformStorage); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h new file mode 100644 index 0000000000..02558ee4dc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2012-2014 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. +// + +// ShaderExecutable11.h: Defines a D3D11-specific class to contain shader +// executable implementation details. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ + +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" + +namespace rx +{ +class Renderer11; +class UniformStorage11; + +class ShaderExecutable11 : public ShaderExecutableD3D +{ + public: + ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable); + ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut); + ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable); + + virtual ~ShaderExecutable11(); + + static ShaderExecutable11 *makeShaderExecutable11(ShaderExecutableD3D *executable); + + ID3D11PixelShader *getPixelShader() const; + ID3D11VertexShader *getVertexShader() const; + ID3D11GeometryShader *getGeometryShader() const; + ID3D11GeometryShader *getStreamOutShader() const; + + private: + ID3D11PixelShader *mPixelExecutable; + ID3D11VertexShader *mVertexExecutable; + ID3D11GeometryShader *mGeometryExecutable; + ID3D11GeometryShader *mStreamOutExecutable; +}; + +class UniformStorage11 : public UniformStorageD3D +{ + public: + UniformStorage11(Renderer11 *renderer, size_t initialSize); + virtual ~UniformStorage11(); + + static const UniformStorage11 *makeUniformStorage11(const UniformStorageD3D *uniformStorage); + + ID3D11Buffer *getConstantBuffer() const { return mConstantBuffer; } + + private: + ID3D11Buffer *mConstantBuffer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_SHADEREXECUTABLE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp new file mode 100644 index 0000000000..298f3ccbd2 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp @@ -0,0 +1,711 @@ +// +// Copyright (c) 2012-2014 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. +// + +// SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain. + +#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" +#include "libANGLE/features.h" + +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" +#include "libANGLE/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" + + +namespace rx +{ + +SwapChain11::SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat) + : mRenderer(renderer), + SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat), + mColorRenderTarget(this, renderer, false), + mDepthStencilRenderTarget(this, renderer, true) +{ + mSwapChain = NULL; + mBackBufferTexture = NULL; + mBackBufferRTView = NULL; + mOffscreenTexture = NULL; + mOffscreenRTView = NULL; + mOffscreenSRView = NULL; + mDepthStencilTexture = NULL; + mDepthStencilDSView = NULL; + mDepthStencilSRView = NULL; + mQuadVB = NULL; + mPassThroughSampler = NULL; + mPassThroughIL = NULL; + mPassThroughVS = NULL; + mPassThroughPS = NULL; + mWidth = -1; + mHeight = -1; + mSwapInterval = 0; + mAppCreatedShareHandle = mShareHandle != NULL; + mPassThroughResourcesInit = false; +} + +SwapChain11::~SwapChain11() +{ + release(); +} + +void SwapChain11::release() +{ + SafeRelease(mSwapChain); + SafeRelease(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + SafeRelease(mOffscreenTexture); + SafeRelease(mOffscreenRTView); + SafeRelease(mOffscreenSRView); + SafeRelease(mDepthStencilTexture); + SafeRelease(mDepthStencilDSView); + SafeRelease(mDepthStencilSRView); + SafeRelease(mQuadVB); + SafeRelease(mPassThroughSampler); + SafeRelease(mPassThroughIL); + SafeRelease(mPassThroughVS); + SafeRelease(mPassThroughPS); + + if (!mAppCreatedShareHandle) + { + mShareHandle = NULL; + } +} + +void SwapChain11::releaseOffscreenTexture() +{ + SafeRelease(mOffscreenTexture); + SafeRelease(mOffscreenRTView); + SafeRelease(mOffscreenSRView); + SafeRelease(mDepthStencilTexture); + SafeRelease(mDepthStencilDSView); + SafeRelease(mDepthStencilSRView); +} + +EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHeight) +{ + ID3D11Device *device = mRenderer->getDevice(); + + ASSERT(device != NULL); + + // D3D11 does not allow zero size textures + ASSERT(backbufferWidth >= 1); + ASSERT(backbufferHeight >= 1); + + // Preserve the render target content + ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; + if (previousOffscreenTexture) + { + previousOffscreenTexture->AddRef(); + } + const int previousWidth = mWidth; + const int previousHeight = mHeight; + + releaseOffscreenTexture(); + + const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel()); + + // If the app passed in a share handle, open the resource + // See EGL_ANGLE_d3d_share_handle_client_buffer + if (mAppCreatedShareHandle) + { + ID3D11Resource *tempResource11; + HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), (void**)&tempResource11); + + if (FAILED(result)) + { + ERR("Failed to open the swap chain pbuffer share handle: %08lX", result); + release(); + return EGL_BAD_PARAMETER; + } + + result = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&mOffscreenTexture); + SafeRelease(tempResource11); + + if (FAILED(result)) + { + ERR("Failed to query texture2d interface in pbuffer share handle: %08lX", result); + release(); + return EGL_BAD_PARAMETER; + } + + // Validate offscreen texture parameters + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; + mOffscreenTexture->GetDesc(&offscreenTextureDesc); + + if (offscreenTextureDesc.Width != (UINT)backbufferWidth || + offscreenTextureDesc.Height != (UINT)backbufferHeight || + offscreenTextureDesc.Format != backbufferFormatInfo.texFormat || + offscreenTextureDesc.MipLevels != 1 || + offscreenTextureDesc.ArraySize != 1) + { + ERR("Invalid texture parameters in the shared offscreen texture pbuffer"); + release(); + return EGL_BAD_PARAMETER; + } + } + else + { + const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); + + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + const int textureLength = std::max(backbufferWidth, backbufferHeight); + offscreenTextureDesc.Width = textureLength; + offscreenTextureDesc.Height = textureLength; +#else + offscreenTextureDesc.Width = backbufferWidth; + offscreenTextureDesc.Height = backbufferHeight; +#endif + offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; + offscreenTextureDesc.MipLevels = 1; + offscreenTextureDesc.ArraySize = 1; + offscreenTextureDesc.SampleDesc.Count = 1; + offscreenTextureDesc.SampleDesc.Quality = 0; + offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT; + offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + offscreenTextureDesc.CPUAccessFlags = 0; + offscreenTextureDesc.MiscFlags = useSharedResource ? D3D11_RESOURCE_MISC_SHARED : 0; + + HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture); + + if (FAILED(result)) + { + ERR("Could not create offscreen texture: %08lX", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + d3d11::SetDebugName(mOffscreenTexture, "Offscreen back buffer texture"); + + // EGL_ANGLE_surface_d3d_texture_2d_share_handle requires that we store a share handle for the client + if (useSharedResource) + { + IDXGIResource *offscreenTextureResource = NULL; + result = mOffscreenTexture->QueryInterface(__uuidof(IDXGIResource), (void**)&offscreenTextureResource); + + // Fall back to no share handle on failure + if (FAILED(result)) + { + ERR("Could not query offscreen texture resource: %08lX", result); + } + else + { + result = offscreenTextureResource->GetSharedHandle(&mShareHandle); + SafeRelease(offscreenTextureResource); + + if (FAILED(result)) + { + mShareHandle = NULL; + ERR("Could not get offscreen texture shared handle: %08lX", result); + } + } + } + } + + + D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc; + offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat; + offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + offscreenRTVDesc.Texture2D.MipSlice = 0; + + HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, &offscreenRTVDesc, &mOffscreenRTView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mOffscreenRTView, "Offscreen back buffer render target"); + + D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; + offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; + offscreenSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + offscreenSRVDesc.Texture2D.MostDetailedMip = 0; + offscreenSRVDesc.Texture2D.MipLevels = static_cast(-1); + + result = device->CreateShaderResourceView(mOffscreenTexture, &offscreenSRVDesc, &mOffscreenSRView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mOffscreenSRView, "Offscreen back buffer shader resource"); + + const d3d11::TextureFormat &depthBufferFormatInfo = d3d11::GetTextureFormatInfo(mDepthBufferFormat, mRenderer->getFeatureLevel()); + + if (mDepthBufferFormat != GL_NONE) + { + D3D11_TEXTURE2D_DESC depthStencilTextureDesc; +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + const int textureLength = std::max(backbufferWidth, backbufferHeight); + depthStencilTextureDesc.Width = textureLength; + depthStencilTextureDesc.Height = textureLength; +#else + depthStencilTextureDesc.Width = backbufferWidth; + depthStencilTextureDesc.Height = backbufferHeight; +#endif + depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; + depthStencilTextureDesc.MipLevels = 1; + depthStencilTextureDesc.ArraySize = 1; + depthStencilTextureDesc.SampleDesc.Count = 1; + depthStencilTextureDesc.SampleDesc.Quality = 0; + depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT; + depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + + if (depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + depthStencilTextureDesc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + + depthStencilTextureDesc.CPUAccessFlags = 0; + depthStencilTextureDesc.MiscFlags = 0; + + result = device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture); + if (FAILED(result)) + { + ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + d3d11::SetDebugName(mDepthStencilTexture, "Offscreen depth stencil texture"); + + D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilDesc; + depthStencilDesc.Format = depthBufferFormatInfo.dsvFormat; + depthStencilDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + depthStencilDesc.Flags = 0; + depthStencilDesc.Texture2D.MipSlice = 0; + + result = device->CreateDepthStencilView(mDepthStencilTexture, &depthStencilDesc, &mDepthStencilDSView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilDSView, "Offscreen depth stencil view"); + + if (depthBufferFormatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilSRVDesc; + depthStencilSRVDesc.Format = depthBufferFormatInfo.srvFormat; + depthStencilSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + depthStencilSRVDesc.Texture2D.MostDetailedMip = 0; + depthStencilSRVDesc.Texture2D.MipLevels = static_cast(-1); + + result = device->CreateShaderResourceView(mDepthStencilTexture, &depthStencilSRVDesc, &mDepthStencilSRView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthStencilSRView, "Offscreen depth stencil shader resource"); + } + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + + if (previousOffscreenTexture != NULL) + { + D3D11_BOX sourceBox = {0}; + sourceBox.left = 0; + sourceBox.right = std::min(previousWidth, mWidth); + sourceBox.top = std::max(previousHeight - mHeight, 0); + sourceBox.bottom = previousHeight; + sourceBox.front = 0; + sourceBox.back = 1; + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + const int yoffset = std::max(mHeight - previousHeight, 0); + deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, previousOffscreenTexture, 0, &sourceBox); + + SafeRelease(previousOffscreenTexture); + + if (mSwapChain) + { + swapRect(0, 0, mWidth, mHeight); + } + } + + return EGL_SUCCESS; +} + +EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) +{ + ID3D11Device *device = mRenderer->getDevice(); + + if (device == NULL) + { + return EGL_BAD_ACCESS; + } + + // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains + if (backbufferWidth < 1 || backbufferHeight < 1) + { + return EGL_SUCCESS; + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + // Can only call resize if we have already created our swap buffer and resources + ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); + + SafeRelease(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + + // Resize swap chain + DXGI_SWAP_CHAIN_DESC desc; + mSwapChain->GetDesc(&desc); + const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel()); + HRESULT result = mSwapChain->ResizeBuffers(desc.BufferCount, backbufferWidth, backbufferHeight, backbufferFormatInfo.texFormat, 0); + + if (FAILED(result)) + { + ERR("Error resizing swap chain buffers: 0x%08X", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); + ASSERT(SUCCEEDED(result)); + if (SUCCEEDED(result)) + { + d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture"); + } + + result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); + ASSERT(SUCCEEDED(result)); + if (SUCCEEDED(result)) + { + d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); + } + + return resetOffscreenTexture(backbufferWidth, backbufferHeight); +#else + // Do nothing on Windows Phone apart from updating the internal buffer/width height + mWidth = backbufferWidth; + mHeight = backbufferHeight; + return EGL_SUCCESS; +#endif +} + +EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +{ + ID3D11Device *device = mRenderer->getDevice(); + + if (device == NULL) + { + return EGL_BAD_ACCESS; + } + + // 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. + SafeRelease(mSwapChain); + SafeRelease(mBackBufferTexture); + SafeRelease(mBackBufferRTView); + + mSwapInterval = static_cast(swapInterval); + if (mSwapInterval > 4) + { + // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4] range + return EGL_BAD_PARAMETER; + } + + // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains + if (backbufferWidth < 1 || backbufferHeight < 1) + { + releaseOffscreenTexture(); + return EGL_SUCCESS; + } + + if (mNativeWindow.getNativeWindow()) + { + const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat, mRenderer->getFeatureLevel()); + + HRESULT result = mNativeWindow.createSwapChain(device, mRenderer->getDxgiFactory(), + backbufferFormatInfo.texFormat, + backbufferWidth, backbufferHeight, &mSwapChain); + + if (FAILED(result)) + { + ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); + release(); + + if (d3d11::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture"); + + result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); + } + + // If we are resizing the swap chain, we don't wish to recreate all the static resources + if (!mPassThroughResourcesInit) + { + mPassThroughResourcesInit = true; + initPassThroughResources(); + } + + return resetOffscreenTexture(backbufferWidth, backbufferHeight); +} + +void SwapChain11::initPassThroughResources() +{ + ID3D11Device *device = mRenderer->getDevice(); + + ASSERT(device != NULL); + + // Make sure our resources are all not allocated, when we create + ASSERT(mQuadVB == NULL && mPassThroughSampler == NULL); + ASSERT(mPassThroughIL == NULL && mPassThroughVS == NULL && mPassThroughPS == NULL); + + D3D11_BUFFER_DESC vbDesc; + vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4; + vbDesc.Usage = D3D11_USAGE_DYNAMIC; + vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + vbDesc.MiscFlags = 0; + vbDesc.StructureByteStride = 0; + + HRESULT result = device->CreateBuffer(&vbDesc, NULL, &mQuadVB); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mQuadVB, "Swap chain quad vertex buffer"); + + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.MipLODBias = 0.0f; + samplerDesc.MaxAnisotropy = 0; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + samplerDesc.BorderColor[0] = 0.0f; + samplerDesc.BorderColor[1] = 0.0f; + samplerDesc.BorderColor[2] = 0.0f; + samplerDesc.BorderColor[3] = 0.0f; + samplerDesc.MinLOD = 0; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + + result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughSampler, "Swap chain pass through sampler"); + + D3D11_INPUT_ELEMENT_DESC quadLayout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = device->CreateInputLayout(quadLayout, 2, g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), &mPassThroughIL); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughIL, "Swap chain pass through layout"); + + result = device->CreateVertexShader(g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), NULL, &mPassThroughVS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughVS, "Swap chain pass through vertex shader"); + + result = device->CreatePixelShader(g_PS_PassthroughRGBA2D, sizeof(g_PS_PassthroughRGBA2D), NULL, &mPassThroughPS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader"); +} + +// parameters should be validated/clamped by caller +EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return EGL_SUCCESS; + } + + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return EGL_BAD_ACCESS; + } + + d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); + + // Create a quad in homogeneous coordinates + float x1 = (x / float(mWidth)) * 2.0f - 1.0f; + float y1 = (y / float(mHeight)) * 2.0f - 1.0f; + float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; + float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + const float dim = std::max(mWidth, mHeight); + float u1 = x / dim; + float v1 = y / dim; + float u2 = (x + width) / dim; + float v2 = (y + height) / dim; + + const NativeWindow::RotationFlags flags = mNativeWindow.rotationFlags(); + const bool rotateL = flags == NativeWindow::RotateLeft; + const bool rotateR = flags == NativeWindow::RotateRight; + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); +#else + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); + float v2 = (y + height) / float(mHeight); + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v1); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); +#endif + + deviceContext->Unmap(mQuadVB, 0); + + static UINT stride = sizeof(d3d11::PositionTexCoordVertex); + static UINT startIdx = 0; + deviceContext->IASetVertexBuffers(0, 1, &mQuadVB, &stride, &startIdx); + + // Apply state + deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); + + static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF); + + deviceContext->RSSetState(NULL); + + // Apply shaders + deviceContext->IASetInputLayout(mPassThroughIL); + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + deviceContext->VSSetShader(mPassThroughVS, NULL, 0); + deviceContext->PSSetShader(mPassThroughPS, NULL, 0); + deviceContext->GSSetShader(NULL, NULL, 0); + + // Apply render targets + mRenderer->setOneTimeRenderTarget(mBackBufferRTView); + + // Set the viewport + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + viewport.Width = (rotateL || rotateR) ? mHeight : mWidth; + viewport.Height = (rotateL || rotateR) ? mWidth : mHeight; +#else + viewport.Width = mWidth; + viewport.Height = mHeight; +#endif + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); + + // Apply textures + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, mOffscreenSRView); + deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler); + + // Draw + deviceContext->Draw(4, 0); + +#if ANGLE_VSYNC == ANGLE_DISABLED + result = mSwapChain->Present(0, 0); +#else + result = mSwapChain->Present(mSwapInterval, 0); +#endif + + if (result == DXGI_ERROR_DEVICE_REMOVED) + { + HRESULT removedReason = device->GetDeviceRemovedReason(); + UNUSED_TRACE_VARIABLE(removedReason); + ERR("Present failed: the D3D11 device was removed: 0x%08X", removedReason); + return EGL_CONTEXT_LOST; + } + else if (result == DXGI_ERROR_DEVICE_RESET) + { + ERR("Present failed: the D3D11 device was reset from a bad command."); + return EGL_CONTEXT_LOST; + } + else if (FAILED(result)) + { + ERR("Present failed with error code 0x%08X", result); + } + + // Unbind + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); + + mRenderer->unapplyRenderTargets(); + mRenderer->markAllStateDirty(); + + return EGL_SUCCESS; +} + +ID3D11Texture2D *SwapChain11::getOffscreenTexture() +{ + return mOffscreenTexture; +} + +ID3D11RenderTargetView *SwapChain11::getRenderTarget() +{ + return mOffscreenRTView; +} + +ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource() +{ + return mOffscreenSRView; +} + +ID3D11DepthStencilView *SwapChain11::getDepthStencil() +{ + return mDepthStencilDSView; +} + +ID3D11ShaderResourceView * SwapChain11::getDepthStencilShaderResource() +{ + return mDepthStencilSRView; +} + +ID3D11Texture2D *SwapChain11::getDepthStencilTexture() +{ + return mDepthStencilTexture; +} + +SwapChain11 *SwapChain11::makeSwapChain11(SwapChainD3D *swapChain) +{ + ASSERT(HAS_DYNAMIC_TYPE(SwapChain11*, swapChain)); + return static_cast(swapChain); +} + +void SwapChain11::recreate() +{ + // possibly should use this method instead of reset +} + +void *rx::SwapChain11::getDevice() +{ + return mRenderer->getDevice(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h new file mode 100644 index 0000000000..48c808a261 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.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. +// + +// SwapChain11.h: Defines a back-end specific class for the D3D11 swap chain. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_SWAPCHAIN11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_SWAPCHAIN11_H_ + +#include "common/angleutils.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" + +namespace rx +{ +class Renderer11; + +class SwapChain11 : public SwapChainD3D +{ + public: + SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat); + virtual ~SwapChain11(); + + EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); + virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + virtual void recreate(); + + RenderTargetD3D *getColorRenderTarget() override { return &mColorRenderTarget; } + RenderTargetD3D *getDepthStencilRenderTarget() override { return &mDepthStencilRenderTarget; } + + virtual ID3D11Texture2D *getOffscreenTexture(); + virtual ID3D11RenderTargetView *getRenderTarget(); + virtual ID3D11ShaderResourceView *getRenderTargetShaderResource(); + + virtual ID3D11Texture2D *getDepthStencilTexture(); + virtual ID3D11DepthStencilView *getDepthStencil(); + virtual ID3D11ShaderResourceView *getDepthStencilShaderResource(); + + EGLint getWidth() const { return mWidth; } + EGLint getHeight() const { return mHeight; } + + virtual void *getDevice(); + + static SwapChain11 *makeSwapChain11(SwapChainD3D *swapChain); + + private: + void release(); + void initPassThroughResources(); + void releaseOffscreenTexture(); + EGLint resetOffscreenTexture(int backbufferWidth, int backbufferHeight); + + Renderer11 *mRenderer; + EGLint mHeight; + EGLint mWidth; + bool mAppCreatedShareHandle; + unsigned int mSwapInterval; + bool mPassThroughResourcesInit; + + DXGISwapChain *mSwapChain; + + ID3D11Texture2D *mBackBufferTexture; + ID3D11RenderTargetView *mBackBufferRTView; + + ID3D11Texture2D *mOffscreenTexture; + ID3D11RenderTargetView *mOffscreenRTView; + ID3D11ShaderResourceView *mOffscreenSRView; + + ID3D11Texture2D *mDepthStencilTexture; + ID3D11DepthStencilView *mDepthStencilDSView; + ID3D11ShaderResourceView *mDepthStencilSRView; + + ID3D11Buffer *mQuadVB; + ID3D11SamplerState *mPassThroughSampler; + ID3D11InputLayout *mPassThroughIL; + ID3D11VertexShader *mPassThroughVS; + ID3D11PixelShader *mPassThroughPS; + + SurfaceRenderTarget11 mColorRenderTarget; + SurfaceRenderTarget11 mDepthStencilRenderTarget; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_D3D11_SWAPCHAIN11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp new file mode 100644 index 0000000000..103e90fed3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp @@ -0,0 +1,2676 @@ +// +// Copyright (c) 2012-2014 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. +// + +// TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. + +#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" + +#include + +#include "common/MemoryBuffer.h" +#include "common/utilities.h" +#include "libANGLE/ImageIndex.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/d3d11/Blit11.h" +#include "libANGLE/renderer/d3d/d3d11/Image11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +namespace rx +{ + +TextureStorage11::SwizzleCacheValue::SwizzleCacheValue() + : swizzleRed(GL_NONE), swizzleGreen(GL_NONE), swizzleBlue(GL_NONE), swizzleAlpha(GL_NONE) +{ +} + +TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha) + : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) +{ +} + +bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const +{ + return swizzleRed == other.swizzleRed && + swizzleGreen == other.swizzleGreen && + swizzleBlue == other.swizzleBlue && + swizzleAlpha == other.swizzleAlpha; +} + +bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const +{ + return !(*this == other); +} + +TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) + : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle) +{ +} + +bool TextureStorage11::SRVKey::operator<(const SRVKey &rhs) const +{ + return std::tie(baseLevel, mipLevels, swizzle) < std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle); +} + +TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags) + : mBindFlags(bindFlags), + mTopLevel(0), + mMipLevels(0), + mInternalFormat(GL_NONE), + mTextureFormat(DXGI_FORMAT_UNKNOWN), + mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), + mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), + mDepthStencilFormat(DXGI_FORMAT_UNKNOWN), + mTextureWidth(0), + mTextureHeight(0), + mTextureDepth(0) +{ + mRenderer = Renderer11::makeRenderer11(renderer); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mLevelSRVs[i] = NULL; + } +} + +TextureStorage11::~TextureStorage11() +{ + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mLevelSRVs[level]); + } + + for (SRVCache::iterator i = mSrvCache.begin(); i != mSrvCache.end(); i++) + { + SafeRelease(i->second); + } + mSrvCache.clear(); +} + +TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11*, storage)); + return static_cast(storage); +} + +DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel, bool renderTarget) +{ + UINT bindFlags = 0; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, featureLevel); + if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + bindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + if (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) + { + bindFlags |= D3D11_BIND_DEPTH_STENCIL; + } + if (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN && renderTarget) + { + bindFlags |= D3D11_BIND_RENDER_TARGET; + } + + return bindFlags; +} + +UINT TextureStorage11::getBindFlags() const +{ + return mBindFlags; +} + +int TextureStorage11::getTopLevel() const +{ + return mTopLevel; +} + +bool TextureStorage11::isRenderTarget() const +{ + return (mBindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL)) != 0; +} + +bool TextureStorage11::isManaged() const +{ + return false; +} + +int TextureStorage11::getLevelCount() const +{ + return mMipLevels - mTopLevel; +} + +int TextureStorage11::getLevelWidth(int mipLevel) const +{ + return std::max(static_cast(mTextureWidth) >> mipLevel, 1); +} + +int TextureStorage11::getLevelHeight(int mipLevel) const +{ + return std::max(static_cast(mTextureHeight) >> mipLevel, 1); +} + +int TextureStorage11::getLevelDepth(int mipLevel) const +{ + return std::max(static_cast(mTextureDepth) >> mipLevel, 1); +} + +UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const +{ + UINT mipSlice = static_cast(index.mipIndex + mTopLevel); + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); + ASSERT(subresource != std::numeric_limits::max()); + return subresource; +} + +gl::Error TextureStorage11::getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV) +{ + bool swizzleRequired = samplerState.swizzleRequired(); + bool mipmapping = gl::IsMipmapFiltered(samplerState); + unsigned int mipLevels = mipmapping ? (samplerState.maxLevel - samplerState.baseLevel + 1) : 1; + + // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0) + mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - samplerState.baseLevel); + + if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + ASSERT(!swizzleRequired); + ASSERT(mipLevels == 1 || mipLevels == mMipLevels); + } + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + // We must ensure that the level zero texture is in sync with mipped texture. + gl::Error error = useLevelZeroWorkaroundTexture(mipLevels == 1); + if (error.isError()) + { + return error; + } + } + + if (swizzleRequired) + { + verifySwizzleExists(samplerState.swizzleRed, samplerState.swizzleGreen, samplerState.swizzleBlue, samplerState.swizzleAlpha); + } + + SRVKey key(samplerState.baseLevel, mipLevels, swizzleRequired); + SRVCache::const_iterator iter = mSrvCache.find(key); + if (iter != mSrvCache.end()) + { + *outSRV = iter->second; + } + else + { + ID3D11Resource *texture = NULL; + if (swizzleRequired) + { + gl::Error error = getSwizzleTexture(&texture); + if (error.isError()) + { + return error; + } + } + else + { + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + } + + ID3D11ShaderResourceView *srv = NULL; + DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); + gl::Error error = createSRV(samplerState.baseLevel, mipLevels, format, texture, &srv); + if (error.isError()) + { + return error; + } + + mSrvCache.insert(std::make_pair(key, srv)); + *outSRV = srv; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + + if (!mLevelSRVs[mipLevel]) + { + ID3D11Resource *resource = NULL; + gl::Error error = getResource(&resource); + if (error.isError()) + { + return error; + } + + error = createSRV(mipLevel, 1, mShaderResourceFormat, resource, &mLevelSRVs[mipLevel]); + if (error.isError()) + { + return error; + } + } + + *outSRV = mLevelSRVs[mipLevel]; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + for (int level = 0; level < getLevelCount(); level++) + { + // Check if the swizzle for this level is out of date + if (mSwizzleCache[level] != swizzleTarget) + { + // Need to re-render the swizzle for this level + ID3D11ShaderResourceView *sourceSRV = NULL; + gl::Error error = getSRVLevel(level, &sourceSRV); + if (error.isError()) + { + return error; + } + + ID3D11RenderTargetView *destRTV = NULL; + error = getSwizzleRenderTarget(level, &destRTV); + if (error.isError()) + { + return error; + } + + gl::Extents size(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + + Blit11 *blitter = mRenderer->getBlitter(); + + error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + if (error.isError()) + { + return error; + } + + mSwizzleCache[level] = swizzleTarget; + } + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel) +{ + if (mipLevel >= 0 && static_cast(mipLevel) < ArraySize(mSwizzleCache)) + { + // The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a + // valid swizzle combination + mSwizzleCache[mipLevel] = SwizzleCacheValue(); + } +} + +void TextureStorage11::invalidateSwizzleCache() +{ + for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++) + { + invalidateSwizzleCacheLevel(mipLevel); + } +} + +gl::Error TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, + const gl::ImageIndex &index, const gl::Box ©Area) +{ + ASSERT(srcTexture); + + GLint level = index.mipIndex; + + invalidateSwizzleCacheLevel(level); + + gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + + bool fullCopy = copyArea.x == 0 && + copyArea.y == 0 && + copyArea.z == 0 && + copyArea.width == texSize.width && + copyArea.height == texSize.height && + copyArea.depth == texSize.depth; + + ID3D11Resource *dstTexture = NULL; + gl::Error error(GL_NO_ERROR); + + // If the zero-LOD workaround is active and we want to update a level greater than zero, then we should + // update the mipmapped texture, even if mapmaps are currently disabled. + if (index.mipIndex > 0 && mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + error = getMippedResource(&dstTexture); + } + else + { + error = getResource(&dstTexture); + } + + if (error.isError()) + { + return error; + } + + unsigned int dstSubresource = getSubresourceIndex(index); + + ASSERT(dstTexture); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); + if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0)) + { + // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead + Blit11 *blitter = mRenderer->getBlitter(); + + return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, + dstTexture, dstSubresource, copyArea, texSize, + NULL); + } + else + { + D3D11_BOX srcBox; + srcBox.left = copyArea.x; + srcBox.top = copyArea.y; + srcBox.right = copyArea.x + roundUp(static_cast(copyArea.width), dxgiFormatInfo.blockWidth); + srcBox.bottom = copyArea.y + roundUp(static_cast(copyArea.height), dxgiFormatInfo.blockHeight); + srcBox.front = copyArea.z; + srcBox.back = copyArea.z + copyArea.depth; + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, + srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, + const gl::ImageIndex &index, const gl::Box ®ion) +{ + ASSERT(dstTexture); + + ID3D11Resource *srcTexture = NULL; + gl::Error error(GL_NO_ERROR); + + // If the zero-LOD workaround is active and we want to update a level greater than zero, then we should + // update the mipmapped texture, even if mapmaps are currently disabled. + if (index.mipIndex > 0 && mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + error = getMippedResource(&srcTexture); + } + else + { + error = getResource(&srcTexture); + } + + if (error.isError()) + { + return error; + } + + ASSERT(srcTexture); + + unsigned int srcSubresource = getSubresourceIndex(index); + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + // D3D11 can't perform partial CopySubresourceRegion on depth/stencil textures, so pSrcBox should be NULL. + D3D11_BOX srcBox; + D3D11_BOX *pSrcBox = NULL; + if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + // However, D3D10Level9 doesn't always perform CopySubresourceRegion correctly unless the source box + // is specified. This is okay, since we don't perform CopySubresourceRegion on depth/stencil + // textures on 9_3. + ASSERT(d3d11::GetDXGIFormatInfo(mTextureFormat).depthBits == 0); + ASSERT(d3d11::GetDXGIFormatInfo(mTextureFormat).stencilBits == 0); + srcBox.left = region.x; + srcBox.right = region.x + region.width; + srcBox.top = region.y; + srcBox.bottom = region.y + region.height; + srcBox.front = region.z; + srcBox.back = region.z + region.depth; + pSrcBox = &srcBox; + } + + context->CopySubresourceRegion(dstTexture, dstSubresource, region.x, region.y, region.z, + srcTexture, srcSubresource, pSrcBox); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + ASSERT(sourceIndex.layerIndex == destIndex.layerIndex); + + invalidateSwizzleCacheLevel(destIndex.mipIndex); + + RenderTargetD3D *source = NULL; + gl::Error error = getRenderTarget(sourceIndex, &source); + if (error.isError()) + { + return error; + } + + RenderTargetD3D *dest = NULL; + error = getRenderTarget(destIndex, &dest); + if (error.isError()) + { + return error; + } + + ID3D11ShaderResourceView *sourceSRV = RenderTarget11::makeRenderTarget11(source)->getShaderResourceView(); + ID3D11RenderTargetView *destRTV = RenderTarget11::makeRenderTarget11(dest)->getRenderTargetView(); + + gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); + gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); + + gl::Box destArea(0, 0, 0, dest->getWidth(), dest->getHeight(), dest->getDepth()); + gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth()); + + Blit11 *blitter = mRenderer->getBlitter(); + return blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL, + gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR); +} + +void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) +{ + SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + for (unsigned int level = 0; level < mMipLevels; level++) + { + ASSERT(mSwizzleCache[level] == swizzleTarget); + } +} + +gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + ID3D11Resource *sourceResouce = NULL; + gl::Error error = getResource(&sourceResouce); + if (error.isError()) + { + return error; + } + + TextureStorage11 *dest11 = TextureStorage11::makeTextureStorage11(destStorage); + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + immediateContext->CopyResource(destResource, sourceResouce); + + dest11->invalidateSwizzleCache(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +{ + ASSERT(!image->isDirty()); + + ID3D11Resource *resource = NULL; + gl::Error error = getResource(&resource); + if (error.isError()) + { + return error; + } + ASSERT(resource); + + UINT destSubresource = getSubresourceIndex(index); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat()); + + gl::Box levelBox(0, 0, 0, getLevelWidth(index.mipIndex), getLevelHeight(index.mipIndex), getLevelDepth(index.mipIndex)); + bool fullUpdate = (destBox == NULL || *destBox == levelBox); + ASSERT(internalFormatInfo.depthBits == 0 || fullUpdate); + + // TODO(jmadill): Handle compressed formats + // Compressed formats have different load syntax, so we'll have to handle them with slightly + // different logic. Will implemnent this in a follow-up patch, and ensure we do not use SetData + // with compressed formats in the calling logic. + ASSERT(!internalFormatInfo.compressed); + + int width = destBox ? destBox->width : static_cast(image->getWidth()); + int height = destBox ? destBox->height : static_cast(image->getHeight()); + int depth = destBox ? destBox->depth : static_cast(image->getDepth()); + UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, width, unpack.alignment, unpack.rowLength); + UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, width, height, unpack.alignment, unpack.rowLength); + + const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat(), mRenderer->getFeatureLevel()); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat); + + size_t outputPixelSize = dxgiFormatInfo.pixelBytes; + + UINT bufferRowPitch = outputPixelSize * width; + UINT bufferDepthPitch = bufferRowPitch * height; + + size_t neededSize = bufferDepthPitch * depth; + MemoryBuffer *conversionBuffer = NULL; + error = mRenderer->getScratchMemoryBuffer(neededSize, &conversionBuffer); + if (error.isError()) + { + return error; + } + + // TODO: fast path + LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type); + loadFunction(width, height, depth, + pixelData, srcRowPitch, srcDepthPitch, + conversionBuffer->data(), bufferRowPitch, bufferDepthPitch); + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + + if (!fullUpdate) + { + ASSERT(destBox); + + D3D11_BOX destD3DBox; + destD3DBox.left = destBox->x; + destD3DBox.right = destBox->x + destBox->width; + destD3DBox.top = destBox->y; + destD3DBox.bottom = destBox->y + destBox->height; + destD3DBox.front = destBox->z; + destD3DBox.back = destBox->z + destBox->depth; + + immediateContext->UpdateSubresource(resource, destSubresource, + &destD3DBox, conversionBuffer->data(), + bufferRowPitch, bufferDepthPitch); + } + else + { + immediateContext->UpdateSubresource(resource, destSubresource, + NULL, conversionBuffer->data(), + bufferRowPitch, bufferDepthPitch); + } + + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain) + : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), + mTexture(swapchain->getOffscreenTexture()), + mSwizzleTexture(NULL), + mLevelZeroTexture(NULL), + mLevelZeroRenderTarget(NULL), + mUseLevelZeroTexture(false) +{ + mTexture->AddRef(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mAssociatedImages[i] = NULL; + mRenderTarget[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + D3D11_TEXTURE2D_DESC texDesc; + mTexture->GetDesc(&texDesc); + mMipLevels = texDesc.MipLevels; + mTextureFormat = texDesc.Format; + mTextureWidth = texDesc.Width; + mTextureHeight = texDesc.Height; + mTextureDepth = 1; + + mInternalFormat = swapchain->GetBackBufferInternalFormat(); + + ID3D11ShaderResourceView *srv = swapchain->getRenderTargetShaderResource(); + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srv->GetDesc(&srvDesc); + mShaderResourceFormat = srvDesc.Format; + + ID3D11RenderTargetView* offscreenRTV = swapchain->getRenderTarget(); + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + offscreenRTV->GetDesc(&rtvDesc); + mRenderTargetFormat = rtvDesc.Format; + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(dxgiFormatInfo.internalFormat, mRenderer->getFeatureLevel()); + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; + + initializeSerials(1, 1); +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)), + mTexture(NULL), + mSwizzleTexture(NULL), + mLevelZeroTexture(NULL), + mLevelZeroRenderTarget(NULL), + mUseLevelZeroTexture(false) +{ + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mAssociatedImages[i] = NULL; + mRenderTarget[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + mInternalFormat = internalformat; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel()); + mTextureFormat = formatInfo.texFormat; + mShaderResourceFormat = formatInfo.srvFormat; + mDepthStencilFormat = formatInfo.dsvFormat; + mRenderTargetFormat = formatInfo.rtvFormat; + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = 1; + + if (hintLevelZeroOnly && levels > 1) + { + //The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. + ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); + mUseLevelZeroTexture = true; + } + + initializeSerials(getLevelCount(), 1); +} + +TextureStorage11_2D::~TextureStorage11_2D() +{ + for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + if (mAssociatedImages[i] != NULL) + { + bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // We must let the Images recover their data before we delete it from the TextureStorage. + gl::Error error = mAssociatedImages[i]->recoverFromAssociatedStorage(); + if (error.isError()) + { + // TODO: Find a way to report this back to the context + } + } + } + } + + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + SafeRelease(mLevelZeroTexture); + SafeDelete(mLevelZeroRenderTarget); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + SafeDelete(mRenderTarget[i]); + SafeRelease(mSwizzleRenderTargets[i]); + } +} + +TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage)); + return static_cast(storage); +} + +gl::Error TextureStorage11_2D::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(destStorage); + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + + // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the corresponding textures in destStorage. + if (mTexture) + { + gl::Error error = dest11->useLevelZeroWorkaroundTexture(false); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + immediateContext->CopyResource(destResource, mTexture); + } + + if (mLevelZeroTexture) + { + gl::Error error = dest11->useLevelZeroWorkaroundTexture(true); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + immediateContext->CopyResource(destResource, mLevelZeroTexture); + } + } + else + { + ID3D11Resource *sourceResouce = NULL; + gl::Error error = getResource(&sourceResouce); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + immediateContext->CopyResource(destResource, sourceResouce); + } + + dest11->invalidateSwizzleCache(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) +{ + if (useLevelZeroTexture && mMipLevels > 1) + { + if (!mUseLevelZeroTexture && mTexture) + { + gl::Error error = ensureTextureExists(1); + if (error.isError()) + { + return error; + } + + // Pull data back from the mipped texture if necessary. + ASSERT(mLevelZeroTexture); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->CopySubresourceRegion(mLevelZeroTexture, 0, 0, 0, 0, mTexture, 0, NULL); + } + + mUseLevelZeroTexture = true; + } + else + { + if (mUseLevelZeroTexture && mLevelZeroTexture) + { + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + // Pull data back from the level zero texture if necessary. + ASSERT(mTexture); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->CopySubresourceRegion(mTexture, 0, 0, 0, 0, mLevelZeroTexture, 0, NULL); + } + + mUseLevelZeroTexture = false; + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &index) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + mAssociatedImages[level] = image; + } +} + +bool TextureStorage11_2D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + // This validation check should never return false. It means the Image/TextureStorage association is broken. + bool retValue = (mAssociatedImages[level] == expectedImage); + ASSERT(retValue); + return retValue; + } + + return false; +} + +// disassociateImage allows an Image to end its association with a Storage. +void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + ASSERT(mAssociatedImages[level] == expectedImage); + + if (mAssociatedImages[level] == expectedImage) + { + mAssociatedImages[level] = NULL; + } + } +} + +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. +gl::Error TextureStorage11_2D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + // No need to let the old Image recover its data, if it is also the incoming Image. + if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) + { + // Ensure that the Image is still associated with this TextureStorage. This should be true. + bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to NULL too. + gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource) +{ + if (mUseLevelZeroTexture && mMipLevels > 1) + { + gl::Error error = ensureTextureExists(1); + if (error.isError()) + { + return error; + } + + *outResource = mLevelZeroTexture; + return gl::Error(GL_NO_ERROR); + } + else + { + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error TextureStorage11_2D::getMippedResource(ID3D11Resource **outResource) +{ + // This shouldn't be called unless the zero max LOD workaround is active. + ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); + + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::ensureTextureExists(int mipLevels) +{ + // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture. + bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround ? (mipLevels == 1) && (mMipLevels > 1) : false; + ID3D11Texture2D **outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; + + // 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 (*outputTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; // Compressed texture size constraints? + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = 1; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(!index.hasLayer()); + + int level = index.mipIndex; + ASSERT(level >= 0 && level < getLevelCount()); + + // In GL ES 2.0, the application can only render to level zero of the texture (Section 4.4.3 of the GLES 2.0 spec, page 113 of version 2.0.25). + // Other parts of TextureStorage11_2D could create RTVs on non-zero levels of the texture (e.g. generateMipmap). + // On Feature Level 9_3, this is unlikely to be useful. The renderer can't create SRVs on the individual levels of the texture, + // so methods like generateMipmap can't do anything useful with non-zero-level RTVs. + // Therefore if level > 0 on 9_3 then there's almost certainly something wrong. + ASSERT(!(mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3 && level > 0)); + + if (!mRenderTarget[level]) + { + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + ID3D11ShaderResourceView *srv = NULL; + error = getSRVLevel(level, &srv); + if (error.isError()) + { + return error; + } + + if (mUseLevelZeroTexture) + { + if (!mLevelZeroRenderTarget) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + ASSERT(SUCCEEDED(result)); + + mLevelZeroRenderTarget = new TextureRenderTarget11(rtv, mLevelZeroTexture, NULL, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelZeroRenderTarget; + return gl::Error(GL_NO_ERROR); + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mTopLevel + level; + dsvDesc.Flags = 0; + + ID3D11DepthStencilView *dsv; + HRESULT result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY,"Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + } + else + { + UNREACHABLE(); + } + } + + ASSERT(outRT); + *outRT = mRenderTarget[level]; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const +{ + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2D.MipLevels = mipLevels; + + ID3D11Resource *srvTexture = texture; + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ASSERT(mTopLevel == 0); + ASSERT(baseLevel == 0); + // This code also assumes that the incoming texture equals either mLevelZeroTexture or mTexture. + + if (mipLevels == 1 && mMipLevels > 1) + { + // We must use a SRV on the level-zero-only texture. + ASSERT(mLevelZeroTexture != NULL && texture == mLevelZeroTexture); + srvTexture = mLevelZeroTexture; + } + else + { + ASSERT(mipLevels == static_cast(mMipLevels)); + ASSERT(mTexture != NULL && texture == mTexture); + srvTexture = mTexture; + } + } + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(srvTexture, &srvDesc, outSRV); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::getSwizzleTexture(ID3D11Resource **outTexture) +{ + ASSERT(outTexture); + + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = 1; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); + } + } + + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } + } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mSwizzleRenderTargets[level] = NULL; + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + mAssociatedImages[face][level] = NULL; + mRenderTarget[face][level] = NULL; + } + } + + mLevelZeroTexture = NULL; + mUseLevelZeroTexture = false; + + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + mLevelZeroRenderTarget[face] = NULL; + } + + mInternalFormat = internalformat; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel()); + mTextureFormat = formatInfo.texFormat; + mShaderResourceFormat = formatInfo.srvFormat; + mDepthStencilFormat = formatInfo.dsvFormat; + mRenderTargetFormat = formatInfo.rtvFormat; + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + // adjust size if needed for compressed textures + int height = size; + d3d11::MakeValidSize(false, mTextureFormat, &size, &height, &mTopLevel); + + mMipLevels = mTopLevel + levels; + mTextureWidth = size; + mTextureHeight = size; + mTextureDepth = 1; + + if (hintLevelZeroOnly && levels > 1) + { + //The LevelZeroOnly hint should only be true if the zero max LOD workaround is active. + ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); + mUseLevelZeroTexture = true; + } + + initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT); +} + +TextureStorage11_Cube::~TextureStorage11_Cube() +{ + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + if (mAssociatedImages[face][level] != NULL) + { + bool imageAssociationCorrect = mAssociatedImages[face][level]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // We must let the Images recover their data before we delete it from the TextureStorage. + mAssociatedImages[face][level]->recoverFromAssociatedStorage(); + } + } + } + } + + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + SafeRelease(mLevelZeroTexture); + + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + SafeDelete(mLevelZeroRenderTarget[face]); + } + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mSwizzleRenderTargets[level]); + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) + { + SafeDelete(mRenderTarget[face][level]); + } + } +} + +TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage)); + return static_cast(storage); +} + +UINT TextureStorage11_Cube::getSubresourceIndex(const gl::ImageIndex &index) const +{ + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround && mUseLevelZeroTexture && index.mipIndex == 0) + { + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT subresource = D3D11CalcSubresource(0, arraySlice, 1); + ASSERT(subresource != std::numeric_limits::max()); + return subresource; + } + else + { + UINT mipSlice = static_cast(index.mipIndex + mTopLevel); + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); + ASSERT(subresource != std::numeric_limits::max()); + return subresource; + } +} + +gl::Error TextureStorage11_Cube::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(destStorage); + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + + // If either mTexture or mLevelZeroTexture exist, then we need to copy them into the corresponding textures in destStorage. + if (mTexture) + { + gl::Error error = dest11->useLevelZeroWorkaroundTexture(false); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + immediateContext->CopyResource(destResource, mTexture); + } + + if (mLevelZeroTexture) + { + gl::Error error = dest11->useLevelZeroWorkaroundTexture(true); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + immediateContext->CopyResource(destResource, mLevelZeroTexture); + } + } + else + { + ID3D11Resource *sourceResouce = NULL; + gl::Error error = getResource(&sourceResouce); + if (error.isError()) + { + return error; + } + + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + immediateContext->CopyResource(destResource, sourceResouce); + } + + dest11->invalidateSwizzleCache(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::useLevelZeroWorkaroundTexture(bool useLevelZeroTexture) +{ + if (useLevelZeroTexture && mMipLevels > 1) + { + if (!mUseLevelZeroTexture && mTexture) + { + gl::Error error = ensureTextureExists(1); + if (error.isError()) + { + return error; + } + + // Pull data back from the mipped texture if necessary. + ASSERT(mLevelZeroTexture); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + for (int face = 0; face < 6; face++) + { + context->CopySubresourceRegion(mLevelZeroTexture, D3D11CalcSubresource(0, face, 1), 0, 0, 0, mTexture, face * mMipLevels, NULL); + } + } + + mUseLevelZeroTexture = true; + } + else + { + if (mUseLevelZeroTexture && mLevelZeroTexture) + { + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + // Pull data back from the level zero texture if necessary. + ASSERT(mTexture); + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + + for (int face = 0; face < 6; face++) + { + context->CopySubresourceRegion(mTexture, D3D11CalcSubresource(0, face, mMipLevels), 0, 0, 0, mLevelZeroTexture, face, NULL); + } + } + + mUseLevelZeroTexture = false; + } + + return gl::Error(GL_NO_ERROR); +} + +void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + { + mAssociatedImages[layerTarget][level] = image; + } + } +} + +bool TextureStorage11_Cube::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + { + // This validation check should never return false. It means the Image/TextureStorage association is broken. + bool retValue = (mAssociatedImages[layerTarget][level] == expectedImage); + ASSERT(retValue); + return retValue; + } + } + + return false; +} + +// disassociateImage allows an Image to end its association with a Storage. +void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + { + ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); + + if (mAssociatedImages[layerTarget][level] == expectedImage) + { + mAssociatedImages[layerTarget][level] = NULL; + } + } + } +} + +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. +gl::Error TextureStorage11_Cube::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); + + if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)) + { + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) + { + // No need to let the old Image recover its data, if it is also the incoming Image. + if (mAssociatedImages[layerTarget][level] != NULL && mAssociatedImages[layerTarget][level] != incomingImage) + { + // Ensure that the Image is still associated with this TextureStorage. This should be true. + bool imageAssociationCorrect = mAssociatedImages[layerTarget][level]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to NULL too. + gl::Error error = mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::getResource(ID3D11Resource **outResource) +{ + if (mUseLevelZeroTexture && mMipLevels > 1) + { + gl::Error error = ensureTextureExists(1); + if (error.isError()) + { + return error; + } + + *outResource = mLevelZeroTexture; + return gl::Error(GL_NO_ERROR); + } + else + { + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error TextureStorage11_Cube::getMippedResource(ID3D11Resource **outResource) +{ + // This shouldn't be called unless the zero max LOD workaround is active. + ASSERT(mRenderer->getWorkarounds().zeroMaxLodWorkaround); + + gl::Error error = ensureTextureExists(mMipLevels); + if (error.isError()) + { + return error; + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::ensureTextureExists(int mipLevels) +{ + // If mMipLevels = 1 then always use mTexture rather than mLevelZeroTexture. + bool useLevelZeroTexture = mRenderer->getWorkarounds().zeroMaxLodWorkaround ? (mipLevels == 1) && (mMipLevels > 1) : false; + ID3D11Texture2D **outputTexture = useLevelZeroTexture ? &mLevelZeroTexture : &mTexture; + + // 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 (*outputTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mipLevels; + desc.ArraySize = CUBE_FACE_COUNT; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, outputTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + int faceIndex = index.layerIndex; + int level = index.mipIndex; + + ASSERT(level >= 0 && level < getLevelCount()); + ASSERT(faceIndex >= 0 && faceIndex < CUBE_FACE_COUNT); + + if (!mRenderTarget[faceIndex][level]) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + if (mUseLevelZeroTexture) + { + if (!mLevelZeroRenderTarget[faceIndex]) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(mLevelZeroTexture, &rtvDesc, &rtv); + + if (result == E_OUTOFMEMORY) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + ASSERT(SUCCEEDED(result)); + + mLevelZeroRenderTarget[faceIndex] = new TextureRenderTarget11(rtv, mLevelZeroTexture, NULL, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelZeroRenderTarget[faceIndex]; + return gl::Error(GL_NO_ERROR); + } + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = faceIndex; + srvDesc.Texture2DArray.ArraySize = 1; + + if (mRenderer->getFeatureLevel() <= D3D_FEATURE_LEVEL_9_3) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube + } + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(texture, &srvDesc, &srv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[faceIndex][level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Flags = 0; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; + dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; + dsvDesc.Texture2DArray.ArraySize = 1; + + ID3D11DepthStencilView *dsv; + result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[faceIndex][level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + ASSERT(outRT); + *outRT = mRenderTarget[faceIndex][level]; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const +{ + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + + // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six 2D textures + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); + if (dxgiFormatInfo.componentType == GL_INT || dxgiFormatInfo.componentType == GL_UNSIGNED_INT) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srvDesc.TextureCube.MipLevels = mipLevels; + srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; + } + + ID3D11Resource *srvTexture = texture; + + if (mRenderer->getWorkarounds().zeroMaxLodWorkaround) + { + ASSERT(mTopLevel == 0); + ASSERT(baseLevel == 0); + // This code also assumes that the incoming texture equals either mLevelZeroTexture or mTexture. + + if (mipLevels == 1 && mMipLevels > 1) + { + // We must use a SRV on the level-zero-only texture. + ASSERT(mLevelZeroTexture != NULL && texture == mLevelZeroTexture); + srvTexture = mLevelZeroTexture; + } + else + { + ASSERT(mipLevels == static_cast(mMipLevels)); + ASSERT(mTexture != NULL && texture == mTexture); + srvTexture = mTexture; + } + } + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(srvTexture, &srvDesc, outSRV); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::getSwizzleTexture(ID3D11Resource **outTexture) +{ + ASSERT(outTexture); + + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = CUBE_FACE_COUNT; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); + } + } + + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } + } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + mAssociatedImages[i] = NULL; + mLevelRenderTargets[i] = NULL; + mSwizzleRenderTargets[i] = NULL; + } + + mInternalFormat = internalformat; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel()); + mTextureFormat = formatInfo.texFormat; + mShaderResourceFormat = formatInfo.srvFormat; + mDepthStencilFormat = formatInfo.dsvFormat; + mRenderTargetFormat = formatInfo.rtvFormat; + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = depth; + + initializeSerials(getLevelCount() * depth, depth); +} + +TextureStorage11_3D::~TextureStorage11_3D() +{ + for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + if (mAssociatedImages[i] != NULL) + { + bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // We must let the Images recover their data before we delete it from the TextureStorage. + mAssociatedImages[i]->recoverFromAssociatedStorage(); + } + } + } + + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (RenderTargetMap::iterator i = mLevelLayerRenderTargets.begin(); i != mLevelLayerRenderTargets.end(); i++) + { + SafeDelete(i->second); + } + mLevelLayerRenderTargets.clear(); + + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) + { + SafeDelete(mLevelRenderTargets[i]); + SafeRelease(mSwizzleRenderTargets[i]); + } +} + +TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_3D*, storage)); + return static_cast(storage); +} + +void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + mAssociatedImages[level] = image; + } +} + +bool TextureStorage11_3D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + // This validation check should never return false. It means the Image/TextureStorage association is broken. + bool retValue = (mAssociatedImages[level] == expectedImage); + ASSERT(retValue); + return retValue; + } + + return false; +} + +// disassociateImage allows an Image to end its association with a Storage. +void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + ASSERT(mAssociatedImages[level] == expectedImage); + + if (mAssociatedImages[level] == expectedImage) + { + mAssociatedImages[level] = NULL; + } + } +} + +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. +gl::Error TextureStorage11_3D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +{ + GLint level = index.mipIndex; + + ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)); + + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) + { + // No need to let the old Image recover its data, if it is also the incoming Image. + if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) + { + // Ensure that the Image is still associated with this TextureStorage. This should be true. + bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to NULL too. + gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_3D::getResource(ID3D11Resource **outResource) +{ + // If the width, height or depth are not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); + } + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const +{ + ASSERT(outSRV); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + srvDesc.Texture3D.MostDetailedMip = baseLevel; + srvDesc.Texture3D.MipLevels = mipLevels; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + int mipLevel = index.mipIndex; + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + + ASSERT(mRenderTargetFormat != DXGI_FORMAT_UNKNOWN); + + if (!index.hasLayer()) + { + if (!mLevelRenderTargets[mipLevel]) + { + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + ID3D11ShaderResourceView *srv = NULL; + error = getSRVLevel(mipLevel, &srv); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = static_cast(-1); + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mLevelRenderTargets[mipLevel] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel), 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); + } + else + { + int layer = index.layerIndex; + + LevelLayerKey key(mipLevel, layer); + if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + // TODO, what kind of SRV is expected here? + ID3D11ShaderResourceView *srv = NULL; + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = layer; + rtvDesc.Texture3D.WSize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + ASSERT(SUCCEEDED(result)); + + mLevelLayerRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelLayerRenderTargets[key]; + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error TextureStorage11_3D::getSwizzleTexture(ID3D11Resource **outTexture) +{ + ASSERT(outTexture); + + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mSwizzleTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mSwizzleTexture); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); + } + } + + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = static_cast(-1); + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } + } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels) + : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderer->getFeatureLevel(), renderTarget)) +{ + mTexture = NULL; + mSwizzleTexture = NULL; + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + mSwizzleRenderTargets[level] = NULL; + } + + mInternalFormat = internalformat; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat, renderer->getFeatureLevel()); + mTextureFormat = formatInfo.texFormat; + mShaderResourceFormat = formatInfo.srvFormat; + mDepthStencilFormat = formatInfo.dsvFormat; + mRenderTargetFormat = formatInfo.rtvFormat; + mSwizzleTextureFormat = formatInfo.swizzleTexFormat; + mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; + mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = depth; + + initializeSerials(getLevelCount() * depth, depth); +} + +TextureStorage11_2DArray::~TextureStorage11_2DArray() +{ + for (ImageMap::iterator i = mAssociatedImages.begin(); i != mAssociatedImages.end(); i++) + { + if (i->second) + { + bool imageAssociationCorrect = i->second->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // We must let the Images recover their data before we delete it from the TextureStorage. + i->second->recoverFromAssociatedStorage(); + } + } + } + mAssociatedImages.clear(); + + SafeRelease(mTexture); + SafeRelease(mSwizzleTexture); + + for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) + { + SafeRelease(mSwizzleRenderTargets[level]); + } + + for (RenderTargetMap::iterator i = mRenderTargets.begin(); i != mRenderTargets.end(); i++) + { + SafeDelete(i->second); + } + mRenderTargets.clear(); +} + +TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2DArray*, storage)); + return static_cast(storage); +} + +void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + ASSERT(0 <= level && level < getLevelCount()); + + if (0 <= level && level < getLevelCount()) + { + LevelLayerKey key(level, layerTarget); + mAssociatedImages[key] = image; + } +} + +bool TextureStorage11_2DArray::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + LevelLayerKey key(level, layerTarget); + + // This validation check should never return false. It means the Image/TextureStorage association is broken. + bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); + ASSERT(retValue); + return retValue; +} + +// disassociateImage allows an Image to end its association with a Storage. +void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + LevelLayerKey key(level, layerTarget); + + bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + mAssociatedImages[key] = NULL; + } +} + +// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. +gl::Error TextureStorage11_2DArray::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) +{ + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + + LevelLayerKey key(level, layerTarget); + + if (mAssociatedImages.find(key) != mAssociatedImages.end()) + { + if (mAssociatedImages[key] != NULL && mAssociatedImages[key] != incomingImage) + { + // Ensure that the Image is still associated with this TextureStorage. This should be true. + bool imageAssociationCorrect = mAssociatedImages[key]->isAssociatedStorageValid(this); + ASSERT(imageAssociationCorrect); + + if (imageAssociationCorrect) + { + // Force the image to recover from storage before its data is overwritten. + // This will reset mAssociatedImages[level] to NULL too. + gl::Error error = mAssociatedImages[key]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::getResource(ID3D11Resource **outResource) +{ + // if the width, height or depth is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); + } + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; + srvDesc.Texture2DArray.MipLevels = mipLevels; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = mTextureDepth; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(index.hasLayer()); + + int mipLevel = index.mipIndex; + int layer = index.layerIndex; + + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + + LevelLayerKey key(mipLevel, layer); + if (mRenderTargets.find(key) == mRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + mipLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = layer; + srvDesc.Texture2DArray.ArraySize = 1; + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(texture, &srvDesc, &srv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = layer; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } + } + + ASSERT(outRT); + *outRT = mRenderTargets[key]; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::getSwizzleTexture(ID3D11Resource **outTexture) +{ + if (!mSwizzleTexture) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mSwizzleTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); + } + } + + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) + { + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) + { + return error; + } + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = mTextureDepth; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } + } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h new file mode 100644 index 0000000000..456e2660f9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h @@ -0,0 +1,326 @@ +// +// Copyright (c) 2012-2013 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. +// + +// TextureStorage11.h: Defines the abstract rx::TextureStorage11 class and its concrete derived +// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ + +#include "libANGLE/Texture.h" +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/TextureStorage.h" + +#include + +namespace gl +{ +struct ImageIndex; +} + +namespace rx +{ +class RenderTargetD3D; +class RenderTarget11; +class Renderer11; +class SwapChain11; +class Image11; + +class TextureStorage11 : public TextureStorage +{ + public: + virtual ~TextureStorage11(); + + static TextureStorage11 *makeTextureStorage11(TextureStorage *storage); + + static DWORD GetTextureBindFlags(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel, bool renderTarget); + + UINT getBindFlags() const; + + virtual gl::Error getResource(ID3D11Resource **outResource) = 0; + virtual gl::Error getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); + + virtual int getTopLevel() const; + virtual bool isRenderTarget() const; + virtual bool isManaged() const; + virtual int getLevelCount() const; + virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; + + gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + void invalidateSwizzleCacheLevel(int mipLevel); + void invalidateSwizzleCache(); + + gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, + const gl::ImageIndex &index, const gl::Box ©Area); + + gl::Error copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, + const gl::ImageIndex &index, const gl::Box ®ion); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index) = 0; + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) = 0; + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) = 0; + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0; + + virtual gl::Error copyToStorage(TextureStorage *destStorage); + virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData); + + protected: + TextureStorage11(Renderer11 *renderer, UINT bindFlags); + int getLevelWidth(int mipLevel) const; + int getLevelHeight(int mipLevel) const; + int getLevelDepth(int mipLevel) const; + + // Some classes (e.g. TextureStorage11_2D) will override getMippedResource. + virtual gl::Error getMippedResource(ID3D11Resource **outResource) { return getResource(outResource); } + + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture) = 0; + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) = 0; + gl::Error getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV); + + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const = 0; + + void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); + + Renderer11 *mRenderer; + int mTopLevel; + unsigned int mMipLevels; + + GLenum mInternalFormat; + DXGI_FORMAT mTextureFormat; + DXGI_FORMAT mShaderResourceFormat; + DXGI_FORMAT mRenderTargetFormat; + DXGI_FORMAT mDepthStencilFormat; + DXGI_FORMAT mSwizzleTextureFormat; + DXGI_FORMAT mSwizzleShaderResourceFormat; + DXGI_FORMAT mSwizzleRenderTargetFormat; + unsigned int mTextureWidth; + unsigned int mTextureHeight; + unsigned int mTextureDepth; + + struct SwizzleCacheValue + { + GLenum swizzleRed; + GLenum swizzleGreen; + GLenum swizzleBlue; + GLenum swizzleAlpha; + + SwizzleCacheValue(); + SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha); + + bool operator ==(const SwizzleCacheValue &other) const; + bool operator !=(const SwizzleCacheValue &other) const; + }; + SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + private: + const UINT mBindFlags; + + struct SRVKey + { + SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); + + bool operator<(const SRVKey &rhs) const; + + int baseLevel; + int mipLevels; + bool swizzle; + }; + typedef std::map SRVCache; + + SRVCache mSrvCache; + ID3D11ShaderResourceView *mLevelSRVs[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_2D : public TextureStorage11 +{ + public: + TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain); + TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly = false); + virtual ~TextureStorage11_2D(); + + static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage); + + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getMippedResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + + virtual gl::Error copyToStorage(TextureStorage *destStorage); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + + virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); + + protected: + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + + gl::Error ensureTextureExists(int mipLevels); + + private: + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + ID3D11Texture2D *mTexture; + RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + // These are members related to the zero max-LOD workaround. + // D3D11 Feature Level 9_3 can't disable mipmaps on a mipmapped texture (i.e. solely sample from level zero). + // These members are used to work around this limitation. + // Usually only mTexture XOR mLevelZeroTexture will exist. + // For example, if an app creates a texture with only one level, then 9_3 will only create mLevelZeroTexture. + // However, in some scenarios, both textures have to be created. This incurs additional memory overhead. + // One example of this is an application that creates a texture, calls glGenerateMipmap, and then disables mipmaps on the texture. + // A more likely example is an app that creates an empty texture, renders to it, and then calls glGenerateMipmap + // TODO: In this rendering scenario, release the mLevelZeroTexture after mTexture has been created to save memory. + ID3D11Texture2D *mLevelZeroTexture; + RenderTarget11 *mLevelZeroRenderTarget; + bool mUseLevelZeroTexture; + + // Swizzle-related variables + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_Cube : public TextureStorage11 +{ + public: + TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); + virtual ~TextureStorage11_Cube(); + + static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage); + + virtual UINT getSubresourceIndex(const gl::ImageIndex &index) const; + + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getMippedResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + + virtual gl::Error copyToStorage(TextureStorage *destStorage); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + + virtual gl::Error useLevelZeroWorkaroundTexture(bool useLevelZeroTexture); + + protected: + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + + gl::Error ensureTextureExists(int mipLevels); + + private: + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + static const size_t CUBE_FACE_COUNT = 6; + + ID3D11Texture2D *mTexture; + RenderTarget11 *mRenderTarget[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + // Level-zero workaround members. See TextureStorage11_2D's workaround members for a description. + ID3D11Texture2D *mLevelZeroTexture; + RenderTarget11 *mLevelZeroRenderTarget[CUBE_FACE_COUNT]; + bool mUseLevelZeroTexture; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + Image11 *mAssociatedImages[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_3D : public TextureStorage11 +{ + public: + TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorage11_3D(); + + static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage); + + virtual gl::Error getResource(ID3D11Resource **outResource); + + // Handles both layer and non-layer RTs + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + + protected: + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + + private: + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + typedef std::pair LevelLayerKey; + typedef std::map RenderTargetMap; + RenderTargetMap mLevelLayerRenderTargets; + + RenderTarget11 *mLevelRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + ID3D11Texture3D *mTexture; + ID3D11Texture3D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; +}; + +class TextureStorage11_2DArray : public TextureStorage11 +{ + public: + TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, + GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual ~TextureStorage11_2DArray(); + + static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage); + + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); + + protected: + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); + + private: + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + typedef std::pair LevelLayerKey; + typedef std::map RenderTargetMap; + RenderTargetMap mRenderTargets; + + ID3D11Texture2D *mTexture; + + ID3D11Texture2D *mSwizzleTexture; + ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + + typedef std::map ImageMap; + ImageMap mAssociatedImages; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_TEXTURESTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp new file mode 100644 index 0000000000..213ce31817 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp @@ -0,0 +1,95 @@ +// +// Copyright (c) 2014 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. +// + +// Trim11.cpp: Trim support utility class. + +#include "libANGLE/renderer/d3d/d3d11/Trim11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" + +#if defined (ANGLE_ENABLE_WINDOWS_STORE) +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::ApplicationModel; +using namespace ABI::Windows::ApplicationModel::Core; +#endif + +namespace rx +{ + +Trim11::Trim11(rx::Renderer11 *renderer) + : mRenderer(renderer) +{ + bool result = true; + result = registerForRendererTrimRequest(); + ASSERT(result); +} + +Trim11::~Trim11() +{ + unregisterForRendererTrimRequest(); +} + +void Trim11::trim() +{ + if (!mRenderer) + { + return; + } + +#if defined (ANGLE_ENABLE_WINDOWS_STORE) + ID3D11Device* device = mRenderer->getDevice(); + // IDXGIDevice3 is only supported on Windows 8.1 and Windows Phone 8.1 and above. + IDXGIDevice3 *dxgiDevice3 = d3d11::DynamicCastComObject(device); + if (dxgiDevice3) + { + dxgiDevice3->Trim(); + } + SafeRelease(dxgiDevice3); +#endif +} + +bool Trim11::registerForRendererTrimRequest() +{ +#if defined (ANGLE_ENABLE_WINDOWS_STORE) + ICoreApplication* coreApplication = nullptr; + HRESULT result = GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), &coreApplication); + if (SUCCEEDED(result)) + { + auto suspendHandler = Callback>( + [this](IInspectable*, ISuspendingEventArgs*) -> HRESULT + { + trim(); + return S_OK; + }); + result = coreApplication->add_Suspending(suspendHandler.Get(), &mApplicationSuspendedEventToken); + } + SafeRelease(coreApplication); + + if (FAILED(result)) + { + return false; + } +#endif + return true; +} + +void Trim11::unregisterForRendererTrimRequest() +{ +#if defined (ANGLE_ENABLE_WINDOWS_STORE) + if (mApplicationSuspendedEventToken.value != 0) + { + ICoreApplication* coreApplication = nullptr; + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), &coreApplication))) + { + coreApplication->remove_Suspending(mApplicationSuspendedEventToken); + } + mApplicationSuspendedEventToken.value = 0; + SafeRelease(coreApplication); + } +#endif +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h new file mode 100644 index 0000000000..f232ad7e8e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Trim11.h @@ -0,0 +1,43 @@ +// +// Copyright (c) 2014 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. +// + +// Trim11.h: Trim support utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_TRIM11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_TRIM11_H_ + +#include "common/angleutils.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Error.h" + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +typedef void* EventRegistrationToken; +#else +#include +#endif + +namespace rx +{ +class Renderer11; + +class Trim11 : angle::NonCopyable +{ + public: + explicit Trim11(Renderer11 *renderer); + ~Trim11(); + + private: + Renderer11 *mRenderer; + EventRegistrationToken mApplicationSuspendedEventToken; + + void trim(); + bool registerForRendererTrimRequest(); + void unregisterForRendererTrimRequest(); +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_TRIM11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h new file mode 100644 index 0000000000..78aad7d106 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexArray11.h @@ -0,0 +1,40 @@ +// +// Copyright 2014 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. +// + +// VertexArray11.h: Defines the rx::VertexArray11 class which implements rx::VertexArrayImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ + +#include "libANGLE/renderer/VertexArrayImpl.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ +class Renderer11; + +class VertexArray11 : public VertexArrayImpl +{ + public: + VertexArray11(Renderer11 *renderer) + : VertexArrayImpl(), + mRenderer(renderer) + { + } + virtual ~VertexArray11() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } + virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } + virtual void enableAttribute(size_t idx, bool enabledState) { } + + private: + Renderer11 *mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXARRAY11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp new file mode 100644 index 0000000000..adc64cef5e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp @@ -0,0 +1,244 @@ +// +// Copyright (c) 2013 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. +// + +// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d11/VertexBuffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Buffer11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/VertexAttribute.h" + +namespace rx +{ + +VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) +{ + mBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; + mMappedResourceData = NULL; +} + +VertexBuffer11::~VertexBuffer11() +{ + ASSERT(mMappedResourceData == NULL); + SafeRelease(mBuffer); +} + +gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) +{ + SafeRelease(mBuffer); + + updateSerial(); + + if (size > 0) + { + ID3D11Device* dxDevice = mRenderer->getDevice(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = size; + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + + HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + + return gl::Error(GL_NO_ERROR); +} + +VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer)); + return static_cast(vetexBuffer); +} + +gl::Error VertexBuffer11::mapResource() +{ + if (mMappedResourceData == NULL) + { + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer, HRESULT: 0x%08x.", result); + } + + mMappedResourceData = reinterpret_cast(mappedResource.pData); + } + + return gl::Error(GL_NO_ERROR); +} + +void VertexBuffer11::hintUnmapResource() +{ + if (mMappedResourceData != NULL) + { + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + dxContext->Unmap(mBuffer, 0); + + mMappedResourceData = NULL; + } +} + +gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + gl::Buffer *buffer = attrib.buffer.get(); + int inputStride = ComputeVertexAttributeStride(attrib); + + // This will map the resource if it isn't already mapped. + gl::Error error = mapResource(); + if (error.isError()) + { + return error; + } + + uint8_t *output = mMappedResourceData + offset; + + const uint8_t *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + BufferD3D *storage = GetImplAs(buffer); + error = storage->getData(&input); + if (error.isError()) + { + return error; + } + input += static_cast(attrib.offset); + } + else + { + input = static_cast(attrib.pointer); + } + } + else + { + input = reinterpret_cast(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mRenderer->getFeatureLevel()); + ASSERT(vertexFormatInfo.copyFunction != NULL); + vertexFormatInfo.copyFunction(input, inputStride, count, output); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, + GLsizei instances, unsigned int *outSpaceRequired) const +{ + unsigned int elementCount = 0; + if (attrib.enabled) + { + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); + } + + gl::VertexFormat vertexFormat(attrib); + const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat, mRenderer->getFeatureLevel()); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(vertexFormatInfo.nativeFormat); + unsigned int elementSize = dxgiFormatInfo.pixelBytes; + if (elementSize <= std::numeric_limits::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * elementCount; + } + return gl::Error(GL_NO_ERROR); + } + else + { + return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return gl::Error(GL_NO_ERROR); + } +} + +unsigned int VertexBuffer11::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error VertexBuffer11::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error VertexBuffer11::discard() +{ + if (!mBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); + + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer for discarding, HRESULT: 0x%08x", result); + } + + dxContext->Unmap(mBuffer, 0); + + return gl::Error(GL_NO_ERROR); +} + +ID3D11Buffer *VertexBuffer11::getBuffer() const +{ + return mBuffer; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h new file mode 100644 index 0000000000..2450e8955c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.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. +// + +// VertexBuffer11.h: Defines the D3D11 VertexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_VERTEXBUFFER11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_VERTEXBUFFER11_H_ + +#include + +#include "libANGLE/renderer/d3d/VertexBuffer.h" + +namespace rx +{ +class Renderer11; + +class VertexBuffer11 : public VertexBuffer +{ + public: + explicit VertexBuffer11(Renderer11 *const renderer); + virtual ~VertexBuffer11(); + + virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + + static VertexBuffer11 *makeVertexBuffer11(VertexBuffer *vetexBuffer); + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); + + virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const; + + virtual unsigned int getBufferSize() const; + virtual gl::Error setBufferSize(unsigned int size); + virtual gl::Error discard(); + + virtual void hintUnmapResource(); + + ID3D11Buffer *getBuffer() const; + + private: + gl::Error mapResource(); + + Renderer11 *const mRenderer; + + ID3D11Buffer *mBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; + + uint8_t *mMappedResourceData; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_VERTEXBUFFER11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.h new file mode 100644 index 0000000000..5501e361f1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2013-2015 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. +// + +// copyvertex.h: Defines D3D11 vertex buffer copying and conversion functions + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_COPYVERTEX_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_COPYVERTEX_H_ + +#include "common/mathutil.h" + +namespace rx +{ + +// 'alphaDefaultValueBits' gives the default value for the alpha channel (4th component) +template +inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void Copy8SintTo16SintVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void Copy8SnormTo16SnormVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void Copy32FixedTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +template +inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +} + +#include "copyvertex.inl" + +#endif // LIBANGLE_RENDERER_D3D_D3D11_COPYVERTEX_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl new file mode 100644 index 0000000000..60678d7b9f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/copyvertex.inl @@ -0,0 +1,377 @@ +// +// Copyright (c) 2014-2015 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. +// + +namespace rx +{ + +template +inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + const size_t attribSize = sizeof(T)* inputComponentCount; + + if (attribSize == stride && inputComponentCount == outputComponentCount) + { + memcpy(output, input, count * attribSize); + } + else + { + const T defaultAlphaValue = gl::bitCast(alphaDefaultValueBits); + const size_t lastNonAlphaOutputComponent = std::min(outputComponentCount, 3); + + for (size_t i = 0; i < count; i++) + { + const T *offsetInput = reinterpret_cast(input + (i * stride)); + T *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + offsetOutput[j] = offsetInput[j]; + } + + for (size_t j = inputComponentCount; j < lastNonAlphaOutputComponent; j++) + { + // Set the remaining G/B channels to 0. + offsetOutput[j] = 0; + } + + if (inputComponentCount < outputComponentCount && outputComponentCount == 4) + { + // Set the remaining alpha channel to the defaultAlphaValue. + offsetOutput[3] = defaultAlphaValue; + } + } + } +} + +template +inline void Copy8SintTo16SintVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + const size_t lastNonAlphaOutputComponent = std::min(outputComponentCount, 3); + + for (size_t i = 0; i < count; i++) + { + const GLbyte *offsetInput = reinterpret_cast(input + i * stride); + GLshort *offsetOutput = reinterpret_cast(output)+i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + offsetOutput[j] = static_cast(offsetInput[j]); + } + + for (size_t j = inputComponentCount; j < lastNonAlphaOutputComponent; j++) + { + // Set remaining G/B channels to 0. + offsetOutput[j] = 0; + } + + if (inputComponentCount < outputComponentCount && outputComponentCount == 4) + { + // On integer formats, we must set the Alpha channel to 1 if it's unused. + offsetOutput[3] = 1; + } + } +} + +template +inline void Copy8SnormTo16SnormVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + for (size_t i = 0; i < count; i++) + { + const GLbyte *offsetInput = reinterpret_cast(input + i * stride); + GLshort *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + // The original GLbyte value ranges from -128 to +127 (INT8_MAX). + // When converted to GLshort, the value must be scaled to between -32768 and +32767 (INT16_MAX). + if (offsetInput[j] > 0) + { + offsetOutput[j] = offsetInput[j] << 8 | offsetInput[j] << 1 | ((offsetInput[j] & 0x40) >> 6); + } + else + { + offsetOutput[j] = offsetInput[j] << 8; + } + } + + for (size_t j = inputComponentCount; j < std::min(outputComponentCount, 3); j++) + { + // Set remaining G/B channels to 0. + offsetOutput[j] = 0; + } + + if (inputComponentCount < outputComponentCount && outputComponentCount == 4) + { + // On normalized formats, we must set the Alpha channel to the max value if it's unused. + offsetOutput[3] = INT16_MAX; + } + } +} + +template +inline void Copy32FixedTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + static const float divisor = 1.0f / (1 << 16); + + for (size_t i = 0; i < count; i++) + { + const GLfixed* offsetInput = reinterpret_cast(input + (stride * i)); + float* offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + offsetOutput[j] = static_cast(offsetInput[j]) * divisor; + } + + // 4-component output formats would need special padding in the alpha channel. + static_assert(!(inputComponentCount < 4 && outputComponentCount == 4), + "An inputComponentCount less than 4 and an outputComponentCount equal to 4 is not supported."); + + for (size_t j = inputComponentCount; j < outputComponentCount; j++) + { + offsetOutput[j] = 0.0f; + } + } +} + +template +inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + typedef std::numeric_limits NL; + + for (size_t i = 0; i < count; i++) + { + const T *offsetInput = reinterpret_cast(input + (stride * i)); + float *offsetOutput = reinterpret_cast(output) + i * outputComponentCount; + + for (size_t j = 0; j < inputComponentCount; j++) + { + if (normalized) + { + if (NL::is_signed) + { + const float divisor = 1.0f / (2 * static_cast(NL::max()) + 1); + offsetOutput[j] = (2 * static_cast(offsetInput[j]) + 1) * divisor; + } + else + { + offsetOutput[j] = static_cast(offsetInput[j]) / NL::max(); + } + } + else + { + offsetOutput[j] = static_cast(offsetInput[j]); + } + } + + // This would require special padding. + static_assert(!(inputComponentCount < 4 && outputComponentCount == 4), + "An inputComponentCount less than 4 and an outputComponentCount equal to 4 is not supported."); + + for (size_t j = inputComponentCount; j < outputComponentCount; j++) + { + offsetOutput[j] = 0.0f; + } + } +} + +namespace priv +{ + +template +static inline void CopyPackedRGB(uint32_t data, uint8_t *output) +{ + const uint32_t rgbSignMask = 0x200; // 1 set at the 9 bit + const uint32_t negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1 + + if (toFloat) + { + GLfloat *floatOutput = reinterpret_cast(output); + if (isSigned) + { + GLfloat finalValue = 0; + if (data & rgbSignMask) + { + int negativeNumber = data | negativeMask; + finalValue = static_cast(negativeNumber); + } + else + { + finalValue = static_cast(data); + } + + if (normalized) + { + const int32_t maxValue = 0x1FF; // 1 set in bits 0 through 8 + const int32_t minValue = 0xFFFFFE01; // Inverse of maxValue + + // A 10-bit two's complement number has the possibility of being minValue - 1 but + // OpenGL's normalization rules dictate that it should be clamped to minValue in this + // case. + if (finalValue < minValue) + { + finalValue = minValue; + } + + const int32_t halfRange = (maxValue - minValue) >> 1; + *floatOutput = ((finalValue - minValue) / halfRange) - 1.0f; + } + else + { + *floatOutput = finalValue; + } + } + else + { + if (normalized) + { + const uint32_t maxValue = 0x3FF; // 1 set in bits 0 through 9 + *floatOutput = static_cast(data) / static_cast(maxValue); + } + else + { + *floatOutput = static_cast(data); + } + } + } + else + { + if (isSigned) + { + GLshort *intOutput = reinterpret_cast(output); + + if (data & rgbSignMask) + { + *intOutput = data | negativeMask; + } + else + { + *intOutput = data; + } + } + else + { + GLushort *uintOutput = reinterpret_cast(output); + *uintOutput = data; + } + } +} + +template +inline void CopyPackedAlpha(uint32_t data, uint8_t *output) +{ + if (toFloat) + { + GLfloat *floatOutput = reinterpret_cast(output); + if (isSigned) + { + if (normalized) + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = -1.0f; break; + case 0x3: *floatOutput = -1.0f; break; + default: UNREACHABLE(); + } + } + else + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = -2.0f; break; + case 0x3: *floatOutput = -1.0f; break; + default: UNREACHABLE(); + } + } + } + else + { + if (normalized) + { + switch (data) + { + case 0x0: *floatOutput = 0.0f / 3.0f; break; + case 0x1: *floatOutput = 1.0f / 3.0f; break; + case 0x2: *floatOutput = 2.0f / 3.0f; break; + case 0x3: *floatOutput = 3.0f / 3.0f; break; + default: UNREACHABLE(); + } + } + else + { + switch (data) + { + case 0x0: *floatOutput = 0.0f; break; + case 0x1: *floatOutput = 1.0f; break; + case 0x2: *floatOutput = 2.0f; break; + case 0x3: *floatOutput = 3.0f; break; + default: UNREACHABLE(); + } + } + } + } + else + { + if (isSigned) + { + GLshort *intOutput = reinterpret_cast(output); + switch (data) + { + case 0x0: *intOutput = 0; break; + case 0x1: *intOutput = 1; break; + case 0x2: *intOutput = -2; break; + case 0x3: *intOutput = -1; break; + default: UNREACHABLE(); + } + } + else + { + GLushort *uintOutput = reinterpret_cast(output); + switch (data) + { + case 0x0: *uintOutput = 0; break; + case 0x1: *uintOutput = 1; break; + case 0x2: *uintOutput = 2; break; + case 0x3: *uintOutput = 3; break; + default: UNREACHABLE(); + } + } + } +} + +} + +template +inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) +{ + const size_t outputComponentSize = toFloat ? 4 : 2; + const size_t componentCount = 4; + + const uint32_t rgbMask = 0x3FF; // 1 set in bits 0 through 9 + const size_t redShift = 0; // red is bits 0 through 9 + const size_t greenShift = 10; // green is bits 10 through 19 + const size_t blueShift = 20; // blue is bits 20 through 29 + + const uint32_t alphaMask = 0x3; // 1 set in bits 0 and 1 + const size_t alphaShift = 30; // Alpha is the 30 and 31 bits + + for (size_t i = 0; i < count; i++) + { + GLuint packedValue = *reinterpret_cast(input + (i * stride)); + uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount); + + priv::CopyPackedRGB( (packedValue >> redShift) & rgbMask, offsetOutput + (0 * outputComponentSize)); + priv::CopyPackedRGB( (packedValue >> greenShift) & rgbMask, offsetOutput + (1 * outputComponentSize)); + priv::CopyPackedRGB( (packedValue >> blueShift) & rgbMask, offsetOutput + (2 * outputComponentSize)); + priv::CopyPackedAlpha((packedValue >> alphaShift) & alphaMask, offsetOutput + (3 * outputComponentSize)); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp new file mode 100644 index 0000000000..2f81d6d608 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp @@ -0,0 +1,1328 @@ +// +// Copyright (c) 2013-2014 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. +// + +// formatutils11.cpp: Queries for GL image formats and their translations to D3D11 +// formats. + +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/Renderer.h" +#include "libANGLE/renderer/d3d/copyimage.h" +#include "libANGLE/renderer/d3d/generatemip.h" +#include "libANGLE/renderer/d3d/loadimage.h" +#include "libANGLE/renderer/d3d/d3d11/copyvertex.h" + +namespace rx +{ + +namespace d3d11 +{ + +typedef std::map DXGIToESFormatMap; + +inline void AddDXGIToESEntry(DXGIToESFormatMap *map, DXGI_FORMAT key, GLenum value) +{ + map->insert(std::make_pair(key, value)); +} + +static DXGIToESFormatMap BuildDXGIToESFormatMap() +{ + DXGIToESFormatMap map; + + AddDXGIToESEntry(&map, DXGI_FORMAT_UNKNOWN, GL_NONE); + + AddDXGIToESEntry(&map, DXGI_FORMAT_A8_UNORM, GL_ALPHA8_EXT); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UNORM, GL_R8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UNORM, GL_RG8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM, GL_RGBA8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, GL_SRGB8_ALPHA8); + AddDXGIToESEntry(&map, DXGI_FORMAT_B8G8R8A8_UNORM, GL_BGRA8_EXT); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SNORM, GL_R8_SNORM); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SNORM, GL_RG8_SNORM); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SNORM, GL_RGBA8_SNORM); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UINT, GL_R8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UINT, GL_R16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_UINT, GL_R32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UINT, GL_RG8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_UINT, GL_RG16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_UINT, GL_RG32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_UINT, GL_RGB32UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UINT, GL_RGBA8UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_UINT, GL_RGBA16UI); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_UINT, GL_RGBA32UI); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SINT, GL_R8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_SINT, GL_R16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_SINT, GL_R32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SINT, GL_RG8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_SINT, GL_RG16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_SINT, GL_RG32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_SINT, GL_RGB32I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SINT, GL_RGBA8I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_SINT, GL_RGBA16I); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_SINT, GL_RGBA32I); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UNORM, GL_RGB10_A2); + AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UINT, GL_RGB10_A2UI); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_FLOAT, GL_R16F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_FLOAT, GL_RG16F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, GL_RGBA16F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT, GL_R32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_FLOAT, GL_RG32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_FLOAT, GL_RGB32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, GL_RGBA32F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, GL_RGB9_E5); + AddDXGIToESEntry(&map, DXGI_FORMAT_R11G11B10_FLOAT, GL_R11F_G11F_B10F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_TYPELESS, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UNORM, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_D16_UNORM, GL_DEPTH_COMPONENT16); + AddDXGIToESEntry(&map, DXGI_FORMAT_R24G8_TYPELESS, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8_OES); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32G8X24_TYPELESS, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8); + AddDXGIToESEntry(&map, DXGI_FORMAT_R32_TYPELESS, GL_DEPTH_COMPONENT32F); + AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT, GL_DEPTH_COMPONENT32F); + + AddDXGIToESEntry(&map, DXGI_FORMAT_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + AddDXGIToESEntry(&map, DXGI_FORMAT_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); + AddDXGIToESEntry(&map, DXGI_FORMAT_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); + + return map; +} + +struct D3D11FastCopyFormat +{ + GLenum destFormat; + GLenum destType; + ColorCopyFunction copyFunction; + + D3D11FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) + : destFormat(destFormat), destType(destType), copyFunction(copyFunction) + { } + + bool operator<(const D3D11FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D11FastCopyFormat)) < 0; + } +}; + +typedef std::multimap D3D11FastCopyMap; + +static D3D11FastCopyMap BuildFastCopyMap() +{ + D3D11FastCopyMap map; + + map.insert(std::make_pair(DXGI_FORMAT_B8G8R8A8_UNORM, D3D11FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); + + return map; +} + +struct DXGIColorFormatInfo +{ + size_t redBits; + size_t greenBits; + size_t blueBits; + + size_t luminanceBits; + + size_t alphaBits; + size_t sharedBits; +}; + +typedef std::map ColorFormatInfoMap; +typedef std::pair ColorFormatInfoPair; + +static inline void InsertDXGIColorFormatInfo(ColorFormatInfoMap *map, DXGI_FORMAT format, size_t redBits, size_t greenBits, + size_t blueBits, size_t alphaBits, size_t sharedBits) +{ + DXGIColorFormatInfo info; + info.redBits = redBits; + info.greenBits = greenBits; + info.blueBits = blueBits; + info.alphaBits = alphaBits; + info.sharedBits = sharedBits; + + map->insert(std::make_pair(format, info)); +} + +static ColorFormatInfoMap BuildColorFormatInfoMap() +{ + ColorFormatInfoMap map; + + // | DXGI format | R | G | B | A | S | + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_A8_UNORM, 0, 0, 0, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_UNORM, 8, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_UNORM, 8, 8, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 8, 8, 8, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 8, 8, 8, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 8, 8, 8, 8, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_SNORM, 8, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_SNORM, 8, 8, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 8, 8, 8, 8, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_UINT, 8, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_UINT, 16, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_UINT, 32, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_UINT, 8, 8, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_UINT, 16, 16, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_UINT, 32, 32, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_UINT, 32, 32, 32, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_UINT, 8, 8, 8, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_UINT, 16, 16, 16, 16, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_UINT, 32, 32, 32, 32, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8_SINT, 8, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_SINT, 16, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_SINT, 32, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8_SINT, 8, 8, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_SINT, 16, 16, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_SINT, 32, 32, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_SINT, 32, 32, 32, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R8G8B8A8_SINT, 8, 8, 8, 8, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_SINT, 16, 16, 16, 16, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_SINT, 32, 32, 32, 32, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 10, 10, 10, 2, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R10G10B10A2_UINT, 10, 10, 10, 2, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16_FLOAT, 16, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16_FLOAT, 16, 16, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 16, 16, 16, 16, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32_FLOAT, 32, 0, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32_FLOAT, 32, 32, 0, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32_FLOAT, 32, 32, 32, 0, 0); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 32, 32, 32, 32, 0); + + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 9, 9, 9, 0, 5); + InsertDXGIColorFormatInfo(&map, DXGI_FORMAT_R11G11B10_FLOAT, 11, 11, 10, 0, 0); + + return map; +} + +struct DXGIDepthStencilInfo +{ + unsigned int depthBits; + unsigned int depthOffset; + unsigned int stencilBits; + unsigned int stencilOffset; +}; + +typedef std::map DepthStencilInfoMap; +typedef std::pair DepthStencilInfoPair; + +static inline void InsertDXGIDepthStencilInfo(DepthStencilInfoMap *map, DXGI_FORMAT format, unsigned int depthBits, + unsigned int depthOffset, unsigned int stencilBits, unsigned int stencilOffset) +{ + DXGIDepthStencilInfo info; + info.depthBits = depthBits; + info.depthOffset = depthOffset; + info.stencilBits = stencilBits; + info.stencilOffset = stencilOffset; + + map->insert(std::make_pair(format, info)); +} + +static DepthStencilInfoMap BuildDepthStencilInfoMap() +{ + DepthStencilInfoMap map; + + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R16_TYPELESS, 16, 0, 0, 0); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R16_UNORM, 16, 0, 0, 0); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D16_UNORM, 16, 0, 0, 0); + + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R24G8_TYPELESS, 24, 0, 8, 24); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 24, 0, 8, 24); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 24, 0, 8, 24); + + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_TYPELESS, 32, 0, 0, 0); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_FLOAT, 32, 0, 0, 0); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D32_FLOAT, 32, 0, 0, 0); + + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 32, 0, 8, 32); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 32, 0, 8, 32); + InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 32, 0, 8, 32); + + return map; +} + +typedef std::map DXGIFormatInfoMap; + +DXGIFormat::DXGIFormat() + : pixelBytes(0), + blockWidth(0), + blockHeight(0), + redBits(0), + greenBits(0), + blueBits(0), + alphaBits(0), + sharedBits(0), + depthBits(0), + depthOffset(0), + stencilBits(0), + stencilOffset(0), + internalFormat(GL_NONE), + componentType(GL_NONE), + mipGenerationFunction(NULL), + colorReadFunction(NULL), + fastCopyFunctions() +{ +} + +ColorCopyFunction DXGIFormat::getFastCopyFunction(GLenum format, GLenum type) const +{ + FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); + return (iter != fastCopyFunctions.end()) ? iter->second : NULL; +} + +void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, + GLenum componentType, MipGenerationFunction mipFunc, ColorReadFunction readFunc) +{ + DXGIFormat info; + info.pixelBytes = pixelBits / 8; + info.blockWidth = blockWidth; + info.blockHeight = blockHeight; + + static const ColorFormatInfoMap colorInfoMap = BuildColorFormatInfoMap(); + ColorFormatInfoMap::const_iterator colorInfoIter = colorInfoMap.find(dxgiFormat); + if (colorInfoIter != colorInfoMap.end()) + { + const DXGIColorFormatInfo &colorInfo = colorInfoIter->second; + info.redBits = colorInfo.redBits; + info.greenBits = colorInfo.greenBits; + info.blueBits = colorInfo.blueBits; + info.alphaBits = colorInfo.alphaBits; + info.sharedBits = colorInfo.sharedBits; + } + + static const DepthStencilInfoMap dsInfoMap = BuildDepthStencilInfoMap(); + DepthStencilInfoMap::const_iterator dsInfoIter = dsInfoMap.find(dxgiFormat); + if (dsInfoIter != dsInfoMap.end()) + { + const DXGIDepthStencilInfo &dsInfo = dsInfoIter->second; + info.depthBits = dsInfo.depthBits; + info.depthOffset = dsInfo.depthOffset; + info.stencilBits = dsInfo.stencilBits; + info.stencilOffset = dsInfo.stencilOffset; + } + + static const DXGIToESFormatMap dxgiToESMap = BuildDXGIToESFormatMap(); + DXGIToESFormatMap::const_iterator dxgiToESIter = dxgiToESMap.find(dxgiFormat); + info.internalFormat = (dxgiToESIter != dxgiToESMap.end()) ? dxgiToESIter->second : GL_NONE; + + info.componentType = componentType; + + info.mipGenerationFunction = mipFunc; + info.colorReadFunction = readFunc; + + static const D3D11FastCopyMap fastCopyMap = BuildFastCopyMap(); + std::pair fastCopyIter = fastCopyMap.equal_range(dxgiFormat); + for (D3D11FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) + { + info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); + } + + map->insert(std::make_pair(dxgiFormat, info)); +} + +// A map to determine the pixel size and mipmap generation function of a given DXGI format +static DXGIFormatInfoMap BuildDXGIFormatInfoMap() +{ + DXGIFormatInfoMap map; + + // | DXGI format |S |W |H |Component Type | Mip generation function | Color read function + AddDXGIFormat(&map, DXGI_FORMAT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL); + + AddDXGIFormat(&map, DXGI_FORMAT_A8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_FLOAT, 96, 1, 1, GL_FLOAT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 128, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); + + AddDXGIFormat(&map, DXGI_FORMAT_R16_TYPELESS, 16, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R24G8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 32, 1, 1, GL_UNSIGNED_INT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 64, 1, 1, GL_UNSIGNED_INT, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R32_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT, 32, 1, 1, GL_FLOAT, NULL, NULL); + + AddDXGIFormat(&map, DXGI_FORMAT_BC1_UNORM, 64, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_BC2_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_BC3_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); + + // Useful formats for vertex buffers + AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UNORM, 64, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); + AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SNORM, 64, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); + + return map; +} + +const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format) +{ + static const DXGIFormatInfoMap infoMap = BuildDXGIFormatInfoMap(); + DXGIFormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + return iter->second; + } + else + { + static DXGIFormat defaultInfo; + return defaultInfo; + } +} + +struct SwizzleSizeType +{ + size_t maxComponentSize; + GLenum componentType; + + SwizzleSizeType() + : maxComponentSize(0), componentType(GL_NONE) + { } + + SwizzleSizeType(size_t maxComponentSize, GLenum componentType) + : maxComponentSize(maxComponentSize), componentType(componentType) + { } + + bool operator<(const SwizzleSizeType& other) const + { + return (maxComponentSize != other.maxComponentSize) ? (maxComponentSize < other.maxComponentSize) + : (componentType < other.componentType); + } +}; + +struct SwizzleFormatInfo +{ + DXGI_FORMAT mTexFormat; + DXGI_FORMAT mSRVFormat; + DXGI_FORMAT mRTVFormat; + + SwizzleFormatInfo() + : mTexFormat(DXGI_FORMAT_UNKNOWN), mSRVFormat(DXGI_FORMAT_UNKNOWN), mRTVFormat(DXGI_FORMAT_UNKNOWN) + { } + + SwizzleFormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat) + : mTexFormat(texFormat), mSRVFormat(srvFormat), mRTVFormat(rtvFormat) + { } +}; + +typedef std::map SwizzleInfoMap; +typedef std::pair SwizzleInfoPair; + +static SwizzleInfoMap BuildSwizzleInfoMap() +{ + SwizzleInfoMap map; + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM))); + map.insert(SwizzleInfoPair(SwizzleSizeType(24, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_SIGNED_NORMALIZED ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM ))); + + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT ))); + + map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT ))); + map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT ))); + + return map; +} + +typedef std::pair InternalFormatInitializerPair; +typedef std::map InternalFormatInitializerMap; + +static InternalFormatInitializerMap BuildInternalFormatInitializerMap() +{ + InternalFormatInitializerMap map; + + map.insert(InternalFormatInitializerPair(GL_RGB8, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB565, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_SRGB8, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB16F, Initialize4ComponentData)); + map.insert(InternalFormatInitializerPair(GL_RGB32F, Initialize4ComponentData)); + map.insert(InternalFormatInitializerPair(GL_RGB8UI, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB8I, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB16UI, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB16I, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB32UI, Initialize4ComponentData )); + map.insert(InternalFormatInitializerPair(GL_RGB32I, Initialize4ComponentData )); + + return map; +} + +// ES3 image loading functions vary based on the internal format and data type given, +// this map type determines the loading function from the internal format and type supplied +// to glTex*Image*D and the destination DXGI_FORMAT. Source formats and types are taken from +// Tables 3.2 and 3.3 of the ES 3 spec. +typedef std::pair TypeLoadFunctionPair; +typedef std::map > D3D11LoadFunctionMap; + +static void UnimplementedLoadFunction(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNIMPLEMENTED(); +} + +static void UnreachableLoadFunction(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNREACHABLE(); +} + +// A helper function to insert data into the D3D11LoadFunctionMap with fewer characters. +static inline void InsertLoadFunction(D3D11LoadFunctionMap *map, GLenum internalFormat, GLenum type, + LoadImageFunction loadFunc) +{ + (*map)[internalFormat].push_back(TypeLoadFunctionPair(type, loadFunc)); +} + +D3D11LoadFunctionMap BuildD3D11_FL9_3_LoadFunctionMap() +{ + D3D11LoadFunctionMap map; + + // From GL_EXT_texture_storage. Also used by GL_ALPHA8 + // On feature level 9_3, A8_UNORM doesn't support mipmaps, so we must use RGBA8 instead + InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadA8ToRGBA8); + + return map; +} + +D3D11LoadFunctionMap BuildD3D11_FL10_0Plus_LoadFunctionMap() +{ + D3D11LoadFunctionMap map; + + // From GL_EXT_texture_storage. Also used by GL_ALPHA8 + InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadToNative); + + return map; +} + +D3D11LoadFunctionMap BuildBaseD3D11LoadFunctionMap() +{ + D3D11LoadFunctionMap map; + + // | Internal format | Type | Load function | + InsertLoadFunction(&map, GL_RGBA8, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA8_SNORM, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, LoadRGBA4ToRGBA8 ); + InsertLoadFunction(&map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative ); + InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, LoadRGB5A1ToRGBA8 ); + InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_INT_2_10_10_10_REV, LoadRGB10A2ToRGBA8 ); + InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT_OES, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA32F, GL_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA16F, GL_FLOAT, Load32FTo16F<4> ); + InsertLoadFunction(&map, GL_RGBA8UI, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA8I, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA16UI, GL_UNSIGNED_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA16I, GL_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA32UI, GL_UNSIGNED_INT, LoadToNative ); + InsertLoadFunction(&map, GL_RGBA32I, GL_INT, LoadToNative ); + InsertLoadFunction(&map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative ); + InsertLoadFunction(&map, GL_RGB8, GL_UNSIGNED_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_SRGB8, GL_UNSIGNED_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB8_SNORM, GL_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, LoadR5G6B5ToRGBA8 ); + InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV, LoadToNative ); + InsertLoadFunction(&map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV, LoadToNative ); + InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT, LoadToNative3To4); + InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT_OES, LoadToNative3To4); + InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT, LoadRGB16FToRG11B10F ); + InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT_OES, LoadRGB16FToRG11B10F ); + InsertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT, LoadRGB16FToRGB9E5 ); + InsertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT_OES, LoadRGB16FToRGB9E5 ); + InsertLoadFunction(&map, GL_RGB32F, GL_FLOAT, LoadToNative3To4); + InsertLoadFunction(&map, GL_RGB16F, GL_FLOAT, LoadRGB32FToRGBA16F ); + InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_FLOAT, LoadRGB32FToRG11B10F ); + InsertLoadFunction(&map, GL_RGB9_E5, GL_FLOAT, LoadRGB32FToRGB9E5 ); + InsertLoadFunction(&map, GL_RGB8UI, GL_UNSIGNED_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB8I, GL_BYTE, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB16UI, GL_UNSIGNED_SHORT, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB16I, GL_SHORT, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB32UI, GL_UNSIGNED_INT, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RGB32I, GL_INT, LoadToNative3To4 ); + InsertLoadFunction(&map, GL_RG8, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RG8_SNORM, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT_OES, LoadToNative ); + InsertLoadFunction(&map, GL_RG32F, GL_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_RG16F, GL_FLOAT, Load32FTo16F<2> ); + InsertLoadFunction(&map, GL_RG8UI, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RG8I, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_RG16UI, GL_UNSIGNED_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_RG16I, GL_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_RG32UI, GL_UNSIGNED_INT, LoadToNative ); + InsertLoadFunction(&map, GL_RG32I, GL_INT, LoadToNative ); + InsertLoadFunction(&map, GL_R8, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_R8_SNORM, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT_OES, LoadToNative ); + InsertLoadFunction(&map, GL_R32F, GL_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_R16F, GL_FLOAT, Load32FTo16F<1> ); + InsertLoadFunction(&map, GL_R8UI, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_R8I, GL_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_R16UI, GL_UNSIGNED_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_R16I, GL_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_R32UI, GL_UNSIGNED_INT, LoadToNative ); + InsertLoadFunction(&map, GL_R32I, GL_INT, LoadToNative ); + InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, LoadToNative ); + InsertLoadFunction(&map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT, LoadR32ToR24G8 ); + InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_INT, LoadR32ToR16 ); + InsertLoadFunction(&map, GL_DEPTH_COMPONENT32F, GL_FLOAT, LoadToNative ); + InsertLoadFunction(&map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8, LoadR32ToR24G8 ); + InsertLoadFunction(&map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, LoadToNative ); + + // Unsized formats + // Load functions are unreachable because they are converted to sized internal formats based on + // the format and type before loading takes place. + InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_RGB, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + InsertLoadFunction(&map, GL_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); + + // From GL_OES_texture_float + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, LoadLA32FToRGBA32F ); + InsertLoadFunction(&map, GL_LUMINANCE, GL_FLOAT, LoadL32FToRGBA32F ); + InsertLoadFunction(&map, GL_ALPHA, GL_FLOAT, LoadA32FToRGBA32F ); + + // From GL_OES_texture_half_float + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT, LoadL16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); + InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT, LoadA16FToRGBA16F ); + InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); + + // From GL_EXT_texture_storage + // GL_ALPHA8_EXT GL_UNSIGNED_BYTE is in the feature-level-specific load function maps, due to differences between 9_3 and 10_0+ + InsertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 ); + InsertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 ); + InsertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F ); + InsertLoadFunction(&map, GL_LUMINANCE32F_EXT, GL_FLOAT, LoadL32FToRGBA32F ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA32F_EXT, GL_FLOAT, LoadLA32FToRGBA32F ); + InsertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT, LoadA16FToRGBA16F ); + InsertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT, LoadL16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); + InsertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); + + // From GL_ANGLE_depth_texture + InsertLoadFunction(&map, GL_DEPTH_COMPONENT32_OES, GL_UNSIGNED_INT, LoadR32ToR24G8 ); + + // From GL_EXT_texture_format_BGRA8888 + InsertLoadFunction(&map, GL_BGRA8_EXT, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, LoadRGBA4ToRGBA8 ); + InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative ); + InsertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, LoadRGB5A1ToRGBA8 ); + InsertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative ); + + // Compressed formats + // From ES 3.0.1 spec, table 3.16 + // | Internal format | Type | Load function | + InsertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); + + // From GL_EXT_texture_compression_dxt1 + InsertLoadFunction(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); + InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); + + // From GL_ANGLE_texture_compression_dxt3 + InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); + + // From GL_ANGLE_texture_compression_dxt5 + InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); + + return map; +} + +// For sized GL internal formats, there is only one corresponding D3D11 format. This map type allows +// querying for the DXGI texture formats to use for textures, SRVs, RTVs and DSVs given a GL internal +// format. +typedef std::map D3D11ES3FormatMap; + +TextureFormat::TextureFormat() + : texFormat(DXGI_FORMAT_UNKNOWN), + srvFormat(DXGI_FORMAT_UNKNOWN), + rtvFormat(DXGI_FORMAT_UNKNOWN), + dsvFormat(DXGI_FORMAT_UNKNOWN), + renderFormat(DXGI_FORMAT_UNKNOWN), + swizzleTexFormat(DXGI_FORMAT_UNKNOWN), + swizzleSRVFormat(DXGI_FORMAT_UNKNOWN), + swizzleRTVFormat(DXGI_FORMAT_UNKNOWN), + dataInitializerFunction(NULL), + loadFunctions() +{ +} + +static inline void InsertD3D11FormatInfoBase(D3D11ES3FormatMap *formatMap, const D3D11LoadFunctionMap &flLoadFunctions, GLenum internalFormat, DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) +{ + TextureFormat info; + info.texFormat = texFormat; + info.srvFormat = srvFormat; + info.rtvFormat = rtvFormat; + info.dsvFormat = dsvFormat; + + // Given a GL internal format, the renderFormat is the DSV format if it is depth- or stencil-renderable, + // the RTV format if it is color-renderable, and the (nonrenderable) texture format otherwise. + if (dsvFormat != DXGI_FORMAT_UNKNOWN) + { + info.renderFormat = dsvFormat; + } + else if (rtvFormat != DXGI_FORMAT_UNKNOWN) + { + info.renderFormat = rtvFormat; + } + else if (texFormat != DXGI_FORMAT_UNKNOWN) + { + info.renderFormat = texFormat; + } + else + { + info.renderFormat = DXGI_FORMAT_UNKNOWN; + } + + // Compute the swizzle formats + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + if (internalFormat != GL_NONE && formatInfo.pixelBytes > 0) + { + if (formatInfo.componentCount != 4 || texFormat == DXGI_FORMAT_UNKNOWN || + srvFormat == DXGI_FORMAT_UNKNOWN || rtvFormat == DXGI_FORMAT_UNKNOWN) + { + // Get the maximum sized component + unsigned int maxBits = 1; + if (formatInfo.compressed) + { + unsigned int compressedBitsPerBlock = formatInfo.pixelBytes * 8; + unsigned int blockSize = formatInfo.compressedBlockWidth * formatInfo.compressedBlockHeight; + maxBits = std::max(compressedBitsPerBlock / blockSize, maxBits); + } + else + { + maxBits = std::max(maxBits, formatInfo.alphaBits); + maxBits = std::max(maxBits, formatInfo.redBits); + maxBits = std::max(maxBits, formatInfo.greenBits); + maxBits = std::max(maxBits, formatInfo.blueBits); + maxBits = std::max(maxBits, formatInfo.luminanceBits); + maxBits = std::max(maxBits, formatInfo.depthBits); + } + + maxBits = roundUp(maxBits, 8U); + + static const SwizzleInfoMap swizzleMap = BuildSwizzleInfoMap(); + SwizzleInfoMap::const_iterator swizzleIter = swizzleMap.find(SwizzleSizeType(maxBits, formatInfo.componentType)); + ASSERT(swizzleIter != swizzleMap.end()); + + const SwizzleFormatInfo &swizzleInfo = swizzleIter->second; + info.swizzleTexFormat = swizzleInfo.mTexFormat; + info.swizzleSRVFormat = swizzleInfo.mSRVFormat; + info.swizzleRTVFormat = swizzleInfo.mRTVFormat; + } + else + { + // The original texture format is suitable for swizzle operations + info.swizzleTexFormat = texFormat; + info.swizzleSRVFormat = srvFormat; + info.swizzleRTVFormat = rtvFormat; + } + } + else + { + // Not possible to swizzle with this texture format since it is either unsized or GL_NONE + info.swizzleTexFormat = DXGI_FORMAT_UNKNOWN; + info.swizzleSRVFormat = DXGI_FORMAT_UNKNOWN; + info.swizzleRTVFormat = DXGI_FORMAT_UNKNOWN; + } + + // Check if there is an initialization function for this texture format + static const InternalFormatInitializerMap initializerMap = BuildInternalFormatInitializerMap(); + InternalFormatInitializerMap::const_iterator initializerIter = initializerMap.find(internalFormat); + info.dataInitializerFunction = (initializerIter != initializerMap.end()) ? initializerIter->second : NULL; + + // Gather all the load functions for this internal format from the base list + static const D3D11LoadFunctionMap loadFunctions = BuildBaseD3D11LoadFunctionMap(); + D3D11LoadFunctionMap::const_iterator loadFunctionIter = loadFunctions.find(internalFormat); + if (loadFunctionIter != loadFunctions.end()) + { + const std::vector &loadFunctionVector = loadFunctionIter->second; + for (size_t i = 0; i < loadFunctionVector.size(); i++) + { + GLenum type = loadFunctionVector[i].first; + LoadImageFunction function = loadFunctionVector[i].second; + info.loadFunctions.insert(std::make_pair(type, function)); + } + } + + // Gather load functions for this internal format from the feature-level-specific list + D3D11LoadFunctionMap::const_iterator flLoadFunctionIter = flLoadFunctions.find(internalFormat); + if (flLoadFunctionIter != flLoadFunctions.end()) + { + const std::vector &flLoadFunctionVector = flLoadFunctionIter->second; + for (size_t i = 0; i < flLoadFunctionVector.size(); i++) + { + GLenum type = flLoadFunctionVector[i].first; + LoadImageFunction function = flLoadFunctionVector[i].second; + info.loadFunctions.insert(std::make_pair(type, function)); + } + } + + formatMap->insert(std::make_pair(internalFormat, info)); +} + +static inline void InsertD3D11_FL9_3_FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) +{ + static const D3D11LoadFunctionMap flLoadFunctions = BuildD3D11_FL9_3_LoadFunctionMap(); + InsertD3D11FormatInfoBase(map, flLoadFunctions, internalFormat, texFormat, srvFormat, rtvFormat, dsvFormat); +} + +static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat, + DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) +{ + static const D3D11LoadFunctionMap flLoadFunctions = BuildD3D11_FL10_0Plus_LoadFunctionMap(); + InsertD3D11FormatInfoBase(map, flLoadFunctions, internalFormat, texFormat, srvFormat, rtvFormat, dsvFormat); +} + +static D3D11ES3FormatMap BuildD3D11_FL9_3FormatOverrideMap() +{ + // D3D11 Feature Level 9_3 doesn't support as many texture formats as Feature Level 10_0+. + // In particular, it doesn't support: + // - mipmaps on DXGI_FORMAT_A8_NORM + // - *_TYPELESS formats + // - DXGI_FORMAT_D32_FLOAT_S8X24_UINT or DXGI_FORMAT_D32_FLOAT + + D3D11ES3FormatMap map; + + // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format + InsertD3D11_FL9_3_FormatInfo(&map, GL_ALPHA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11_FL9_3_FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); + InsertD3D11_FL9_3_FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11_FL9_3_FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); + + return map; +} + +static D3D11ES3FormatMap BuildD3D11FormatMap() +{ + D3D11ES3FormatMap map; + + // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + InsertD3D11FormatInfo(&map, GL_NONE, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R8, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG8, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB8, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB565, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA4, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB5_A1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA8, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB10_A2, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB10_A2UI, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_SRGB8, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_SRGB8_ALPHA8, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R16F, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG16F, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB16F, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA16F, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R32F, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG32F, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB32F, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA32F, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R11F_G11F_B10F, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB9_E5, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R8I, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R8UI, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R16I, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R16UI, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R32I, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_R32UI, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG8I, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG8UI, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG16I, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG16UI, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG32I, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RG32UI, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB8I, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB8UI, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB16I, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB16UI, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB32I, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB32UI, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA8I, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA8UI, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA16I, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA16UI, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA32I, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA32UI, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN); + + // Unsized formats, TODO: Are types of float and half float allowed for the unsized types? Would it change the DXGI format? + InsertD3D11FormatInfo(&map, GL_ALPHA, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_LUMINANCE, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGB, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_BGRA_EXT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN); + + // From GL_EXT_texture_storage + // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_ALPHA16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_BGRA8_EXT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_BGRA4_ANGLEX, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_BGR5_A1_ANGLEX, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + + // Depth stencil formats + InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM ); + InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); + InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT ); + InsertD3D11FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); + InsertD3D11FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); + InsertD3D11FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_X24_TYPELESS_G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); + + // From GL_ANGLE_depth_texture + // Since D3D11 doesn't have a D32_UNORM format, use D24S8 which has comparable precision and matches the ES3 format. + InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); + + // Compressed formats, From ES 3.0.1 spec, table 3.16 + // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | + InsertD3D11FormatInfo(&map, GL_COMPRESSED_R11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SIGNED_R11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RG11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SIGNED_RG11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB8_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + + // From GL_EXT_texture_compression_dxt1 + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + + // From GL_ANGLE_texture_compression_dxt3 + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + + // From GL_ANGLE_texture_compression_dxt5 + InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + + return map; +} + +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel) +{ + static const D3D11ES3FormatMap formatMap = BuildD3D11FormatMap(); + static const D3D11ES3FormatMap formatMapFL9_3Override = BuildD3D11_FL9_3FormatOverrideMap(); + + if (featureLevel == D3D_FEATURE_LEVEL_9_3) + { + // First see if the internalFormat has a special map for FL9_3 + D3D11ES3FormatMap::const_iterator fl9_3Iter = formatMapFL9_3Override.find(internalFormat); + if (fl9_3Iter != formatMapFL9_3Override.end()) + { + return fl9_3Iter->second; + } + } + + D3D11ES3FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + static const TextureFormat defaultInfo; + return defaultInfo; + } +} + +typedef std::map D3D11VertexFormatInfoMap; +typedef std::pair D3D11VertexFormatPair; + +VertexFormat::VertexFormat() + : conversionType(VERTEX_CONVERT_NONE), + nativeFormat(DXGI_FORMAT_UNKNOWN), + copyFunction(NULL) +{ +} + +static void AddVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLboolean normalized, GLuint componentCount, + VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) +{ + gl::VertexFormat inputFormat(inputType, normalized, componentCount, false); + + VertexFormat info; + info.conversionType = conversionType; + info.nativeFormat = nativeFormat; + info.copyFunction = copyFunction; + + map->insert(D3D11VertexFormatPair(inputFormat, info)); +} + +static void AddIntegerVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLuint componentCount, + VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) +{ + gl::VertexFormat inputFormat(inputType, GL_FALSE, componentCount, true); + + VertexFormat info; + info.conversionType = conversionType; + info.nativeFormat = nativeFormat; + info.copyFunction = copyFunction; + + map->insert(D3D11VertexFormatPair(inputFormat, info)); +} + +static D3D11VertexFormatInfoMap BuildD3D11_FL9_3VertexFormatInfoOverrideMap() +{ + // D3D11 Feature Level 9_3 doesn't support as many formats for vertex buffer resource as Feature Level 10_0+. + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff471324(v=vs.85).aspx + + D3D11VertexFormatInfoMap map; + + // GL_BYTE -- unnormalized + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &Copy8SintTo16SintVertexData<1, 2>); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &Copy8SintTo16SintVertexData<2, 2>); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &Copy8SintTo16SintVertexData<3, 4>); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &Copy8SintTo16SintVertexData<4, 4>); + + // GL_BYTE -- normalized + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &Copy8SnormTo16SnormVertexData<1, 2>); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &Copy8SnormTo16SnormVertexData<2, 2>); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &Copy8SnormTo16SnormVertexData<3, 4>); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &Copy8SnormTo16SnormVertexData<4, 4>); + + // GL_UNSIGNED_BYTE -- unnormalized + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + // NOTE: 3 and 4 component unnormalized GL_UNSIGNED_BYTE should use the default format table. + + // GL_UNSIGNED_BYTE -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + // NOTE: 3 and 4 component normalized GL_UNSIGNED_BYTE should use the default format table. + + // GL_SHORT -- unnormalized + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + // NOTE: 2, 3 and 4 component unnormalized GL_SHORT should use the default format table. + + // GL_SHORT -- normalized + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); + // NOTE: 2, 3 and 4 component normalized GL_SHORT should use the default format table. + + // GL_UNSIGNED_SHORT -- unnormalized + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + + // GL_UNSIGNED_SHORT -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + + // GL_FIXED + // TODO: Add test to verify that this works correctly. + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<1, 2>); + // NOTE: 2, 3 and 4 component GL_FIXED should use the default format table. + + // GL_FLOAT + // TODO: Add test to verify that this works correctly. + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); + // NOTE: 2, 3 and 4 component GL_FLOAT should use the default format table. + + return map; +} + +static D3D11VertexFormatInfoMap BuildD3D11VertexFormatInfoMap() +{ + D3D11VertexFormatInfoMap map; + + // TODO: column legend + + // + // Float formats + // + + // GL_BYTE -- un-normalized + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + + // GL_BYTE -- normalized + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); + + // GL_UNSIGNED_BYTE -- un-normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + + // GL_UNSIGNED_BYTE -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); + + // GL_SHORT -- un-normalized + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + + // GL_SHORT -- normalized + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); + + // GL_UNSIGNED_SHORT -- un-normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + + // GL_UNSIGNED_SHORT -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); + + // GL_INT -- un-normalized + AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + + // GL_INT -- normalized + AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + + // GL_UNSIGNED_INT -- un-normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, &CopyNativeVertexData); + + // GL_UNSIGNED_INT -- normalized + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); + + // GL_FIXED + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &Copy32FixedTo32FVertexData<1, 1>); + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<2, 2>); + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &Copy32FixedTo32FVertexData<3, 3>); + AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &Copy32FixedTo32FVertexData<4, 4>); + + // GL_HALF_FLOAT + AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); + + // GL_FLOAT + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, &CopyNativeVertexData); + AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyNativeVertexData); + + // GL_INT_2_10_10_10_REV + AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + + // GL_UNSIGNED_INT_2_10_10_10_REV + AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); + AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, &CopyNativeVertexData); + + // + // Integer Formats + // + + // GL_BYTE + AddIntegerVertexFormatInfo(&map, GL_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); + + // GL_UNSIGNED_BYTE + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); + + // GL_SHORT + AddIntegerVertexFormatInfo(&map, GL_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); + + // GL_UNSIGNED_SHORT + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); + + // GL_INT + AddIntegerVertexFormatInfo(&map, GL_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + + // GL_UNSIGNED_INT + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); + + // GL_INT_2_10_10_10_REV + AddIntegerVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyXYZ10W2ToXYZW32FVertexData); + + // GL_UNSIGNED_INT_2_10_10_10_REV + AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, &CopyNativeVertexData); + + return map; +} + +const VertexFormat &GetVertexFormatInfo(const gl::VertexFormat &vertexFormat, D3D_FEATURE_LEVEL featureLevel) +{ + static const D3D11VertexFormatInfoMap vertexFormatMap = BuildD3D11VertexFormatInfoMap(); + static const D3D11VertexFormatInfoMap vertexFormatMapFL9_3Override = BuildD3D11_FL9_3VertexFormatInfoOverrideMap(); + + if (featureLevel == D3D_FEATURE_LEVEL_9_3) + { + // First see if the format has a special mapping for FL9_3 + D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMapFL9_3Override.find(vertexFormat); + if (iter != vertexFormatMapFL9_3Override.end()) + { + return iter->second; + } + } + + D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMap.find(vertexFormat); + if (iter != vertexFormatMap.end()) + { + return iter->second; + } + else + { + static const VertexFormat defaultInfo; + return defaultInfo; + } +} + +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h new file mode 100644 index 0000000000..33fe29dc39 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/formatutils11.h @@ -0,0 +1,93 @@ +// +// Copyright (c) 2013-2014 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. +// + +// formatutils11.h: Queries for GL image formats and their translations to D3D11 +// formats. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_ + +#include "libANGLE/renderer/d3d/formatutilsD3D.h" +#include "libANGLE/angletypes.h" + +#include "common/platform.h" + +#include + +namespace rx +{ + +namespace d3d11 +{ + +typedef std::map, ColorCopyFunction> FastCopyFunctionMap; + +struct DXGIFormat +{ + DXGIFormat(); + + GLuint pixelBytes; + GLuint blockWidth; + GLuint blockHeight; + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + GLuint alphaBits; + GLuint sharedBits; + + GLuint depthBits; + GLuint depthOffset; + GLuint stencilBits; + GLuint stencilOffset; + + GLenum internalFormat; + GLenum componentType; + + MipGenerationFunction mipGenerationFunction; + ColorReadFunction colorReadFunction; + + FastCopyFunctionMap fastCopyFunctions; + ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; +}; +const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format); + +struct TextureFormat +{ + TextureFormat(); + + DXGI_FORMAT texFormat; + DXGI_FORMAT srvFormat; + DXGI_FORMAT rtvFormat; + DXGI_FORMAT dsvFormat; + DXGI_FORMAT renderFormat; + + DXGI_FORMAT swizzleTexFormat; + DXGI_FORMAT swizzleSRVFormat; + DXGI_FORMAT swizzleRTVFormat; + + InitializeTextureDataFunction dataInitializerFunction; + + typedef std::map LoadFunctionMap; + LoadFunctionMap loadFunctions; +}; +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat, D3D_FEATURE_LEVEL featureLevel); + +struct VertexFormat +{ + VertexFormat(); + + VertexConversionType conversionType; + DXGI_FORMAT nativeFormat; + VertexCopyFunction copyFunction; +}; +const VertexFormat &GetVertexFormatInfo(const gl::VertexFormat &vertexFormat, D3D_FEATURE_LEVEL featureLevel); + +} + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_FORMATUTILS11_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp new file mode 100644 index 0000000000..63085f497f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp @@ -0,0 +1,1378 @@ +// +// Copyright (c) 2012-2014 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. +// + +// renderer11_utils.cpp: Conversion functions and other utility routines +// specific to the D3D11 renderer. + +#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" +#include "libANGLE/renderer/d3d/d3d11/formatutils11.h" +#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/Workarounds.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Program.h" +#include "libANGLE/Framebuffer.h" + +#include "common/debug.h" + +#include + +#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY +# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2 +#endif +#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT +# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1 +#endif +#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT +# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4 +#endif +#ifndef D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT +# define D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT 65535 +#endif +#ifndef D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT +# define D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT 1048575 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION +# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512 +#endif +#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION +# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION +# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048 +#endif +#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION +# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256 +#endif +#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION +# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 +#endif +#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION +# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 +#endif +#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION +# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 +#endif +#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION +# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 +#endif +#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP +# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 +#endif +#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP +# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 +#endif +#ifndef D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT +# define D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT 32 +#endif +#ifndef D3D11_STANDARD_VERTEX_ELEMENT_COUNT +# define D3D11_STANDARD_VERTEX_ELEMENT_COUNT 32 +#endif +#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT +# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 +#endif +#ifndef D3D11_SO_BUFFER_SLOT_COUNT +# define D3D11_SO_BUFFER_SLOT_COUNT 4 +#endif +#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT +# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 +#endif +#ifndef D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT +# define D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT 16 +#endif +#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE +# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -8 +#endif +#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE +# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE 7 +#endif +#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT +# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 +#endif +#ifndef D3D11_PS_INPUT_REGISTER_COUNT +# define D3D11_PS_INPUT_REGISTER_COUNT 32 +#endif +#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT +# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 +#endif +#if defined(ANGLE_MINGW32_COMPAT) +static const IID WKPDID_D3DDebugObjectName = { 0x429b8c22, 0x9188, 0x4b0c, 0x87, 0x42, 0xac, 0xb0, 0xbf, 0x85, 0xc2, 0x00 }; +#endif + +namespace rx +{ + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) +{ + D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; + + switch (glBlend) + { + case GL_ZERO: d3dBlend = D3D11_BLEND_ZERO; break; + case GL_ONE: d3dBlend = D3D11_BLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_SRC_ALPHA : D3D11_BLEND_SRC_COLOR); break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC_ALPHA : D3D11_BLEND_INV_SRC_COLOR); break; + case GL_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_DEST_COLOR); break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_INV_DEST_COLOR); break; + case GL_SRC_ALPHA: d3dBlend = D3D11_BLEND_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3D11_BLEND_INV_SRC_ALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3D11_BLEND_DEST_ALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3D11_BLEND_INV_DEST_ALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) +{ + D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; + + switch (glBlendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3D11_BLEND_OP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_REV_SUBTRACT; break; + case GL_MIN: d3dBlendOp = D3D11_BLEND_OP_MIN; break; + case GL_MAX: d3dBlendOp = D3D11_BLEND_OP_MAX; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + UINT8 mask = 0; + if (red) + { + mask |= D3D11_COLOR_WRITE_ENABLE_RED; + } + if (green) + { + mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + } + if (blue) + { + mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + } + if (alpha) + { + mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + } + return mask; +} + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode) +{ + D3D11_CULL_MODE cull = D3D11_CULL_NONE; + + if (cullEnabled) + { + switch (cullMode) + { + case GL_FRONT: cull = D3D11_CULL_FRONT; break; + case GL_BACK: cull = D3D11_CULL_BACK; break; + case GL_FRONT_AND_BACK: cull = D3D11_CULL_NONE; break; + default: UNREACHABLE(); + } + } + else + { + cull = D3D11_CULL_NONE; + } + + return cull; +} + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) +{ + D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; + switch (comparison) + { + case GL_NEVER: d3dComp = D3D11_COMPARISON_NEVER; break; + case GL_ALWAYS: d3dComp = D3D11_COMPARISON_ALWAYS; break; + case GL_LESS: d3dComp = D3D11_COMPARISON_LESS; break; + case GL_LEQUAL: d3dComp = D3D11_COMPARISON_LESS_EQUAL; break; + case GL_EQUAL: d3dComp = D3D11_COMPARISON_EQUAL; break; + case GL_GREATER: d3dComp = D3D11_COMPARISON_GREATER; break; + case GL_GEQUAL: d3dComp = D3D11_COMPARISON_GREATER_EQUAL; break; + case GL_NOTEQUAL: d3dComp = D3D11_COMPARISON_NOT_EQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) +{ + return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; +} + +UINT8 ConvertStencilMask(GLuint stencilmask) +{ + return static_cast(stencilmask); +} + +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) +{ + D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3D11_STENCIL_OP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3D11_STENCIL_OP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3D11_STENCIL_OP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; break; + case GL_DECR: d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; break; + case GL_INVERT: d3dStencilOp = D3D11_STENCIL_OP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode) +{ + bool comparison = comparisonMode != GL_NONE; + + if (maxAnisotropy > 1.0f) + { + return D3D11_ENCODE_ANISOTROPIC_FILTER(static_cast(comparison)); + } + else + { + D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT; + D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT; + switch (minFilter) + { + case GL_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_NEAREST_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; + case GL_NEAREST_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_LINEAR; break; + case GL_LINEAR_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_LINEAR; break; + default: UNREACHABLE(); + } + + D3D11_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT; + switch (magFilter) + { + case GL_NEAREST: dxMag = D3D11_FILTER_TYPE_POINT; break; + case GL_LINEAR: dxMag = D3D11_FILTER_TYPE_LINEAR; break; + default: UNREACHABLE(); + } + + return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, static_cast(comparison)); + } +} + +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; + case GL_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; + case GL_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; + default: UNREACHABLE(); + } + + return D3D11_TEXTURE_ADDRESS_WRAP; +} + +D3D11_QUERY ConvertQueryType(GLenum queryType) +{ + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: return D3D11_QUERY_OCCLUSION; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: return D3D11_QUERY_SO_STATISTICS; + default: UNREACHABLE(); return D3D11_QUERY_EVENT; + } +} + +} + + +namespace d3d11_gl +{ + +GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 3; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 2; + + default: UNREACHABLE(); return 0; + } +} + +static gl::TextureCaps GenerateTextureFormatCaps(GLint maxClientVersion, GLenum internalFormat, ID3D11Device *device) +{ + gl::TextureCaps textureCaps; + + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat, device->GetFeatureLevel()); + + UINT formatSupport; + if (SUCCEEDED(device->CheckFormatSupport(formatInfo.texFormat, &formatSupport))) + { + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + if (internalFormatInfo.depthBits > 0 || internalFormatInfo.stencilBits > 0) + { + textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0); + } + else + { + UINT formatSupportMask = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_TEXTURECUBE; + if (maxClientVersion > 2) + { + formatSupportMask |= D3D11_FORMAT_SUPPORT_TEXTURE3D; + } + textureCaps.texturable = ((formatSupport & formatSupportMask) == formatSupportMask); + } + } + + if (SUCCEEDED(device->CheckFormatSupport(formatInfo.renderFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) != 0)) + { + for (size_t sampleCount = 1; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount++) + { + UINT qualityCount = 0; + if (SUCCEEDED(device->CheckMultisampleQualityLevels(formatInfo.renderFormat, sampleCount, &qualityCount)) && + qualityCount > 0) + { + textureCaps.sampleCounts.insert(sampleCount); + } + } + } + + textureCaps.filterable = SUCCEEDED(device->CheckFormatSupport(formatInfo.srvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) != 0; + textureCaps.renderable = (SUCCEEDED(device->CheckFormatSupport(formatInfo.rtvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)) != 0) || + (SUCCEEDED(device->CheckFormatSupport(formatInfo.dsvFormat, &formatSupport)) && + ((formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) != 0)); + + return textureCaps; +} + +static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_MAX_MAXANISOTROPY; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return 16; + + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; + + default: UNREACHABLE(); return 0; + } +} + +static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return true; + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return true; + + default: UNREACHABLE(); return false; + } +} + +static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + // Feature Level 9_3 supports instancing, but slot 0 in the input layout must not be instanced. + // D3D9 has a similar restriction, where stream 0 must not be instanced. + // This restriction can be worked around by remapping any non-instanced slot to slot 0. + // This works because HLSL uses shader semantics to match the vertex inputs to the elements in the input layout, rather than the slots. + // Note that we only support instancing via ANGLE_instanced_array on 9_3, since 9_3 doesn't support OpenGL ES 3.0 + case D3D_FEATURE_LEVEL_9_3: return true; + + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetFramebufferMultisampleSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetFramebufferBlitSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) +{ + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb509588.aspx states that shader model + // ps_2_x is required for the ddx (and other derivative functions). + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that feature level + // 9.3 supports shader model ps_2_x. + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_9_3: return true; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static bool GetShaderTextureLODSupport(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return false; + + default: UNREACHABLE(); return false; + } +} + +static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_VIEWPORT_BOUNDS_MAX; + + // No constants for D3D11 Feature Level 9 viewport size limits, use the maximum texture sizes + case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) +{ + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since that's what's + // returned from glGetInteger + static_assert(D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + static_assert(D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) +{ + // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since that's what's + // returned from glGetInteger + static_assert(D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + static_assert(D3D10_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32, "Unexpected D3D11 constant value."); + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; + case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT; + case D3D_FEATURE_LEVEL_10_0: return D3D10_STANDARD_VERTEX_ELEMENT_COUNT; + + // From http://http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx "Max Input Slots" + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 16; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +{ + // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::VSSetConstantBuffers + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 255; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetReservedVertexUniformBuffers() +{ + // Reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + + // Uniform blocks not supported on D3D11 Feature Level 9 + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetReservedVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +{ + // According to The OpenGL ES Shading Language specifications + // (Language Version 1.00 section 10.16, Language Version 3.10 section 12.21) + // built-in special variables (e.g. gl_FragCoord, or gl_PointCoord) + // which are statically used in the shader should be included in the variable packing algorithm. + // Therefore, we should not reserve output vectors for them. + + switch (featureLevel) + { + // We must reserve one output vector for dx_Position. + // We also reserve one for gl_Position, which we unconditionally output on Feature Levels 10_0+, + // even if it's unused in the shader (e.g. for transform feedback). TODO: This could be improved. +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 2; + + // Just reserve dx_Position on Feature Level 9, since we don't ever need to output gl_Position. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 1; + + default: UNREACHABLE(); return 0; + } + + return 1; +} + +static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +{ + static_assert(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT, "Unexpected D3D11 constant value."); + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_10_0: return D3D10_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + // Use Shader Model 2.X limits + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 8 - GetReservedVertexOutputVectors(featureLevel); + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; + + // Vertex textures not supported on D3D11 Feature Level 9 according to + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx + // ID3D11DeviceContext::VSSetSamplers and ID3D11DeviceContext::VSSetShaderResources + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) +{ + // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::PSSetConstantBuffers + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 32; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetReservedPixelUniformBuffers() +{ + // Reserve one buffer for the application uniforms, and one for driver uniforms + return 2; +} + +static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + + // Uniform blocks not supported on D3D11 Feature Level 9 + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + // Use Shader Model 2.X limits + case D3D_FEATURE_LEVEL_9_3: return 8 - GetReservedVertexOutputVectors(featureLevel); + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 8 - GetReservedVertexOutputVectors(featureLevel); + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::PSSetShaderResources + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 16; + + default: UNREACHABLE(); return 0; + } +} + +static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; + + // Sampling functions with offsets are not available below shader model 4.0. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; + + // Sampling functions with offsets are not available below shader model 4.0. + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) +{ + // Returns a size_t despite the limit being a GLuint64 because size_t is the maximum size of + // any buffer that could be allocated. + + const size_t bytesPerComponent = 4 * sizeof(float); + + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; + + // Limits from http://msdn.microsoft.com/en-us/library/windows/desktop/ff476501.aspx remarks section + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 4096 * bytesPerComponent; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_SO_BUFFER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SO_BUFFER_SLOT_COUNT; + case D3D_FEATURE_LEVEL_10_0: return D3D10_SO_BUFFER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return GetMaximumVertexOutputVectors(featureLevel) * 4; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) +{ + switch (featureLevel) + { +#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: +#endif + case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / + GetMaximumStreamOutputBuffers(featureLevel); + + + // D3D 10 and 10.1 only allow one output per output slot if an output slot other than zero is used. + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 4; + + case D3D_FEATURE_LEVEL_9_3: + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: return 0; + + default: UNREACHABLE(); return 0; + } +} + +void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) +{ + D3D_FEATURE_LEVEL featureLevel = device->GetFeatureLevel(); + + GLuint maxSamples = 0; + const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); + for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(GetMaximumClientVersion(featureLevel), *internalFormat, device); + textureCapsMap->insert(*internalFormat, textureCaps); + + maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + + if (gl::GetInternalFormatInfo(*internalFormat).compressed) + { + caps->compressedTextureFormats.push_back(*internalFormat); + } + } + + // GL core feature limits + caps->maxElementIndex = static_cast(std::numeric_limits::max()); + caps->max3DTextureSize = GetMaximum3DTextureSize(featureLevel); + caps->max2DTextureSize = GetMaximum2DTextureSize(featureLevel); + caps->maxCubeMapTextureSize = GetMaximumCubeMapTextureSize(featureLevel); + caps->maxArrayTextureLayers = GetMaximum2DTextureArraySize(featureLevel); + + // Unimplemented, set to minimum required + caps->maxLODBias = 2.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Maximum draw buffers and color attachments are the same, max color attachments could eventually be + // increased to 16 + caps->maxDrawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel); + caps->maxColorAttachments = GetMaximumSimultaneousRenderTargets(featureLevel); + + // D3D11 has the same limit for viewport width and height + caps->maxViewportWidth = GetMaximumViewportSize(featureLevel); + caps->maxViewportHeight = caps->maxViewportWidth; + + // Choose a reasonable maximum, enforced in the shader. + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = 1024.0f; + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // Primitive count limits + caps->maxElementsIndices = GetMaximumDrawIndexedIndexCount(featureLevel); + caps->maxElementsVertices = GetMaximumDrawVertexCount(featureLevel); + + // Program and shader binary formats (no supported shader binary formats) + caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); + + caps->vertexHighpFloat.setIEEEFloat(); + caps->vertexMediumpFloat.setIEEEFloat(); + caps->vertexLowpFloat.setIEEEFloat(); + caps->fragmentHighpFloat.setIEEEFloat(); + caps->fragmentMediumpFloat.setIEEEFloat(); + caps->fragmentLowpFloat.setIEEEFloat(); + + // 32-bit integers are natively supported + caps->vertexHighpInt.setTwosComplementInt(32); + caps->vertexMediumpInt.setTwosComplementInt(32); + caps->vertexLowpInt.setTwosComplementInt(32); + caps->fragmentHighpInt.setTwosComplementInt(32); + caps->fragmentMediumpInt.setTwosComplementInt(32); + caps->fragmentLowpInt.setTwosComplementInt(32); + + // We do not wait for server fence objects internally, so report a max timeout of zero. + caps->maxServerWaitTimeout = 0; + + // Vertex shader limits + caps->maxVertexAttributes = GetMaximumVertexInputSlots(featureLevel); + caps->maxVertexUniformComponents = GetMaximumVertexUniformVectors(featureLevel) * 4; + caps->maxVertexUniformVectors = GetMaximumVertexUniformVectors(featureLevel); + caps->maxVertexUniformBlocks = GetMaximumVertexUniformBlocks(featureLevel); + caps->maxVertexOutputComponents = GetMaximumVertexOutputVectors(featureLevel) * 4; + caps->maxVertexTextureImageUnits = GetMaximumVertexTextureUnits(featureLevel); + + // Fragment shader limits + caps->maxFragmentUniformComponents = GetMaximumPixelUniformVectors(featureLevel) * 4; + caps->maxFragmentUniformVectors = GetMaximumPixelUniformVectors(featureLevel); + caps->maxFragmentUniformBlocks = GetMaximumPixelUniformBlocks(featureLevel); + caps->maxFragmentInputComponents = GetMaximumPixelInputVectors(featureLevel) * 4; + caps->maxTextureImageUnits = GetMaximumPixelTextureUnits(featureLevel); + caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel); + caps->maxProgramTexelOffset = GetMaximumTexelOffset(featureLevel); + + // Aggregate shader limits + caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; + caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel); + + // Setting a large alignment forces uniform buffers to bind with zero offset + caps->uniformBufferOffsetAlignment = static_cast(std::numeric_limits::max()); +#if defined(ANGLE_ENABLE_D3D11_1) + ID3D11DeviceContext1 *deviceContext1 = d3d11::DynamicCastComObject(deviceContext); + + if (deviceContext1) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; + device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + + if (d3d11Options.ConstantBufferOffsetting) + { + // With DirectX 11.1, constant buffer offset and size must be a multiple of 16 constants of 16 bytes each. + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404649%28v=vs.85%29.aspx + caps->uniformBufferOffsetAlignment = 256; + } + + SafeRelease(deviceContext1); + } +#endif + + caps->maxCombinedUniformBlocks = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; + caps->maxCombinedVertexUniformComponents = (static_cast(caps->maxVertexUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + + static_cast(caps->maxVertexUniformComponents); + caps->maxCombinedFragmentUniformComponents = (static_cast(caps->maxFragmentUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + + static_cast(caps->maxFragmentUniformComponents); + caps->maxVaryingComponents = GetMaximumVertexOutputVectors(featureLevel) * 4; + caps->maxVaryingVectors = GetMaximumVertexOutputVectors(featureLevel); + caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponents(featureLevel); + caps->maxTransformFeedbackSeparateAttributes = GetMaximumStreamOutputBuffers(featureLevel); + caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateComponents(featureLevel); + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = true; + extensions->packedDepthStencil = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = true; + extensions->mapBuffer = true; + extensions->mapBufferRange = true; + extensions->textureNPOT = GetNPOTTextureSupport(featureLevel); + extensions->drawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel) > 1; + extensions->textureStorage = true; + extensions->textureFilterAnisotropic = true; + extensions->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel); + extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel); + extensions->fence = GetEventQuerySupport(featureLevel); + extensions->timerQuery = false; // Unimplemented + extensions->robustness = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel); + extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel); + extensions->maxSamples = maxSamples; + extensions->instancedArrays = GetInstancingSupport(featureLevel); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel); + extensions->shaderTextureLOD = GetShaderTextureLODSupport(featureLevel); + extensions->fragDepth = true; + extensions->textureUsage = true; // This could be false since it has no effect in D3D11 + extensions->translatedShaderSource = true; +} + +} + +namespace d3d11 +{ + +void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + const DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); + + int upsampleCount = 0; + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < static_cast(dxgiFormatInfo.blockWidth) || + *requestHeight < static_cast(dxgiFormatInfo.blockHeight)) + { + while (*requestWidth % dxgiFormatInfo.blockWidth != 0 || *requestHeight % dxgiFormatInfo.blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; +} + +void GenerateInitialTextureData(GLint internalFormat, D3D_FEATURE_LEVEL featureLevel, GLuint width, GLuint height, GLuint depth, + GLuint mipLevels, std::vector *outSubresourceData, + std::vector< std::vector > *outData) +{ + const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(internalFormat, featureLevel); + ASSERT(d3dFormatInfo.dataInitializerFunction != NULL); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3dFormatInfo.texFormat); + + outSubresourceData->resize(mipLevels); + outData->resize(mipLevels); + + for (unsigned int i = 0; i < mipLevels; i++) + { + unsigned int mipWidth = std::max(width >> i, 1U); + unsigned int mipHeight = std::max(height >> i, 1U); + unsigned int mipDepth = std::max(depth >> i, 1U); + + unsigned int rowWidth = dxgiFormatInfo.pixelBytes * mipWidth; + unsigned int imageSize = rowWidth * height; + + outData->at(i).resize(rowWidth * mipHeight * mipDepth); + d3dFormatInfo.dataInitializerFunction(mipWidth, mipHeight, mipDepth, outData->at(i).data(), rowWidth, imageSize); + + outSubresourceData->at(i).pSysMem = outData->at(i).data(); + outSubresourceData->at(i).SysMemPitch = rowWidth; + outSubresourceData->at(i).SysMemSlicePitch = imageSize; + } +} + +void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v) +{ + vertex->x = x; + vertex->y = y; + vertex->u = u; + vertex->v = v; +} + +void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, + unsigned int layer, float u, float v, float s) +{ + vertex->x = x; + vertex->y = y; + vertex->l = layer; + vertex->u = u; + vertex->v = v; + vertex->s = s; +} + +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) +{ +#if defined(_DEBUG) + return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); +#else + return S_OK; +#endif +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget11 **outRT) +{ + RenderTargetD3D *renderTarget = NULL; + gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + *outRT = RenderTarget11::makeRenderTarget11(renderTarget); + return gl::Error(GL_NO_ERROR); +} + +Workarounds GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel) +{ + Workarounds workarounds; + workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = true; + workarounds.zeroMaxLodWorkaround = (featureLevel <= D3D_FEATURE_LEVEL_9_3); + workarounds.useInstancedPointSpriteEmulation = (featureLevel <= D3D_FEATURE_LEVEL_9_3); + return workarounds; +} + +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h new file mode 100644 index 0000000000..207e6b5404 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h @@ -0,0 +1,190 @@ +// +// Copyright (c) 2012-2014 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. +// + +// renderer11_utils.h: Conversion functions and other utility routines +// specific to the D3D11 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" + +#include + +namespace gl +{ +class FramebufferAttachment; +} + +namespace rx +{ +class RenderTarget11; +struct Workarounds; + +namespace gl_d3d11 +{ + +D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha); +D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp); +UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha); + +D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode); + +D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); +D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); +UINT8 ConvertStencilMask(GLuint stencilmask); +D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); + +D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode); +D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); + +D3D11_QUERY ConvertQueryType(GLenum queryType); + +} + +namespace d3d11_gl +{ + +GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel); +void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); + +} + +namespace d3d11 +{ + +void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +void GenerateInitialTextureData(GLint internalFormat, D3D_FEATURE_LEVEL featureLevel, GLuint width, GLuint height, GLuint depth, + GLuint mipLevels, std::vector *outSubresourceData, + std::vector< std::vector > *outData); + +struct PositionTexCoordVertex +{ + float x, y; + float u, v; +}; +void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v); + +struct PositionLayerTexCoord3DVertex +{ + float x, y; + unsigned int l; + float u, v, s; +}; +void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, + unsigned int layer, float u, float v, float s); + +template +struct PositionDepthColorVertex +{ + float x, y, z; + T r, g, b, a; +}; + +template +void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z, + const gl::Color &color) +{ + vertex->x = x; + vertex->y = y; + vertex->z = z; + vertex->r = color.red; + vertex->g = color.green; + vertex->b = color.blue; + vertex->a = color.alpha; +} + +HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); + +template +outType* DynamicCastComObject(IUnknown* object) +{ + outType *outObject = NULL; + HRESULT result = object->QueryInterface(__uuidof(outType), reinterpret_cast(&outObject)); + if (SUCCEEDED(result)) + { + return outObject; + } + else + { + SafeRelease(outObject); + return NULL; + } +} + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case DXGI_ERROR_DEVICE_HUNG: + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_DEVICE_RESET: + case DXGI_ERROR_DRIVER_INTERNAL_ERROR: + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: + return true; + default: + return false; + } +} + +template +inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11VertexShader *vs = NULL; + HRESULT result = device->CreateVertexShader(byteCode, N, NULL, &vs); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(vs, name); + return vs; +} + +template +inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11GeometryShader *gs = NULL; + HRESULT result = device->CreateGeometryShader(byteCode, N, NULL, &gs); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(gs, name); + return gs; +} + +template +inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) +{ + ID3D11PixelShader *ps = NULL; + HRESULT result = device->CreatePixelShader(byteCode, N, NULL, &ps); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + SetDebugName(ps, name); + return ps; +} + +// Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to +// represent an entire buffer. +template +inline void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value) +{ + D3D11_MAPPED_SUBRESOURCE mappedResource; + context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + + memcpy(mappedResource.pData, &value, sizeof(T)); + + context->Unmap(constantBuffer, 0); +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget11 **outRT); + +Workarounds GenerateWorkarounds(D3D_FEATURE_LEVEL featureLevel); + +} + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_RENDERER11_UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl new file mode 100644 index 0000000000..c43734f6a3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl @@ -0,0 +1,77 @@ +Buffer Buffer4F : register(t0); +Buffer Buffer4I : register(t0); +Buffer Buffer4UI : register(t0); + +struct VS_OUTPUT +{ + float4 position : SV_Position; + uint index : TEXCOORD0; + uint slice : LAYER; +}; + +struct GS_OUTPUT +{ + float4 position : SV_Position; + uint index : TEXCOORD0; + uint slice : SV_RenderTargetArrayIndex; +}; + +cbuffer BufferCopyParams : register(b0) +{ + uint FirstPixelOffset; + uint PixelsPerRow; + uint RowStride; + uint RowsPerSlice; + float2 PositionOffset; + float2 PositionScale; + int2 TexLocationOffset; + int2 TexLocationScale; + uint FirstSlice; +} + +void ComputePositionAndIndex(uint vertexID, out VS_OUTPUT outVertex) +{ + uint PixelsPerSlice = PixelsPerRow * RowsPerSlice; + uint SliceStride = RowStride * RowsPerSlice; + + uint slice = vertexID / PixelsPerSlice; + uint sliceOffset = slice * PixelsPerSlice; + uint row = (vertexID - sliceOffset) / PixelsPerRow; + uint col = vertexID - sliceOffset - (row * PixelsPerRow); + + float2 coords = float2(float(col), float(row)); + + outVertex.position = float4(PositionOffset + PositionScale * coords, 0.0f, 1.0f); + outVertex.index = FirstPixelOffset + slice * SliceStride + row * RowStride + col; + outVertex.slice = FirstSlice + slice; +} + +void VS_BufferToTexture(in uint vertexID : SV_VertexID, out VS_OUTPUT outVertex) +{ + ComputePositionAndIndex(vertexID, outVertex); +} + +[maxvertexcount(1)] +void GS_BufferToTexture(point VS_OUTPUT inVertex[1], inout PointStream outStream) +{ + GS_OUTPUT outVertex; + outVertex.position = inVertex[0].position; + outVertex.index = inVertex[0].index; + outVertex.slice = inVertex[0].slice; + outStream.Append(outVertex); +} + +float4 PS_BufferToTexture_4F(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4F.Load(inIndex); +} + +int4 PS_BufferToTexture_4I(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4I.Load(inIndex); +} + +uint4 PS_BufferToTexture_4UI(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target +{ + return Buffer4UI.Load(inIndex); +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl new file mode 100644 index 0000000000..2b3e1ebe4c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl @@ -0,0 +1,119 @@ +// Assume we are in SM4+, which has 8 color outputs + +void VS_ClearFloat( in float3 inPosition : POSITION, in float4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out float4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputFloat +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; + float4 color4 : SV_TARGET4; + float4 color5 : SV_TARGET5; + float4 color6 : SV_TARGET6; + float4 color7 : SV_TARGET7; +}; + +PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +{ + PS_OutputFloat outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} + +struct PS_OutputFloat_FL9 +{ + float4 color0 : SV_TARGET0; + float4 color1 : SV_TARGET1; + float4 color2 : SV_TARGET2; + float4 color3 : SV_TARGET3; +}; + +PS_OutputFloat_FL9 PS_ClearFloat_FL9(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) +{ + PS_OutputFloat_FL9 outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + return outColor; +} + +void VS_ClearUint( in float3 inPosition : POSITION, in uint4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out uint4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputUint +{ + uint4 color0 : SV_TARGET0; + uint4 color1 : SV_TARGET1; + uint4 color2 : SV_TARGET2; + uint4 color3 : SV_TARGET3; + uint4 color4 : SV_TARGET4; + uint4 color5 : SV_TARGET5; + uint4 color6 : SV_TARGET6; + uint4 color7 : SV_TARGET7; +}; + +PS_OutputUint PS_ClearUint(in float4 inPosition : SV_POSITION, in uint4 inColor : COLOR) +{ + PS_OutputUint outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} + + +void VS_ClearSint( in float3 inPosition : POSITION, in int4 inColor : COLOR, + out float4 outPosition : SV_POSITION, out int4 outColor : COLOR) +{ + outPosition = float4(inPosition, 1.0f); + outColor = inColor; +} + +struct PS_OutputSint +{ + int4 color0 : SV_TARGET0; + int4 color1 : SV_TARGET1; + int4 color2 : SV_TARGET2; + int4 color3 : SV_TARGET3; + int4 color4 : SV_TARGET4; + int4 color5 : SV_TARGET5; + int4 color6 : SV_TARGET6; + int4 color7 : SV_TARGET7; +}; + +PS_OutputSint PS_ClearSint(in float4 inPosition : SV_POSITION, in int4 inColor : COLOR) +{ + PS_OutputSint outColor; + outColor.color0 = inColor; + outColor.color1 = inColor; + outColor.color2 = inColor; + outColor.color3 = inColor; + outColor.color4 = inColor; + outColor.color5 = inColor; + outColor.color6 = inColor; + outColor.color7 = inColor; + return outColor; +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl new file mode 100644 index 0000000000..8671c39fb7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl @@ -0,0 +1,111 @@ +Texture2D TextureF : register(t0); +Texture2D TextureUI : register(t0); +Texture2D TextureI : register(t0); + +SamplerState Sampler : register(s0); + +void VS_Passthrough2D( in float2 inPosition : POSITION, in float2 inTexCoord : TEXCOORD0, + out float4 outPosition : SV_POSITION, out float2 outTexCoord : TEXCOORD0) +{ + outPosition = float4(inPosition, 0.0f, 1.0f); + outTexCoord = inTexCoord; +} + +float PS_PassthroughDepth2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_DEPTH +{ + return TextureF.Sample(Sampler, inTexCoord).r; +} + +float4 PS_PassthroughRGBA2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, inTexCoord).rgba; +} + +uint4 PS_PassthroughRGBA2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return TextureUI.Load(int3(size * inTexCoord, 0)).rgba; +} + +int4 PS_PassthroughRGBA2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return TextureI.Load(int3(size * inTexCoord, 0)).rgba; +} + +float4 PS_PassthroughRGB2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rgb, 1.0f); +} + +uint4 PS_PassthroughRGB2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rgb, 0); +} + +int4 PS_PassthroughRGB2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).rgb, 0); +} + +float4 PS_PassthroughRG2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rg, 0.0f, 1.0f); +} + +uint4 PS_PassthroughRG2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); +} + +int4 PS_PassthroughRG2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); +} + +float4 PS_PassthroughR2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).r, 0.0f, 0.0f, 1.0f); +} + +uint4 PS_PassthroughR2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI.GetDimensions(size.x, size.y); + + return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); +} + +int4 PS_PassthroughR2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI.GetDimensions(size.x, size.y); + + return int4(TextureI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); +} + +float4 PS_PassthroughLum2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, inTexCoord).rrr, 1.0f); +} + +float4 PS_PassthroughLumAlpha2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, inTexCoord).rrra; +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl new file mode 100644 index 0000000000..c23c9032ec --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl @@ -0,0 +1,146 @@ +Texture3D TextureF : register(t0); +Texture3D TextureUI : register(t0); +Texture3D TextureI : register(t0); + +SamplerState Sampler : register(s0); + +struct VS_INPUT +{ + float2 Position : POSITION; + uint Layer : LAYER; + float3 TexCoord : TEXCOORD; +}; + +struct VS_OUTPUT +{ + float4 Position : SV_POSITION; + uint Layer : LAYER; + float3 TexCoord : TEXCOORD; +}; + +struct GS_OUTPUT +{ + float4 Position : SV_POSITION; + uint Layer : SV_RENDERTARGETARRAYINDEX; + float3 TexCoord : TEXCOORD; +}; + +VS_OUTPUT VS_Passthrough3D(VS_INPUT input) +{ + VS_OUTPUT output; + + output.Position = float4(input.Position, 0.0f, 1.0f); + output.Layer = input.Layer; + output.TexCoord = input.TexCoord; + + return output; +} + +[maxvertexcount(3)] +void GS_Passthrough3D(triangle VS_OUTPUT input[3], inout TriangleStream outputStream) +{ + GS_OUTPUT output; + + for (int i = 0; i < 3; i++) + { + output.Position = input[i].Position; + output.Layer = input[i].Layer; + output.TexCoord = input[i].TexCoord; + + outputStream.Append(output); + } +} + +float4 PS_PassthroughRGBA3D(GS_OUTPUT input) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, input.TexCoord).rgba; +} + +uint4 PS_PassthroughRGBA3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return TextureUI.Load(int4(size * input.TexCoord, 0)).rgba; +} + +int4 PS_PassthroughRGBA3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return TextureI.Load(int4(size * input.TexCoord, 0)).rgba; +} + +float4 PS_PassthroughRGB3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rgb, 1.0f); +} + +uint4 PS_PassthroughRGB3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rgb, 0); +} + +int4 PS_PassthroughRGB3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rgb, 0); +} + +float4 PS_PassthroughRG3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rg, 0.0f, 1.0f); +} + +uint4 PS_PassthroughRG3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); +} + +int4 PS_PassthroughRG3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); +} + +float4 PS_PassthroughR3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).r, 0.0f, 0.0f, 1.0f); +} + +uint4 PS_PassthroughR3DUI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureUI.GetDimensions(size.x, size.y, size.z); + + return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); +} + +int4 PS_PassthroughR3DI(GS_OUTPUT input) : SV_TARGET0 +{ + uint3 size; + TextureI.GetDimensions(size.x, size.y, size.z); + + return int4(TextureI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); +} + +float4 PS_PassthroughLum3D(GS_OUTPUT input) : SV_TARGET0 +{ + return float4(TextureF.Sample(Sampler, input.TexCoord).rrr, 1.0f); +} + +float4 PS_PassthroughLumAlpha3D(GS_OUTPUT input) : SV_TARGET0 +{ + return TextureF.Sample(Sampler, input.TexCoord).rrra; +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl new file mode 100644 index 0000000000..505e222137 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl @@ -0,0 +1,99 @@ +Texture2D TextureF2D : register(t0); +Texture2D TextureUI2D : register(t0); +Texture2D TextureI2D : register(t0); + +Texture3D TextureF3D : register(t0); +Texture3D TextureUI3D : register(t0); +Texture3D TextureI3D : register(t0); + +Texture2DArray TextureF2DArray : register(t0); +Texture2DArray TextureUI2DArray : register(t0); +Texture2DArray TextureI2DArray : register(t0); + +SamplerState Sampler : register(s0); + +cbuffer SwizzleProperties : register(b0) +{ + uint4 SwizzleIndices : packoffset(c0); +} + +float4 SwizzleLookup(in float4 sample) +{ + float lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return float4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +int4 SwizzleLookup(in int4 sample) +{ + int lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return int4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +uint4 SwizzleLookup(in uint4 sample) +{ + uint lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; + return uint4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); +} + +float4 PS_SwizzleF2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF2D.Sample(Sampler, inTexCoord)); +} + +int4 PS_SwizzleI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureI2D.GetDimensions(size.x, size.y); + + return SwizzleLookup(TextureI2D.Load(int3(size * inTexCoord, 0))); +} + +uint4 PS_SwizzleUI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint2 size; + TextureUI2D.GetDimensions(size.x, size.y); + + return SwizzleLookup(TextureUI2D.Load(int3(size * inTexCoord, 0))); +} + +float4 PS_SwizzleF3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF3D.Sample(Sampler, inTexCoord)); +} + +int4 PS_SwizzleI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureI3D.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureI3D.Load(int4(size * inTexCoord, 0))); +} + +uint4 PS_SwizzleUI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureUI3D.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureUI3D.Load(int4(size * inTexCoord, 0))); +} + +float4 PS_SwizzleF2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + return SwizzleLookup(TextureF2DArray.Sample(Sampler, float3(inTexCoord.xy, inLayer))); +} + +int4 PS_SwizzleI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureI2DArray.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); +} + +uint4 PS_SwizzleUI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 +{ + uint3 size; + TextureUI2DArray.GetDimensions(size.x, size.y, size.z); + + return SwizzleLookup(TextureUI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp new file mode 100644 index 0000000000..9d8f0bb96c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp @@ -0,0 +1,68 @@ +// +// Copyright (c) 2014 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. +// + +// NativeWindow.cpp: Handler for managing HWND native window types. + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +#include "common/debug.h" + +namespace rx +{ + +NativeWindow::NativeWindow(EGLNativeWindowType window) : mWindow(window) +{ +} + +bool NativeWindow::initialize() +{ + return true; +} + +bool NativeWindow::getClientRect(LPRECT rect) +{ + return GetClientRect(mWindow, rect) == TRUE; +} + +bool NativeWindow::isIconic() +{ + return IsIconic(mWindow) == TRUE; +} + +bool NativeWindow::isValidNativeWindow(EGLNativeWindowType window) +{ + return IsWindow(window) == TRUE; +} + +HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, + DXGI_FORMAT format, unsigned int width, unsigned int height, + DXGISwapChain** swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; + swapChainDesc.BufferCount = 1; + swapChainDesc.BufferDesc.Format = format; + swapChainDesc.BufferDesc.Width = width; + swapChainDesc.BufferDesc.Height = height; + swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; + swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.Flags = 0; + swapChainDesc.OutputWindow = mWindow; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.Windowed = TRUE; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + + return factory->CreateSwapChain(device, &swapChainDesc, swapChain); +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp new file mode 100644 index 0000000000..350526c867 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp @@ -0,0 +1,214 @@ +// +// Copyright (c) 2014 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. +// + +// CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" + +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +CoreWindowNativeWindow::~CoreWindowNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) +{ + mOrientationChangedEventToken.value = 0; + ComPtr props = propertySet; + ComPtr win = window; + SIZE swapChainSize = {}; + bool swapChainSizeSpecified = false; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (SUCCEEDED(result)) + { + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mCoreWindow); + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output occurs automatically because if + // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain. + if (swapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + mSupportsSwapChainResize = false; + } + else + { + result = GetCoreWindowSizeInPixels(mCoreWindow, &mClientRect); + } + } + + if (SUCCEEDED(result)) + { + ComPtr displayInformation; + result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), &displayInformation); + if (SUCCEEDED(result)) + { + result = displayInformation->GetForCurrentView(&mDisplayInformation); + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool CoreWindowNativeWindow::registerForSizeChangeEvents() +{ + ComPtr sizeChangedHandler; + HRESULT result = Microsoft::WRL::MakeAndInitialize(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); + if (SUCCEEDED(result)) + { + result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); + } + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + ComPtr orientationChangedHandler; + result = sizeChangedHandler.As(&orientationChangedHandler); + if (SUCCEEDED(result)) + { + result = mDisplayInformation->add_OrientationChanged(orientationChangedHandler.Get(), &mOrientationChangedEventToken); + } +#endif + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void CoreWindowNativeWindow::unregisterForSizeChangeEvents() +{ + if (mCoreWindow) + { + (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken); + } +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + if (mDisplayInformation) + { + (void)mDisplayInformation->remove_OrientationChanged(mOrientationChangedEventToken); + } +#endif + mSizeChangedEventToken.value = 0; + mOrientationChangedEventToken.value = 0; +} + +HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + + *swapChain = nullptr; + + ComPtr newSwapChain; + HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + if (SUCCEEDED(result)) + { + +#if 0 //(WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // Qt: allow Windows Phone to resize, but don't modify the backing texture in the swap chain. + // Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On + // other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed + // (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations. + if (newSwapChain->ResizeBuffers(swapChainDesc.BufferCount, swapChainDesc.Width, swapChainDesc.Height, swapChainDesc.Format, DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) == DXGI_ERROR_UNSUPPORTED) + { + mSupportsSwapChainResize = false; + } +#endif // (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + + result = newSwapChain.CopyTo(swapChain); + } + + if (SUCCEEDED(result)) + { + // If automatic swapchain resize behaviors have been disabled, then + // unregister for the resize change events. + if (mSupportsSwapChainResize == false) + { + unregisterForSizeChangeEvents(); + } + } + + return result; +} + +HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize) +{ + ABI::Windows::Foundation::Rect bounds; + HRESULT result = coreWindow->get_Bounds(&bounds); + if (SUCCEEDED(result)) + { + *windowSize = { 0, 0, ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) }; + } + + return result; +} + +static float GetLogicalDpi() +{ + ComPtr displayProperties; + float dpi = 96.0f; + + if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) + { + if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) + { + return dpi; + } + } + return dpi; +} + +long ConvertDipsToPixels(float dips) +{ + static const float dipsPerInch = 96.0f; + return lround((dips * GetLogicalDpi() / dipsPerInch)); +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h new file mode 100644 index 0000000000..59df9d5a6c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h @@ -0,0 +1,110 @@ +// +// Copyright (c) 2014 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. +// + +// CoreWindowNativeWindow.h: NativeWindow for managing ICoreWindow native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ + +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" + +#include +#include + +typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t IWindowSizeChangedEventHandler; +typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CGraphics__CDisplay__CDisplayInformation_IInspectable_t IDisplayOrientationEventHandler; + +namespace rx +{ +long ConvertDipsToPixels(float dips); + +class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this +{ + public: + ~CoreWindowNativeWindow(); + + bool initialize(EGLNativeWindowType window, IPropertySet *propertySet); + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); + + private: + ComPtr mCoreWindow; + ComPtr> mPropertyMap; + ComPtr mDisplayInformation; + EventRegistrationToken mOrientationChangedEventToken; +}; + +[uuid(7F924F66-EBAE-40E5-A10B-B8F35E245190)] +class CoreWindowSizeChangedHandler : + public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler, IDisplayOrientationEventHandler> +{ + public: + CoreWindowSizeChangedHandler() { } + HRESULT RuntimeClassInitialize(std::shared_ptr host) + { + if (!host) + { + return E_INVALIDARG; + } + + mHost = host; + return S_OK; + } + + // IWindowSizeChangedEventHandler + IFACEMETHOD(Invoke)(ABI::Windows::UI::Core::ICoreWindow *sender, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *sizeChangedEventArgs) + { + std::shared_ptr host = mHost.lock(); + if (host) + { + ABI::Windows::Foundation::Size windowSize; + if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) + { + SIZE windowSizeInPixels = { ConvertDipsToPixels(windowSize.Width), ConvertDipsToPixels(windowSize.Height) }; + host->setNewClientSize(windowSizeInPixels); + } + } + + return S_OK; + } + + IFACEMETHOD(Invoke)(ABI::Windows::Graphics::Display::IDisplayInformation *displayInformation, IInspectable *) + { +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + NativeWindow::RotationFlags flags = NativeWindow::RotateNone; + ABI::Windows::Graphics::Display::DisplayOrientations orientation; + if (SUCCEEDED(displayInformation->get_CurrentOrientation(&orientation))) + { + switch (orientation) + { + case ABI::Windows::Graphics::Display::DisplayOrientations_Landscape: + flags = NativeWindow::RotateLeft; + break; + case ABI::Windows::Graphics::Display::DisplayOrientations_LandscapeFlipped: + flags = NativeWindow::RotateRight; + break; + default: + break; + } + } + std::shared_ptr host = mHost.lock(); + if (host) + { + host->setRotationFlags(flags); + } +#endif + return S_OK; + } + + private: + std::weak_ptr mHost; +}; + +HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize); +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_COREWINDOWNATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp new file mode 100644 index 0000000000..2bf48c5d94 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp @@ -0,0 +1,291 @@ +// +// Copyright (c) 2014 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. +// + +// InspectableNativeWindow.cpp: NativeWindow base class for managing IInspectable native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +namespace rx +{ +NativeWindow::NativeWindow(EGLNativeWindowType window) +{ + mWindow = window; +} + +bool NativeWindow::initialize() +{ + // If the native window type is a IPropertySet, extract the + // EGLNativeWindowType (IInspectable) and initialize the + // proper host with this IPropertySet. + ComPtr propertySet; + ComPtr eglNativeWindow; + if (IsEGLConfiguredPropertySet(mWindow, &propertySet, &eglNativeWindow)) + { + // A property set was found and the EGLNativeWindowType was + // retrieved. The mWindow member of the host to must be updated + // to use the EGLNativeWindowType specified in the property set. + // mWindow is treated as a raw pointer not an AddRef'd interface, so + // the old mWindow does not need a Release() before this assignment. + mWindow = eglNativeWindow.Get(); + } + + ComPtr coreWindow; + ComPtr swapChainPanel; + if (IsCoreWindow(mWindow, &coreWindow)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(mWindow, propertySet.Get()); + } + } + else if (IsSwapChainPanel(mWindow, &swapChainPanel)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(mWindow, propertySet.Get()); + } + } + else + { + ERR("Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include ICoreWindow, ISwapChainPanel and IPropertySet"); + } + + return false; +} + +bool NativeWindow::getClientRect(RECT *rect) +{ + if (mImpl) + { + return mImpl->getClientRect(rect); + } + + return false; +} + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +NativeWindow::RotationFlags NativeWindow::rotationFlags() const +{ + if (mImpl) + { + return mImpl->rotationFlags(); + } + + return NativeWindow::RotateNone; +} +#endif + +bool NativeWindow::isIconic() +{ + return false; +} + +bool NativeWindow::isValidNativeWindow(EGLNativeWindowType window) +{ + return IsValidEGLNativeWindowType(window); +} + +HRESULT NativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (mImpl) + { + return mImpl->createSwapChain(device, factory, format, width, height, swapChain); + } + + return E_UNEXPECTED; +} + +bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow) +{ + if (!window) + { + return false; + } + + ComPtr win = window; + ComPtr coreWin; + if (SUCCEEDED(win.As(&coreWin))) + { + if (coreWindow != nullptr) + { + *coreWindow = coreWin.Detach(); + } + return true; + } + + return false; +} + +bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel) +{ + if (!window) + { + return false; + } + + ComPtr win = window; + ComPtr panel; + if (SUCCEEDED(win.As(&panel))) + { + if (swapChainPanel != nullptr) + { + *swapChainPanel = panel.Detach(); + } + return true; + } + + return false; +} + +bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet, IInspectable **eglNativeWindow) +{ + if (!window) + { + return false; + } + + ComPtr props = window; + ComPtr propSet; + ComPtr nativeWindow; + ComPtr> propMap; + boolean hasEglNativeWindowPropertyKey = false; + + HRESULT result = props.As(&propSet); + if (SUCCEEDED(result)) + { + result = propSet.As(&propMap); + } + + // Look for the presence of the EGLNativeWindowType in the property set + if (SUCCEEDED(result)) + { + result = propMap->HasKey(HStringReference(EGLNativeWindowTypeProperty).Get(), &hasEglNativeWindowPropertyKey); + } + + // If the IPropertySet does not contain the required EglNativeWindowType key, the property set is + // considered invalid. + if (SUCCEEDED(result) && !hasEglNativeWindowPropertyKey) + { + ERR("Could not find EGLNativeWindowTypeProperty in IPropertySet. Valid EGLNativeWindowTypeProperty values include ICoreWindow"); + return false; + } + + // The EglNativeWindowType property exists, so retreive the IInspectable that represents the EGLNativeWindowType + if (SUCCEEDED(result) && hasEglNativeWindowPropertyKey) + { + result = propMap->Lookup(HStringReference(EGLNativeWindowTypeProperty).Get(), &nativeWindow); + } + + if (SUCCEEDED(result)) + { + if (propertySet != nullptr) + { + result = propSet.CopyTo(propertySet); + } + } + + if (SUCCEEDED(result)) + { + if (eglNativeWindow != nullptr) + { + result = nativeWindow.CopyTo(eglNativeWindow); + } + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +// A Valid EGLNativeWindowType IInspectable can only be: +// +// ICoreWindow +// IPropertySet +// +// Anything else will be rejected as an invalid IInspectable. +bool IsValidEGLNativeWindowType(EGLNativeWindowType window) +{ + return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window); +} + +// Attempts to read an optional SIZE property value that is assumed to be in the form of +// an ABI::Windows::Foundation::Size. This function validates the Size value before returning +// it to the caller. +// +// Possible return values are: +// S_OK, valueExists == true - optional SIZE value was successfully retrieved and validated +// S_OK, valueExists == false - optional SIZE value was not found +// E_INVALIDARG, valueExists = false - optional SIZE value was malformed in the property set. +// * Incorrect property type ( must be PropertyType_Size) +// * Invalid property value (width/height must be > 0) +// Additional errors may be returned from IMap or IPropertyValue +// +HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists) +{ + if (!propertyMap || !propertyName || !value || !valueExists) + { + return false; + } + + // Assume that the value does not exist + *valueExists = false; + *value = { 0, 0 }; + + ComPtr propertyValue; + ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty; + Size sizeValue = { 0, 0 }; + boolean hasKey = false; + + HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), &hasKey); + if (SUCCEEDED(result) && !hasKey) + { + // Value does not exist, so return S_OK and set the exists parameter to false to indicate + // that a the optional property does not exist. + *valueExists = false; + return S_OK; + } + + if (SUCCEEDED(result)) + { + result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue); + } + + if (SUCCEEDED(result)) + { + result = propertyValue->get_Type(&propertyType); + } + + // Check if the expected Size property is of PropertyType_Size type. + if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size) + { + if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0)) + { + // A valid property value exists + *value = { static_cast(sizeValue.Width), static_cast(sizeValue.Height) }; + *valueExists = true; + result = S_OK; + } + else + { + // An invalid Size property was detected. Width/Height values must > 0 + result = E_INVALIDARG; + } + } + else + { + // An invalid property type was detected. Size property must be of PropertyType_Size + result = E_INVALIDARG; + } + + return result; +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h new file mode 100644 index 0000000000..575bdf8a58 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h @@ -0,0 +1,105 @@ +// +// Copyright (c) 2014 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. +// + +// InspectableNativeWindow.h: Host specific implementation interface for +// managing IInspectable native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ + +#include "libANGLE/renderer/d3d/d3d11/NativeWindow.h" + +#include "common/platform.h" + +#include "angle_windowsstore.h" + +#include +#include + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +class InspectableNativeWindow +{ + public: + InspectableNativeWindow() : + mSupportsSwapChainResize(true), + mRequiresSwapChainScaling(false), + mClientRectChanged(false), + mClientRect({0,0,0,0}), + mNewClientRect({0,0,0,0}), + mRotationFlags(NativeWindow::RotateNone) + { + mSizeChangedEventToken.value = 0; + } + virtual ~InspectableNativeWindow(){} + + virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0; + virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0; + virtual bool registerForSizeChangeEvents() = 0; + virtual void unregisterForSizeChangeEvents() = 0; + virtual HRESULT scaleSwapChain(const SIZE& newSize) { return S_OK; } + + bool getClientRect(RECT *rect) + { + if (mClientRectChanged && mSupportsSwapChainResize) + { + mClientRect = mNewClientRect; + } + + *rect = mClientRect; + + return true; + } + + void setNewClientSize(const SIZE &newSize) + { + if (mSupportsSwapChainResize && !mRequiresSwapChainScaling) + { + mNewClientRect = { 0, 0, newSize.cx, newSize.cy }; + mClientRectChanged = true; + } + + if (mRequiresSwapChainScaling) + { + scaleSwapChain(newSize); + } + } + + NativeWindow::RotationFlags rotationFlags() const + { + return mRotationFlags; + } + + void setRotationFlags(NativeWindow::RotationFlags flags) + { + mRotationFlags = flags; + } + +protected: + bool mSupportsSwapChainResize; + bool mRequiresSwapChainScaling; + RECT mClientRect; + RECT mNewClientRect; + bool mClientRectChanged; + NativeWindow::RotationFlags mRotationFlags; + + EventRegistrationToken mSizeChangedEventToken; +}; + +bool IsValidEGLNativeWindowType(EGLNativeWindowType window); +bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow = nullptr); +bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel = nullptr); +bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr); +HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists); + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_INSPECTABLENATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp new file mode 100644 index 0000000000..53899dbb30 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp @@ -0,0 +1,228 @@ +// +// Copyright (c) 2014 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. +// + +// SwapChainPanelNativeWindow.cpp: NativeWindow for managing ISwapChainPanel native window types. + +#include "libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h" + +#include +#include + +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) +{ + ComPtr props = propertySet; + ComPtr win = window; + SIZE swapChainSize = {}; + bool swapChainSizeSpecified = false; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (SUCCEEDED(result)) + { + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mSwapChainPanel); + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output needs to be handled by the + // host for swapchain panels even though the scaling mode setting + // DXGI_SCALING_STRETCH is configured on the swapchain. + if (swapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + + // Enable host swapchain scaling + mRequiresSwapChainScaling = true; + } + else + { + result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect); + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() +{ + ComPtr sizeChangedHandler; + ComPtr frameworkElement; + HRESULT result = Microsoft::WRL::MakeAndInitialize(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&frameworkElement); + } + + if (SUCCEEDED(result)) + { + result = frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() +{ + ComPtr frameworkElement; + if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) + { + (void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken); + } + + mSizeChangedEventToken.value = 0; +} + +HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + + *swapChain = nullptr; + + ComPtr newSwapChain; + ComPtr swapChainPanelNative; + RECT currentPanelSize = {}; + + HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&swapChainPanelNative); + } + + if (SUCCEEDED(result)) + { + result = swapChainPanelNative->SetSwapChain(newSwapChain.Get()); + } + + if (SUCCEEDED(result)) + { + // The swapchain panel host requires an instance of the swapchain set on the SwapChainPanel + // to perform the runtime-scale behavior. This swapchain is cached here because there are + // no methods for retreiving the currently configured on from ISwapChainPanelNative. + mSwapChain = newSwapChain; + result = newSwapChain.CopyTo(swapChain); + } + + // If the host is responsible for scaling the output of the swapchain, then + // scale it now before returning an instance to the caller. This is done by + // first reading the current size of the swapchain panel, then scaling + if (SUCCEEDED(result) && mRequiresSwapChainScaling) + { + result = GetSwapChainPanelSize(mSwapChainPanel, ¤tPanelSize); + } + + // Scale the swapchain to fit inside the contents of the panel. + if (SUCCEEDED(result) && mRequiresSwapChainScaling) + { + SIZE currentSize = { currentPanelSize.right, currentPanelSize.bottom }; + result = scaleSwapChain(currentSize); + } + + if (SUCCEEDED(result)) + { + // If automatic swapchain resize behaviors have been disabled, then + // unregister for the resize change events. + if (mSupportsSwapChainResize == false) + { + unregisterForSizeChangeEvents(); + } + } + + return result; +} + +HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) +{ + ABI::Windows::Foundation::Size renderScale = { (float)newSize.cx/(float)mClientRect.right, (float)newSize.cy/(float)mClientRect.bottom }; + // Setup a scale matrix for the swap chain + DXGI_MATRIX_3X2_F scaleMatrix = {}; + scaleMatrix._11 = renderScale.Width; + scaleMatrix._22 = renderScale.Height; + + ComPtr swapChain2; + HRESULT result = mSwapChain.As(&swapChain2); + if (SUCCEEDED(result)) + { + result = swapChain2->SetMatrixTransform(&scaleMatrix); + } + + return result; +} + +HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize) +{ + ComPtr uiElement; + ABI::Windows::Foundation::Size renderSize = { 0, 0 }; + HRESULT result = swapChainPanel.As(&uiElement); + if (SUCCEEDED(result)) + { + result = uiElement->get_RenderSize(&renderSize); + } + + if (SUCCEEDED(result)) + { + *windowSize = { 0, 0, lround(renderSize.Width), lround(renderSize.Height) }; + } + + return result; +} +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h new file mode 100644 index 0000000000..caf327d913 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h @@ -0,0 +1,79 @@ +// +// Copyright (c) 2014 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. +// + +// SwapChainPanelNativeWindow.h: NativeWindow for managing ISwapChainPanel native window types. + +#ifndef LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ +#define LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ + +#include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" + +namespace rx +{ +class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this +{ + public: + ~SwapChainPanelNativeWindow(); + + bool initialize(EGLNativeWindowType window, IPropertySet *propertySet); + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); + HRESULT scaleSwapChain(const SIZE &newSize); + + private: + ComPtr mSwapChainPanel; + ComPtr> mPropertyMap; + ComPtr mSwapChain; +}; + +[uuid(8ACBD974-8187-4508-AD80-AEC77F93CF36)] +class SwapChainPanelSizeChangedHandler : + public Microsoft::WRL::RuntimeClass, ABI::Windows::UI::Xaml::ISizeChangedEventHandler> +{ + public: + SwapChainPanelSizeChangedHandler() { } + HRESULT RuntimeClassInitialize(std::shared_ptr host) + { + if (!host) + { + return E_INVALIDARG; + } + + mHost = host; + return S_OK; + } + + // ISizeChangedEventHandler + IFACEMETHOD(Invoke)(IInspectable *sender, ABI::Windows::UI::Xaml::ISizeChangedEventArgs *sizeChangedEventArgs) + { + std::shared_ptr host = mHost.lock(); + if (host) + { + // The size of the ISwapChainPanel control is returned in DIPs. + // We are keeping these in dips because the swapchain created for composition + // also uses dip units. This keeps dimensions, viewports, etc in the same unit. + // XAML Clients of the ISwapChainPanel are required to use dips to define their + // layout sizes as well. + ABI::Windows::Foundation::Size newSize; + HRESULT result = sizeChangedEventArgs->get_NewSize(&newSize); + if (SUCCEEDED(result)) + { + SIZE windowSize = { lround(newSize.Width), lround(newSize.Height) }; + host->setNewClientSize(windowSize); + } + } + + return S_OK; + } + + private: + std::weak_ptr mHost; +}; + +HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize); +} +#endif // LIBANGLE_RENDERER_D3D_D3D11_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp new file mode 100644 index 0000000000..a0bc2960b7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp @@ -0,0 +1,679 @@ +// +// 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. +// + +// Blit9.cpp: Surface copy utility class. + +#include "libANGLE/renderer/d3d/d3d9/Blit9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" + +namespace +{ +// Precompiled shaders +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/standardvs.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/flipyvs.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/passthroughps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/luminanceps.h" +#include "libANGLE/renderer/d3d/d3d9/shaders/compiled/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 rx +{ + +Blit9::Blit9(Renderer9 *renderer) + : mRenderer(renderer), + mGeometryLoaded(false), + mQuadVertexBuffer(NULL), + mQuadVertexDeclaration(NULL), + mSavedStateBlock(NULL), + mSavedRenderTarget(NULL), + mSavedDepthStencil(NULL) +{ + memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); +} + +Blit9::~Blit9() +{ + SafeRelease(mSavedStateBlock); + SafeRelease(mQuadVertexBuffer); + SafeRelease(mQuadVertexDeclaration); + + for (int i = 0; i < SHADER_COUNT; i++) + { + SafeRelease(mCompiledShaders[i]); + } +} + +gl::Error Blit9::initialize() +{ + if (mGeometryLoaded) + { + return gl::Error(GL_NO_ERROR); + } + + static const float quad[] = + { + -1, -1, + -1, 1, + 1, -1, + 1, 1 + }; + + IDirect3DDevice9 *device = mRenderer->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 gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal blit vertex shader, result: 0x%X.", result); + } + + void *lockPtr = NULL; + result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); + + if (FAILED(result) || lockPtr == NULL) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(mQuadVertexBuffer); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex shader, result: 0x%X.", result); + } + + 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); + SafeRelease(mQuadVertexBuffer); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex declaration, result: 0x%X.", result); + } + + mGeometryLoaded = true; + return gl::Error(GL_NO_ERROR); +} + +template +gl::Error Blit9::setShader(ShaderId source, const char *profile, + gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) +{ + IDirect3DDevice9 *device = mRenderer->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]; + + gl::Error error = (mRenderer->*createShader)(reinterpret_cast(shaderCode), shaderSize, &shader); + if (error.isError()) + { + return error; + } + + mCompiledShaders[source] = shader; + } + + HRESULT hr = (device->*setShader)(shader); + if (FAILED(hr)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to set shader for blit operation, result: 0x%X.", hr); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit9::setVertexShader(ShaderId shader) +{ + return setShader(shader, "vs_2_0", &Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader); +} + +gl::Error Blit9::setPixelShader(ShaderId shader) +{ + return setShader(shader, "ps_2_0", &Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader); +} + +RECT Blit9::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; +} + +gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +{ + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + + IDirect3DTexture9 *texture = NULL; + error = copySurfaceToTexture(source, getSurfaceRect(source), &texture); + if (error.isError()) + { + return error; + } + + IDirect3DDevice9 *device = mRenderer->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), gl::Offset(0, 0, 0)); + + render(); + + SafeRelease(texture); + + restoreState(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit9::copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget9 = NULL; + error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget9); + + IDirect3DSurface9 *source = renderTarget9->getSurface(); + ASSERT(source); + + IDirect3DSurface9 *destSurface = NULL; + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + error = storage9->getSurfaceLevel(level, true, &destSurface); + if (error.isError()) + { + return error; + } + ASSERT(destSurface); + + gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface); + + SafeRelease(destSurface); + SafeRelease(source); + + return result; +} + +gl::Error Blit9::copyCube(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) +{ + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget9 = NULL; + error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget9); + + IDirect3DSurface9 *source = renderTarget9->getSurface(); + ASSERT(source); + + IDirect3DSurface9 *destSurface = NULL; + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + error = storage9->getCubeMapSurface(target, level, true, &destSurface); + if (error.isError()) + { + return error; + } + ASSERT(destSurface); + + gl::Error result = copy(source, sourceRect, destFormat, destOffset, destSurface); + + SafeRelease(destSurface); + SafeRelease(source); + + return result; +} + +gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest) +{ + ASSERT(source != NULL && dest != NULL); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DSURFACE_DESC sourceDesc; + D3DSURFACE_DESC destDesc; + source->GetDesc(&sourceDesc); + dest->GetDesc(&destDesc); + + if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET && + d3d9_gl::IsFormatChannelEquivalent(destDesc.Format, destFormat)) // Can use StretchRect + { + RECT destRect = { destOffset.x, destOffset.y, destOffset.x + (sourceRect.right - sourceRect.left), destOffset.y + (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 gl::Error(GL_OUT_OF_MEMORY, "Failed to blit between textures, StretchRect result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); + } + else + { + return formatConvert(source, sourceRect, destFormat, destOffset, dest); + } +} + +gl::Error Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest) +{ + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + + IDirect3DTexture9 *texture = NULL; + error = copySurfaceToTexture(source, sourceRect, &texture); + if (error.isError()) + { + return error; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + saveState(); + + device->SetTexture(0, texture); + device->SetRenderTarget(0, dest); + + setViewport(sourceRect, destOffset); + + setCommonBlitState(); + + error = setFormatConvertShaders(destFormat); + if (!error.isError()) + { + render(); + } + + SafeRelease(texture); + + restoreState(); + + return error; +} + +gl::Error Blit9::setFormatConvertShaders(GLenum destFormat) +{ + gl::Error error = setVertexShader(SHADER_VS_STANDARD); + if (error.isError()) + { + return error; + } + + switch (destFormat) + { + default: UNREACHABLE(); + case GL_RGBA: + case GL_BGRA_EXT: + case GL_RGB: + case GL_RG_EXT: + case GL_RED_EXT: + case GL_ALPHA: + error = setPixelShader(SHADER_PS_COMPONENTMASK); + break; + + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + error = setPixelShader(SHADER_PS_LUMINANCE); + break; + } + + if (error.isError()) + { + return error; + } + + 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. + // Allocate one array for both registers and split it into two float4's. + float psConst[8] = { 0 }; + float *multConst = &psConst[0]; + float *addConst = &psConst[4]; + + switch (destFormat) + { + default: UNREACHABLE(); + case GL_RGBA: + case GL_BGRA_EXT: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 1; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + + case GL_RGB: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 1; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_RG_EXT: + multConst[X] = 1; + multConst[Y] = 1; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_RED_EXT: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_ALPHA: + multConst[X] = 0; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + + case GL_LUMINANCE: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 0; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 1; + break; + + case GL_LUMINANCE_ALPHA: + multConst[X] = 1; + multConst[Y] = 0; + multConst[Z] = 0; + multConst[W] = 1; + addConst[X] = 0; + addConst[Y] = 0; + addConst[Z] = 0; + addConst[W] = 0; + break; + } + + mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture) +{ + ASSERT(surface); + + IDirect3DDevice9 *device = mRenderer->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 gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for blit, result: 0x%X.", result); + } + + IDirect3DSurface9 *textureSurface; + result = texture->GetSurfaceLevel(0, &textureSurface); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(texture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query surface of internal blit texture, result: 0x%X.", result); + } + + mRenderer->endScene(); + result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); + + SafeRelease(textureSurface); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(texture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy between internal blit textures, result: 0x%X.", result); + } + + *outTexture = texture; + return gl::Error(GL_NO_ERROR); +} + +void Blit9::setViewport(const RECT &sourceRect, const gl::Offset &offset) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + D3DVIEWPORT9 vp; + vp.X = offset.x; + vp.Y = offset.y; + 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 Blit9::setCommonBlitState() +{ + IDirect3DDevice9 *device = mRenderer->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 < gl::MAX_VERTEX_ATTRIBS; i++) + { + device->SetStreamSourceFreq(i, 1); + } +} + +void Blit9::render() +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float)); + hr = device->SetVertexDeclaration(mQuadVertexDeclaration); + + mRenderer->startScene(); + hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); +} + +void Blit9::saveState() +{ + IDirect3DDevice9 *device = mRenderer->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[8] = { 0 }; + + device->SetVertexShader(NULL); + device->SetVertexShaderConstantF(0, dummyConst, 2); + device->SetPixelShader(NULL); + device->SetPixelShaderConstantF(0, dummyConst, 2); + + 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 Blit9::restoreState() +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + device->SetDepthStencilSurface(mSavedDepthStencil); + SafeRelease(mSavedDepthStencil); + + device->SetRenderTarget(0, mSavedRenderTarget); + SafeRelease(mSavedRenderTarget); + + ASSERT(mSavedStateBlock != NULL); + + if (mSavedStateBlock != NULL) + { + mSavedStateBlock->Apply(); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h new file mode 100644 index 0000000000..586abd2580 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Blit9.h @@ -0,0 +1,97 @@ +// +// 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. +// + +// Blit9.cpp: Surface copy utility class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ + +#include "common/angleutils.h" +#include "libANGLE/Error.h" + +#include + +namespace gl +{ +class Framebuffer; +struct Offset; +} + +namespace rx +{ +class Renderer9; +class TextureStorage; + +class Blit9 : angle::NonCopyable +{ + public: + explicit Blit9(Renderer9 *renderer); + ~Blit9(); + + gl::Error initialize(); + + // Copy from source surface to dest surface. + // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) + gl::Error copy2D(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLint level); + gl::Error copyCube(const gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); + + // 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. + gl::Error formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest); + + // 2x2 box filter sample from source to dest. + // Requires that source is RGB(A) and dest has the same format as source. + gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + private: + Renderer9 *mRenderer; + + bool mGeometryLoaded; + IDirect3DVertexBuffer9 *mQuadVertexBuffer; + IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; + + gl::Error setFormatConvertShaders(GLenum destFormat); + + gl::Error copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, const gl::Offset &destOffset, IDirect3DSurface9 *dest); + gl::Error copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture); + void setViewport(const RECT &sourceRect, const gl::Offset &offset); + 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 + gl::Error setShader(ShaderId source, const char *profile, + gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); + + gl::Error setVertexShader(ShaderId shader); + gl::Error setPixelShader(ShaderId shader); + void render(); + + void saveState(); + void restoreState(); + IDirect3DStateBlock9 *mSavedStateBlock; + IDirect3DSurface9 *mSavedRenderTarget; + IDirect3DSurface9 *mSavedDepthStencil; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_BLIT9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp new file mode 100644 index 0000000000..b051c81aa8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp @@ -0,0 +1,116 @@ +// +// Copyright 2014 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. +// + +// Buffer9.cpp Defines the Buffer9 class. + +#include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +Buffer9::Buffer9(Renderer9 *renderer) + : BufferD3D(renderer), + mRenderer(renderer), + mSize(0) +{} + +Buffer9::~Buffer9() +{ + mSize = 0; +} + +Buffer9 *Buffer9::makeBuffer9(BufferImpl *buffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Buffer9*, buffer)); + return static_cast(buffer); +} + +gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) +{ + if (size > mMemory.size()) + { + if (!mMemory.resize(size)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); + } + } + + mSize = size; + if (data && size > 0) + { + memcpy(mMemory.data(), data, size); + } + + invalidateStaticData(); + + if (usage == GL_STATIC_DRAW) + { + initializeStaticData(); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer9::getData(const uint8_t **outData) +{ + *outData = mMemory.data(); + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) +{ + if (offset + size > mMemory.size()) + { + if (!mMemory.resize(offset + size)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); + } + } + + mSize = std::max(mSize, offset + size); + if (data && size > 0) + { + memcpy(mMemory.data() + offset, data, size); + } + + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) +{ + // Note: this method is currently unreachable + Buffer9* sourceBuffer = makeBuffer9(source); + ASSERT(sourceBuffer); + + memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); + + invalidateStaticData(); + + return gl::Error(GL_NO_ERROR); +} + +// We do not support buffer mapping in D3D9 +gl::Error Buffer9::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Buffer9::unmap() +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +void Buffer9::markTransformFeedbackUsage() +{ + UNREACHABLE(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h new file mode 100644 index 0000000000..c1984146fc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Buffer9.h @@ -0,0 +1,49 @@ +// +// Copyright 2014 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. +// + +// Buffer9.h: Defines the rx::Buffer9 class which implements rx::BufferImpl via rx::BufferD3D. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ + +#include "common/MemoryBuffer.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" + +namespace rx +{ +class Renderer9; + +class Buffer9 : public BufferD3D +{ + public: + Buffer9(Renderer9 *renderer); + virtual ~Buffer9(); + + static Buffer9 *makeBuffer9(BufferImpl *buffer); + + // BufferD3D implementation + virtual size_t getSize() const { return mSize; } + virtual bool supportsDirectBinding() const { return false; } + + // BufferImpl implementation + virtual gl::Error setData(const void* data, size_t size, GLenum usage); + gl::Error getData(const uint8_t **outData) override; + virtual gl::Error setSubData(const void* data, size_t size, size_t offset); + virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); + virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); + virtual gl::Error unmap(); + virtual void markTransformFeedbackUsage(); + + private: + Renderer9 *mRenderer; + MemoryBuffer mMemory; + size_t mSize; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_BUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp new file mode 100644 index 0000000000..09b229bcb1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp @@ -0,0 +1,36 @@ +// +// Copyright 2015 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. +// +// DebugAnnotator9.h: D3D9 helpers for adding trace annotations. +// + +#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h" + +#include "common/platform.h" + +namespace rx +{ + +void DebugAnnotator9::beginEvent(const std::wstring &eventName) +{ + D3DPERF_BeginEvent(0, eventName.c_str()); +} + +void DebugAnnotator9::endEvent() +{ + D3DPERF_EndEvent(); +} + +void DebugAnnotator9::setMarker(const std::wstring &markerName) +{ + D3DPERF_SetMarker(0, markerName.c_str()); +} + +bool DebugAnnotator9::getStatus() +{ + return !!D3DPERF_GetStatus(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h new file mode 100644 index 0000000000..02956f7183 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h @@ -0,0 +1,29 @@ +// +// Copyright 2015 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. +// +// DebugAnnotator9.h: D3D9 helpers for adding trace annotations. +// + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ + +#include "common/debug.h" + +namespace rx +{ + +class DebugAnnotator9 : public gl::DebugAnnotator +{ + public: + DebugAnnotator9() {} + void beginEvent(const std::wstring &eventName) override; + void endEvent() override; + void setMarker(const std::wstring &markerName) override; + bool getStatus() override; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_DEBUGANNOTATOR9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp new file mode 100644 index 0000000000..27c265e28d --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp @@ -0,0 +1,90 @@ +// +// Copyright (c) 2013 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. +// + +// Fence9.cpp: Defines the rx::FenceNV9 class. + +#include "libANGLE/renderer/d3d/d3d9/Fence9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +FenceNV9::FenceNV9(Renderer9 *renderer) + : FenceNVImpl(), + mRenderer(renderer), + mQuery(NULL) +{ +} + +FenceNV9::~FenceNV9() +{ + SafeRelease(mQuery); +} + +gl::Error FenceNV9::set() +{ + if (!mQuery) + { + gl::Error error = mRenderer->allocateEventQuery(&mQuery); + if (error.isError()) + { + return error; + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_END); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(mQuery); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to end event query, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceNV9::test(bool flushCommandBuffer, GLboolean *outFinished) +{ + ASSERT(mQuery); + + DWORD getDataFlags = (flushCommandBuffer ? D3DGETDATA_FLUSH : 0); + HRESULT result = mQuery->GetData(NULL, 0, getDataFlags); + + if (d3d9::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); + } + else if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); + } + + ASSERT(result == S_OK || result == S_FALSE); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceNV9::finishFence(GLboolean *outFinished) +{ + ASSERT(outFinished); + + while (*outFinished != GL_TRUE) + { + gl::Error error = test(true, outFinished); + if (error.isError()) + { + return error; + } + + Sleep(0); + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h new file mode 100644 index 0000000000..4b86747396 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Fence9.h @@ -0,0 +1,36 @@ +// +// Copyright (c) 2013 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. +// + +// Fence9.h: Defines the rx::FenceNV9 class which implements rx::FenceNVImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ + +#include "libANGLE/renderer/FenceNVImpl.h" +#include "libANGLE/renderer/FenceSyncImpl.h" + +namespace rx +{ +class Renderer9; + +class FenceNV9 : public FenceNVImpl +{ + public: + explicit FenceNV9(Renderer9 *renderer); + virtual ~FenceNV9(); + + gl::Error set(); + gl::Error test(bool flushCommandBuffer, GLboolean *outFinished); + gl::Error finishFence(GLboolean *outFinished); + + private: + Renderer9 *mRenderer; + IDirect3DQuery9 *mQuery; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FENCE9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp new file mode 100644 index 0000000000..dbdfc6d6de --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp @@ -0,0 +1,422 @@ +// +// Copyright 2014 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. +// + +// Framebuffer9.cpp: Implements the Framebuffer9 class. + +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Texture.h" + +namespace rx +{ + +Framebuffer9::Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer) + : FramebufferD3D(data, renderer), + mRenderer(renderer) +{ + ASSERT(mRenderer != nullptr); +} + +Framebuffer9::~Framebuffer9() +{ +} + +gl::Error Framebuffer9::clear(const gl::State &state, const ClearParameters &clearParams) +{ + const gl::FramebufferAttachment *colorAttachment = mData.mColorAttachments[0]; + const gl::FramebufferAttachment *depthStencilAttachment = mData.getDepthOrStencilAttachment(); + + gl::Error error = mRenderer->applyRenderTarget(colorAttachment, depthStencilAttachment); + if (error.isError()) + { + return error; + } + + float nearZ, farZ; + state.getDepthRange(&nearZ, &farZ); + mRenderer->setViewport(state.getViewport(), nearZ, farZ, GL_TRIANGLES, state.getRasterizerState().frontFace, true); + + mRenderer->setScissorRectangle(state.getScissor(), state.isScissorTestEnabled()); + + return mRenderer->clear(clearParams, colorAttachment, depthStencilAttachment); +} + +gl::Error Framebuffer9::readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) const +{ + ASSERT(pack.pixelBuffer.get() == NULL); + + const gl::FramebufferAttachment *colorbuffer = mData.mColorAttachments[0]; + ASSERT(colorbuffer); + + RenderTarget9 *renderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget); + + IDirect3DSurface9 *surface = renderTarget->getSurface(); + ASSERT(surface); + + D3DSURFACE_DESC desc; + surface->GetDesc(&desc); + + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) + { + UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "ReadPixels is unimplemented for multisampled framebuffer attachments."); + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + ASSERT(device); + + HRESULT result; + IDirect3DSurface9 *systemSurface = NULL; + bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && mRenderer->getShareHandleSupport() && + area.x == 0 && area.y == 0 && + static_cast(area.width) == desc.Width && static_cast(area.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 = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, reinterpret_cast(&pixels)); + if (FAILED(result)) + { + // Try again without the shared handle + directToPixels = false; + } + } + + if (!directToPixels) + { + result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, + D3DPOOL_SYSTEMMEM, &systemSurface, NULL); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for ReadPixels."); + } + } + + result = device->GetRenderTargetData(surface, systemSurface); + SafeRelease(surface); + + if (FAILED(result)) + { + SafeRelease(systemSurface); + + // It turns out that D3D will sometimes produce more error + // codes than those documented. + if (d3d9::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + } + else + { + UNREACHABLE(); + } + + return gl::Error(GL_OUT_OF_MEMORY, "Failed to read internal render target data."); + } + + if (directToPixels) + { + SafeRelease(systemSurface); + return gl::Error(GL_NO_ERROR); + } + + RECT rect; + rect.left = gl::clamp(area.x, 0L, static_cast(desc.Width)); + rect.top = gl::clamp(area.y, 0L, static_cast(desc.Height)); + rect.right = gl::clamp(area.x + area.width, 0L, static_cast(desc.Width)); + rect.bottom = gl::clamp(area.y + area.height, 0L, static_cast(desc.Height)); + + D3DLOCKED_RECT lock; + result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); + + if (FAILED(result)) + { + UNREACHABLE(); + SafeRelease(systemSurface); + + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal render target."); + } + + uint8_t *source; + int inputPitch; + if (pack.reverseRowOrder) + { + source = reinterpret_cast(lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); + inputPitch = -lock.Pitch; + } + else + { + source = reinterpret_cast(lock.pBits); + inputPitch = lock.Pitch; + } + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3dFormatInfo.internalFormat); + if (sourceFormatInfo.format == format && sourceFormatInfo.type == type) + { + // Direct copy possible + for (int y = 0; y < rect.bottom - rect.top; y++) + { + memcpy(pixels + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourceFormatInfo.pixelBytes); + } + } + else + { + const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + ColorCopyFunction fastCopyFunc = sourceD3DFormatInfo.getFastCopyFunction(format, type); + + GLenum sizedDestInternalFormat = gl::GetSizedInternalFormat(format, type); + const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(sizedDestInternalFormat); + + if (fastCopyFunc) + { + // Fast copy is possible through some special function + for (int y = 0; y < rect.bottom - rect.top; y++) + { + for (int x = 0; x < rect.right - rect.left; x++) + { + uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + fastCopyFunc(src, dest); + } + } + } + else + { + ColorReadFunction colorReadFunction = sourceD3DFormatInfo.colorReadFunction; + ColorWriteFunction colorWriteFunction = GetColorWriteFunction(format, type); + + uint8_t temp[sizeof(gl::ColorF)]; + for (int y = 0; y < rect.bottom - rect.top; y++) + { + for (int x = 0; x < rect.right - rect.left; x++) + { + uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; + const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; + + // readFunc and writeFunc will be using the same type of color, CopyTexImage + // will not allow the copy otherwise. + colorReadFunction(src, temp); + colorWriteFunction(temp, dest); + } + } + } + } + + systemSurface->UnlockRect(); + SafeRelease(systemSurface); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Framebuffer9::blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) +{ + ASSERT(filter == GL_NEAREST); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + ASSERT(device); + + mRenderer->endScene(); + + if (blitRenderTarget) + { + const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getColorbuffer(0); + ASSERT(readBuffer); + + RenderTarget9 *readRenderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(readRenderTarget); + + const gl::FramebufferAttachment *drawBuffer = mData.mColorAttachments[0]; + ASSERT(drawBuffer); + + RenderTarget9 *drawRenderTarget = NULL; + error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(drawRenderTarget); + + // The getSurface calls do an AddRef so save them until after no errors are possible + IDirect3DSurface9* readSurface = readRenderTarget->getSurface(); + ASSERT(readSurface); + + IDirect3DSurface9* drawSurface = drawRenderTarget->getSurface(); + ASSERT(drawSurface); + + gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); + gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); + + RECT srcRect; + srcRect.left = sourceArea.x; + srcRect.right = sourceArea.x + sourceArea.width; + srcRect.top = sourceArea.y; + srcRect.bottom = sourceArea.y + sourceArea.height; + + RECT dstRect; + dstRect.left = destArea.x; + dstRect.right = destArea.x + destArea.width; + dstRect.top = destArea.y; + dstRect.bottom = destArea.y + destArea.height; + + // Clip the rectangles to the scissor rectangle + if (scissor) + { + if (dstRect.left < scissor->x) + { + srcRect.left += (scissor->x - dstRect.left); + dstRect.left = scissor->x; + } + if (dstRect.top < scissor->y) + { + srcRect.top += (scissor->y - dstRect.top); + dstRect.top = scissor->y; + } + if (dstRect.right > scissor->x + scissor->width) + { + srcRect.right -= (dstRect.right - (scissor->x + scissor->width)); + dstRect.right = scissor->x + scissor->width; + } + if (dstRect.bottom > scissor->y + scissor->height) + { + srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height)); + dstRect.bottom = scissor->y + scissor->height; + } + } + + // Clip the rectangles to the destination size + if (dstRect.left < 0) + { + srcRect.left += -dstRect.left; + dstRect.left = 0; + } + if (dstRect.right > dstSize.width) + { + srcRect.right -= (dstRect.right - dstSize.width); + dstRect.right = dstSize.width; + } + if (dstRect.top < 0) + { + srcRect.top += -dstRect.top; + dstRect.top = 0; + } + if (dstRect.bottom > dstSize.height) + { + srcRect.bottom -= (dstRect.bottom - dstSize.height); + dstRect.bottom = dstSize.height; + } + + // Clip the rectangles to the source size + if (srcRect.left < 0) + { + dstRect.left += -srcRect.left; + srcRect.left = 0; + } + if (srcRect.right > srcSize.width) + { + dstRect.right -= (srcRect.right - srcSize.width); + srcRect.right = srcSize.width; + } + if (srcRect.top < 0) + { + dstRect.top += -srcRect.top; + srcRect.top = 0; + } + if (srcRect.bottom > srcSize.height) + { + dstRect.bottom -= (srcRect.bottom - srcSize.height); + srcRect.bottom = srcSize.height; + } + + HRESULT result = device->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE); + + SafeRelease(readSurface); + SafeRelease(drawSurface); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); + } + } + + if (blitDepth || blitStencil) + { + const gl::FramebufferAttachment *readBuffer = sourceFramebuffer->getDepthOrStencilbuffer(); + ASSERT(readBuffer); + + RenderTarget9 *readDepthStencil = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readDepthStencil); + if (error.isError()) + { + return error; + } + ASSERT(readDepthStencil); + + const gl::FramebufferAttachment *drawBuffer = mData.getDepthOrStencilAttachment(); + ASSERT(drawBuffer); + + RenderTarget9 *drawDepthStencil = NULL; + error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawDepthStencil); + if (error.isError()) + { + return error; + } + ASSERT(drawDepthStencil); + + // The getSurface calls do an AddRef so save them until after no errors are possible + IDirect3DSurface9* readSurface = readDepthStencil->getSurface(); + ASSERT(readDepthStencil); + + IDirect3DSurface9* drawSurface = drawDepthStencil->getSurface(); + ASSERT(drawDepthStencil); + + HRESULT result = device->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE); + + SafeRelease(readSurface); + SafeRelease(drawSurface); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum Framebuffer9::getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const +{ + RenderTarget9 *renderTarget9 = RenderTarget9::makeRenderTarget9(renderTarget); + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(renderTarget9->getD3DFormat()); + return d3dFormatInfo.internalFormat; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h new file mode 100644 index 0000000000..292118e6db --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h @@ -0,0 +1,41 @@ +// +// Copyright 2014 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. +// + +// Framebuffer9.h: Defines the Framebuffer9 class. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ + +#include "libANGLE/renderer/d3d/FramebufferD3D.h" + +namespace rx +{ +class Renderer9; + +class Framebuffer9 : public FramebufferD3D +{ + public: + Framebuffer9(const gl::Framebuffer::Data &data, Renderer9 *renderer); + virtual ~Framebuffer9(); + + private: + gl::Error clear(const gl::State &state, const ClearParameters &clearParams) override; + + gl::Error readPixels(const gl::Rectangle &area, GLenum format, GLenum type, size_t outputPitch, + const gl::PixelPackState &pack, uint8_t *pixels) const override; + + gl::Error blit(const gl::Rectangle &sourceArea, const gl::Rectangle &destArea, const gl::Rectangle *scissor, + bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter, + const gl::Framebuffer *sourceFramebuffer) override; + + GLenum getRenderTargetImplementationFormat(RenderTargetD3D *renderTarget) const override; + + Renderer9 *const mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FRAMBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp new file mode 100644 index 0000000000..d149f7a806 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.cpp @@ -0,0 +1,788 @@ +// +// 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. +// + +// Image9.cpp: Implements the rx::Image9 class, which acts as the interface to +// the actual underlying surfaces of a Texture. + +#include "libANGLE/renderer/d3d/d3d9/Image9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Renderbuffer.h" +#include "common/utilities.h" + +namespace rx +{ + +Image9::Image9(Renderer9 *renderer) +{ + mSurface = NULL; + mRenderer = NULL; + + mD3DPool = D3DPOOL_SYSTEMMEM; + mD3DFormat = D3DFMT_UNKNOWN; + + mRenderer = renderer; +} + +Image9::~Image9() +{ + SafeRelease(mSurface); +} + +gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) +{ + D3DSURFACE_DESC destDesc; + HRESULT result = destSurface->GetDesc(&destDesc); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the source surface description for mipmap generation, result: 0x%X.", result); + } + + D3DSURFACE_DESC sourceDesc; + result = sourceSurface->GetDesc(&sourceDesc); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the destination surface description for mipmap generation, result: 0x%X.", result); + } + + ASSERT(sourceDesc.Format == destDesc.Format); + ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); + ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); + ASSERT(d3dFormatInfo.mipGenerationFunction != NULL); + + D3DLOCKED_RECT sourceLocked = {0}; + result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface for mipmap generation, result: 0x%X.", result); + } + + D3DLOCKED_RECT destLocked = {0}; + result = destSurface->LockRect(&destLocked, NULL, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + sourceSurface->UnlockRect(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the destination surface for mipmap generation, result: 0x%X.", result); + } + + const uint8_t *sourceData = reinterpret_cast(sourceLocked.pBits); + uint8_t *destData = reinterpret_cast(destLocked.pBits); + + ASSERT(sourceData && destData); + + d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, + destData, destLocked.Pitch, 0); + + destSurface->UnlockRect(); + sourceSurface->UnlockRect(); + + return gl::Error(GL_NO_ERROR); +} + +Image9 *Image9::makeImage9(ImageD3D *img) +{ + ASSERT(HAS_DYNAMIC_TYPE(Image9*, img)); + return static_cast(img); +} + +gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source) +{ + IDirect3DSurface9 *sourceSurface = NULL; + gl::Error error = source->getSurface(&sourceSurface); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *destSurface = NULL; + error = dest->getSurface(&destSurface); + if (error.isError()) + { + return error; + } + + error = generateMip(destSurface, sourceSurface); + if (error.isError()) + { + return error; + } + + dest->markDirty(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) +{ + D3DLOCKED_RECT sourceLock = {0}; + D3DLOCKED_RECT destLock = {0}; + + HRESULT result; + + result = source->LockRect(&sourceLock, NULL, 0); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + } + + result = dest->LockRect(&destLock, NULL, 0); + if (FAILED(result)) + { + source->UnlockRect(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + } + + ASSERT(sourceLock.pBits && destLock.pBits); + + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + unsigned int rows = desc.Height / d3dFormatInfo.blockHeight; + + unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight); + ASSERT(bytes <= static_cast(sourceLock.Pitch) && + bytes <= static_cast(destLock.Pitch)); + + for(unsigned int i = 0; i < rows; i++) + { + memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); + } + + source->UnlockRect(); + dest->UnlockRect(); + + return gl::Error(GL_NO_ERROR); +} + +bool Image9::redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(size.depth <= 1); + + // Only 2D and cube texture are supported by the D3D9 backend. + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP); + + if (mWidth != size.width || + mHeight != size.height || + mDepth != size.depth || + mInternalFormat != internalformat || + forceRelease) + { + mWidth = size.width; + mHeight = size.height; + mDepth = size.depth; + mInternalFormat = internalformat; + + // compute the d3d format that will be used + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mD3DFormat = d3d9FormatInfo.texFormat; + mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN); + + SafeRelease(mSurface); + mDirty = (d3d9FormatInfo.dataInitializerFunction != NULL); + + return true; + } + + return false; +} + +gl::Error Image9::createSurface() +{ + if (mSurface) + { + return gl::Error(GL_NO_ERROR); + } + + IDirect3DTexture9 *newTexture = NULL; + IDirect3DSurface9 *newSurface = NULL; + const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; + const D3DFORMAT d3dFormat = getD3DFormat(); + + if (mWidth != 0 && mHeight != 0) + { + int levelToFetch = 0; + GLsizei requestWidth = mWidth; + GLsizei requestHeight = mHeight; + d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat, + poolToUse, &newTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create image surface, result: 0x%X.", result); + } + + newTexture->GetSurfaceLevel(levelToFetch, &newSurface); + SafeRelease(newTexture); + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + if (d3dFormatInfo.dataInitializerFunction != NULL) + { + RECT entireRect; + entireRect.left = 0; + entireRect.right = mWidth; + entireRect.top = 0; + entireRect.bottom = mHeight; + + D3DLOCKED_RECT lockedRect; + result = newSurface->LockRect(&lockedRect, &entireRect, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + } + + d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast(lockedRect.pBits), + lockedRect.Pitch, 0); + + result = newSurface->UnlockRect(); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock image surface, result: 0x%X.", result); + } + } + } + + mSurface = newSurface; + mDirty = false; + mD3DPool = poolToUse; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect) +{ + gl::Error error = createSurface(); + if (error.isError()) + { + return error; + } + + if (mSurface) + { + HRESULT result = mSurface->LockRect(lockedRect, &rect, 0); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + } + + mDirty = true; + } + + return gl::Error(GL_NO_ERROR); +} + +void Image9::unlock() +{ + if (mSurface) + { + HRESULT result = mSurface->UnlockRect(); + UNUSED_ASSERTION_VARIABLE(result); + ASSERT(SUCCEEDED(result)); + } +} + +D3DFORMAT Image9::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; +} + +bool Image9::isDirty() const +{ + // Make sure to that this image is marked as dirty even if the staging texture hasn't been created yet + // if initialization is required before use. + return (mSurface || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty; +} + +gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface) +{ + gl::Error error = createSurface(); + if (error.isError()) + { + return error; + } + + *outSurface = mSurface; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level) +{ + IDirect3DSurface9 *surface = NULL; + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + gl::Error error = storage9->getSurfaceLevel(level, false, &surface); + if (error.isError()) + { + return error; + } + return setManagedSurface(surface); +} + +gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level) +{ + IDirect3DSurface9 *surface = NULL; + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + gl::Error error = storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface); + if (error.isError()) + { + return error; + } + return setManagedSurface(surface); +} + +gl::Error Image9::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) + { + gl::Error error = copyLockableSurfaces(surface, mSurface); + SafeRelease(mSurface); + if (error.isError()) + { + return error; + } + } + + mSurface = surface; + mD3DPool = desc.Pool; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) +{ + gl::Error error = createSurface(); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *destSurface = NULL; + + if (index.type == GL_TEXTURE_2D) + { + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + error = storage9->getSurfaceLevel(index.mipIndex, true, &destSurface); + if (error.isError()) + { + return error; + } + } + else + { + ASSERT(gl::IsCubeMapTextureTarget(index.type)); + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + error = storage9->getCubeMapSurface(index.type, index.mipIndex, true, &destSurface); + if (error.isError()) + { + return error; + } + } + + error = copyToSurface(destSurface, region); + SafeRelease(destSurface); + return error; +} + +gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, const gl::Box &area) +{ + ASSERT(area.width > 0 && area.height > 0 && area.depth == 1); + ASSERT(destSurface); + + IDirect3DSurface9 *sourceSurface = NULL; + gl::Error error = getSurface(&sourceSurface); + if (error.isError()) + { + return error; + } + + ASSERT(sourceSurface && sourceSurface != destSurface); + + RECT rect; + rect.left = area.x; + rect.top = area.y; + rect.right = area.x + area.width; + rect.bottom = area.y + area.height; + + POINT point = {rect.left, rect.top}; + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + if (mD3DPool == D3DPOOL_MANAGED) + { + D3DSURFACE_DESC desc; + sourceSurface->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal CreateOffscreenPlainSurface call failed, result: 0x%X.", result); + } + + copyLockableSurfaces(surf, sourceSurface); + result = device->UpdateSurface(surf, &rect, destSurface, &point); + SafeRelease(surf); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + } + } + else + { + // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools + HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); +} + +// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input +// into the target pixel rectangle. +gl::Error Image9::loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(area.z == 0 && area.depth == 1); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength); + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + ASSERT(d3dFormatInfo.loadFunction != NULL); + + RECT lockRect = + { + area.x, area.y, + area.x + area.width, area.y + area.height + }; + + D3DLOCKED_RECT locked; + gl::Error error = lock(&locked, lockRect); + if (error.isError()) + { + return error; + } + + d3dFormatInfo.loadFunction(area.width, area.height, area.depth, + reinterpret_cast(input), inputRowPitch, 0, + reinterpret_cast(locked.pBits), locked.Pitch, 0); + + unlock(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::loadCompressedData(const gl::Box &area, const void *input) +{ + // 3D textures are not supported by the D3D9 backend. + ASSERT(area.z == 0 && area.depth == 1); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); + GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0); + GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0); + + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); + + ASSERT(area.x % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0); + ASSERT(area.y % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0); + + ASSERT(d3d9FormatInfo.loadFunction != NULL); + + RECT lockRect = + { + area.x, area.y, + area.x + area.width, area.y + area.height + }; + + D3DLOCKED_RECT locked; + gl::Error error = lock(&locked, lockRect); + if (error.isError()) + { + return error; + } + + d3d9FormatInfo.loadFunction(area.width, area.height, area.depth, + reinterpret_cast(input), inputRowPitch, inputDepthPitch, + reinterpret_cast(locked.pBits), locked.Pitch, 0); + + unlock(); + + return gl::Error(GL_NO_ERROR); +} + +// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures +gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source) +{ + ASSERT(source); + + // ES3.0 only behaviour to copy into a 3d texture + ASSERT(destOffset.z == 0); + + RenderTarget9 *renderTarget = RenderTarget9::makeRenderTarget9(source); + + IDirect3DSurface9 *surface = renderTarget->getSurface(); + ASSERT(surface); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + IDirect3DSurface9 *renderTargetData = NULL; + D3DSURFACE_DESC description; + surface->GetDesc(&description); + + HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); + + if (FAILED(result)) + { + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "Could not create matching destination surface, result: 0x%X.", result); + } + + result = device->GetRenderTargetData(surface, renderTargetData); + + if (FAILED(result)) + { + SafeRelease(renderTargetData); + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "GetRenderTargetData unexpectedly failed, result: 0x%X.", result); + } + + int width = sourceArea.width; + int height = sourceArea.height; + + RECT sourceRect = { sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height }; + RECT destRect = { destOffset.x, destOffset.y, destOffset.x + width, destOffset.y + height }; + + D3DLOCKED_RECT sourceLock = {0}; + result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); + + if (FAILED(result)) + { + SafeRelease(renderTargetData); + SafeRelease(surface); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface (rectangle might be invalid), result: 0x%X.", result); + } + + D3DLOCKED_RECT destLock = {0}; + gl::Error error = lock(&destLock, destRect); + if (error.isError()) + { + renderTargetData->UnlockRect(); + SafeRelease(renderTargetData); + SafeRelease(surface); + return error; + } + + ASSERT(destLock.pBits && sourceLock.pBits); + + unsigned char *sourcePixels = (unsigned char*)sourceLock.pBits; + unsigned char *destPixels = (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(destPixels, sourcePixels, 4 * width); + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + destPixels[x] = sourcePixels[x * 4 + 2]; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2]; + destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3]; + } + sourcePixels += sourceLock.Pitch; + destPixels += 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*)sourcePixels)[x]; + unsigned char red = (rgb & 0xF800) >> 8; + unsigned char green = (rgb & 0x07E0) >> 3; + unsigned char blue = (rgb & 0x001F) << 3; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 6); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = 0xFF; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0xF8; + destPixels[x] = red | (red >> 5); + } + sourcePixels += sourceLock.Pitch; + destPixels += 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*)sourcePixels)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 5); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = 0xFF; + } + sourcePixels += sourceLock.Pitch; + destPixels += 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*)sourcePixels)[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; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 5); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = alpha; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; + destPixels[x] = (red << 1) | (red >> 4); + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; + destPixels[x * 2 + 0] = (red << 1) | (red >> 4); + destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + default: + UNREACHABLE(); + } + + unlock(); + renderTargetData->UnlockRect(); + + SafeRelease(renderTargetData); + SafeRelease(surface); + + mDirty = true; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::copy(const gl::Offset &destOffset, const gl::Box &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage) +{ + // Currently unreachable, due to only being used in a D3D11-only workaround + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h new file mode 100644 index 0000000000..8cbfbbebf6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Image9.h @@ -0,0 +1,73 @@ +// +// Copyright (c) 2002-2014 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. +// + +// Image9.h: Defines the rx::Image9 class, which acts as the interface to +// the actual underlying surfaces of a Texture. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ + +#include "libANGLE/renderer/d3d/ImageD3D.h" +#include "common/debug.h" + +namespace gl +{ +class Framebuffer; +} + +namespace rx +{ +class Renderer9; + +class Image9 : public ImageD3D +{ + public: + Image9(Renderer9 *renderer); + ~Image9(); + + static Image9 *makeImage9(ImageD3D *img); + + static gl::Error generateMipmap(Image9 *dest, Image9 *source); + static gl::Error generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); + static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); + + bool redefine(GLenum target, GLenum internalformat, const gl::Extents &size, bool forceRelease) override; + + D3DFORMAT getD3DFormat() const; + + virtual bool isDirty() const; + + virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level); + virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level); + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); + + virtual gl::Error loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input); + virtual gl::Error loadCompressedData(const gl::Box &area, const void *input); + + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Rectangle &sourceArea, RenderTargetD3D *source); + virtual gl::Error copy(const gl::Offset &destOffset, const gl::Box &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source); + + private: + gl::Error getSurface(IDirect3DSurface9 **outSurface); + + gl::Error createSurface(); + gl::Error setManagedSurface(IDirect3DSurface9 *surface); + gl::Error copyToSurface(IDirect3DSurface9 *dest, const gl::Box &area); + + gl::Error lock(D3DLOCKED_RECT *lockedRect, const RECT &rect); + void unlock(); + + Renderer9 *mRenderer; + + D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable. + D3DFORMAT mD3DFormat; + + IDirect3DSurface9 *mSurface; +}; +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_IMAGE9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp new file mode 100644 index 0000000000..c5d72e6a50 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp @@ -0,0 +1,173 @@ +// +// Copyright (c) 2002-2014 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. +// + +// Indexffer9.cpp: Defines the D3D9 IndexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ + +IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer) +{ + mIndexBuffer = NULL; + mBufferSize = 0; + mIndexType = 0; + mDynamic = false; +} + +IndexBuffer9::~IndexBuffer9() +{ + SafeRelease(mIndexBuffer); +} + +gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) +{ + SafeRelease(mIndexBuffer); + + updateSerial(); + + if (bufferSize > 0) + { + D3DFORMAT format = D3DFMT_UNKNOWN; + if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE) + { + format = D3DFMT_INDEX16; + } + else if (indexType == GL_UNSIGNED_INT) + { + ASSERT(mRenderer->getRendererExtensions().elementIndexUint); + format = D3DFMT_INDEX32; + } + else UNREACHABLE(); + + DWORD usageFlags = D3DUSAGE_WRITEONLY; + if (dynamic) + { + usageFlags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); + } + } + + mBufferSize = bufferSize; + mIndexType = indexType; + mDynamic = dynamic; + + return gl::Error(GL_NO_ERROR); +} + +IndexBuffer9 *IndexBuffer9::makeIndexBuffer9(IndexBuffer *indexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer9*, indexBuffer)); + return static_cast(indexBuffer); +} + +gl::Error IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0; + + void *mapPtr = NULL; + HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); + } + + *outMappedMemory = mapPtr; + return gl::Error(GL_NO_ERROR); +} + +gl::Error IndexBuffer9::unmapBuffer() +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + HRESULT result = mIndexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +GLenum IndexBuffer9::getIndexType() const +{ + return mIndexType; +} + +unsigned int IndexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType) +{ + if (bufferSize > mBufferSize || indexType != mIndexType) + { + return initialize(bufferSize, indexType, mDynamic); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error IndexBuffer9::discard() +{ + if (!mIndexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); + } + + void *dummy; + HRESULT result; + + result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); + } + + result = mIndexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +D3DFORMAT IndexBuffer9::getIndexFormat() const +{ + switch (mIndexType) + { + case GL_UNSIGNED_BYTE: return D3DFMT_INDEX16; + case GL_UNSIGNED_SHORT: return D3DFMT_INDEX16; + case GL_UNSIGNED_INT: return D3DFMT_INDEX32; + default: UNREACHABLE(); return D3DFMT_UNKNOWN; + } +} + +IDirect3DIndexBuffer9 * IndexBuffer9::getBuffer() const +{ + return mIndexBuffer; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h new file mode 100644 index 0000000000..61f8b11566 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h @@ -0,0 +1,51 @@ +// +// 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. +// + +// Indexffer9.h: Defines the D3D9 IndexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ + +#include "libANGLE/renderer/d3d/IndexBuffer.h" + +namespace rx +{ +class Renderer9; + +class IndexBuffer9 : public IndexBuffer +{ + public: + explicit IndexBuffer9(Renderer9 *const renderer); + virtual ~IndexBuffer9(); + + virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); + + static IndexBuffer9 *makeIndexBuffer9(IndexBuffer *indexBuffer); + + virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); + virtual gl::Error unmapBuffer(); + + virtual GLenum getIndexType() const; + virtual unsigned int getBufferSize() const; + virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); + + virtual gl::Error discard(); + + D3DFORMAT getIndexFormat() const; + IDirect3DIndexBuffer9 *getBuffer() const; + + private: + Renderer9 *const mRenderer; + + IDirect3DIndexBuffer9 *mIndexBuffer; + unsigned int mBufferSize; + GLenum mIndexType; + bool mDynamic; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_INDEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp new file mode 100644 index 0000000000..96f12d7868 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.cpp @@ -0,0 +1,144 @@ +// +// Copyright (c) 2013 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. +// + +// Query9.cpp: Defines the rx::Query9 class which implements rx::QueryImpl. + +#include "libANGLE/renderer/d3d/d3d9/Query9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +#include + +namespace rx +{ +Query9::Query9(Renderer9 *renderer, GLenum type) + : QueryImpl(type), + mResult(GL_FALSE), + mQueryFinished(false), + mRenderer(renderer), + mQuery(NULL) +{ +} + +Query9::~Query9() +{ + SafeRelease(mQuery); +} + +gl::Error Query9::begin() +{ + if (mQuery == NULL) + { + HRESULT result = mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); + } + } + + HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::end() +{ + ASSERT(mQuery); + + HRESULT result = mQuery->Issue(D3DISSUE_END); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to end internal query, result: 0x%X.", result); + } + + mQueryFinished = false; + mResult = GL_FALSE; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::getResult(GLuint *params) +{ + while (!mQueryFinished) + { + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + if (!mQueryFinished) + { + Sleep(0); + } + } + + ASSERT(mQueryFinished); + *params = mResult; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::isResultAvailable(GLuint *available) +{ + gl::Error error = testQuery(); + if (error.isError()) + { + return error; + } + + *available = (mQueryFinished ? GL_TRUE : GL_FALSE); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Query9::testQuery() +{ + if (!mQueryFinished) + { + ASSERT(mQuery); + + DWORD numPixels = 0; + + HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); + if (hres == S_OK) + { + mQueryFinished = true; + + switch (getType()) + { + case GL_ANY_SAMPLES_PASSED_EXT: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: + mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; + break; + + default: + UNREACHABLE(); + break; + } + } + else if (d3d9::isDeviceLostError(hres)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + } + else if (mRenderer->testDeviceLost()) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); + } + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h new file mode 100644 index 0000000000..399da2ed83 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Query9.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2013 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. +// + +// Query9.h: Defines the rx::Query9 class which implements rx::QueryImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ + +#include "libANGLE/renderer/QueryImpl.h" + +namespace rx +{ +class Renderer9; + +class Query9 : public QueryImpl +{ + public: + Query9(Renderer9 *renderer, GLenum type); + virtual ~Query9(); + + virtual gl::Error begin(); + virtual gl::Error end(); + virtual gl::Error getResult(GLuint *params); + virtual gl::Error isResultAvailable(GLuint *available); + + private: + gl::Error testQuery(); + + GLuint mResult; + bool mQueryFinished; + + Renderer9 *mRenderer; + IDirect3DQuery9 *mQuery; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_QUERY9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp new file mode 100644 index 0000000000..412c0109f5 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp @@ -0,0 +1,139 @@ +// +// Copyright (c) 2012-2014 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. +// + +// RenderTarget9.cpp: Implements a D3D9-specific wrapper for IDirect3DSurface9 +// pointers retained by renderbuffers. + +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" + +namespace rx +{ + +RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTargetD3D *target) +{ + ASSERT(HAS_DYNAMIC_TYPE(RenderTarget9*, target)); + return static_cast(target); +} + +// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given. +TextureRenderTarget9::TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, + GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mD3DFormat(D3DFMT_UNKNOWN), + mSamples(samples), + mRenderTarget(surface) +{ + ASSERT(mDepth == 1); + + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + mD3DFormat = description.Format; + } +} + +TextureRenderTarget9::~TextureRenderTarget9() +{ + SafeRelease(mRenderTarget); +} + +GLsizei TextureRenderTarget9::getWidth() const +{ + return mWidth; +} + +GLsizei TextureRenderTarget9::getHeight() const +{ + return mHeight; +} + +GLsizei TextureRenderTarget9::getDepth() const +{ + return mDepth; +} + +GLenum TextureRenderTarget9::getInternalFormat() const +{ + return mInternalFormat; +} + +GLsizei TextureRenderTarget9::getSamples() const +{ + return mSamples; +} + +IDirect3DSurface9 *TextureRenderTarget9::getSurface() +{ + // Caller is responsible for releasing the returned surface reference. + // TODO: remove the AddRef to match RenderTarget11 + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +D3DFORMAT TextureRenderTarget9::getD3DFormat() const +{ + return mD3DFormat; +} + +SurfaceRenderTarget9::SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth) + : mSwapChain(swapChain), + mDepth(depth) +{ +} + +SurfaceRenderTarget9::~SurfaceRenderTarget9() +{ +} + +GLsizei SurfaceRenderTarget9::getWidth() const +{ + return mSwapChain->getWidth(); +} + +GLsizei SurfaceRenderTarget9::getHeight() const +{ + return mSwapChain->getHeight(); +} + +GLsizei SurfaceRenderTarget9::getDepth() const +{ + return 1; +} + +GLenum SurfaceRenderTarget9::getInternalFormat() const +{ + return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat()); +} + +GLsizei SurfaceRenderTarget9::getSamples() const +{ + // Our EGL surfaces do not support multisampling. + return 0; +} + +IDirect3DSurface9 *SurfaceRenderTarget9::getSurface() +{ + return (mDepth ? mSwapChain->getDepthStencil() : mSwapChain->getRenderTarget()); +} + +D3DFORMAT SurfaceRenderTarget9::getD3DFormat() const +{ + return d3d9::GetTextureFormatInfo(getInternalFormat()).texFormat; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h new file mode 100644 index 0000000000..32c7dfa09c --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h @@ -0,0 +1,84 @@ +// +// 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. +// + +// RenderTarget9.h: Defines a D3D9-specific wrapper for IDirect3DSurface9 pointers +// retained by Renderbuffers. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ + +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" + +namespace rx +{ +class Renderer9; +class SwapChain9; + +class RenderTarget9 : public RenderTargetD3D +{ + public: + RenderTarget9() { } + virtual ~RenderTarget9() { } + + static RenderTarget9 *makeRenderTarget9(RenderTargetD3D *renderTarget); + + virtual IDirect3DSurface9 *getSurface() = 0; + + virtual D3DFORMAT getD3DFormat() const = 0; +}; + +class TextureRenderTarget9 : public RenderTarget9 +{ + public: + TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, + GLsizei samples); + virtual ~TextureRenderTarget9(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + IDirect3DSurface9 *getSurface() override; + + D3DFORMAT getD3DFormat() const override; + + private: + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + D3DFORMAT mD3DFormat; + GLsizei mSamples; + + IDirect3DSurface9 *mRenderTarget; +}; + +class SurfaceRenderTarget9 : public RenderTarget9 +{ + public: + SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth); + virtual ~SurfaceRenderTarget9(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLsizei getSamples() const override; + + IDirect3DSurface9 *getSurface() override; + + D3DFORMAT getD3DFormat() const override; + + private: + SwapChain9 *mSwapChain; + bool mDepth; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERTARGET9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp new file mode 100644 index 0000000000..bf1c367693 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp @@ -0,0 +1,2933 @@ +// +// Copyright (c) 2012-2014 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. +// + +// Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +#include "common/utilities.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Display.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/Program.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/State.h" +#include "libANGLE/Surface.h" +#include "libANGLE/Texture.h" +#include "libANGLE/angletypes.h" +#include "libANGLE/features.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/CompilerD3D.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/d3d/IndexDataManager.h" +#include "libANGLE/renderer/d3d/ProgramD3D.h" +#include "libANGLE/renderer/d3d/RenderbufferD3D.h" +#include "libANGLE/renderer/d3d/ShaderD3D.h" +#include "libANGLE/renderer/d3d/SurfaceD3D.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/renderer/d3d/TransformFeedbackD3D.h" +#include "libANGLE/renderer/d3d/d3d9/Blit9.h" +#include "libANGLE/renderer/d3d/d3d9/Buffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Fence9.h" +#include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Image9.h" +#include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Query9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexArray9.h" +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" + +#include "third_party/trace_event/trace_event.h" + +#include + +#include + +#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) +#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 +#endif + +// Enable ANGLE_SUPPORT_SHADER_MODEL_2 if you wish devices with only shader model 2. +// Such a device would not be conformant. +#ifndef ANGLE_SUPPORT_SHADER_MODEL_2 +#define ANGLE_SUPPORT_SHADER_MODEL_2 0 +#endif + +namespace rx +{ + +enum +{ + MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256, + MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32, + MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224, + MAX_VARYING_VECTORS_SM2 = 8, + MAX_VARYING_VECTORS_SM3 = 10, + + MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4 +}; + +Renderer9::Renderer9(egl::Display *display) + : RendererD3D(display) +{ + // Initialize global annotator + gl::InitializeDebugAnnotations(&mAnnotator); + + mD3d9Module = NULL; + + mD3d9 = NULL; + mD3d9Ex = NULL; + mDevice = NULL; + mDeviceEx = NULL; + mDeviceWindow = NULL; + mBlit = NULL; + + mAdapter = D3DADAPTER_DEFAULT; + + const egl::AttributeMap &attributes = display->getAttributeMap(); + EGLint requestedDeviceType = attributes.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); + switch (requestedDeviceType) + { + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: + mDeviceType = D3DDEVTYPE_HAL; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + mDeviceType = D3DDEVTYPE_REF; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + mDeviceType = D3DDEVTYPE_NULLREF; + break; + + default: + UNREACHABLE(); + } + + mMaskedClearSavedState = NULL; + + mVertexDataManager = NULL; + mIndexDataManager = NULL; + mLineLoopIB = NULL; + mCountingIB = NULL; + + mMaxNullColorbufferLRU = 0; + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + mNullColorbufferCache[i].lruCount = 0; + mNullColorbufferCache[i].width = 0; + mNullColorbufferCache[i].height = 0; + mNullColorbufferCache[i].buffer = NULL; + } + + mAppliedVertexShader = NULL; + mAppliedPixelShader = NULL; + mAppliedProgramSerial = 0; +} + +Renderer9::~Renderer9() +{ + if (mDevice) + { + // If the device is lost, reset it first to prevent leaving the driver in an unstable state + if (testDeviceLost()) + { + resetDevice(); + } + } + + release(); + + gl::UninitializeDebugAnnotations(); +} + +void Renderer9::release() +{ + RendererD3D::cleanup(); + + releaseDeviceResources(); + + SafeRelease(mDevice); + SafeRelease(mDeviceEx); + SafeRelease(mD3d9); + SafeRelease(mD3d9Ex); + + mCompiler.release(); + + if (mDeviceWindow) + { + DestroyWindow(mDeviceWindow); + mDeviceWindow = NULL; + } + + mD3d9Module = NULL; +} + +Renderer9 *Renderer9::makeRenderer9(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(Renderer9*, renderer)); + return static_cast(renderer); +} + +egl::Error Renderer9::initialize() +{ + if (!mCompiler.initialize()) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D9_INIT_COMPILER_ERROR, + "Compiler failed to initialize."); + } + + TRACE_EVENT0("gpu", "GetModuleHandle_d3d9"); + mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); + + if (mD3d9Module == NULL) + { + return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "No D3D9 module found."); + } + + 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_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) + { + TRACE_EVENT0("gpu", "D3d9Ex_QueryInterface"); + ASSERT(mD3d9Ex); + mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast(&mD3d9)); + ASSERT(mD3d9); + } + else + { + TRACE_EVENT0("gpu", "Direct3DCreate9"); + mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); + } + + if (!mD3d9) + { + return egl::Error(EGL_NOT_INITIALIZED, D3D9_INIT_MISSING_DEP, "Could not create D3D9 device."); + } + + if (mDisplay->getNativeDisplayId() != nullptr) + { + // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to + } + + HRESULT result; + + // Give up on getting device caps after about one second. + { + TRACE_EVENT0("gpu", "GetDeviceCaps"); + 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 + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D9_INIT_OTHER_ERROR, + "Failed to get device caps: Error code 0x%x\n", result); + } + } + } + +#if ANGLE_SUPPORT_SHADER_MODEL_2 + size_t minShaderModel = 2; +#else + size_t minShaderModel = 3; +#endif + + if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(minShaderModel, 0)) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D9_INIT_UNSUPPORTED_VERSION, + "Renderer does not support PS %u.%u.aborting!", minShaderModel, 0); + } + + // 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::ensureRenderTarget. + if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) + { + return egl::Error(EGL_NOT_INITIALIZED, + D3D9_INIT_UNSUPPORTED_STRETCHRECT, + "Renderer does not support StretctRect from textures."); + } + + { + TRACE_EVENT0("gpu", "GetAdapterIdentifier"); + mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); + } + + static const TCHAR windowName[] = TEXT("AngleHiddenWindow"); + static const TCHAR className[] = TEXT("STATIC"); + + { + TRACE_EVENT0("gpu", "CreateWindowEx"); + mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL); + } + + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED; + + { + TRACE_EVENT0("gpu", "D3d9_CreateDevice"); + 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 egl::Error(EGL_BAD_ALLOC, D3D9_INIT_OUT_OF_MEMORY, + "CreateDevice failed: device lost of out of memory"); + } + + if (FAILED(result)) + { + TRACE_EVENT0("gpu", "D3d9_CreateDevice2"); + 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 egl::Error(EGL_BAD_ALLOC, D3D9_INIT_OUT_OF_MEMORY, + "CreateDevice2 failed: device lost, not available, or of out of memory"); + } + } + + if (mD3d9Ex) + { + TRACE_EVENT0("gpu", "mDevice_QueryInterface"); + result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); + ASSERT(SUCCEEDED(result)); + } + + { + TRACE_EVENT0("gpu", "ShaderCache initialize"); + mVertexShaderCache.initialize(mDevice); + mPixelShaderCache.initialize(mDevice); + } + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + // Check vertex texture support + // Only Direct3D 10 ready devices support all the necessary vertex texture formats. + // We test this using D3D9 by checking support for the R16F format. + mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) && + SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); + + initializeDevice(); + + return egl::Error(EGL_SUCCESS); +} + +// 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 Renderer9::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 + } + + const gl::Caps &rendererCaps = getRendererCaps(); + + mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + + mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); + + mCurVertexTextureSerials.resize(rendererCaps.maxVertexTextureImageUnits); + mCurPixelTextureSerials.resize(rendererCaps.maxTextureImageUnits); + + markAllStateDirty(); + + mSceneStarted = false; + + ASSERT(!mBlit); + mBlit = new Blit9(this); + mBlit->initialize(); + + ASSERT(!mVertexDataManager && !mIndexDataManager); + mVertexDataManager = new VertexDataManager(this); + mIndexDataManager = new IndexDataManager(this, getRendererClass()); +} + +D3DPRESENT_PARAMETERS Renderer9::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; +} + +egl::ConfigSet Renderer9::generateConfigs() const +{ + static const GLenum colorBufferFormats[] = + { + GL_BGR5_A1_ANGLEX, + GL_BGRA8_EXT, + GL_RGB565, + + }; + + static const GLenum depthStencilBufferFormats[] = + { + GL_NONE, + GL_DEPTH_COMPONENT32_OES, + GL_DEPTH24_STENCIL8_OES, + GL_DEPTH_COMPONENT24_OES, + GL_DEPTH_COMPONENT16, + }; + + const gl::Caps &rendererCaps = getRendererCaps(); + const gl::TextureCapsMap &rendererTextureCaps = getRendererTextureCaps(); + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + // Determine the min and max swap intervals + int minSwapInterval = 4; + int maxSwapInterval = 0; + + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) + { + minSwapInterval = std::min(minSwapInterval, 0); + maxSwapInterval = std::max(maxSwapInterval, 0); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) + { + minSwapInterval = std::min(minSwapInterval, 1); + maxSwapInterval = std::max(maxSwapInterval, 1); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) + { + minSwapInterval = std::min(minSwapInterval, 2); + maxSwapInterval = std::max(maxSwapInterval, 2); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) + { + minSwapInterval = std::min(minSwapInterval, 3); + maxSwapInterval = std::max(maxSwapInterval, 3); + } + if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) + { + minSwapInterval = std::min(minSwapInterval, 4); + maxSwapInterval = std::max(maxSwapInterval, 4); + } + + egl::ConfigSet configs; + for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++) + { + GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex]; + const gl::TextureCaps &colorBufferFormatCaps = rendererTextureCaps.get(colorBufferInternalFormat); + if (colorBufferFormatCaps.renderable) + { + for (size_t depthStencilIndex = 0; depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++) + { + GLenum depthStencilBufferInternalFormat = depthStencilBufferFormats[depthStencilIndex]; + const gl::TextureCaps &depthStencilBufferFormatCaps = rendererTextureCaps.get(depthStencilBufferInternalFormat); + if (depthStencilBufferFormatCaps.renderable || depthStencilBufferInternalFormat == GL_NONE) + { + const gl::InternalFormat &colorBufferFormatInfo = gl::GetInternalFormatInfo(colorBufferInternalFormat); + const gl::InternalFormat &depthStencilBufferFormatInfo = gl::GetInternalFormatInfo(depthStencilBufferInternalFormat); + const d3d9::TextureFormat &d3d9ColorBufferFormatInfo = d3d9::GetTextureFormatInfo(colorBufferInternalFormat); + + egl::Config config; + config.renderTargetFormat = colorBufferInternalFormat; + config.depthStencilFormat = depthStencilBufferInternalFormat; + config.bufferSize = colorBufferFormatInfo.pixelBytes * 8; + config.redSize = colorBufferFormatInfo.redBits; + config.greenSize = colorBufferFormatInfo.greenBits; + config.blueSize = colorBufferFormatInfo.blueBits; + config.luminanceSize = colorBufferFormatInfo.luminanceBits; + config.alphaSize = colorBufferFormatInfo.alphaBits; + config.alphaMaskSize = 0; + config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB); + config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || colorBufferFormatInfo.format == GL_BGRA_EXT); + config.colorBufferType = EGL_RGB_BUFFER; + // Mark as slow if blits to the back-buffer won't be straight forward + config.configCaveat = (currentDisplayMode.Format == d3d9ColorBufferFormatInfo.renderFormat) ? EGL_NONE : EGL_SLOW_CONFIG; + config.configID = static_cast(configs.size() + 1); + config.conformant = EGL_OPENGL_ES2_BIT; + config.depthSize = depthStencilBufferFormatInfo.depthBits; + config.level = 0; + config.matchNativePixmap = EGL_NONE; + config.maxPBufferWidth = rendererCaps.max2DTextureSize; + config.maxPBufferHeight = rendererCaps.max2DTextureSize; + config.maxPBufferPixels = rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize; + config.maxSwapInterval = maxSwapInterval; + config.minSwapInterval = minSwapInterval; + config.nativeRenderable = EGL_FALSE; + config.nativeVisualID = 0; + config.nativeVisualType = EGL_NONE; + config.renderableType = EGL_OPENGL_ES2_BIT; + config.sampleBuffers = 0; // FIXME: enumerate multi-sampling + config.samples = 0; + config.stencilSize = depthStencilBufferFormatInfo.stencilBits; + config.surfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + config.transparentType = EGL_NONE; + config.transparentRedValue = 0; + config.transparentGreenValue = 0; + config.transparentBlueValue = 0; + + configs.add(config); + } + } + } + } + + ASSERT(configs.size() > 0); + return configs; +} + +void Renderer9::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 Renderer9::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; + } +} + +gl::Error Renderer9::flush() +{ + IDirect3DQuery9* query = NULL; + gl::Error error = allocateEventQuery(&query); + if (error.isError()) + { + return error; + } + + HRESULT result = query->Issue(D3DISSUE_END); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result); + } + + // Grab the query data once + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + freeEventQuery(query); + if (FAILED(result)) + { + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } + + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::finish() +{ + IDirect3DQuery9* query = NULL; + gl::Error error = allocateEventQuery(&query); + if (error.isError()) + { + return error; + } + + HRESULT result = query->Issue(D3DISSUE_END); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result); + } + + // Grab the query data once + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + if (FAILED(result)) + { + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } + + freeEventQuery(query); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + // Loop until the query completes + while (result == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + Sleep(0); + + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + + // 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 (result == S_FALSE && testDeviceLost()) + { + result = D3DERR_DEVICELOST; + } + + if (FAILED(result)) + { + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } + + freeEventQuery(query); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + } + + freeEventQuery(query); + + return gl::Error(GL_NO_ERROR); +} + +SwapChainD3D *Renderer9::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +{ + return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); +} + +gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) +{ + if (mEventQueryPool.empty()) + { + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, outQuery); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate event query, result: 0x%X.", result); + } + } + else + { + *outQuery = mEventQueryPool.back(); + mEventQueryPool.pop_back(); + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::freeEventQuery(IDirect3DQuery9* query) +{ + if (mEventQueryPool.size() > 1000) + { + SafeRelease(query); + } + else + { + mEventQueryPool.push_back(query); + } +} + +gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader) +{ + return mVertexShaderCache.create(function, length, outShader); +} + +gl::Error Renderer9::createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader) +{ + return mPixelShaderCache.create(function, length, outShader); +} + +HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer) +{ + D3DPOOL Pool = getBufferPool(Usage); + return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL); +} + +VertexBuffer *Renderer9::createVertexBuffer() +{ + return new VertexBuffer9(this); +} + +HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer) +{ + D3DPOOL Pool = getBufferPool(Usage); + return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL); +} + +IndexBuffer *Renderer9::createIndexBuffer() +{ + return new IndexBuffer9(this); +} + +BufferImpl *Renderer9::createBuffer() +{ + return new Buffer9(this); +} + +VertexArrayImpl *Renderer9::createVertexArray() +{ + return new VertexArray9(this); +} + +QueryImpl *Renderer9::createQuery(GLenum type) +{ + return new Query9(this, type); +} + +FenceNVImpl *Renderer9::createFenceNV() +{ + return new FenceNV9(this); +} + +FenceSyncImpl *Renderer9::createFenceSync() +{ + // Renderer9 doesn't support ES 3.0 and its sync objects. + UNREACHABLE(); + return NULL; +} + +TransformFeedbackImpl* Renderer9::createTransformFeedback() +{ + return new TransformFeedbackD3D(); +} + +bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const +{ + // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. + return false; +} + +gl::Error Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +{ + // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::generateSwizzle(gl::Texture *texture) +{ + // Swizzled textures are not available in ES2 or D3D9 + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerState) +{ + std::vector &forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; + std::vector &appliedSamplers = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates: mCurVertexSamplerStates; + + if (forceSetSamplers[index] || memcmp(&samplerState, &appliedSamplers[index], sizeof(gl::SamplerState)) != 0) + { + int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + + // Make sure to add the level offset for our tiny compressed texture workaround + TextureD3D *textureD3D = GetImplAs(texture); + + TextureStorage *storage = nullptr; + gl::Error error = textureD3D->getNativeTexture(&storage); + if (error.isError()) + { + return error; + } + + // Storage should exist, texture should be complete + ASSERT(storage); + + DWORD baseLevel = samplerState.baseLevel + storage->getTopLevel(); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS)); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT)); + + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy)); + D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; + gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel); + if (getRendererExtensions().textureFilterAnisotropic) + { + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); + } + } + + forceSetSamplers[index] = false; + appliedSamplers[index] = samplerState; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture) +{ + int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; + int d3dSampler = index + d3dSamplerOffset; + IDirect3DBaseTexture9 *d3dTexture = NULL; + unsigned int serial = 0; + bool forceSetTexture = false; + + std::vector &appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials; + + if (texture) + { + TextureD3D *textureImpl = GetImplAs(texture); + + TextureStorage *texStorage = nullptr; + gl::Error error = textureImpl->getNativeTexture(&texStorage); + if (error.isError()) + { + return error; + } + + // Texture should be complete and have a storage + ASSERT(texStorage); + + TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage); + error = storage9->getBaseTexture(&d3dTexture); + if (error.isError()) + { + return error; + } + + // If we get NULL back from getBaseTexture here, something went wrong + // in the texture class and we're unexpectedly missing the d3d texture + ASSERT(d3dTexture != NULL); + + serial = texture->getTextureSerial(); + forceSetTexture = textureImpl->hasDirtyImages(); + textureImpl->resetDirty(); + } + + if (forceSetTexture || appliedSerials[index] != serial) + { + mDevice->SetTexture(d3dSampler, d3dTexture); + } + + appliedSerials[index] = serial; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setUniformBuffers(const gl::Data &/*data*/, + const GLint /*vertexUniformBuffers*/[], + const GLint /*fragmentUniformBuffers*/[]) +{ + // No effect in ES2/D3D9 + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setRasterizerState(const gl::RasterizerState &rasterState) +{ + bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0; + + if (rasterStateChanged) + { + // Set the cull mode + if (rasterState.cullFace) + { + mDevice->SetRenderState(D3DRS_CULLMODE, gl_d3d9::ConvertCullMode(rasterState.cullMode, rasterState.frontFace)); + } + else + { + mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + if (rasterState.polygonOffsetFill) + { + if (mCurDepthSize > 0) + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&rasterState.polygonOffsetFactor); + + float depthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast(mCurDepthSize)); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&depthBias); + } + } + else + { + mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); + mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); + } + + mCurRasterState = rasterState; + } + + mForceSetRasterState = false; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) +{ + bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0; + bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0; + bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask; + + if (blendStateChanged || blendColorChanged) + { + if (blendState.blend) + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && + blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) + { + mDevice->SetRenderState(D3DRS_BLENDFACTOR, gl_d3d9::ConvertColor(blendColor)); + } + else + { + mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha), + gl::unorm<8>(blendColor.alpha), + gl::unorm<8>(blendColor.alpha), + gl::unorm<8>(blendColor.alpha))); + } + + mDevice->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB)); + mDevice->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB)); + mDevice->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB)); + + if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha || + blendState.destBlendRGB != blendState.destBlendAlpha || + blendState.blendEquationRGB != blendState.blendEquationAlpha) + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + + mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha)); + mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha)); + mDevice->SetRenderState(D3DRS_BLENDOPALPHA, gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + } + } + else + { + mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + if (blendState.sampleAlphaToCoverage) + { + FIXME("Sample alpha to coverage is unimplemented."); + } + + gl::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer(); + GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE; + + // Set the color mask + bool zeroColorMaskAllowed = getVendorId() != VENDOR_ID_AMD; + // 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 + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + DWORD colorMask = gl_d3d9::ConvertColorMask(formatInfo.redBits > 0 && blendState.colorMaskRed, + formatInfo.greenBits > 0 && blendState.colorMaskGreen, + formatInfo.blueBits > 0 && blendState.colorMaskBlue, + formatInfo.alphaBits > 0 && blendState.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_DITHERENABLE, blendState.dither ? TRUE : FALSE); + + mCurBlendState = blendState; + mCurBlendColor = blendColor; + } + + if (sampleMaskChanged) + { + // Set the multisample mask + mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast(sampleMask)); + + mCurSampleMask = sampleMask; + } + + mForceSetBlendState = false; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW) +{ + bool depthStencilStateChanged = mForceSetDepthStencilState || + memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0; + bool stencilRefChanged = mForceSetDepthStencilState || stencilRef != mCurStencilRef || + stencilBackRef != mCurStencilBackRef; + bool frontFaceCCWChanged = mForceSetDepthStencilState || frontFaceCCW != mCurFrontFaceCCW; + + if (depthStencilStateChanged) + { + if (depthStencilState.depthTest) + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + mDevice->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthStencilState.depthFunc)); + } + else + { + mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } + + mCurDepthStencilState = depthStencilState; + } + + if (depthStencilStateChanged || stencilRefChanged || frontFaceCCWChanged) + { + if (depthStencilState.stencilTest && mCurStencilSize > 0) + { + 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; + + ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); + ASSERT(stencilRef == stencilBackRef); + ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); + + // get the maximum size of the stencil ref + unsigned int maxStencil = (1 << mCurStencilSize) - 1; + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, + depthStencilState.stencilWritemask); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + gl_d3d9::ConvertComparison(depthStencilState.stencilFunc)); + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, + (stencilRef < (int)maxStencil) ? stencilRef : maxStencil); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, + depthStencilState.stencilMask); + + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilFail)); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthFail)); + mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthPass)); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, + depthStencilState.stencilBackWritemask); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, + gl_d3d9::ConvertComparison(depthStencilState.stencilBackFunc)); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, + (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, + depthStencilState.stencilBackMask); + + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackFail)); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthFail)); + mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, + gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthPass)); + } + else + { + mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + mDevice->SetRenderState(D3DRS_ZWRITEENABLE, depthStencilState.depthMask ? TRUE : FALSE); + + mCurStencilRef = stencilRef; + mCurStencilBackRef = stencilBackRef; + mCurFrontFaceCCW = frontFaceCCW; + } + + mForceSetDepthStencilState = false; + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) +{ + bool scissorChanged = mForceSetScissor || + memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || + enabled != mScissorEnabled; + + if (scissorChanged) + { + if (enabled) + { + RECT rect; + rect.left = gl::clamp(scissor.x, 0, static_cast(mRenderTargetDesc.width)); + rect.top = gl::clamp(scissor.y, 0, static_cast(mRenderTargetDesc.height)); + rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast(mRenderTargetDesc.width)); + rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast(mRenderTargetDesc.height)); + mDevice->SetScissorRect(&rect); + } + + mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, enabled ? TRUE : FALSE); + + mScissorEnabled = enabled; + mCurScissor = scissor; + } + + mForceSetScissor = false; +} + +void Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) +{ + gl::Rectangle actualViewport = viewport; + float actualZNear = gl::clamp01(zNear); + float actualZFar = gl::clamp01(zFar); + if (ignoreViewport) + { + actualViewport.x = 0; + actualViewport.y = 0; + actualViewport.width = mRenderTargetDesc.width; + actualViewport.height = mRenderTargetDesc.height; + actualZNear = 0.0f; + actualZFar = 1.0f; + } + + D3DVIEWPORT9 dxViewport; + dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast(mRenderTargetDesc.width)); + dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast(mRenderTargetDesc.height)); + dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast(mRenderTargetDesc.width) - static_cast(dxViewport.X)); + dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast(mRenderTargetDesc.height) - static_cast(dxViewport.Y)); + dxViewport.MinZ = actualZNear; + dxViewport.MaxZ = actualZFar; + + float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f); + + bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || + actualZNear != mCurNear || actualZFar != mCurFar || mCurDepthFront != depthFront; + if (viewportChanged) + { + mDevice->SetViewport(&dxViewport); + + mCurViewport = actualViewport; + mCurNear = actualZNear; + mCurFar = actualZFar; + mCurDepthFront = depthFront; + + dx_VertexConstants vc = {0}; + dx_PixelConstants pc = {0}; + + vc.viewAdjust[0] = (float)((actualViewport.width - (int)dxViewport.Width) + 2 * (actualViewport.x - (int)dxViewport.X) - 1) / dxViewport.Width; + vc.viewAdjust[1] = (float)((actualViewport.height - (int)dxViewport.Height) + 2 * (actualViewport.y - (int)dxViewport.Y) - 1) / dxViewport.Height; + vc.viewAdjust[2] = (float)actualViewport.width / dxViewport.Width; + vc.viewAdjust[3] = (float)actualViewport.height / dxViewport.Height; + + pc.viewCoords[0] = actualViewport.width * 0.5f; + pc.viewCoords[1] = actualViewport.height * 0.5f; + pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); + pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); + + pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f; + pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f; + pc.depthFront[2] = depthFront; + + vc.depthRange[0] = actualZNear; + vc.depthRange[1] = actualZFar; + vc.depthRange[2] = actualZFar - actualZNear; + + pc.depthRange[0] = actualZNear; + pc.depthRange[1] = actualZFar; + pc.depthRange[2] = actualZFar - actualZNear; + + if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants)) != 0) + { + mVertexConstants = vc; + mDxUniformsDirty = true; + } + + if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants)) != 0) + { + mPixelConstants = pc; + mDxUniformsDirty = true; + } + } + + mForceSetViewport = false; +} + +bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count, bool usesPointSize) +{ + switch (mode) + { + case GL_POINTS: + mPrimitiveType = D3DPT_POINTLIST; + mPrimitiveCount = count; + break; + case GL_LINES: + mPrimitiveType = D3DPT_LINELIST; + mPrimitiveCount = count / 2; + break; + case GL_LINE_LOOP: + mPrimitiveType = D3DPT_LINESTRIP; + mPrimitiveCount = count - 1; // D3D doesn't support line loops, so we draw the last line separately + break; + case GL_LINE_STRIP: + mPrimitiveType = D3DPT_LINESTRIP; + mPrimitiveCount = count - 1; + break; + case GL_TRIANGLES: + mPrimitiveType = D3DPT_TRIANGLELIST; + mPrimitiveCount = count / 3; + break; + case GL_TRIANGLE_STRIP: + mPrimitiveType = D3DPT_TRIANGLESTRIP; + mPrimitiveCount = count - 2; + break; + case GL_TRIANGLE_FAN: + mPrimitiveType = D3DPT_TRIANGLEFAN; + mPrimitiveCount = count - 2; + break; + default: + UNREACHABLE(); + return false; + } + + return mPrimitiveCount > 0; +} + + +gl::Error Renderer9::getNullColorbuffer(const gl::FramebufferAttachment *depthbuffer, const gl::FramebufferAttachment **outColorBuffer) +{ + ASSERT(depthbuffer); + + GLsizei width = depthbuffer->getWidth(); + GLsizei height = depthbuffer->getHeight(); + + // search cached nullcolorbuffers + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + if (mNullColorbufferCache[i].buffer != NULL && + mNullColorbufferCache[i].width == width && + mNullColorbufferCache[i].height == height) + { + mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU; + *outColorBuffer = mNullColorbufferCache[i].buffer; + return gl::Error(GL_NO_ERROR); + } + } + + gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(createRenderbuffer(), 0); + gl::Error error = nullRenderbuffer->setStorage(GL_NONE, width, height); + if (error.isError()) + { + SafeDelete(nullRenderbuffer); + return error; + } + + gl::RenderbufferAttachment *nullbuffer = new gl::RenderbufferAttachment(GL_NONE, nullRenderbuffer); + + // add nullbuffer to the cache + NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0]; + for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + if (mNullColorbufferCache[i].lruCount < oldest->lruCount) + { + oldest = &mNullColorbufferCache[i]; + } + } + + delete oldest->buffer; + oldest->buffer = nullbuffer; + oldest->lruCount = ++mMaxNullColorbufferLRU; + oldest->width = width; + oldest->height = height; + + *outColorBuffer = nullbuffer; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyRenderTarget(const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer) +{ + // 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. + if (!colorBuffer) + { + gl::Error error = getNullColorbuffer(depthStencilBuffer, &colorBuffer); + if (error.isError()) + { + return error; + } + } + ASSERT(colorBuffer); + + size_t renderTargetWidth = 0; + size_t renderTargetHeight = 0; + D3DFORMAT renderTargetFormat = D3DFMT_UNKNOWN; + + bool renderTargetChanged = false; + unsigned int renderTargetSerial = GetAttachmentSerial(colorBuffer); + if (renderTargetSerial != mAppliedRenderTargetSerial) + { + // Apply the render target on the device + RenderTarget9 *renderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(colorBuffer, &renderTarget); + if (error.isError()) + { + return error; + } + ASSERT(renderTarget); + + IDirect3DSurface9 *renderTargetSurface = renderTarget->getSurface(); + ASSERT(renderTargetSurface); + + mDevice->SetRenderTarget(0, renderTargetSurface); + SafeRelease(renderTargetSurface); + + renderTargetWidth = renderTarget->getWidth(); + renderTargetHeight = renderTarget->getHeight(); + renderTargetFormat = renderTarget->getD3DFormat(); + + mAppliedRenderTargetSerial = renderTargetSerial; + renderTargetChanged = true; + } + + unsigned int depthStencilSerial = (depthStencilBuffer != nullptr) ? GetAttachmentSerial(depthStencilBuffer) : 0; + if (depthStencilSerial != mAppliedDepthStencilSerial || !mDepthStencilInitialized) + { + unsigned int depthSize = 0; + unsigned int stencilSize = 0; + + // Apply the depth stencil on the device + if (depthStencilBuffer) + { + RenderTarget9 *depthStencilRenderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(depthStencilBuffer, &depthStencilRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(depthStencilRenderTarget); + + IDirect3DSurface9 *depthStencilSurface = depthStencilRenderTarget->getSurface(); + ASSERT(depthStencilSurface); + + mDevice->SetDepthStencilSurface(depthStencilSurface); + SafeRelease(depthStencilSurface); + + depthSize = depthStencilBuffer->getDepthSize(); + stencilSize = depthStencilBuffer->getStencilSize(); + } + else + { + mDevice->SetDepthStencilSurface(NULL); + } + + if (!mDepthStencilInitialized || depthSize != mCurDepthSize) + { + mCurDepthSize = depthSize; + mForceSetRasterState = true; + } + + if (!mDepthStencilInitialized || stencilSize != mCurStencilSize) + { + mCurStencilSize = stencilSize; + mForceSetDepthStencilState = true; + } + + mAppliedDepthStencilSerial = depthStencilSerial; + mDepthStencilInitialized = true; + } + + if (renderTargetChanged || !mRenderTargetDescInitialized) + { + mForceSetScissor = true; + mForceSetViewport = true; + mForceSetBlendState = true; + + mRenderTargetDesc.width = renderTargetWidth; + mRenderTargetDesc.height = renderTargetHeight; + mRenderTargetDesc.format = renderTargetFormat; + mRenderTargetDescInitialized = true; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyRenderTarget(const gl::Framebuffer *framebuffer) +{ + return applyRenderTarget(framebuffer->getColorbuffer(0), framebuffer->getDepthOrStencilbuffer()); +} + +gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances) +{ + TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; + gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); + if (error.isError()) + { + return error; + } + + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getProgram(), instances, &mRepeatDraw); +} + +// Applies the indices and element array bindings to the Direct3D 9 device +gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) +{ + gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); + if (error.isError()) + { + return error; + } + + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(indexInfo->storage == NULL); + + if (indexInfo->serial != mAppliedIBSerial) + { + IndexBuffer9* indexBuffer = IndexBuffer9::makeIndexBuffer9(indexInfo->indexBuffer); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = indexInfo->serial; + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::applyTransformFeedbackBuffers(const gl::State& state) +{ + ASSERT(!state.isTransformFeedbackActiveUnpaused()); +} + +gl::Error Renderer9::drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) +{ + ASSERT(!data.state->isTransformFeedbackActiveUnpaused()); + + startScene(); + + if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, GL_NONE, NULL, 0, NULL); + } + else if (instances > 0) + { + StaticIndexBufferInterface *countingIB = NULL; + gl::Error error = getCountingIB(count, &countingIB); + if (error.isError()) + { + return error; + } + + if (mAppliedIBSerial != countingIB->getSerial()) + { + IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(countingIB->getIndexBuffer()); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = countingIB->getSerial(); + } + + for (int i = 0; i < mRepeatDraw; i++) + { + mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount); + } + + return gl::Error(GL_NO_ERROR); + } + else // Regular case + { + mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/) +{ + startScene(); + + int minIndex = static_cast(indexInfo.indexRange.start); + + if (mode == GL_POINTS) + { + return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer); + } + else if (mode == GL_LINE_LOOP) + { + return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); + } + else + { + for (int i = 0; i < mRepeatDraw; i++) + { + GLsizei vertexCount = static_cast(indexInfo.indexRange.length()) + 1; + mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount); + } + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Get the raw indices for an indexed draw + if (type != GL_NONE && elementArrayBuffer) + { + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + indices = bufferData + offset; + } + + unsigned int startIndex = 0; + + if (getRendererExtensions().elementIndexUint) + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + } + + const unsigned int spaceNeeded = (static_cast(count)+1) * sizeof(unsigned int); + gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset = 0; + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + startIndex = static_cast(offset) / 4; + unsigned int *data = reinterpret_cast(mappedMemory); + + 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(); + } + + error = mLineLoopIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + else + { + if (!mLineLoopIB) + { + mLineLoopIB = new StreamingIndexBufferInterface(this); + gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); + if (error.isError()) + { + SafeDelete(mLineLoopIB); + return error; + } + } + + // Checked by Renderer9::applyPrimitiveType + ASSERT(count >= 0); + + if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned short))) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required."); + } + + const unsigned int spaceNeeded = (static_cast(count) + 1) * sizeof(unsigned short); + gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); + if (error.isError()) + { + return error; + } + + void* mappedMemory = NULL; + unsigned int offset; + error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); + if (error.isError()) + { + return error; + } + + startIndex = static_cast(offset) / 2; + unsigned short *data = reinterpret_cast(mappedMemory); + + 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(); + } + + error = mLineLoopIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + + if (mAppliedIBSerial != mLineLoopIB->getSerial()) + { + IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(mLineLoopIB->getIndexBuffer()); + + mDevice->SetIndices(indexBuffer->getBuffer()); + mAppliedIBSerial = mLineLoopIB->getSerial(); + } + + mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); + + return gl::Error(GL_NO_ERROR); +} + +template +static gl::Error drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices, int minIndex) +{ + for (int i = 0; i < count; i++) + { + unsigned int indexValue = static_cast(static_cast(indices)[i]) - minIndex; + device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) +{ + // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call + // for each individual point. This call is not expected to happen often. + + if (elementArrayBuffer) + { + BufferD3D *storage = GetImplAs(elementArrayBuffer); + intptr_t offset = reinterpret_cast(indices); + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; + } + + switch (type) + { + case GL_UNSIGNED_BYTE: return drawPoints(mDevice, count, indices, minIndex); + case GL_UNSIGNED_SHORT: return drawPoints(mDevice, count, indices, minIndex); + case GL_UNSIGNED_INT: return drawPoints(mDevice, count, indices, minIndex); + default: UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION); + } +} + +gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **outIB) +{ + // Update the counting index buffer if it is not large enough or has not been created yet. + if (count <= 65536) // 16-bit indices + { + const unsigned int spaceNeeded = count * sizeof(unsigned short); + + if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) + { + SafeDelete(mCountingIB); + mCountingIB = new StaticIndexBufferInterface(this); + mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); + + void *mappedMemory = NULL; + gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); + if (error.isError()) + { + return error; + } + + unsigned short *data = reinterpret_cast(mappedMemory); + for (size_t i = 0; i < count; i++) + { + data[i] = i; + } + + error = mCountingIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + } + else if (getRendererExtensions().elementIndexUint) + { + const unsigned int spaceNeeded = count * sizeof(unsigned int); + + if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) + { + SafeDelete(mCountingIB); + mCountingIB = new StaticIndexBufferInterface(this); + mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); + + void *mappedMemory = NULL; + gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); + if (error.isError()) + { + return error; + } + + unsigned int *data = reinterpret_cast(mappedMemory); + for (size_t i = 0; i < count; i++) + { + data[i] = i; + } + + error = mCountingIB->unmapBuffer(); + if (error.isError()) + { + return error; + } + } + } + else + { + return gl::Error(GL_OUT_OF_MEMORY, "Could not create a counting index buffer for glDrawArraysInstanced."); + } + + *outIB = mCountingIB; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) +{ + ASSERT(!transformFeedbackActive); + ASSERT(!rasterizerDiscard); + + ProgramD3D *programD3D = GetImplAs(program); + + ShaderExecutableD3D *vertexExe = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe, nullptr); + if (error.isError()) + { + return error; + } + + ShaderExecutableD3D *pixelExe = NULL; + error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + if (error.isError()) + { + return error; + } + + IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL); + IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL); + + if (vertexShader != mAppliedVertexShader) + { + mDevice->SetVertexShader(vertexShader); + mAppliedVertexShader = vertexShader; + } + + if (pixelShader != mAppliedPixelShader) + { + mDevice->SetPixelShader(pixelShader); + mAppliedPixelShader = pixelShader; + } + + // D3D9 has a quirk where creating multiple shaders with the same content + // can return the same shader pointer. Because GL programs store different data + // per-program, checking the program serial guarantees we upload fresh + // uniform data even if our shader pointers are the same. + // https://code.google.com/p/angleproject/issues/detail?id=661 + unsigned int programSerial = programD3D->getSerial(); + if (programSerial != mAppliedProgramSerial) + { + programD3D->dirtyAllUniforms(); + mDxUniformsDirty = true; + mAppliedProgramSerial = programSerial; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) +{ + for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) + { + gl::LinkedUniform *targetUniform = uniformArray[uniformIndex]; + + if (targetUniform->dirty) + { + GLfloat *f = (GLfloat*)targetUniform->data; + GLint *i = (GLint*)targetUniform->data; + + switch (targetUniform->type) + { + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + break; + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + applyUniformnbv(targetUniform, i); + 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_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + applyUniformniv(targetUniform, i); + break; + default: + UNREACHABLE(); + } + } + } + + // Driver uniforms + if (mDxUniformsDirty) + { + mDevice->SetVertexShaderConstantF(0, (float*)&mVertexConstants, sizeof(dx_VertexConstants) / sizeof(float[4])); + mDevice->SetPixelShaderConstantF(0, (float*)&mPixelConstants, sizeof(dx_PixelConstants) / sizeof(float[4])); + mDxUniformsDirty = false; + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v) +{ + if (targetUniform->isReferencedByFragmentShader()) + { + mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount); + } + + if (targetUniform->isReferencedByVertexShader()) + { + mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount); + } +} + +void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v) +{ + ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); + GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; + + for (unsigned int i = 0; i < targetUniform->registerCount; i++) + { + vector[i][0] = (GLfloat)v[4 * i + 0]; + vector[i][1] = (GLfloat)v[4 * i + 1]; + vector[i][2] = (GLfloat)v[4 * i + 2]; + vector[i][3] = (GLfloat)v[4 * i + 3]; + } + + applyUniformnfv(targetUniform, (GLfloat*)vector); +} + +void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v) +{ + ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); + GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; + + for (unsigned int i = 0; i < targetUniform->registerCount; i++) + { + vector[i][0] = (v[4 * i + 0] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][1] = (v[4 * i + 1] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][2] = (v[4 * i + 2] == GL_FALSE) ? 0.0f : 1.0f; + vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f; + } + + applyUniformnfv(targetUniform, (GLfloat*)vector); +} + +gl::Error Renderer9::clear(const ClearParameters &clearParams, + const gl::FramebufferAttachment *colorBuffer, + const gl::FramebufferAttachment *depthStencilBuffer) +{ + if (clearParams.colorClearType != GL_FLOAT) + { + // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0 + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + bool clearColor = clearParams.clearColor[0]; + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + if (clearParams.clearColor[i] != clearColor) + { + // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0 + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + } + + float depth = gl::clamp01(clearParams.depthClearValue); + DWORD stencil = clearParams.stencilClearValue & 0x000000FF; + + unsigned int stencilUnmasked = 0x0; + if (clearParams.clearStencil && depthStencilBuffer->getStencilSize() > 0) + { + RenderTargetD3D *stencilRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(depthStencilBuffer, &stencilRenderTarget); + if (error.isError()) + { + return error; + } + + RenderTarget9 *stencilRenderTarget9 = RenderTarget9::makeRenderTarget9(stencilRenderTarget); + ASSERT(stencilRenderTarget9); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(stencilRenderTarget9->getD3DFormat()); + stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1; + } + + const bool needMaskedStencilClear = clearParams.clearStencil && + (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; + + bool needMaskedColorClear = false; + D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); + if (clearColor) + { + RenderTargetD3D *colorRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(colorBuffer, &colorRenderTarget); + if (error.isError()) + { + return error; + } + + RenderTarget9 *colorRenderTarget9 = RenderTarget9::makeRenderTarget9(colorRenderTarget); + ASSERT(colorRenderTarget9); + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(colorBuffer->getInternalFormat()); + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(colorRenderTarget9->getD3DFormat()); + + color = D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), + gl::unorm<8>((formatInfo.redBits == 0 && d3dFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), + gl::unorm<8>((formatInfo.greenBits == 0 && d3dFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), + gl::unorm<8>((formatInfo.blueBits == 0 && d3dFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue)); + + if ((formatInfo.redBits > 0 && !clearParams.colorMaskRed) || + (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || + (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || + (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) + { + needMaskedColorClear = true; + } + } + + 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 < gl::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 (clearColor) + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, + gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, + clearParams.colorMaskGreen, + clearParams.colorMaskBlue, + clearParams.colorMaskAlpha)); + } + else + { + mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + } + + if (stencilUnmasked != 0x0 && clearParams.clearStencil) + { + 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, clearParams.stencilWriteMask); + mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); + mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + } + 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 < gl::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; + + startScene(); + mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4])); + + if (clearParams.clearDepth) + { + 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 (clearColor || clearParams.clearDepth || clearParams.clearStencil) + { + DWORD dxClearFlags = 0; + if (clearColor) + { + dxClearFlags |= D3DCLEAR_TARGET; + } + if (clearParams.clearDepth) + { + dxClearFlags |= D3DCLEAR_ZBUFFER; + } + if (clearParams.clearStencil) + { + dxClearFlags |= D3DCLEAR_STENCIL; + } + + mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil); + } + + return gl::Error(GL_NO_ERROR); +} + +void Renderer9::markAllStateDirty() +{ + mAppliedRenderTargetSerial = 0; + mAppliedDepthStencilSerial = 0; + mDepthStencilInitialized = false; + mRenderTargetDescInitialized = false; + + mForceSetDepthStencilState = true; + mForceSetRasterState = true; + mForceSetScissor = true; + mForceSetViewport = true; + mForceSetBlendState = true; + + ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexTextureSerials.size()); + for (unsigned int i = 0; i < mForceSetVertexSamplerStates.size(); i++) + { + mForceSetVertexSamplerStates[i] = true; + mCurVertexTextureSerials[i] = 0; + } + + ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelTextureSerials.size()); + for (unsigned int i = 0; i < mForceSetPixelSamplerStates.size(); i++) + { + mForceSetPixelSamplerStates[i] = true; + mCurPixelTextureSerials[i] = 0; + } + + mAppliedIBSerial = 0; + mAppliedVertexShader = NULL; + mAppliedPixelShader = NULL; + mAppliedProgramSerial = 0; + mDxUniformsDirty = true; + + mVertexDeclarationCache.markStateDirty(); +} + +void Renderer9::releaseDeviceResources() +{ + for (size_t i = 0; i < mEventQueryPool.size(); i++) + { + SafeRelease(mEventQueryPool[i]); + } + mEventQueryPool.clear(); + + SafeRelease(mMaskedClearSavedState); + + mVertexShaderCache.clear(); + mPixelShaderCache.clear(); + + SafeDelete(mBlit); + SafeDelete(mVertexDataManager); + SafeDelete(mIndexDataManager); + SafeDelete(mLineLoopIB); + SafeDelete(mCountingIB); + + for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) + { + SafeDelete(mNullColorbufferCache[i].buffer); + } +} + +// set notify to true to broadcast a message to all contexts of the device loss +bool Renderer9::testDeviceLost() +{ + HRESULT status = getDeviceStatusCode(); + bool isLost = FAILED(status); + + if (isLost) + { + // ensure we note the device loss -- + // we'll probably get this done again by notifyDeviceLost + // but best to remember it! + // Note that we don't want to clear the device loss status here + // -- this needs to be done by resetDevice + mDeviceLost = true; + } + + return isLost; +} + +HRESULT Renderer9::getDeviceStatusCode() +{ + HRESULT status = D3D_OK; + + if (mDeviceEx) + { + status = mDeviceEx->CheckDeviceState(NULL); + } + else if (mDevice) + { + status = mDevice->TestCooperativeLevel(); + } + + return status; +} + +bool Renderer9::testDeviceResettable() +{ + // On D3D9Ex, DEVICELOST represents a hung device that needs to be restarted + // DEVICEREMOVED indicates the device has been stopped and must be recreated + switch (getDeviceStatusCode()) + { + case D3DERR_DEVICENOTRESET: + case D3DERR_DEVICEHUNG: + return true; + case D3DERR_DEVICELOST: + return (mDeviceEx != NULL); + case D3DERR_DEVICEREMOVED: + ASSERT(mDeviceEx != NULL); + return isRemovedDeviceResettable(); + default: + return false; + } +} + +bool Renderer9::resetDevice() +{ + releaseDeviceResources(); + + D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); + + HRESULT result = D3D_OK; + bool lost = testDeviceLost(); + bool removedDevice = (getDeviceStatusCode() == D3DERR_DEVICEREMOVED); + + // Device Removed is a feature which is only present with D3D9Ex + ASSERT(mDeviceEx != NULL || !removedDevice); + + for (int attempts = 3; lost && attempts > 0; attempts--) + { + if (removedDevice) + { + // Device removed, which may trigger on driver reinstallation, + // may cause a longer wait other reset attempts before the + // system is ready to handle creating a new device. + Sleep(800); + lost = !resetRemovedDevice(); + } + else if (mDeviceEx) + { + Sleep(500); // Give the graphics driver some CPU time + result = mDeviceEx->ResetEx(&presentParameters, NULL); + lost = testDeviceLost(); + } + 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(); + } + } + + if (FAILED(result)) + { + ERR("Reset/ResetEx failed multiple times: 0x%08X", result); + return false; + } + + if (removedDevice && lost) + { + ERR("Device lost reset failed multiple times"); + return false; + } + + // If the device was removed, we already finished re-initialization in resetRemovedDevice + if (!removedDevice) + { + // reset device defaults + initializeDevice(); + } + + mDeviceLost = false; + + return true; +} + +bool Renderer9::isRemovedDeviceResettable() const +{ + bool success = false; + +#if ANGLE_D3D9EX == ANGLE_ENABLED + IDirect3D9Ex *d3d9Ex = NULL; + typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); + Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); + + if (Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &d3d9Ex))) + { + D3DCAPS9 deviceCaps; + HRESULT result = d3d9Ex->GetDeviceCaps(mAdapter, mDeviceType, &deviceCaps); + success = SUCCEEDED(result); + } + + SafeRelease(d3d9Ex); +#else + ASSERT(UNREACHABLE()); +#endif + + return success; +} + +bool Renderer9::resetRemovedDevice() +{ + // From http://msdn.microsoft.com/en-us/library/windows/desktop/bb172554(v=vs.85).aspx: + // The hardware adapter has been removed. Application must destroy the device, do enumeration of + // adapters and create another Direct3D device. If application continues rendering without + // calling Reset, the rendering calls will succeed. Applies to Direct3D 9Ex only. + release(); + return !initialize().isError(); +} + +VendorID Renderer9::getVendorId() const +{ + return static_cast(mAdapterIdentifier.VendorId); +} + +std::string Renderer9::getRendererDescription() const +{ + std::ostringstream rendererString; + + rendererString << mAdapterIdentifier.Description; + if (getShareHandleSupport()) + { + rendererString << " Direct3D9Ex"; + } + else + { + rendererString << " Direct3D9"; + } + + rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion); + rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); + + return rendererString.str(); +} + +GUID Renderer9::getAdapterIdentifier() const +{ + return mAdapterIdentifier.DeviceIdentifier; +} + +unsigned int Renderer9::getReservedVertexUniformVectors() const +{ + return 2; // dx_ViewAdjust and dx_DepthRange. +} + +unsigned int Renderer9::getReservedFragmentUniformVectors() const +{ + return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. +} + +unsigned int Renderer9::getReservedVertexUniformBuffers() const +{ + return 0; +} + +unsigned int Renderer9::getReservedFragmentUniformBuffers() const +{ + return 0; +} + +bool Renderer9::getShareHandleSupport() const +{ + // PIX doesn't seem to support using share handles, so disable them. + return (mD3d9Ex != NULL) && !gl::DebugAnnotationsActive(); +} + +bool Renderer9::getPostSubBufferSupport() const +{ + return true; +} + +int Renderer9::getMajorShaderModel() const +{ + return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion); +} + +int Renderer9::getMinorShaderModel() const +{ + return D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); +} + +std::string Renderer9::getShaderModelSuffix() const +{ + return ""; +} + +DWORD Renderer9::getCapsDeclTypes() const +{ + return mDeviceCaps.DeclTypes; +} + +D3DPOOL Renderer9::getBufferPool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & D3DUSAGE_DYNAMIC)) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +gl::Error Renderer9::copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copy2D(framebuffer, rect, destFormat, destOffset, storage, level); +} + +gl::Error Renderer9::copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level) +{ + RECT rect; + rect.left = sourceRect.x; + rect.top = sourceRect.y; + rect.right = sourceRect.x + sourceRect.width; + rect.bottom = sourceRect.y + sourceRect.height; + + return mBlit->copyCube(framebuffer, rect, destFormat, destOffset, storage, target, level); +} + +gl::Error Renderer9::copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + // 3D textures are not available in the D3D9 backend. + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level) +{ + // 2D array textures are not available in the D3D9 backend. + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT) +{ + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(format); + + const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); + + IDirect3DSurface9 *renderTarget = NULL; + if (width > 0 && height > 0) + { + bool requiresInitialization = false; + HRESULT result = D3DERR_INVALIDCALL; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + result = mDevice->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &renderTarget, NULL); + } + else + { + requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != NULL); + result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &renderTarget, NULL); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target, result: 0x%X.", result); + } + + if (requiresInitialization) + { + // This format requires that the data be initialized before the render target can be used + // Unfortunately this requires a Get call on the d3d device but it is far better than having + // to mark the render target as lockable and copy data to the gpu. + IDirect3DSurface9 *prevRenderTarget = NULL; + mDevice->GetRenderTarget(0, &prevRenderTarget); + mDevice->SetRenderTarget(0, renderTarget); + mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); + mDevice->SetRenderTarget(0, prevRenderTarget); + } + } + + *outRT = new TextureRenderTarget9(renderTarget, format, width, height, 1, supportedSamples); + return gl::Error(GL_NO_ERROR); +} + +FramebufferImpl *Renderer9::createDefaultFramebuffer(const gl::Framebuffer::Data &data) +{ + return createFramebuffer(data); +} + +FramebufferImpl *Renderer9::createFramebuffer(const gl::Framebuffer::Data &data) +{ + return new Framebuffer9(data, this); +} + +CompilerImpl *Renderer9::createCompiler(const gl::Data &data) +{ + return new CompilerD3D(data, SH_HLSL9_OUTPUT); +} + +ShaderImpl *Renderer9::createShader(GLenum type) +{ + return new ShaderD3D(type); +} + +ProgramImpl *Renderer9::createProgram() +{ + return new ProgramD3D(this); +} + +gl::Error Renderer9::loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable) +{ + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(transformFeedbackVaryings.size() == 0); + + switch (type) + { + case SHADER_VERTEX: + { + IDirect3DVertexShader9 *vshader = NULL; + gl::Error error = createVertexShader((DWORD*)function, length, &vshader); + if (error.isError()) + { + return error; + } + *outExecutable = new ShaderExecutable9(function, length, vshader); + } + break; + case SHADER_PIXEL: + { + IDirect3DPixelShader9 *pshader = NULL; + gl::Error error = createPixelShader((DWORD*)function, length, &pshader); + if (error.isError()) + { + return error; + } + *outExecutable = new ShaderExecutable9(function, length, pshader); + } + break; + default: + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable) +{ + // Transform feedback is not supported in ES2 or D3D9 + ASSERT(transformFeedbackVaryings.size() == 0); + + const char *profileType = NULL; + switch (type) + { + case SHADER_VERTEX: + profileType = "vs"; + break; + case SHADER_PIXEL: + profileType = "ps"; + break; + default: + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); + } + unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2; + unsigned int profileMinorVersion = 0; + std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); + + UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; + + if (workarounds.skipOptimization) + { + flags = D3DCOMPILE_SKIP_OPTIMIZATION; + } + else if (workarounds.useMaxOptimization) + { + flags = D3DCOMPILE_OPTIMIZATION_LEVEL3; + } + + if (gl::DebugAnnotationsActive()) + { +#ifndef NDEBUG + flags = D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + flags |= D3DCOMPILE_DEBUG; + } + + // 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. + std::vector configs; + configs.push_back(CompileConfig(flags, "default" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control")); + + ID3DBlob *binary = NULL; + std::string debugInfo; + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, NULL, &binary, &debugInfo); + if (error.isError()) + { + return error; + } + + // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL + // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. + if (!binary) + { + *outExectuable = NULL; + return gl::Error(GL_NO_ERROR); + } + + error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers, outExectuable); + + SafeRelease(binary); + if (error.isError()) + { + return error; + } + + if (!debugInfo.empty()) + { + (*outExectuable)->appendDebugInfo(debugInfo); + } + + return gl::Error(GL_NO_ERROR); +} + +UniformStorageD3D *Renderer9::createUniformStorage(size_t storageSize) +{ + return new UniformStorageD3D(storageSize); +} + +gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +{ + return mBlit->boxFilter(source, dest); +} + +D3DPOOL Renderer9::getTexturePool(DWORD usage) const +{ + if (mD3d9Ex != NULL) + { + return D3DPOOL_DEFAULT; + } + else + { + if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET))) + { + return D3DPOOL_MANAGED; + } + } + + return D3DPOOL_DEFAULT; +} + +gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +{ + ASSERT(source && dest); + + HRESULT result = D3DERR_OUTOFVIDEOMEMORY; + + if (fromManaged) + { + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + + if (SUCCEEDED(result)) + { + Image9::copyLockableSurfaces(surf, source); + result = mDevice->UpdateSurface(surf, NULL, dest, NULL); + SafeRelease(surf); + } + } + else + { + endScene(); + result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit internal texture, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); +} + +ImageD3D *Renderer9::createImage() +{ + return new Image9(this); +} + +gl::Error Renderer9::generateMipmap(ImageD3D *dest, ImageD3D *src) +{ + Image9 *src9 = Image9::makeImage9(src); + Image9 *dst9 = Image9::makeImage9(dest); + return Image9::generateMipmap(dst9, src9); +} + +TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain) +{ + SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); + return new TextureStorage9_2D(this, swapChain9); +} + +TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly) +{ + return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels); +} + +TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) +{ + return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels, hintLevelZeroOnly); +} + +TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + // 3D textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return NULL; +} + +TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) +{ + // 2D array textures are not supported by the D3D9 backend. + UNREACHABLE(); + + return NULL; +} + +TextureImpl *Renderer9::createTexture(GLenum target) +{ + switch(target) + { + case GL_TEXTURE_2D: return new TextureD3D_2D(this); + case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); + default: UNREACHABLE(); + } + + return NULL; +} + +RenderbufferImpl *Renderer9::createRenderbuffer() +{ + RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); + return renderbuffer; +} + +bool Renderer9::getLUID(LUID *adapterLuid) const +{ + adapterLuid->HighPart = 0; + adapterLuid->LowPart = 0; + + if (mD3d9Ex) + { + mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid); + return true; + } + + return false; +} + +VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +{ + return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).conversionType; +} + +GLenum Renderer9::getVertexComponentType(const gl::VertexFormat &vertexFormat) const +{ + return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).componentType; +} + +void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const +{ + d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, outExtensions); +} + +Workarounds Renderer9::generateWorkarounds() const +{ + return d3d9::GenerateWorkarounds(); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h new file mode 100644 index 0000000000..19bea3eb35 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.h @@ -0,0 +1,377 @@ +// +// Copyright (c) 2012-2014 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. +// + +// Renderer9.h: Defines a back-end specific class for the D3D9 renderer. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ + +#include "common/angleutils.h" +#include "common/mathutil.h" +#include "libANGLE/renderer/d3d/HLSLCompiler.h" +#include "libANGLE/renderer/d3d/RendererD3D.h" +#include "libANGLE/renderer/d3d/RenderTargetD3D.h" +#include "libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h" +#include "libANGLE/renderer/d3d/d3d9/ShaderCache.h" +#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" + +namespace gl +{ +class FramebufferAttachment; +} + +namespace egl +{ +class AttributeMap; +} + +namespace rx +{ +class Blit9; +class IndexDataManager; +class StreamingIndexBufferInterface; +class StaticIndexBufferInterface; +class VertexDataManager; +struct ClearParameters; +struct TranslatedAttribute; + +enum D3D9InitError +{ + D3D9_INIT_SUCCESS = 0, + // Failed to load the D3D or ANGLE compiler + D3D9_INIT_COMPILER_ERROR, + // Failed to load a necessary DLL + D3D9_INIT_MISSING_DEP, + // Device creation error + D3D9_INIT_CREATE_DEVICE_ERROR, + // System does not meet minimum shader spec + D3D9_INIT_UNSUPPORTED_VERSION, + // System does not support stretchrect from textures + D3D9_INIT_UNSUPPORTED_STRETCHRECT, + // A call returned out of memory or device lost + D3D9_INIT_OUT_OF_MEMORY, + // Other unspecified error + D3D9_INIT_OTHER_ERROR, + NUM_D3D9_INIT_ERRORS +}; + +class Renderer9 : public RendererD3D +{ + public: + explicit Renderer9(egl::Display *display); + virtual ~Renderer9(); + + static Renderer9 *makeRenderer9(Renderer *renderer); + + egl::Error initialize() override; + virtual bool resetDevice(); + + egl::ConfigSet generateConfigs() const override; + + void startScene(); + void endScene(); + + gl::Error flush() override; + gl::Error finish() override; + + virtual SwapChainD3D *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + + gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery); + void freeEventQuery(IDirect3DQuery9* query); + + // resource creation + gl::Error createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader); + gl::Error createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader); + HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); + HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer); + virtual gl::Error generateSwizzle(gl::Texture *texture); + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler); + virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); + + gl::Error setUniformBuffers(const gl::Data &data, + const GLint vertexUniformBuffers[], + const GLint fragmentUniformBuffers[]) override; + + virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); + gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) override; + virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW); + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); + virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport); + + gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; + gl::Error applyRenderTarget(const gl::FramebufferAttachment *colorBuffer, const gl::FramebufferAttachment *depthStencilBuffer); + virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive); + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray); + virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount, bool usesPointSize); + virtual gl::Error applyVertexBuffer(const gl::State &state, GLenum mode, GLint first, GLsizei count, GLsizei instances); + virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); + + void applyTransformFeedbackBuffers(const gl::State &state) override; + + gl::Error drawArrays(const gl::Data &data, GLenum mode, GLsizei count, GLsizei instances, bool usesPointSize) override; + virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); + + gl::Error clear(const ClearParameters &clearParams, + const gl::FramebufferAttachment *colorBuffer, + const gl::FramebufferAttachment *depthStencilBuffer); + + virtual void markAllStateDirty(); + + // lost device + bool testDeviceLost() override; + bool testDeviceResettable() override; + + VendorID getVendorId() const override; + std::string getRendererDescription() const override; + GUID getAdapterIdentifier() const override; + + IDirect3DDevice9 *getDevice() { return mDevice; } + + virtual unsigned int getReservedVertexUniformVectors() const; + virtual unsigned int getReservedFragmentUniformVectors() const; + virtual unsigned int getReservedVertexUniformBuffers() const; + virtual unsigned int getReservedFragmentUniformBuffers() const; + virtual bool getShareHandleSupport() const; + virtual bool getPostSubBufferSupport() const; + + virtual int getMajorShaderModel() const; + int getMinorShaderModel() const override; + std::string getShaderModelSuffix() const override; + + DWORD getCapsDeclTypes() const; + + // Pixel operations + virtual gl::Error copyImage2D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImageCube(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLenum target, GLint level); + virtual gl::Error copyImage3D(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImage2DArray(const gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + const gl::Offset &destOffset, TextureStorage *storage, GLint level); + + // RenderTarget creation + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTargetD3D **outRT); + + // Framebuffer creation + FramebufferImpl *createDefaultFramebuffer(const gl::Framebuffer::Data &data) override; + FramebufferImpl *createFramebuffer(const gl::Framebuffer::Data &data) override; + + // Shader creation + virtual CompilerImpl *createCompiler(const gl::Data &data); + virtual ShaderImpl *createShader(GLenum type); + virtual ProgramImpl *createProgram(); + + // Shader operations + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutableD3D **outExecutable); + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, const D3DCompilerWorkarounds &workarounds, + ShaderExecutableD3D **outExectuable); + virtual UniformStorageD3D *createUniformStorage(size_t storageSize); + + // Image operations + virtual ImageD3D *createImage(); + gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override; + virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain); + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly); + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); + + // Texture creation + virtual TextureImpl *createTexture(GLenum target); + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer(); + + // Buffer creation + virtual BufferImpl *createBuffer(); + virtual VertexBuffer *createVertexBuffer(); + virtual IndexBuffer *createIndexBuffer(); + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray(); + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type); + virtual FenceNVImpl *createFenceNV(); + virtual FenceSyncImpl *createFenceSync(); + + // Transform Feedback creation + virtual TransformFeedbackImpl* createTransformFeedback(); + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + // D3D9-renderer specific methods + gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + + D3DPOOL getTexturePool(DWORD usage) const; + + bool getLUID(LUID *adapterLuid) const override; + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; + + gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + + RendererClass getRendererClass() const override { return RENDERER_D3D9; } + + D3DDEVTYPE getD3D9DeviceType() const { return mDeviceType; } + + private: + void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override; + Workarounds generateWorkarounds() const override; + + void release(); + + void applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v); + void applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v); + void applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v); + + gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + gl::Error drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + + gl::Error getCountingIB(size_t count, StaticIndexBufferInterface **outIB); + + gl::Error getNullColorbuffer(const gl::FramebufferAttachment *depthbuffer, const gl::FramebufferAttachment **outColorBuffer); + + D3DPOOL getBufferPool(DWORD usage) const; + + HMODULE mD3d9Module; + + void initializeDevice(); + D3DPRESENT_PARAMETERS getDefaultPresentParameters(); + void releaseDeviceResources(); + + HRESULT getDeviceStatusCode(); + bool isRemovedDeviceResettable() const; + bool resetRemovedDevice(); + + 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. + + HLSLCompiler mCompiler; + + Blit9 *mBlit; + + HWND mDeviceWindow; + + D3DCAPS9 mDeviceCaps; + D3DADAPTER_IDENTIFIER9 mAdapterIdentifier; + + D3DPRIMITIVETYPE mPrimitiveType; + int mPrimitiveCount; + GLsizei mRepeatDraw; + + bool mSceneStarted; + + bool mVertexTextureSupport; + + // current render target states + unsigned int mAppliedRenderTargetSerial; + unsigned int mAppliedDepthStencilSerial; + bool mDepthStencilInitialized; + bool mRenderTargetDescInitialized; + unsigned int mCurStencilSize; + unsigned int mCurDepthSize; + + struct RenderTargetDesc + { + size_t width; + size_t height; + D3DFORMAT format; + }; + RenderTargetDesc mRenderTargetDesc; + + IDirect3DStateBlock9 *mMaskedClearSavedState; + + // previously set render states + bool mForceSetDepthStencilState; + gl::DepthStencilState mCurDepthStencilState; + int mCurStencilRef; + int mCurStencilBackRef; + bool mCurFrontFaceCCW; + + bool mForceSetRasterState; + gl::RasterizerState mCurRasterState; + + bool mForceSetScissor; + gl::Rectangle mCurScissor; + bool mScissorEnabled; + + bool mForceSetViewport; + gl::Rectangle mCurViewport; + float mCurNear; + float mCurFar; + float mCurDepthFront; + + bool mForceSetBlendState; + gl::BlendState mCurBlendState; + gl::ColorF mCurBlendColor; + GLuint mCurSampleMask; + + // Currently applied sampler states + std::vector mForceSetVertexSamplerStates; + std::vector mCurVertexSamplerStates; + + std::vector mForceSetPixelSamplerStates; + std::vector mCurPixelSamplerStates; + + // Currently applied textures + std::vector mCurVertexTextureSerials; + std::vector mCurPixelTextureSerials; + + unsigned int mAppliedIBSerial; + IDirect3DVertexShader9 *mAppliedVertexShader; + IDirect3DPixelShader9 *mAppliedPixelShader; + unsigned int mAppliedProgramSerial; + + dx_VertexConstants mVertexConstants; + dx_PixelConstants mPixelConstants; + bool mDxUniformsDirty; + + // A pool of event queries that are currently unused. + std::vector mEventQueryPool; + VertexShaderCache mVertexShaderCache; + PixelShaderCache mPixelShaderCache; + + VertexDataManager *mVertexDataManager; + VertexDeclarationCache mVertexDeclarationCache; + + IndexDataManager *mIndexDataManager; + StreamingIndexBufferInterface *mLineLoopIB; + StaticIndexBufferInterface *mCountingIB; + + enum { NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 }; + struct NullColorbufferCacheEntry + { + UINT lruCount; + int width; + int height; + gl::FramebufferAttachment *buffer; + } mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES]; + UINT mMaxNullColorbufferLRU; + + DebugAnnotator9 mAnnotator; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h new file mode 100644 index 0000000000..cf831c62fa --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderCache.h @@ -0,0 +1,108 @@ +// +// 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. +// + +// ShaderCache: Defines rx::ShaderCache, a cache of Direct3D shader objects +// keyed by their byte code. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ + +#include "libANGLE/Error.h" + +#include "common/debug.h" + +#include +#include +#include + +namespace rx +{ +template +class ShaderCache : angle::NonCopyable +{ + public: + ShaderCache() : mDevice(NULL) + { + } + + ~ShaderCache() + { + // Call clear while the device is still valid. + ASSERT(mMap.empty()); + } + + void initialize(IDirect3DDevice9* device) + { + mDevice = device; + } + + gl::Error create(const DWORD *function, size_t length, ShaderObject **outShaderObject) + { + std::string key(reinterpret_cast(function), length); + typename Map::iterator it = mMap.find(key); + if (it != mMap.end()) + { + it->second->AddRef(); + *outShaderObject = it->second; + return gl::Error(GL_NO_ERROR); + } + + ShaderObject *shader; + HRESULT result = createShader(function, &shader); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader, result: 0x%X.", result); + } + + // Random eviction policy. + if (mMap.size() >= kMaxMapSize) + { + SafeRelease(mMap.begin()->second); + mMap.erase(mMap.begin()); + } + + shader->AddRef(); + mMap[key] = shader; + + *outShaderObject = shader; + return gl::Error(GL_NO_ERROR); + } + + void clear() + { + for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) + { + SafeRelease(it->second); + } + + mMap.clear(); + } + + private: + 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); + } + + typedef std::unordered_map Map; + Map mMap; + + IDirect3DDevice9 *mDevice; +}; + +typedef ShaderCache VertexShaderCache; +typedef ShaderCache PixelShaderCache; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_SHADERCACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp new file mode 100644 index 0000000000..280e80930b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp @@ -0,0 +1,53 @@ +// +// Copyright (c) 2012-2013 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. +// + +// ShaderExecutable9.cpp: Implements a D3D9-specific class to contain shader +// executable implementation details. + +#include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h" + +#include "common/debug.h" + +namespace rx +{ + +ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable) + : ShaderExecutableD3D(function, length) +{ + mPixelExecutable = executable; + mVertexExecutable = NULL; +} + +ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable) + : ShaderExecutableD3D(function, length) +{ + mVertexExecutable = executable; + mPixelExecutable = NULL; +} + +ShaderExecutable9::~ShaderExecutable9() +{ + SafeRelease(mVertexExecutable); + SafeRelease(mPixelExecutable); +} + +ShaderExecutable9 *ShaderExecutable9::makeShaderExecutable9(ShaderExecutableD3D *executable) +{ + ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable9*, executable)); + return static_cast(executable); +} + +IDirect3DVertexShader9 *ShaderExecutable9::getVertexShader() const +{ + return mVertexExecutable; +} + +IDirect3DPixelShader9 *ShaderExecutable9::getPixelShader() const +{ + return mPixelExecutable; +} + +} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h new file mode 100644 index 0000000000..561f7defc8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2012-2013 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. +// + +// ShaderExecutable9.h: Defines a D3D9-specific class to contain shader +// executable implementation details. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ + +#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" + +namespace rx +{ + +class ShaderExecutable9 : public ShaderExecutableD3D +{ + public: + ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable); + ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable); + virtual ~ShaderExecutable9(); + + static ShaderExecutable9 *makeShaderExecutable9(ShaderExecutableD3D *executable); + + IDirect3DPixelShader9 *getPixelShader() const; + IDirect3DVertexShader9 *getVertexShader() const; + + private: + IDirect3DPixelShader9 *mPixelExecutable; + IDirect3DVertexShader9 *mVertexExecutable; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_SHADEREXECUTABLE9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp new file mode 100644 index 0000000000..1620668166 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp @@ -0,0 +1,425 @@ +// +// Copyright (c) 2012-2014 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. +// + +// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain. + +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/features.h" + +namespace rx +{ + +SwapChain9::SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat) + : mRenderer(renderer), + SwapChainD3D(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat), + mColorRenderTarget(this, false), + mDepthStencilRenderTarget(this, true) +{ + mSwapChain = NULL; + mBackBuffer = NULL; + mDepthStencil = NULL; + mRenderTarget = NULL; + mOffscreenTexture = NULL; + mWidth = -1; + mHeight = -1; + mSwapInterval = -1; +} + +SwapChain9::~SwapChain9() +{ + release(); +} + +void SwapChain9::release() +{ + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mDepthStencil); + SafeRelease(mRenderTarget); + SafeRelease(mOffscreenTexture); + + if (mNativeWindow.getNativeWindow()) + { + mShareHandle = NULL; + } +} + +static DWORD convertInterval(EGLint interval) +{ +#if ANGLE_VSYNC == ANGLE_DISABLED + return D3DPRESENT_INTERVAL_IMMEDIATE; +#else + 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; +#endif +} + +EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight) +{ + // D3D9 does not support resizing swap chains without recreating them + return reset(backbufferWidth, backbufferHeight, mSwapInterval); +} + +EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +{ + IDirect3DDevice9 *device = mRenderer->getDevice(); + + if (device == NULL) + { + return EGL_BAD_ACCESS; + } + + // 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. + SafeRelease(mSwapChain); + SafeRelease(mBackBuffer); + SafeRelease(mOffscreenTexture); + SafeRelease(mDepthStencil); + + HANDLE *pShareHandle = NULL; + if (!mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport()) + { + pShareHandle = &mShareHandle; + } + + const d3d9::TextureFormat &backBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mBackBufferFormat); + result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, + backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, + pShareHandle); + if (FAILED(result)) + { + ERR("Could not create offscreen texture: %08lX", result); + release(); + + if (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + 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; + } + + mRenderer->endScene(); + + result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); + ASSERT(SUCCEEDED(result)); + + SafeRelease(oldRenderTarget); + } + + const d3d9::TextureFormat &depthBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mDepthBufferFormat); + + // Don't create a swapchain for NULLREF devices + D3DDEVTYPE deviceType = mRenderer->getD3D9DeviceType(); + EGLNativeWindowType window = mNativeWindow.getNativeWindow(); + if (window && deviceType != D3DDEVTYPE_NULLREF) + { + D3DPRESENT_PARAMETERS presentParameters = {0}; + presentParameters.AutoDepthStencilFormat = depthBufferd3dFormatInfo.renderFormat; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = backBufferd3dFormatInfo.renderFormat; + presentParameters.EnableAutoDepthStencil = FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = window; + presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented + presentParameters.PresentationInterval = convertInterval(swapInterval); + 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. + if (mRenderer->getVendorId() == 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 (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); + ASSERT(SUCCEEDED(result)); + InvalidateRect(window, NULL, FALSE); + } + + if (mDepthBufferFormat != GL_NONE) + { + result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, + depthBufferd3dFormatInfo.renderFormat, + 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 (d3d9::isDeviceLostError(result)) + { + return EGL_CONTEXT_LOST; + } + else + { + return EGL_BAD_ALLOC; + } + } + } + + mWidth = backbufferWidth; + mHeight = backbufferHeight; + mSwapInterval = swapInterval; + + return EGL_SUCCESS; +} + +// parameters should be validated/clamped by caller +EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +{ + if (!mSwapChain) + { + return EGL_SUCCESS; + } + + IDirect3DDevice9 *device = mRenderer->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); + + for (UINT streamIndex = 0; streamIndex < gl::MAX_VERTEX_ATTRIBS; streamIndex++) + { + device->SetStreamSourceFreq(streamIndex, 1); + } + + 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 + + mRenderer->startScene(); + device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); + mRenderer->endScene(); + + device->SetTexture(0, NULL); + + RECT rect = + { + x, mHeight - y - height, + x + width, mHeight - y + }; + + HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0); + + mRenderer->markAllStateDirty(); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) + { + return EGL_BAD_ALLOC; + } + + // On Windows 8 systems, IDirect3DSwapChain9::Present sometimes returns 0x88760873 when the windows is + // in the process of entering/exiting fullscreen. This code doesn't seem to have any documentation. The + // device appears to be ok after emitting this error so simply return a failure to swap. + if (result == 0x88760873) + { + return EGL_BAD_MATCH; + } + + // http://crbug.com/313210 + // If our swap failed, trigger a device lost event. Resetting will work around an AMD-specific + // device removed bug with lost contexts when reinstalling drivers. + if (FAILED(result)) + { + mRenderer->notifyDeviceLost(); + return EGL_CONTEXT_LOST; + } + + return EGL_SUCCESS; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +// TODO: remove the AddRef to match SwapChain11 +IDirect3DSurface9 *SwapChain9::getRenderTarget() +{ + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} + +// Increments refcount on surface. +// caller must Release() the returned surface +// TODO: remove the AddRef to match SwapChain11 +IDirect3DSurface9 *SwapChain9::getDepthStencil() +{ + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + return mDepthStencil; +} + +// Increments refcount on texture. +// caller must Release() the returned texture +// TODO: remove the AddRef to match SwapChain11 +IDirect3DTexture9 *SwapChain9::getOffscreenTexture() +{ + if (mOffscreenTexture) + { + mOffscreenTexture->AddRef(); + } + + return mOffscreenTexture; +} + +SwapChain9 *SwapChain9::makeSwapChain9(SwapChainD3D *swapChain) +{ + ASSERT(HAS_DYNAMIC_TYPE(SwapChain9*, swapChain)); + return static_cast(swapChain); +} + +void SwapChain9::recreate() +{ + if (!mSwapChain) + { + return; + } + + IDirect3DDevice9 *device = mRenderer->getDevice(); + if (device == NULL) + { + return; + } + + D3DPRESENT_PARAMETERS presentParameters; + HRESULT result = mSwapChain->GetPresentParameters(&presentParameters); + ASSERT(SUCCEEDED(result)); + + IDirect3DSwapChain9* newSwapChain = NULL; + result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain); + if (FAILED(result)) + { + return; + } + + SafeRelease(mSwapChain); + mSwapChain = newSwapChain; + + SafeRelease(mBackBuffer); + result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); + ASSERT(SUCCEEDED(result)); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h new file mode 100644 index 0000000000..81ac08ca7b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h @@ -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. +// + +// SwapChain9.h: Defines a back-end specific class for the D3D9 swap chain. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ + +#include "common/angleutils.h" +#include "libANGLE/renderer/d3d/SwapChainD3D.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" + +namespace rx +{ +class Renderer9; + +class SwapChain9 : public SwapChainD3D +{ + public: + SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, + GLenum backBufferFormat, GLenum depthBufferFormat); + virtual ~SwapChain9(); + + EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); + virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + virtual void recreate(); + + RenderTargetD3D *getColorRenderTarget() override { return &mColorRenderTarget; } + RenderTargetD3D *getDepthStencilRenderTarget() override { return &mDepthStencilRenderTarget; } + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual IDirect3DSurface9 *getDepthStencil(); + virtual IDirect3DTexture9 *getOffscreenTexture(); + + EGLint getWidth() const { return mWidth; } + EGLint getHeight() const { return mHeight; } + + static SwapChain9 *makeSwapChain9(SwapChainD3D *swapChain); + + private: + void release(); + + Renderer9 *mRenderer; + EGLint mHeight; + EGLint mWidth; + EGLint mSwapInterval; + + IDirect3DSwapChain9 *mSwapChain; + IDirect3DSurface9 *mBackBuffer; + IDirect3DSurface9 *mRenderTarget; + IDirect3DSurface9 *mDepthStencil; + IDirect3DTexture9* mOffscreenTexture; + + SurfaceRenderTarget9 mColorRenderTarget; + SurfaceRenderTarget9 mDepthStencilRenderTarget; +}; + +} +#endif // LIBANGLE_RENDERER_D3D_D3D9_SWAPCHAIN9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp new file mode 100644 index 0000000000..139cb3eb08 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp @@ -0,0 +1,472 @@ +// +// Copyright (c) 2012-2014 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. +// + +// TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived +// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the +// D3D9 texture. + +#include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/SwapChain9.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/TextureD3D.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Texture.h" + +namespace rx +{ +TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage) + : mTopLevel(0), + mMipLevels(0), + mTextureWidth(0), + mTextureHeight(0), + mInternalFormat(GL_NONE), + mTextureFormat(D3DFMT_UNKNOWN), + mRenderer(Renderer9::makeRenderer9(renderer)), + mD3DUsage(usage), + mD3DPool(mRenderer->getTexturePool(usage)) +{ +} + +TextureStorage9::~TextureStorage9() +{ +} + +TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage)); + return static_cast(storage); +} + +DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) +{ + DWORD d3dusage = 0; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + d3dusage |= D3DUSAGE_DEPTHSTENCIL; + } + else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)) + { + d3dusage |= D3DUSAGE_RENDERTARGET; + } + + return d3dusage; +} + + +bool TextureStorage9::isRenderTarget() const +{ + return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0; +} + +bool TextureStorage9::isManaged() const +{ + return (mD3DPool == D3DPOOL_MANAGED); +} + +D3DPOOL TextureStorage9::getPool() const +{ + return mD3DPool; +} + +DWORD TextureStorage9::getUsage() const +{ + return mD3DUsage; +} + +int TextureStorage9::getTopLevel() const +{ + return mTopLevel; +} + +int TextureStorage9::getLevelCount() const +{ + return mMipLevels - mTopLevel; +} + +gl::Error TextureStorage9::setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain) + : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) +{ + IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); + mTexture = surfaceTexture; + mMipLevels = surfaceTexture->GetLevelCount(); + + mInternalFormat = swapchain->GetBackBufferInternalFormat(); + + D3DSURFACE_DESC surfaceDesc; + surfaceTexture->GetLevelDesc(0, &surfaceDesc); + mTextureWidth = surfaceDesc.Width; + mTextureHeight = surfaceDesc.Height; + mTextureFormat = surfaceDesc.Format; + + mRenderTarget = NULL; + + initializeSerials(1, 1); +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = NULL; + mRenderTarget = NULL; + + mInternalFormat = internalformat; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mTextureFormat = d3dFormatInfo.texFormat; + + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel); + mTextureWidth = width; + mTextureHeight = height; + mMipLevels = mTopLevel + levels; + + initializeSerials(getLevelCount(), 1); +} + +TextureStorage9_2D::~TextureStorage9_2D() +{ + SafeRelease(mTexture); + SafeDelete(mRenderTarget); +} + +TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage)); + return static_cast(storage); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +gl::Error TextureStorage9_2D::getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface) +{ + IDirect3DBaseTexture9 *baseTexture = NULL; + gl::Error error = getBaseTexture(&baseTexture); + if (error.isError()) + { + return error; + } + + IDirect3DTexture9 *texture = static_cast(baseTexture); + + HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface); + + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); + } + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level + mTopLevel != 0 && isManaged() && dirty) + { + texture->AddDirtyRect(NULL); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &/*index*/, RenderTargetD3D **outRT) +{ + if (!mRenderTarget && isRenderTarget()) + { + IDirect3DSurface9 *surface = NULL; + gl::Error error = getSurfaceLevel(0, false, &surface); + if (error.isError()) + { + return error; + } + + mRenderTarget = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0); + } + + ASSERT(outRT); + *outRT = mRenderTarget; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + IDirect3DSurface9 *upper = NULL; + gl::Error error = getSurfaceLevel(sourceIndex.mipIndex, false, &upper); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *lower = NULL; + error = getSurfaceLevel(destIndex.mipIndex, true, &lower); + if (error.isError()) + { + SafeRelease(upper); + return error; + } + + ASSERT(upper && lower); + error = mRenderer->boxFilter(upper, lower); + + SafeRelease(upper); + SafeRelease(lower); + + return error; +} + +gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +{ + // 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 (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + HRESULT result = device->CreateTexture(mTextureWidth, mTextureHeight, mMipLevels, getUsage(), mTextureFormat, + getPool(), &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result); + } + } + + *outTexture = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(destStorage); + + int levels = getLevelCount(); + for (int i = 0; i < levels; ++i) + { + IDirect3DSurface9 *srcSurf = NULL; + gl::Error error = getSurfaceLevel(i, false, &srcSurf); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *dstSurf = NULL; + error = dest9->getSurfaceLevel(i, true, &dstSurf); + if (error.isError()) + { + SafeRelease(srcSurf); + return error; + } + + error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged()); + + SafeRelease(srcSurf); + SafeRelease(dstSurf); + + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = NULL; + for (int i = 0; i < CUBE_FACE_COUNT; ++i) + { + mRenderTarget[i] = NULL; + } + + mInternalFormat = internalformat; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mTextureFormat = d3dFormatInfo.texFormat; + + int height = size; + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel); + mTextureWidth = size; + mTextureHeight = size; + mMipLevels = mTopLevel + levels; + + initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT); +} + +TextureStorage9_Cube::~TextureStorage9_Cube() +{ + SafeRelease(mTexture); + + for (int i = 0; i < CUBE_FACE_COUNT; ++i) + { + SafeDelete(mRenderTarget[i]); + } +} + +TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage) +{ + ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage)); + return static_cast(storage); +} + +// Increments refcount on surface. +// caller must Release() the returned surface +gl::Error TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface) +{ + IDirect3DBaseTexture9 *baseTexture = NULL; + gl::Error error = getBaseTexture(&baseTexture); + if (error.isError()) + { + return error; + } + + IDirect3DCubeTexture9 *texture = static_cast(baseTexture); + + D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget); + HRESULT result = texture->GetCubeMapSurface(face, level + mTopLevel, outSurface); + + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); + } + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + texture->AddDirtyRect(face, NULL); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) +{ + ASSERT(outRT); + ASSERT(index.mipIndex == 0); + ASSERT(index.layerIndex >= 0 && index.layerIndex < CUBE_FACE_COUNT); + + if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget()) + { + IDirect3DSurface9 *surface = NULL; + gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, 0, false, &surface); + if (error.isError()) + { + return error; + } + + mRenderTarget[index.layerIndex] = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0); + } + + *outRT = mRenderTarget[index.layerIndex]; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + IDirect3DSurface9 *upper = NULL; + gl::Error error = getCubeMapSurface(sourceIndex.type, sourceIndex.mipIndex, false, &upper); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *lower = NULL; + error = getCubeMapSurface(destIndex.type, destIndex.mipIndex, true, &lower); + if (error.isError()) + { + SafeRelease(upper); + return error; + } + + ASSERT(upper && lower); + error = mRenderer->boxFilter(upper, lower); + + SafeRelease(upper); + SafeRelease(lower); + + return error; +} + +gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +{ + // 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 (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + ASSERT(mTextureWidth == mTextureHeight); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + HRESULT result = device->CreateCubeTexture(mTextureWidth, mMipLevels, getUsage(), mTextureFormat, getPool(), + &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube storage texture, result: 0x%X.", result); + } + } + + *outTexture = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(destStorage); + + int levels = getLevelCount(); + for (int f = 0; f < CUBE_FACE_COUNT; f++) + { + for (int i = 0; i < levels; i++) + { + IDirect3DSurface9 *srcSurf = NULL; + gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *dstSurf = NULL; + error = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf); + if (error.isError()) + { + SafeRelease(srcSurf); + return error; + } + + error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged()); + + SafeRelease(srcSurf); + SafeRelease(dstSurf); + + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h new file mode 100644 index 0000000000..5cc06f07b1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h @@ -0,0 +1,108 @@ +// +// Copyright (c) 2012-2013 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. +// + +// TextureStorage9.h: Defines the abstract rx::TextureStorage9 class and its concrete derived +// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the +// D3D9 texture. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ + +#include "libANGLE/renderer/d3d/TextureStorage.h" +#include "common/debug.h" + +namespace rx +{ +class Renderer9; +class SwapChain9; +class RenderTargetD3D; +class RenderTarget9; + +class TextureStorage9 : public TextureStorage +{ + public: + virtual ~TextureStorage9(); + + static TextureStorage9 *makeTextureStorage9(TextureStorage *storage); + + static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget); + + D3DPOOL getPool() const; + DWORD getUsage() const; + + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) = 0; + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT) = 0; + + virtual int getTopLevel() const; + virtual bool isRenderTarget() const; + virtual bool isManaged() const; + virtual int getLevelCount() const; + + virtual gl::Error setData(const gl::ImageIndex &index, ImageD3D *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData); + + protected: + int mTopLevel; + size_t mMipLevels; + size_t mTextureWidth; + size_t mTextureHeight; + GLenum mInternalFormat; + D3DFORMAT mTextureFormat; + + Renderer9 *mRenderer; + + TextureStorage9(Renderer9 *renderer, DWORD usage); + + private: + const DWORD mD3DUsage; + const D3DPOOL mD3DPool; +}; + +class TextureStorage9_2D : public TextureStorage9 +{ + public: + TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain); + TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + virtual ~TextureStorage9_2D(); + + static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage); + + gl::Error getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture); + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); + virtual gl::Error copyToStorage(TextureStorage *destStorage); + + private: + IDirect3DTexture9 *mTexture; + RenderTarget9 *mRenderTarget; +}; + +class TextureStorage9_Cube : public TextureStorage9 +{ + public: + TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels, bool hintLevelZeroOnly); + virtual ~TextureStorage9_Cube(); + + static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage); + + gl::Error getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture); + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); + virtual gl::Error copyToStorage(TextureStorage *destStorage); + + private: + static const size_t CUBE_FACE_COUNT = 6; + + IDirect3DCubeTexture9 *mTexture; + RenderTarget9 *mRenderTarget[CUBE_FACE_COUNT]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_TEXTURESTORAGE9_H_ + diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h new file mode 100644 index 0000000000..fb626bc0cf --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexArray9.h @@ -0,0 +1,41 @@ +// +// Copyright 2014 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. +// + +// VertexArray9.h: Defines the rx::VertexArray9 class which implements rx::VertexArrayImpl. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ + +#include "libANGLE/renderer/VertexArrayImpl.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" + +namespace rx +{ +class Renderer9; + +class VertexArray9 : public VertexArrayImpl +{ + public: + VertexArray9(Renderer9 *renderer) + : VertexArrayImpl(), + mRenderer(renderer) + { + } + + virtual ~VertexArray9() { } + + virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } + virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } + virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } + virtual void enableAttribute(size_t idx, bool enabledState) { } + + private: + Renderer9 *mRenderer; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp new file mode 100644 index 0000000000..cb5003997f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -0,0 +1,239 @@ +// +// 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. +// + +// VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation. + +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/vertexconversion.h" +#include "libANGLE/renderer/d3d/BufferD3D.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/Buffer.h" + +namespace rx +{ + +VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer) +{ + mVertexBuffer = NULL; + mBufferSize = 0; + mDynamicUsage = false; +} + +VertexBuffer9::~VertexBuffer9() +{ + SafeRelease(mVertexBuffer); +} + +gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) +{ + SafeRelease(mVertexBuffer); + + updateSerial(); + + if (size > 0) + { + DWORD flags = D3DUSAGE_WRITEONLY; + if (dynamicUsage) + { + flags |= D3DUSAGE_DYNAMIC; + } + + HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); + } + } + + mBufferSize = size; + mDynamicUsage = dynamicUsage; + return gl::Error(GL_NO_ERROR); +} + +VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); + return static_cast(vertexBuffer); +} + +gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset) +{ + if (!mVertexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + gl::Buffer *buffer = attrib.buffer.get(); + + int inputStride = gl::ComputeVertexAttributeStride(attrib); + int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); + + DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; + + uint8_t *mapPtr = NULL; + + unsigned int mapSize; + gl::Error error = spaceRequired(attrib, count, instances, &mapSize); + if (error.isError()) + { + return error; + } + + HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast(&mapPtr), lockFlags); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result); + } + + const uint8_t *input = NULL; + if (attrib.enabled) + { + if (buffer) + { + BufferD3D *storage = GetImplAs(buffer); + ASSERT(storage); + error = storage->getData(&input); + if (error.isError()) + { + return error; + } + input += static_cast(attrib.offset); + } + else + { + input = static_cast(attrib.pointer); + } + } + else + { + input = reinterpret_cast(currentValue.FloatValues); + } + + if (instances == 0 || attrib.divisor == 0) + { + input += inputStride * start; + } + + gl::VertexFormat vertexFormat(attrib, currentValue.Type); + const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); + bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0; + + if (!needsConversion && inputStride == elementSize) + { + size_t copySize = static_cast(count) * static_cast(inputStride); + memcpy(mapPtr, input, copySize); + } + else + { + d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr); + } + + mVertexBuffer->Unlock(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, + unsigned int *outSpaceRequired) const +{ + return spaceRequired(attrib, count, instances, outSpaceRequired); +} + +unsigned int VertexBuffer9::getBufferSize() const +{ + return mBufferSize; +} + +gl::Error VertexBuffer9::setBufferSize(unsigned int size) +{ + if (size > mBufferSize) + { + return initialize(size, mDynamicUsage); + } + else + { + return gl::Error(GL_NO_ERROR); + } +} + +gl::Error VertexBuffer9::discard() +{ + if (!mVertexBuffer) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); + } + + void *dummy; + HRESULT result; + + result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal buffer for discarding, HRESULT: 0x%08x", result); + } + + result = mVertexBuffer->Unlock(); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal buffer for discarding, HRESULT: 0x%08x", result); + } + + return gl::Error(GL_NO_ERROR); +} + +IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const +{ + return mVertexBuffer; +} + +gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired) const +{ + gl::VertexFormat vertexFormat(attrib, GL_FLOAT); + const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); + + if (attrib.enabled) + { + unsigned int elementCount = 0; + if (instances == 0 || attrib.divisor == 0) + { + elementCount = count; + } + else + { + // Round up to divisor, if possible + elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); + } + + if (d3d9VertexInfo.outputElementSize <= std::numeric_limits::max() / elementCount) + { + if (outSpaceRequired) + { + *outSpaceRequired = d3d9VertexInfo.outputElementSize * elementCount; + } + return gl::Error(GL_NO_ERROR); + } + else + { + return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); + } + } + else + { + const unsigned int elementSize = 4; + if (outSpaceRequired) + { + *outSpaceRequired = elementSize * 4; + } + return gl::Error(GL_NO_ERROR); + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h new file mode 100644 index 0000000000..f5b110b22b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h @@ -0,0 +1,52 @@ +// +// 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. +// + +// VertexBuffer9.h: Defines the D3D9 VertexBuffer implementation. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ + +#include "libANGLE/renderer/d3d/VertexBuffer.h" + +namespace rx +{ +class Renderer9; + +class VertexBuffer9 : public VertexBuffer +{ + public: + explicit VertexBuffer9(Renderer9 *renderer); + virtual ~VertexBuffer9(); + + virtual gl::Error initialize(unsigned int size, bool dynamicUsage); + + static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer); + + virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, + GLint start, GLsizei count, GLsizei instances, unsigned int offset); + + virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; + + virtual unsigned int getBufferSize() const; + virtual gl::Error setBufferSize(unsigned int size); + virtual gl::Error discard(); + + IDirect3DVertexBuffer9 *getBuffer() const; + + private: + Renderer9 *mRenderer; + + IDirect3DVertexBuffer9 *mVertexBuffer; + unsigned int mBufferSize; + bool mDynamicUsage; + + gl::Error spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, + unsigned int *outSpaceRequired) const; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp new file mode 100644 index 0000000000..f9eded9b50 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp @@ -0,0 +1,237 @@ +// +// 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. +// + +// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations. + +#include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h" +#include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/Program.h" +#include "libANGLE/VertexAttribute.h" + +namespace rx +{ + +VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + mVertexDeclCache[i].vertexDeclaration = NULL; + mVertexDeclCache[i].lruCount = 0; + } + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = NULL; + mInstancingEnabled = true; +} + +VertexDeclarationCache::~VertexDeclarationCache() +{ + for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) + { + SafeRelease(mVertexDeclCache[i].vertexDeclaration); + } +} + +gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::Program *program, GLsizei instances, GLsizei *repeatDraw) +{ + *repeatDraw = 1; + + int indexedAttribute = gl::MAX_VERTEX_ATTRIBS; + int instancedAttribute = gl::MAX_VERTEX_ATTRIBS; + + if (instances == 0) + { + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) + { + if (attributes[i].divisor != 0) + { + // If a divisor is set, it still applies even if an instanced draw was not used, so treat + // as a single-instance draw. + instances = 1; + break; + } + } + } + + if (instances > 0) + { + // Find an indexed attribute to be mapped to D3D stream 0 + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0) + { + indexedAttribute = i; + } + else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0) + { + instancedAttribute = i; + } + if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS) + break; // Found both an indexed and instanced attribute + } + } + + // The validation layer checks that there is at least one active attribute with a zero divisor as per + // the GL_ANGLE_instanced_arrays spec. + ASSERT(indexedAttribute != gl::MAX_VERTEX_ATTRIBS); + } + + D3DCAPS9 caps; + device->GetDeviceCaps(&caps); + + D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1]; + D3DVERTEXELEMENT9 *element = &elements[0]; + + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + if (attributes[i].active) + { + // Directly binding the storage buffer is not supported for d3d9 + ASSERT(attributes[i].storage == NULL); + + 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 == gl::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; + } + } + + VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer); + + if (mAppliedVBs[stream].serial != attributes[i].serial || + mAppliedVBs[stream].stride != attributes[i].stride || + mAppliedVBs[stream].offset != attributes[i].offset) + { + device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); + mAppliedVBs[stream].serial = attributes[i].serial; + mAppliedVBs[stream].stride = attributes[i].stride; + mAppliedVBs[stream].offset = attributes[i].offset; + } + + gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT); + const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexFormat); + + element->Stream = stream; + element->Offset = 0; + element->Type = d3d9VertexInfo.nativeFormat; + element->Method = D3DDECLMETHOD_DEFAULT; + element->Usage = D3DDECLUSAGE_TEXCOORD; + element->UsageIndex = program->getSemanticIndex(i); + element++; + } + } + + if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS) + { + if (mInstancingEnabled) + { + for (int i = 0; i < gl::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::Error(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) + { + SafeRelease(lastCache->vertexDeclaration); + // mLastSetVDecl is set to the replacement, so we don't have to worry + // about it. + } + + memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)); + HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal vertex declaration, result: 0x%X.", result); + } + + device->SetVertexDeclaration(lastCache->vertexDeclaration); + mLastSetVDecl = lastCache->vertexDeclaration; + lastCache->lruCount = ++mMaxLru; + + return gl::Error(GL_NO_ERROR); +} + +void VertexDeclarationCache::markStateDirty() +{ + for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) + { + mAppliedVBs[i].serial = 0; + } + + mLastSetVDecl = NULL; + mInstancingEnabled = true; // Forces it to be disabled when not used +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h new file mode 100644 index 0000000000..fbd673097f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h @@ -0,0 +1,60 @@ +// +// 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. +// + +// VertexDeclarationCache.h: Defines a helper class to construct and cache vertex declarations. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ + +#include "libANGLE/Error.h" +#include "libANGLE/renderer/d3d/VertexDataManager.h" + +namespace gl +{ +class VertexDataManager; +class Program; +} + +namespace rx +{ + +class VertexDeclarationCache +{ + public: + VertexDeclarationCache(); + ~VertexDeclarationCache(); + + gl::Error applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::Program *program, 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[gl::MAX_VERTEX_ATTRIBS]; + IDirect3DVertexDeclaration9 *mLastSetVDecl; + bool mInstancingEnabled; + + struct VertexDeclCacheEntry + { + D3DVERTEXELEMENT9 cachedElements[gl::MAX_VERTEX_ATTRIBS + 1]; + UINT lruCount; + IDirect3DVertexDeclaration9 *vertexDeclaration; + } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES]; +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXDECLARATIONCACHE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp new file mode 100644 index 0000000000..9bad5503d9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp @@ -0,0 +1,602 @@ +// +// Copyright (c) 2013-2014 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. +// + +// formatutils9.cpp: Queries for GL image formats and their translations to D3D9 +// formats. + +#include "libANGLE/renderer/d3d/copyimage.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/d3d9/Renderer9.h" +#include "libANGLE/renderer/d3d/d3d9/vertexconversion.h" +#include "libANGLE/renderer/d3d/generatemip.h" +#include "libANGLE/renderer/d3d/loadimage.h" + +namespace rx +{ + +namespace d3d9 +{ + +const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); +const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); + +struct D3D9FastCopyFormat +{ + GLenum destFormat; + GLenum destType; + ColorCopyFunction copyFunction; + + D3D9FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) + : destFormat(destFormat), destType(destType), copyFunction(copyFunction) + { } + + bool operator<(const D3D9FastCopyFormat& other) const + { + return memcmp(this, &other, sizeof(D3D9FastCopyFormat)) < 0; + } +}; + +typedef std::multimap D3D9FastCopyMap; + +static D3D9FastCopyMap BuildFastCopyMap() +{ + D3D9FastCopyMap map; + + map.insert(std::make_pair(D3DFMT_A8R8G8B8, D3D9FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); + + return map; +} + +// A map to determine the pixel size and mip generation function of a given D3D format +typedef std::map D3D9FormatInfoMap; + +D3DFormat::D3DFormat() + : pixelBytes(0), + blockWidth(0), + blockHeight(0), + redBits(0), + greenBits(0), + blueBits(0), + alphaBits(0), + luminanceBits(0), + depthBits(0), + stencilBits(0), + internalFormat(GL_NONE), + mipGenerationFunction(NULL), + colorReadFunction(NULL), + fastCopyFunctions() +{ +} + +ColorCopyFunction D3DFormat::getFastCopyFunction(GLenum format, GLenum type) const +{ + FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); + return (iter != fastCopyFunctions.end()) ? iter->second : NULL; +} + +static inline void InsertD3DFormatInfo(D3D9FormatInfoMap *map, D3DFORMAT format, GLuint bits, GLuint blockWidth, + GLuint blockHeight, GLuint redBits, GLuint greenBits, GLuint blueBits, + GLuint alphaBits, GLuint lumBits, GLuint depthBits, GLuint stencilBits, + GLenum internalFormat, MipGenerationFunction mipFunc, + ColorReadFunction colorReadFunc) +{ + D3DFormat info; + info.pixelBytes = bits / 8; + info.blockWidth = blockWidth; + info.blockHeight = blockHeight; + info.redBits = redBits; + info.greenBits = greenBits; + info.blueBits = blueBits; + info.alphaBits = alphaBits; + info.luminanceBits = lumBits; + info.depthBits = depthBits; + info.stencilBits = stencilBits; + info.internalFormat = internalFormat; + info.mipGenerationFunction = mipFunc; + info.colorReadFunction = colorReadFunc; + + static const D3D9FastCopyMap fastCopyMap = BuildFastCopyMap(); + std::pair fastCopyIter = fastCopyMap.equal_range(format); + for (D3D9FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) + { + info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); + } + + map->insert(std::make_pair(format, info)); +} + +static D3D9FormatInfoMap BuildD3D9FormatInfoMap() +{ + D3D9FormatInfoMap map; + + // | D3DFORMAT | S |W |H | R | G | B | A | L | D | S | Internal format | Mip generation function | Color read function | + InsertD3DFormatInfo(&map, D3DFMT_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GL_NONE, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, GL_NONE, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_L8, 8, 1, 1, 0, 0, 0, 0, 8, 0, 0, GL_LUMINANCE8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A8, 8, 1, 1, 0, 0, 0, 8, 0, 0, 0, GL_ALPHA8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A8L8, 16, 1, 1, 0, 0, 0, 8, 8, 0, 0, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4, 16, 1, 1, 4, 4, 4, 4, 0, 0, 0, GL_BGRA4_ANGLEX, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5, 16, 1, 1, 5, 5, 5, 1, 0, 0, 0, GL_BGR5_A1_ANGLEX, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_R5G6B5, 16, 1, 1, 5, 6, 5, 0, 0, 0, 0, GL_RGB565, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_X8R8G8B8, 32, 1, 1, 8, 8, 8, 0, 0, 0, 0, GL_BGRA8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A8R8G8B8, 32, 1, 1, 8, 8, 8, 8, 0, 0, 0, GL_BGRA8_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_R16F, 16, 1, 1, 16, 0, 0, 0, 0, 0, 0, GL_R16F_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_G16R16F, 32, 1, 1, 16, 16, 0, 0, 0, 0, 0, GL_RG16F_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A16B16G16R16F, 64, 1, 1, 16, 16, 16, 16, 0, 0, 0, GL_RGBA16F_EXT, GenerateMip, ReadColor); + InsertD3DFormatInfo(&map, D3DFMT_R32F, 32, 1, 1, 32, 0, 0, 0, 0, 0, 0, GL_R32F_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_G32R32F, 64, 1, 1, 32, 32, 0, 0, 0, 0, 0, GL_RG32F_EXT, GenerateMip, ReadColor ); + InsertD3DFormatInfo(&map, D3DFMT_A32B32G32R32F, 128, 1, 1, 32, 32, 32, 32, 0, 0, 0, GL_RGBA32F_EXT, GenerateMip, ReadColor); + + InsertD3DFormatInfo(&map, D3DFMT_D16, 16, 1, 1, 0, 0, 0, 0, 0, 16, 0, GL_DEPTH_COMPONENT16, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D24S8, 32, 1, 1, 0, 0, 0, 0, 0, 24, 8, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D24X8, 32, 1, 1, 0, 0, 0, 0, 0, 24, 0, GL_DEPTH_COMPONENT16, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_D32, 32, 1, 1, 0, 0, 0, 0, 0, 32, 0, GL_DEPTH_COMPONENT32_OES, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_INTZ, 32, 1, 1, 0, 0, 0, 0, 0, 24, 8, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); + + InsertD3DFormatInfo(&map, D3DFMT_DXT1, 64, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_DXT3, 128, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL, NULL ); + InsertD3DFormatInfo(&map, D3DFMT_DXT5, 128, 4, 4, 0, 0, 0, 0, 0, 0, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL, NULL ); + + return map; +} + +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format) +{ + static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); + D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); + if (iter != infoMap.end()) + { + return iter->second; + } + else + { + static const D3DFormat defaultInfo; + return defaultInfo; + } +} + + + +typedef std::pair InternalFormatInitialzerPair; +typedef std::map InternalFormatInitialzerMap; + +static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() +{ + InternalFormatInitialzerMap map; + + map.insert(InternalFormatInitialzerPair(GL_RGB16F, Initialize4ComponentData)); + map.insert(InternalFormatInitialzerPair(GL_RGB32F, Initialize4ComponentData)); + + return map; +} + +// Each GL internal format corresponds to one D3D format and data loading function. +// Due to not all formats being available all the time, some of the function/format types are wrapped +// in templates that perform format support queries on a Renderer9 object which is supplied +// when requesting the function or format. + +typedef bool(*FallbackPredicateFunction)(); + +template +static void FallbackLoad(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + if (pred()) + { + prefered(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); + } + else + { + fallback(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); + } +} + +static void UnreachableLoad(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + UNREACHABLE(); +} + +typedef std::pair D3D9FormatPair; +typedef std::map D3D9FormatMap; + +TextureFormat::TextureFormat() + : texFormat(D3DFMT_UNKNOWN), + renderFormat(D3DFMT_UNKNOWN), + dataInitializerFunction(NULL), + loadFunction(UnreachableLoad) +{ +} + +static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalFormat, D3DFORMAT texFormat, + D3DFORMAT renderFormat, LoadImageFunction loadFunction) +{ + TextureFormat info; + info.texFormat = texFormat; + info.renderFormat = renderFormat; + + static const InternalFormatInitialzerMap dataInitializationMap = BuildInternalFormatInitialzerMap(); + InternalFormatInitialzerMap::const_iterator dataInitIter = dataInitializationMap.find(internalFormat); + info.dataInitializerFunction = (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : NULL; + + info.loadFunction = loadFunction; + + map->insert(std::make_pair(internalFormat, info)); +} + +static D3D9FormatMap BuildD3D9FormatMap() +{ + D3D9FormatMap map; + + // | Internal format | Texture format | Render format | Load function | + InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ); + + // We choose to downsample the GL_DEPTH_COMPONENT32_OES format to a 24-bit format because D3DFMT_D32 is not widely + // supported. We're allowed to do this because: + // - The ES spec 2.0.25 sec 3.7.1 states that we're allowed to store texture formats with internal format + // resolutions of our own choosing. + // - OES_depth_texture states that downsampling of the depth formats is allowed. + // - ANGLE_depth_texture does not state minimum required resolutions of the depth texture formats it + // introduces. + // In ES3 however, there are minimum resolutions for the texture formats and this would not be allowed. + + InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT16, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, D3DFMT_INTZ, D3DFMT_D24X8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_DEPTH24_STENCIL8_OES, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); + InsertD3D9FormatInfo(&map, GL_STENCIL_INDEX8, D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ); // TODO: What's the texture format? + + InsertD3D9FormatInfo(&map, GL_RGBA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_RGB32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4); + InsertD3D9FormatInfo(&map, GL_RG32F_EXT, D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_R32F_EXT, D3DFMT_R32F, D3DFMT_R32F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F ); + + InsertD3D9FormatInfo(&map, GL_RGBA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_RGB16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4 ); + InsertD3D9FormatInfo(&map, GL_RG16F_EXT, D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_R16F_EXT, D3DFMT_R16F, D3DFMT_R16F, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F ); + + InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad); + + InsertD3D9FormatInfo(&map, GL_RGB8_OES, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 ); + InsertD3D9FormatInfo(&map, GL_RGB565, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad); + InsertD3D9FormatInfo(&map, GL_RGBA4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_RGB5_A1, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_R8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 ); + InsertD3D9FormatInfo(&map, GL_RG8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 ); + + InsertD3D9FormatInfo(&map, GL_BGRA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_BGRA4_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 ); + InsertD3D9FormatInfo(&map, GL_BGR5_A1_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 ); + + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ); + InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ); + + // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and + // then changing the format and loading function appropriately. + InsertD3D9FormatInfo(&map, GL_LUMINANCE8_EXT, D3DFMT_L8, D3DFMT_UNKNOWN, LoadToNative ); + InsertD3D9FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, D3DFMT_A8L8, D3DFMT_UNKNOWN, LoadToNative ); + + return map; +} + +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat) +{ + static const D3D9FormatMap formatMap = BuildD3D9FormatMap(); + D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat); + if (iter != formatMap.end()) + { + return iter->second; + } + else + { + static const TextureFormat defaultInfo; + return defaultInfo; + } +} + +static GLenum GetDeclTypeComponentType(D3DDECLTYPE declType) +{ + switch (declType) + { + case D3DDECLTYPE_FLOAT1: return GL_FLOAT; + case D3DDECLTYPE_FLOAT2: return GL_FLOAT; + case D3DDECLTYPE_FLOAT3: return GL_FLOAT; + case D3DDECLTYPE_FLOAT4: return GL_FLOAT; + case D3DDECLTYPE_UBYTE4: return GL_UNSIGNED_INT; + case D3DDECLTYPE_SHORT2: return GL_INT; + case D3DDECLTYPE_SHORT4: return GL_INT; + case D3DDECLTYPE_UBYTE4N: return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT4N: return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT4N: return GL_UNSIGNED_NORMALIZED; + case D3DDECLTYPE_SHORT2N: return GL_SIGNED_NORMALIZED; + case D3DDECLTYPE_USHORT2N: return GL_UNSIGNED_NORMALIZED; + default: UNREACHABLE(); return GL_NONE; + } +} + +// Attribute format conversion +enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; + +struct TranslationDescription +{ + DWORD capsFlag; + VertexFormat preferredConversion; + VertexFormat fallbackConversion; +}; + +// 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 : NoWiden { }; +template struct WidenRule : WidenToEven { }; +template struct WidenRule : WidenToEven { }; +template struct WidenRule : WidenToFour { }; +template struct WidenRule : WidenToFour { }; +template struct WidenRule : 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 : Cast::type, typename D3DToCType::type> { }; + +// All conversions from normalized types to float use the Normalize operator. +template struct ConversionRule : Normalize::type> { }; + +// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules. +template <> struct ConversionRule : FixedToFloat { }; +template <> struct ConversionRule : 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 : NormalizedDefaultValues { }; +template struct DefaultVertexValuesStage2 : SimpleDefaultValues { }; + +// Work out the default value rule for a D3D type (expressed as the C type) and +template struct DefaultVertexValues : DefaultVertexValuesStage2 { }; +template struct DefaultVertexValues : 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 + : 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 }; +}; + +VertexFormat::VertexFormat() + : conversionType(VERTEX_CONVERT_NONE), + outputElementSize(0), + copyFunction(NULL), + nativeFormat(D3DDECLTYPE_UNUSED), + componentType(GL_NONE) +{ +} + +// Initialize a TranslationInfo +VertexFormat CreateVertexFormatInfo(bool identity, size_t elementSize, VertexCopyFunction copyFunc, D3DDECLTYPE nativeFormat) +{ + VertexFormat formatInfo; + formatInfo.conversionType = identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU; + formatInfo.outputElementSize = elementSize; + formatInfo.copyFunction = copyFunc; + formatInfo.nativeFormat = nativeFormat; + formatInfo.componentType = GetDeclTypeComponentType(nativeFormat); + return formatInfo; +} + +#define TRANSLATION(type, norm, size, preferred) \ + CreateVertexFormatInfo \ + ( \ + 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) }, \ + } + +static inline unsigned int ComputeTypeIndex(GLenum type) +{ + 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; + } +} + +const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat) +{ + static bool initialized = false; + static DWORD intializedDeclTypes = 0; + static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; + if (intializedDeclTypes != supportedDeclTypes) + { + const TranslationDescription translations[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) + }; + 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 (translations[i][j][k].capsFlag == 0 || (supportedDeclTypes & translations[i][j][k].capsFlag) != 0) + { + formatConverters[i][j][k] = translations[i][j][k].preferredConversion; + } + else + { + formatConverters[i][j][k] = translations[i][j][k].fallbackConversion; + } + } + } + } + initialized = true; + intializedDeclTypes = supportedDeclTypes; + } + + // Pure integer attributes only supported in ES3.0 + ASSERT(!vertexFormat.mPureInteger); + return formatConverters[ComputeTypeIndex(vertexFormat.mType)][vertexFormat.mNormalized][vertexFormat.mComponents - 1]; +} + +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h new file mode 100644 index 0000000000..15e26599c8 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/formatutils9.h @@ -0,0 +1,86 @@ +// +// Copyright (c) 2013-2014 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. +// + +// formatutils9.h: Queries for GL image formats and their translations to D3D9 +// formats. + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ + +#include "libANGLE/renderer/d3d/formatutilsD3D.h" +#include "libANGLE/angletypes.h" + +#include "common/platform.h" + +#include + +namespace rx +{ + +class Renderer9; + +namespace d3d9 +{ + +typedef std::map, ColorCopyFunction> FastCopyFunctionMap; + +struct D3DFormat +{ + D3DFormat(); + + GLuint pixelBytes; + GLuint blockWidth; + GLuint blockHeight; + + GLuint redBits; + GLuint greenBits; + GLuint blueBits; + GLuint alphaBits; + GLuint luminanceBits; + + GLuint depthBits; + GLuint stencilBits; + + GLenum internalFormat; + + MipGenerationFunction mipGenerationFunction; + ColorReadFunction colorReadFunction; + + FastCopyFunctionMap fastCopyFunctions; + ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; +}; +const D3DFormat &GetD3DFormatInfo(D3DFORMAT format); + +struct VertexFormat +{ + VertexFormat(); + + VertexConversionType conversionType; + size_t outputElementSize; + VertexCopyFunction copyFunction; + D3DDECLTYPE nativeFormat; + GLenum componentType; +}; +const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat); + +struct TextureFormat +{ + TextureFormat(); + + D3DFORMAT texFormat; + D3DFORMAT renderFormat; + + InitializeTextureDataFunction dataInitializerFunction; + + LoadImageFunction loadFunction; +}; +const TextureFormat &GetTextureFormatInfo(GLenum internalFormat); + +} + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_FORMATUTILS9_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp new file mode 100644 index 0000000000..c9711ac052 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp @@ -0,0 +1,597 @@ +// +// Copyright (c) 2002-2014 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. +// + +// renderer9_utils.cpp: Conversion functions and other utility routines +// specific to the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/d3d/FramebufferD3D.h" +#include "libANGLE/renderer/Workarounds.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" + +#include "common/mathutil.h" +#include "common/debug.h" + +#include "third_party/systeminfo/SystemInfo.h" + +namespace rx +{ + +namespace gl_d3d9 +{ + +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::ColorF 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; + case GL_MIN_EXT: d3dBlendOp = D3DBLENDOP_MIN; break; + case GL_MAX_EXT: d3dBlendOp = D3DBLENDOP_MAX; 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; + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) +{ + return (samples > 1) ? static_cast(samples) : D3DMULTISAMPLE_NONE; +} + +} + +namespace d3d9_gl +{ + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) +{ + return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).internalFormat; + GLenum convertedFormat = gl::GetInternalFormatInfo(internalFormat).format; + return convertedFormat == format; +} + +static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3D9 *d3d9, D3DDEVTYPE deviceType, + UINT adapter, D3DFORMAT adapterFormat) +{ + gl::TextureCaps textureCaps; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat); + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + + if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN) + { + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + else + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat)); + } + + textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + + if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN) + { + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + + if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) && !textureCaps.renderable) + { + textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + } + + textureCaps.sampleCounts.insert(1); + for (size_t i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++) + { + D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); + + HRESULT result = d3d9->CheckDeviceMultiSampleType(adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, NULL); + if (SUCCEEDED(result)) + { + textureCaps.sampleCounts.insert(i); + } + } + } + + return textureCaps; +} + +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) +{ + D3DCAPS9 deviceCaps; + if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) + { + // Can't continue with out device caps + return; + } + + D3DDISPLAYMODE currentDisplayMode; + d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); + + GLuint maxSamples = 0; + const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); + for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, + currentDisplayMode.Format); + textureCapsMap->insert(*internalFormat, textureCaps); + + maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + + if (gl::GetInternalFormatInfo(*internalFormat).compressed) + { + caps->compressedTextureFormats.push_back(*internalFormat); + } + } + + // GL core feature limits + caps->maxElementIndex = static_cast(std::numeric_limits::max()); + + // 3D textures are unimplemented in D3D9 + caps->max3DTextureSize = 1; + + // Only one limit in GL, use the minimum dimension + caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight); + + // D3D treats cube maps as a special case of 2D textures + caps->maxCubeMapTextureSize = caps->max2DTextureSize; + + // Array textures are not available in D3D9 + caps->maxArrayTextureLayers = 1; + + // ES3-only feature + caps->maxLODBias = 0.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Draw buffers are not supported in D3D9 + caps->maxDrawBuffers = 1; + caps->maxColorAttachments = 1; + + // No specific limits on viewport size, maximum 2D texture size is equivalent + caps->maxViewportWidth = caps->max2DTextureSize; + caps->maxViewportHeight = caps->maxViewportWidth; + + // Point size is clamped to 1.0f when the shader model is less than 3 + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize : 1.0f); + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // Primitive count limits (unused in ES2) + caps->maxElementsIndices = 0; + caps->maxElementsVertices = 0; + + // Program and shader binary formats (no supported shader binary formats) + caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); + + caps->vertexHighpFloat.setIEEEFloat(); + caps->vertexMediumpFloat.setIEEEFloat(); + caps->vertexLowpFloat.setIEEEFloat(); + caps->fragmentHighpFloat.setIEEEFloat(); + caps->fragmentMediumpFloat.setIEEEFloat(); + caps->fragmentLowpFloat.setIEEEFloat(); + + // Some (most) hardware only supports single-precision floating-point numbers, + // which can accurately represent integers up to +/-16777216 + caps->vertexHighpInt.setSimulatedInt(24); + caps->vertexMediumpInt.setSimulatedInt(24); + caps->vertexLowpInt.setSimulatedInt(24); + caps->fragmentHighpInt.setSimulatedInt(24); + caps->fragmentMediumpInt.setSimulatedInt(24); + caps->fragmentLowpInt.setSimulatedInt(24); + + // WaitSync is ES3-only, set to zero + caps->maxServerWaitTimeout = 0; + + // Vertex shader limits + caps->maxVertexAttributes = 16; + + const size_t reservedVertexUniformVectors = 2; // dx_ViewAdjust and dx_DepthRange. + const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; + caps->maxVertexUniformVectors = MAX_VERTEX_CONSTANT_VECTORS_D3D9 - reservedVertexUniformVectors; + caps->maxVertexUniformComponents = caps->maxVertexUniformVectors * 4; + + caps->maxVertexUniformBlocks = 0; + + // SM3 only supports 11 output variables, with a special 12th register for PSIZE. + const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 9; + const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 7; + caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3 + : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4; + + // Only Direct3D 10 ready devices support all the necessary vertex texture formats. + // We test this using D3D9 by checking support for the R16F format. + if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F))) + { + const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4; + caps->maxVertexTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3; + } + else + { + caps->maxVertexTextureImageUnits = 0; + } + + // Fragment shader limits + const size_t reservedPixelUniformVectors = 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. + + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224; + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32; + caps->maxFragmentUniformVectors = ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 + : MAX_PIXEL_CONSTANT_VECTORS_SM2) - reservedPixelUniformVectors; + caps->maxFragmentUniformComponents = caps->maxFragmentUniformVectors * 4; + caps->maxFragmentUniformBlocks = 0; + caps->maxFragmentInputComponents = caps->maxVertexOutputComponents; + caps->maxTextureImageUnits = 16; + caps->minProgramTexelOffset = 0; + caps->maxProgramTexelOffset = 0; + + // Aggregate shader limits (unused in ES2) + caps->maxUniformBufferBindings = 0; + caps->maxUniformBlockSize = 0; + caps->uniformBufferOffsetAlignment = 0; + caps->maxCombinedUniformBlocks = 0; + caps->maxCombinedVertexUniformComponents = 0; + caps->maxCombinedFragmentUniformComponents = 0; + caps->maxVaryingComponents = 0; + + // Aggregate shader limits + caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4; + caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = 0; + caps->maxTransformFeedbackSeparateAttributes = 0; + caps->maxTransformFeedbackSeparateComponents = 0; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16); + extensions->packedDepthStencil = true; + extensions->getProgramBinary = true; + extensions->rgb8rgba8 = true; + extensions->readFormatBGRA = true; + extensions->pixelBufferObject = false; + extensions->mapBuffer = false; + extensions->mapBufferRange = false; + + // textureRG is emulated and not performant. + extensions->textureRG = false; + + D3DADAPTER_IDENTIFIER9 adapterId = { 0 }; + if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) + { + // ATI cards on XP have problems with non-power-of-two textures. + extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(!isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); + + // Disable depth texture support on AMD cards (See ANGLE issue 839) + if (adapterId.VendorId == VENDOR_ID_AMD) + { + extensions->depthTextures = false; + } + } + else + { + extensions->textureNPOT = false; + } + + extensions->drawBuffers = false; + extensions->textureStorage = true; + + // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec + extensions->textureFilterAnisotropic = (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2; + extensions->maxTextureAnisotropy = static_cast(deviceCaps.MaxAnisotropy); + + // Check occlusion query support by trying to create one + IDirect3DQuery9 *occlusionQuery = NULL; + extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; + SafeRelease(occlusionQuery); + + // Check event query support by trying to create one + IDirect3DQuery9 *eventQuery = NULL; + extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; + SafeRelease(eventQuery); + + extensions->timerQuery = false; // Unimplemented + extensions->robustness = true; + extensions->blendMinMax = true; + extensions->framebufferBlit = true; + extensions->framebufferMultisample = true; + extensions->maxSamples = maxSamples; + extensions->instancedArrays = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + extensions->packReverseRowOrder = true; + extensions->standardDerivatives = (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; + extensions->shaderTextureLOD = true; + extensions->fragDepth = true; + extensions->textureUsage = true; + extensions->translatedShaderSource = true; + extensions->colorBufferFloat = false; +} + +} + +namespace d3d9 +{ + +GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height) +{ + const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); + GLuint numBlocksWide = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth; + GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight; + return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight); +} + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) +{ + const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); + + int upsampleCount = 0; + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < static_cast(d3dFormatInfo.blockWidth) || + *requestHeight < static_cast(d3dFormatInfo.blockHeight)) + { + while (*requestWidth % d3dFormatInfo.blockWidth != 0 || *requestHeight % d3dFormatInfo.blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget9 **outRT) +{ + RenderTargetD3D *renderTarget = NULL; + gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + *outRT = RenderTarget9::makeRenderTarget9(renderTarget); + return gl::Error(GL_NO_ERROR); +} + +Workarounds GenerateWorkarounds() +{ + Workarounds workarounds; + workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = false; + workarounds.useInstancedPointSpriteEmulation = false; + return workarounds; +} + +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h new file mode 100644 index 0000000000..3c6a57aee3 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h @@ -0,0 +1,86 @@ +// +// Copyright (c) 2002-2014 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. +// + +// renderer9_utils.h: Conversion functions and other utility routines +// specific to the D3D9 renderer + +#ifndef LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ + +#include "libANGLE/angletypes.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Error.h" + +namespace gl +{ +class FramebufferAttachment; +} + +namespace rx +{ +class RenderTarget9; +struct Workarounds; + +namespace gl_d3d9 +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison); +D3DCOLOR ConvertColor(gl::ColorF 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); + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples); + +} + +namespace d3d9_gl +{ + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type); + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); + +void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); + +} + +namespace d3d9 +{ + +GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height); + +void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); + +inline bool isDeviceLostError(HRESULT errorCode) +{ + switch (errorCode) + { + case D3DERR_DRIVERINTERNALERROR: + case D3DERR_DEVICELOST: + case D3DERR_DEVICEHUNG: + case D3DERR_DEVICEREMOVED: + return true; + default: + return false; + } +} + +gl::Error GetAttachmentRenderTarget(const gl::FramebufferAttachment *attachment, RenderTarget9 **outRT); +Workarounds GenerateWorkarounds(); + +} + +} + +#endif // LIBANGLE_RENDERER_D3D_D3D9_RENDERER9UTILS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps new file mode 100644 index 0000000000..dc357d0fa6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps @@ -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. +// + +sampler2D tex : s0; + +uniform float4 mult : c0; +uniform float4 add : c1; + +// 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 +// Performs a mad operation using the LA data from the texture with mult.xw and add.xw. +// Returns data in the form of llla +float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR +{ + return (tex2D(tex, texcoord.xy).xw * mult.xw + add.xw).xxxy; +}; + +// RGB/A Component Mask Pixel Shader +// Performs a mad operation using the texture's RGBA data with mult.xyzw and add.xyzw. +// Returns data in the form of rgba +float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR +{ + return tex2D(tex, texcoord.xy) * mult + add; +}; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs new file mode 100644 index 0000000000..3a36980b93 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/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/libANGLE/renderer/d3d/d3d9/vertexconversion.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h new file mode 100644 index 0000000000..32eb376a78 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/vertexconversion.h @@ -0,0 +1,197 @@ +// +// 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 LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ +#define LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ + +#include +#include +#include + +namespace rx +{ + +// 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 uint8_t *input, size_t stride, size_t n, uint8_t *output) + { + OutputType *out = reinterpret_cast(output); + + for (std::size_t i = 0; i < n; i++) + { + const InputType *ein = reinterpret_cast(input + 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; + } + } + + private: + 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 // LIBANGLE_RENDERER_D3D_D3D9_VERTEXCONVERSION_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp new file mode 100644 index 0000000000..8a4d41cbd9 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.cpp @@ -0,0 +1,147 @@ +// +// Copyright (c) 2015 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. +// + +// formatutils9.cpp: Queries for GL image formats and their translations to D3D +// formats. + +#include "libANGLE/renderer/d3d/formatutilsD3D.h" + +#include + +#include "common/debug.h" +#include "libANGLE/renderer/d3d/imageformats.h" +#include "libANGLE/renderer/d3d/copyimage.h" + +namespace rx +{ + +typedef std::pair FormatTypePair; +typedef std::pair FormatWriteFunctionPair; +typedef std::map FormatWriteFunctionMap; + +static inline void InsertFormatWriteFunctionMapping(FormatWriteFunctionMap *map, GLenum format, GLenum type, + ColorWriteFunction writeFunc) +{ + map->insert(FormatWriteFunctionPair(FormatTypePair(format, type), writeFunc)); +} + +static FormatWriteFunctionMap BuildFormatWriteFunctionMap() +{ + FormatWriteFunctionMap map; + + // | Format | Type | Color write function | + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_FLOAT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_HALF_FLOAT, WriteColor); + InsertFormatWriteFunctionMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, WriteColor); + + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RGB_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG, GL_HALF_FLOAT_OES, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RG_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED, GL_HALF_FLOAT_OES, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_SHORT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_RED_INTEGER, GL_INT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_HALF_FLOAT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, WriteColor ); + InsertFormatWriteFunctionMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, WriteColor ); + + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, NULL ); + + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, NULL ); + + InsertFormatWriteFunctionMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, NULL ); + + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL ); + InsertFormatWriteFunctionMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL ); + + return map; +} + +ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type) +{ + static const FormatWriteFunctionMap formatTypeMap = BuildFormatWriteFunctionMap(); + FormatWriteFunctionMap::const_iterator iter = formatTypeMap.find(FormatTypePair(format, type)); + ASSERT(iter != formatTypeMap.end()); + if (iter != formatTypeMap.end()) + { + return iter->second; + } + else + { + return NULL; + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h new file mode 100644 index 0000000000..6dd59ca94b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/formatutilsD3D.h @@ -0,0 +1,50 @@ +// +// Copyright (c) 2015 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. +// + +// formatutils9.h: Queries for GL image formats and their translations to D3D +// formats. + +#ifndef LIBANGLE_RENDERER_D3D_FORMATUTILSD3D_H_ +#define LIBANGLE_RENDERER_D3D_FORMATUTILSD3D_H_ + +#include "angle_gl.h" + +#include +#include + +namespace rx +{ + +typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +typedef void (*LoadImageFunction)(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +typedef void (*InitializeTextureDataFunction)(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +typedef void (*ColorReadFunction)(const uint8_t *source, uint8_t *dest); +typedef void (*ColorWriteFunction)(const uint8_t *source, uint8_t *dest); +typedef void (*ColorCopyFunction)(const uint8_t *source, uint8_t *dest); + +typedef void (*VertexCopyFunction)(const uint8_t *input, size_t stride, size_t count, uint8_t *output); + +enum VertexConversionType +{ + VERTEX_CONVERT_NONE = 0, + VERTEX_CONVERT_CPU = 1, + VERTEX_CONVERT_GPU = 2, + VERTEX_CONVERT_BOTH = 3 +}; + +ColorWriteFunction GetColorWriteFunction(GLenum format, GLenum type); + +} + +#endif // LIBANGLE_RENDERER_D3D_FORMATUTILSD3D_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h new file mode 100644 index 0000000000..398ef26b30 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2002-2015 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. +// + +// generatemip.h: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#ifndef LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ +#define LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ + +#include "libANGLE/renderer/d3d/imageformats.h" +#include "libANGLE/angletypes.h" + +namespace rx +{ + +template +inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +} + +#include "generatemip.inl" + +#endif // LIBANGLE_RENDERER_D3D_GENERATEMIP_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl new file mode 100644 index 0000000000..265783641e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/generatemip.inl @@ -0,0 +1,266 @@ +// +// Copyright (c) 2015 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. +// + +// generatemip.inl: Defines the GenerateMip function, templated on the format +// type of the image for which mip levels are being generated. + +#include "common/mathutil.h" + +namespace rx +{ + +namespace priv +{ + +template +static inline T *GetPixel(uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template +static inline const T *GetPixel(const uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); +} + +template +static void GenerateMip_Y(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel(sourceData, 0, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, y, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_X(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth == 1); + + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, 0, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2 + 1, 0, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, 0, 0, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_Z(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + const T *src0 = GetPixel(sourceData, 0, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, 0, z, destRowPitch, destDepthPitch); + + T::average(dst, src0, src1); + } +} + +template +static void GenerateMip_XY(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth == 1); + + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2 + 1, y * 2, 0, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, y, 0, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_YZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth == 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + const T *src0 = GetPixel(sourceData, 0, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, 0, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, 0, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, 0, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, 0, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_XZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight == 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2 + 1, 0, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2 + 1, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, 0, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(dst, &tmp0, &tmp1); + } + } +} + +template +static void GenerateMip_XYZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + ASSERT(sourceWidth > 1); + ASSERT(sourceHeight > 1); + ASSERT(sourceDepth > 1); + + for (size_t z = 0; z < destDepth; z++) + { + for (size_t y = 0; y < destHeight; y++) + { + for (size_t x = 0; x < destWidth; x++) + { + const T *src0 = GetPixel(sourceData, x * 2, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src1 = GetPixel(sourceData, x * 2, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src2 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src3 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src4 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src5 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + const T *src6 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); + const T *src7 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); + T *dst = GetPixel(destData, x, y, z, destRowPitch, destDepthPitch); + + T tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + + T::average(&tmp0, src0, src1); + T::average(&tmp1, src2, src3); + T::average(&tmp2, src4, src5); + T::average(&tmp3, src6, src7); + + T::average(&tmp4, &tmp0, &tmp1); + T::average(&tmp5, &tmp2, &tmp3); + + T::average(dst, &tmp4, &tmp5); + } + } + } +} + + +typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + size_t destWidth, size_t destHeight, size_t destDepth, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); + +template +static MipGenerationFunction GetMipGenerationFunction(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth) +{ + uint8_t index = ((sourceWidth > 1) ? 1 : 0) | + ((sourceHeight > 1) ? 2 : 0) | + ((sourceDepth > 1) ? 4 : 0); + + switch (index) + { + case 0: return NULL; + case 1: return GenerateMip_X; // W x 1 x 1 + case 2: return GenerateMip_Y; // 1 x H x 1 + case 3: return GenerateMip_XY; // W x H x 1 + case 4: return GenerateMip_Z; // 1 x 1 x D + case 5: return GenerateMip_XZ; // W x 1 x D + case 6: return GenerateMip_YZ; // 1 x H x D + case 7: return GenerateMip_XYZ; // W x H x D + } + + UNREACHABLE(); + return NULL; +} + +} + +template +inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, + const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, + uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) +{ + size_t mipWidth = std::max(1, sourceWidth >> 1); + size_t mipHeight = std::max(1, sourceHeight >> 1); + size_t mipDepth = std::max(1, sourceDepth >> 1); + + priv::MipGenerationFunction generationFunction = priv::GetMipGenerationFunction(sourceWidth, sourceHeight, sourceDepth); + ASSERT(generationFunction != NULL); + + generationFunction(sourceWidth, sourceHeight, sourceDepth, sourceData, sourceRowPitch, sourceDepthPitch, + mipWidth, mipHeight, mipDepth, destData, destRowPitch, destDepthPitch); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h new file mode 100644 index 0000000000..e0f9a16c1a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/imageformats.h @@ -0,0 +1,2031 @@ +// +// Copyright (c) 2013-2015 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. +// + +// imageformats.h: Defines image format types with functions for mip generation +// and copying. + +#ifndef LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ +#define LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ + +#include "libANGLE/angletypes.h" + +#include "common/mathutil.h" + +namespace rx +{ + +// Several structures share functionality for reading, writing or mipmapping but the layout +// must match the texture format which the structure represents. If collapsing or typedefing +// structs in this header, make sure the functionality and memory layout is exactly the same. + +struct L8 +{ + unsigned char L; + + static void readColor(gl::ColorF *dst, const L8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; + } + + static void writeColor(L8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); + } + + static void average(L8 *dst, const L8 *src1, const L8 *src2) + { + dst->L = gl::average(src1->L, src2->L); + } +}; + +struct R8 +{ + unsigned char R; + + static void readColor(gl::ColorF *dst, const R8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R8 *dst, const R8 *src1, const R8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct A8 +{ + unsigned char A; + + static void readColor(gl::ColorF *dst, const A8 *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(A8 *dst, const gl::ColorF *src) + { + dst->A = gl::floatToNormalized(src->alpha); + } + + static void average(A8 *dst, const A8 *src1, const A8 *src2) + { + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct L8A8 +{ + unsigned char L; + unsigned char A; + + static void readColor(gl::ColorF *dst, const L8A8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(L8A8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct A8L8 +{ + unsigned char A; + unsigned char L; + + static void readColor(gl::ColorF *dst, const A8L8 *src) + { + const float lum = gl::normalizedToFloat(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void writeColor(A8L8 *dst, const gl::ColorF *src) + { + dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::floatToNormalized(src->alpha); + } + + 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 R8G8 +{ + unsigned char R; + unsigned char G; + + static void readColor(gl::ColorF *dst, const R8G8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8G8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8G8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R8G8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2) + { + *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); + } +}; + +struct R8G8B8 +{ + unsigned char R; + unsigned char G; + unsigned char B; + + static void readColor(gl::ColorF *dst, const R8G8B8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R8G8B8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; + } + + static void writeColor(R8G8B8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R8G8B8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct B8G8R8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + + static void readColor(gl::ColorF *dst, const B8G8R8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const B8G8R8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->G; + dst->alpha = 1; + } + + static void writeColor(B8G8R8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(B8G8R8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R5G6B5 +{ + unsigned short RGB; + + static void readColor(gl::ColorF *dst, const R5G6B5 *src) + { + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGB)); + dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->RGB)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGB)); + dst->alpha = 1.0f; + } + + static void writeColor(R5G6B5 *dst, const gl::ColorF *src) + { + dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)) | + gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); + } + + static void average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2) + { + dst->RGB = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGB), gl::getShiftedData<5, 11>(src2->RGB))) | + gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->RGB), gl::getShiftedData<6, 5>(src2->RGB))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGB), gl::getShiftedData<5, 0>(src2->RGB))); + } +}; + +struct A8R8G8B8 +{ + unsigned char A; + unsigned char R; + unsigned char G; + unsigned char B; + + static void readColor(gl::ColorF *dst, const A8R8G8B8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const A8R8G8B8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(A8R8G8B8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(A8R8G8B8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + 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 R8G8B8A8 +{ + unsigned char R; + unsigned char G; + unsigned char B; + unsigned char A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R8G8B8A8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R8G8B8A8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R8G8B8A8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct B8G8R8A8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + unsigned char A; + + static void readColor(gl::ColorF *dst, const B8G8R8A8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const B8G8R8A8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(B8G8R8A8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(B8G8R8A8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + } +}; + +struct B8G8R8X8 +{ + unsigned char B; + unsigned char G; + unsigned char R; + unsigned char X; + + static void readColor(gl::ColorF *dst, const B8G8R8X8 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const B8G8R8X8 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(B8G8R8X8 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->X = 255; + } + + static void writeColor(B8G8R8X8 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->X = 255; + } + + static void average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2) + { + *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); + dst->X = 255; + } +}; + +struct B5G5R5A1 +{ + unsigned short BGRA; + + static void readColor(gl::ColorF *dst, const B5G5R5A1 *src) + { + dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->BGRA)); + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->BGRA)); + dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->BGRA)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->BGRA)); + } + + static void writeColor(B5G5R5A1 *dst, const gl::ColorF *src) + { + dst->BGRA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) | + gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->red)) | + gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); + } + + static void average(B5G5R5A1 *dst, const B5G5R5A1 *src1, const B5G5R5A1 *src2) + { + dst->BGRA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->BGRA), gl::getShiftedData<1, 15>(src2->BGRA))) | + gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->BGRA), gl::getShiftedData<5, 10>(src2->BGRA))) | + gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->BGRA), gl::getShiftedData<5, 5>(src2->BGRA))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->BGRA), gl::getShiftedData<5, 0>(src2->BGRA))); + } +}; + +struct R5G5B5A1 +{ + unsigned short RGBA; + + static void readColor(gl::ColorF *dst, const R5G5B5A1 *src) + { + dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->RGBA)); + dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->RGBA)); + dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->RGBA)); + dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGBA)); + } + + static void writeColor(R5G5B5A1 *dst, const gl::ColorF *src) + { + dst->RGBA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) | + gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->blue)) | + gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) | + gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->red)); + } + + static void average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2) + { + dst->RGBA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->RGBA), gl::getShiftedData<1, 15>(src2->RGBA))) | + gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->RGBA), gl::getShiftedData<5, 10>(src2->RGBA))) | + gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->RGBA), gl::getShiftedData<5, 5>(src2->RGBA))) | + gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGBA), gl::getShiftedData<5, 0>(src2->RGBA))); + } +}; + +struct R4G4B4A4 +{ + unsigned char R : 4; + unsigned char G : 4; + unsigned char B : 4; + unsigned char A : 4; + + static void readColor(gl::ColorF *dst, const R4G4B4A4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(R4G4B4A4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct A4R4G4B4 +{ + unsigned char A : 4; + unsigned char R : 4; + unsigned char G : 4; + unsigned char B : 4; + + static void readColor(gl::ColorF *dst, const A4R4G4B4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct B4G4R4A4 +{ + unsigned char B : 4; + unsigned char G : 4; + unsigned char R : 4; + unsigned char A : 4; + + static void readColor(gl::ColorF *dst, const B4G4R4A4 *src) + { + dst->red = gl::normalizedToFloat<4>(src->R); + dst->green = gl::normalizedToFloat<4>(src->G); + dst->blue = gl::normalizedToFloat<4>(src->B); + dst->alpha = gl::normalizedToFloat<4>(src->A); + } + + static void writeColor(B4G4R4A4 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<4, unsigned char>(src->red); + dst->G = gl::floatToNormalized<4, unsigned char>(src->green); + dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); + dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); + } + + static void average(B4G4R4A4 *dst, const B4G4R4A4 *src1, const B4G4R4A4 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R16 +{ + unsigned short R; + + static void readColor(gl::ColorF *dst, const R16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R16 *dst, const R16 *src1, const R16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R16G16 +{ + unsigned short R; + unsigned short G; + + static void readColor(gl::ColorF *dst, const R16G16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16G16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16G16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R16G16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R16G16B16 +{ + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const R16G16B16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R16G16B16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R16G16B16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R16G16B16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R16G16B16A16 +{ + unsigned short R; + unsigned short G; + unsigned short B; + unsigned short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R16G16B16A16 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R16G16B16A16 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R16G16B16A16 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32 +{ + unsigned int R; + + static void readColor(gl::ColorF *dst, const R32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32 *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R32 *dst, const R32 *src1, const R32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R32G32 +{ + unsigned int R; + unsigned int G; + + static void readColor(gl::ColorF *dst, const R32G32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32G32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32G32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R32G32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32 +{ + unsigned int R; + unsigned int G; + unsigned int B; + + static void readColor(gl::ColorF *dst, const R32G32B32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorUI *dst, const R32G32B32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R32G32B32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R32G32B32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R32G32B32A32 +{ + unsigned int R; + unsigned int G; + unsigned int B; + unsigned int A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32 *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorUI *dst, const R32G32B32A32 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R32G32B32A32 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R8S +{ + char R; + + static void readColor(gl::ColorF *dst, const R8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R8S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R8S *dst, const R8S *src1, const R8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R8G8S +{ + char R; + char G; + + static void readColor(gl::ColorF *dst, const R8G8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8G8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R8G8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R8G8S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R8G8B8S +{ + char R; + char G; + char B; + + static void readColor(gl::ColorF *dst, const R8G8B8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R8G8B8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R8G8B8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R8G8B8S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R8G8B8A8S +{ + char R; + char G; + char B; + char A; + + static void readColor(gl::ColorF *dst, const R8G8B8A8S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R8G8B8A8S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R8G8B8A8S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R8G8B8A8S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R16S +{ + short R; + + static void readColor(gl::ColorF *dst, const R16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R16S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R16S *dst, const R16S *src1, const R16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R16G16S +{ + short R; + short G; + + static void readColor(gl::ColorF *dst, const R16G16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16G16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R16G16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R16G16S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R16G16B16S +{ + short R; + short G; + short B; + + static void readColor(gl::ColorF *dst, const R16G16B16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R16G16B16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R16G16B16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R16G16B16S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R16G16B16A16S +{ + short R; + short G; + short B; + short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R16G16B16A16S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R16G16B16A16S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R16G16B16A16S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R16G16B16A16S *dst, const R16G16B16A16S *src1, const R16G16B16A16S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32S +{ + int R; + + static void readColor(gl::ColorF *dst, const R32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32S *src) + { + dst->red = src->R; + dst->green = 0; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + } + + static void writeColor(R32S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + } + + static void average(R32S *dst, const R32S *src1, const R32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct R32G32S +{ + int R; + int G; + + static void readColor(gl::ColorF *dst, const R32G32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32G32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0; + dst->alpha = 1; + } + + static void writeColor(R32G32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + } + + static void writeColor(R32G32S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + } + + static void average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32S +{ + int R; + int G; + int B; + + static void readColor(gl::ColorF *dst, const R32G32B32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = 1.0f; + } + + static void readColor(gl::ColorI *dst, const R32G32B32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1; + } + + static void writeColor(R32G32B32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + } + + static void writeColor(R32G32B32S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + } + + static void average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R32G32B32A32S +{ + int R; + int G; + int B; + int A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32S *src) + { + dst->red = gl::normalizedToFloat(src->R); + dst->green = gl::normalizedToFloat(src->G); + dst->blue = gl::normalizedToFloat(src->B); + dst->alpha = gl::normalizedToFloat(src->A); + } + + static void readColor(gl::ColorI *dst, const R32G32B32A32S *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32S *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized(src->red); + dst->G = gl::floatToNormalized(src->green); + dst->B = gl::floatToNormalized(src->blue); + dst->A = gl::floatToNormalized(src->alpha); + } + + static void writeColor(R32G32B32A32S *dst, const gl::ColorI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R32G32B32A32S *dst, const R32G32B32A32S *src1, const R32G32B32A32S *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct A16B16G16R16F +{ + unsigned short A; + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const A16B16G16R16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(A16B16G16R16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16G16B16A16F +{ + unsigned short R; + unsigned short G; + unsigned short B; + unsigned short A; + + static void readColor(gl::ColorF *dst, const R16G16B16A16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(R16G16B16A16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(R16G16B16A16F *dst, const R16G16B16A16F *src1, const R16G16B16A16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16F +{ + unsigned short R; + + static void readColor(gl::ColorF *dst, const R16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + } + + static void average(R16F *dst, const R16F *src1, const R16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + } +}; + +struct A16F +{ + unsigned short A; + + static void readColor(gl::ColorF *dst, const A16F *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(A16F *dst, const gl::ColorF *src) + { + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(A16F *dst, const A16F *src1, const A16F *src2) + { + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct L16F +{ + unsigned short L; + + static void readColor(gl::ColorF *dst, const L16F *src) + { + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = 1.0f; + } + + static void writeColor(L16F *dst, const gl::ColorF *src) + { + dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); + } + + static void average(L16F *dst, const L16F *src1, const L16F *src2) + { + dst->L = gl::averageHalfFloat(src1->L, src2->L); + } +}; + +struct L16A16F +{ + unsigned short L; + unsigned short A; + + static void readColor(gl::ColorF *dst, const L16A16F *src) + { + float lum = gl::float16ToFloat32(src->L); + dst->red = lum; + dst->green = lum; + dst->blue = lum; + dst->alpha = gl::float16ToFloat32(src->A); + } + + static void writeColor(L16A16F *dst, const gl::ColorF *src) + { + dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); + dst->A = gl::float32ToFloat16(src->alpha); + } + + static void average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2) + { + dst->L = gl::averageHalfFloat(src1->L, src2->L); + dst->A = gl::averageHalfFloat(src1->A, src2->A); + } +}; + +struct R16G16F +{ + unsigned short R; + unsigned short G; + + static void readColor(gl::ColorF *dst, const R16G16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R16G16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + } + + static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + } +}; + +struct R16G16B16F +{ + unsigned short R; + unsigned short G; + unsigned short B; + + static void readColor(gl::ColorF *dst, const R16G16B16F *src) + { + dst->red = gl::float16ToFloat32(src->R); + dst->green = gl::float16ToFloat32(src->G); + dst->blue = gl::float16ToFloat32(src->B); + dst->alpha = 1.0f; + } + + static void writeColor(R16G16B16F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat16(src->red); + dst->G = gl::float32ToFloat16(src->green); + dst->B = gl::float32ToFloat16(src->blue); + } + + static void average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2) + { + dst->R = gl::averageHalfFloat(src1->R, src2->R); + dst->G = gl::averageHalfFloat(src1->G, src2->G); + dst->B = gl::averageHalfFloat(src1->B, src2->B); + } +}; + +struct A32B32G32R32F +{ + float A; + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const A32B32G32R32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(A32B32G32R32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; + } + + static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32G32B32A32F +{ + float R; + float G; + float B; + float A; + + static void readColor(gl::ColorF *dst, const R32G32B32A32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R32G32B32A32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + dst->A = src->alpha; + } + + static void average(R32G32B32A32F *dst, const R32G32B32A32F *src1, const R32G32B32A32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32F +{ + float R; + + static void readColor(gl::ColorF *dst, const R32F *src) + { + dst->red = src->R; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + } + + static void average(R32F *dst, const R32F *src1, const R32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + } +}; + +struct A32F +{ + float A; + + static void readColor(gl::ColorF *dst, const A32F *src) + { + dst->red = 0.0f; + dst->green = 0.0f; + dst->blue = 0.0f; + dst->alpha = src->A; + } + + static void writeColor(A32F *dst, const gl::ColorF *src) + { + dst->A = src->alpha; + } + + static void average(A32F *dst, const A32F *src1, const A32F *src2) + { + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct L32F +{ + float L; + + static void readColor(gl::ColorF *dst, const L32F *src) + { + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = 1.0f; + } + + static void writeColor(L32F *dst, const gl::ColorF *src) + { + dst->L = (src->red + src->green + src->blue) / 3.0f; + } + + static void average(L32F *dst, const L32F *src1, const L32F *src2) + { + dst->L = gl::average(src1->L, src2->L); + } +}; + +struct L32A32F +{ + float L; + float A; + + static void readColor(gl::ColorF *dst, const L32A32F *src) + { + dst->red = src->L; + dst->green = src->L; + dst->blue = src->L; + dst->alpha = src->A; + } + + static void writeColor(L32A32F *dst, const gl::ColorF *src) + { + dst->L = (src->red + src->green + src->blue) / 3.0f; + dst->A = src->alpha; + } + + static void average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2) + { + dst->L = gl::average(src1->L, src2->L); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R32G32F +{ + float R; + float G; + + static void readColor(gl::ColorF *dst, const R32G32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = 0.0f; + dst->alpha = 1.0f; + } + + static void writeColor(R32G32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + } + + static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + } +}; + +struct R32G32B32F +{ + float R; + float G; + float B; + + static void readColor(gl::ColorF *dst, const R32G32B32F *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = 1.0f; + } + + static void writeColor(R32G32B32F *dst, const gl::ColorF *src) + { + dst->R = src->red; + dst->G = src->green; + dst->B = src->blue; + } + + static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + } +}; + +struct R10G10B10A2 +{ + unsigned int R : 10; + unsigned int G : 10; + unsigned int B : 10; + unsigned int A : 2; + + static void readColor(gl::ColorF *dst, const R10G10B10A2 *src) + { + dst->red = gl::normalizedToFloat<10>(src->R); + dst->green = gl::normalizedToFloat<10>(src->G); + dst->blue = gl::normalizedToFloat<10>(src->B); + dst->alpha = gl::normalizedToFloat< 2>(src->A); + } + + static void readColor(gl::ColorUI *dst, const R10G10B10A2 *src) + { + dst->red = src->R; + dst->green = src->G; + dst->blue = src->B; + dst->alpha = src->A; + } + + static void writeColor(R10G10B10A2 *dst, const gl::ColorF *src) + { + dst->R = gl::floatToNormalized<10, unsigned int>(src->red); + dst->G = gl::floatToNormalized<10, unsigned int>(src->green); + dst->B = gl::floatToNormalized<10, unsigned int>(src->blue); + dst->A = gl::floatToNormalized< 2, unsigned int>(src->alpha); + } + + static void writeColor(R10G10B10A2 *dst, const gl::ColorUI *src) + { + dst->R = static_cast(src->red); + dst->G = static_cast(src->green); + dst->B = static_cast(src->blue); + dst->A = static_cast(src->alpha); + } + + static void average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *src2) + { + dst->R = gl::average(src1->R, src2->R); + dst->G = gl::average(src1->G, src2->G); + dst->B = gl::average(src1->B, src2->B); + dst->A = gl::average(src1->A, src2->A); + } +}; + +struct R9G9B9E5 +{ + unsigned int R : 9; + unsigned int G : 9; + unsigned int B : 9; + unsigned int E : 5; + + static void readColor(gl::ColorF *dst, const R9G9B9E5 *src) + { + gl::convert999E5toRGBFloats(gl::bitCast(*src), &dst->red, &dst->green, &dst->blue); + dst->alpha = 1.0f; + } + + static void writeColor(R9G9B9E5 *dst, const gl::ColorF *src) + { + *reinterpret_cast(dst) = gl::convertRGBFloatsTo999E5(src->red, + src->green, + src->blue); + } + + static void average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2) + { + float r1, g1, b1; + gl::convert999E5toRGBFloats(*reinterpret_cast(src1), &r1, &g1, &b1); + + float r2, g2, b2; + gl::convert999E5toRGBFloats(*reinterpret_cast(src2), &r2, &g2, &b2); + + *reinterpret_cast(dst) = gl::convertRGBFloatsTo999E5(gl::average(r1, r2), + gl::average(g1, g2), + gl::average(b1, b2)); + } +}; + +struct R11G11B10F +{ + unsigned int R : 11; + unsigned int G : 11; + unsigned int B : 10; + + static void readColor(gl::ColorF *dst, const R11G11B10F *src) + { + dst->red = gl::float11ToFloat32(src->R); + dst->green = gl::float11ToFloat32(src->G); + dst->blue = gl::float10ToFloat32(src->B); + dst->alpha = 1.0f; + } + + static void writeColor(R11G11B10F *dst, const gl::ColorF *src) + { + dst->R = gl::float32ToFloat11(src->red); + dst->G = gl::float32ToFloat11(src->green); + dst->B = gl::float32ToFloat10(src->blue); + } + + static void average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2) + { + dst->R = gl::averageFloat11(src1->R, src2->R); + dst->G = gl::averageFloat11(src1->G, src2->G); + dst->B = gl::averageFloat10(src1->B, src2->B); + } +}; + +} + +#endif // LIBANGLE_RENDERER_D3D_IMAGEFORMATS_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp new file mode 100644 index 0000000000..172832b3e7 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.cpp @@ -0,0 +1,662 @@ +// +// Copyright (c) 2013-2015 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. +// + +// loadimage.cpp: Defines image loading functions. + +#include "libANGLE/renderer/d3d/loadimage.h" + +namespace rx +{ + +void LoadA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = static_cast(source[x]) << 24; + } + } + } +} + +void LoadA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0.0f; + dest[4 * x + 1] = 0.0f; + dest[4 * x + 2] = 0.0f; + dest[4 * x + 3] = source[x]; + } + } + } +} + +void LoadA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t 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 LoadL8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint8_t sourceVal = source[x]; + dest[4 * x + 0] = sourceVal; + dest[4 * x + 1] = sourceVal; + dest[4 * x + 2] = sourceVal; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadL8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadL8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadL32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t 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 LoadL16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t 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] = gl::Float16One; + } + } + } +} + +void LoadLA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t 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 LoadLA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + // Same as loading to RGBA + LoadLA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); +} + +void LoadLA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t 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 LoadLA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t 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 LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t 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 LoadRG8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = source[x * 2 + 1]; + dest[4 * x + 2] = source[x * 2 + 0]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[4 * x + 0] = 0x00; + dest[4 * x + 1] = 0x00; + dest[4 * x + 2] = source[x]; + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + dest[4 * x + 0] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2); + dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9); + dest[4 * x + 2] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13); + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgb = source[x]; + dest[4 * x + 0] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13); + dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9); + dest[4 * x + 2] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2); + dest[4 * x + 3] = 0xFF; + } + } + } +} + +void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } +} + +void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t 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 LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); + dest[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); + dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); + } + } + } +} + +void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + dest[4 * x + 0] = ((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12); + dest[4 * x + 1] = ((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8); + dest[4 * x + 2] = ((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4); + dest[4 * x + 3] = ((bgra & 0x000F) << 4) | ((bgra & 0x000F) >> 0); + } + } + } +} + +void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t 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 LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t rgba = source[x]; + dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); + dest[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); + dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; + } + } + } +} + + +void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint16_t bgra = source[x]; + dest[4 * x + 0] = ((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13); + dest[4 * x + 1] = ((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8); + dest[4 * x + 2] = ((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3); + dest[4 * x + 3] = (bgra & 0x0001) ? 0xFF : 0; + } + } + } +} + +void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t rgba = source[x]; + dest[4 * x + 0] = (rgba & 0x000003FF) >> 2; + dest[4 * x + 1] = (rgba & 0x000FFC00) >> 12; + dest[4 * x + 2] = (rgba & 0x3FF00000) >> 22; + dest[4 * x + 3] = ((rgba & 0xC0000000) >> 30) * 0x55; + } + } + } +} + +void LoadRGB16FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(gl::float16ToFloat32(source[x * 3 + 0]), + gl::float16ToFloat32(source[x * 3 + 1]), + gl::float16ToFloat32(source[x * 3 + 2])); + } + } + } +} + +void LoadRGB32FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = gl::convertRGBFloatsTo999E5(source[x * 3 + 0], source[x * 3 + 1], source[x * 3 + 2]); + } + } + } +} + +void LoadRGB16FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 0])) << 0) | + (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 1])) << 11) | + (gl::float32ToFloat10(gl::float16ToFloat32(source[x * 3 + 2])) << 22); + } + } + } +} + +void LoadRGB32FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = (gl::float32ToFloat11(source[x * 3 + 0]) << 0) | + (gl::float32ToFloat11(source[x * 3 + 1]) << 11) | + (gl::float32ToFloat10(source[x * 3 + 2]) << 22); + } + } + } +} + +void LoadG8R24ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + uint32_t d = source[x] >> 8; + uint8_t s = source[x] & 0xFF; + dest[x] = d | (s << 24); + } + } + } +} + +void LoadRGB32FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = gl::float32ToFloat16(source[x * 3 + 0]); + dest[x * 4 + 1] = gl::float32ToFloat16(source[x * 3 + 1]); + dest[x * 4 + 2] = gl::float32ToFloat16(source[x * 3 + 2]); + dest[x * 4 + 3] = gl::Float16One; + } + } + } +} + +void LoadR32ToR16(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 16; + } + } + } +} + +void LoadR32ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < width; x++) + { + dest[x] = source[x] >> 8; + } + } + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h new file mode 100644 index 0000000000..6967dc868e --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.h @@ -0,0 +1,193 @@ +// +// Copyright (c) 2013-2015 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. +// + +// loadimage.h: Defines image loading functions + +#ifndef LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ +#define LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ + +#include "libANGLE/angletypes.h" + +#include + +namespace rx +{ + +void LoadA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadL16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA8ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA32FToRGBA32F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadLA16FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRG8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR8ToBGRX8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB16FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRGB9E5(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB16FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRG11B10F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadG8R24ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void LoadToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void LoadToNative3To4(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void Load32FTo16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadRGB32FToRGBA16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR32ToR16(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +void LoadR32ToR24G8(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); + +template +inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); + +template +inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); + +} + +#include "loadimage.inl" + +#endif // LIBANGLE_RENDERER_D3D_LOADIMAGE_H_ diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl new file mode 100644 index 0000000000..920e667db1 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimage.inl @@ -0,0 +1,156 @@ +// +// Copyright (c) 2014-2015 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 "common/mathutil.h" + +namespace rx +{ + +template +inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); +} + +template +inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) +{ + return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); +} + +template +inline void LoadToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t rowSize = width * sizeof(type) * componentCount; + const size_t layerSize = rowSize * height; + const size_t imageSize = layerSize * depth; + + if (layerSize == inputDepthPitch && layerSize == outputDepthPitch) + { + ASSERT(rowSize == inputRowPitch && rowSize == outputRowPitch); + memcpy(output, input, imageSize); + } + else if (rowSize == inputRowPitch && rowSize == outputRowPitch) + { + for (size_t z = 0; z < depth; z++) + { + const type *source = OffsetDataPointer(input, 0, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer(output, 0, z, outputRowPitch, outputDepthPitch); + + memcpy(dest, source, layerSize); + } + } + else + { + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, width * sizeof(type) * componentCount); + } + } + } +} + +template +inline void LoadToNative3To4(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const type fourthValue = gl::bitCast(fourthComponentBits); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const type *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + type *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + dest[x * 4 + 0] = source[x * 3 + 0]; + dest[x * 4 + 1] = source[x * 3 + 1]; + dest[x * 4 + 2] = source[x * 3 + 2]; + dest[x * 4 + 3] = fourthValue; + } + } + } +} + +template +inline void Load32FTo16F(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t elementWidth = componentCount * width; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + for (size_t x = 0; x < elementWidth; x++) + { + dest[x] = gl::float32ToFloat16(source[x]); + } + } + } +} + +template +inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + const size_t columns = (width + (blockWidth - 1)) / blockWidth; + const size_t rows = (height + (blockHeight - 1)) / blockHeight; + + for (size_t z = 0; z < depth; ++z) + { + for (size_t y = 0; y < rows; ++y) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + memcpy(dest, source, columns * blockSize); + } + } +} + +template +inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ + type writeValues[4] = + { + gl::bitCast(firstBits), + gl::bitCast(secondBits), + gl::bitCast(thirdBits), + gl::bitCast(fourthBits), + }; + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + type *destRow = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + for (size_t x = 0; x < width; x++) + { + type* destPixel = destRow + x * 4; + + // This could potentially be optimized by generating an entire row of initialization + // data and copying row by row instead of pixel by pixel. + memcpy(destPixel, writeValues, sizeof(type) * 4); + } + } + } +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp new file mode 100644 index 0000000000..c87d35c82b --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/loadimageSSE2.cpp @@ -0,0 +1,125 @@ +// +// Copyright (c) 2002-2015 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. +// + +// loadimageSSE2.cpp: Defines image loading functions. 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 "libANGLE/renderer/d3d/loadimage.h" + +#include "common/platform.h" + +#ifdef ANGLE_USE_SSE +#include +#endif + +namespace rx +{ + +void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ +#if defined(ANGLE_USE_SSE) + __m128i zeroWide = _mm_setzero_si128(); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((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; + } + } + } +#else + // Ensure that this function is reported as not implemented for ARM builds because + // the instructions below are not present for that architecture. + UNIMPLEMENTED(); + return; +#endif +} + +void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, + const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, + uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) +{ +#if defined(ANGLE_USE_SSE) + __m128i brMask = _mm_set1_epi32(0x00ff00ff); + + for (size_t z = 0; z < depth; z++) + { + for (size_t y = 0; y < height; y++) + { + const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); + uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); + + size_t x = 0; + + // Make output writes aligned + for (; ((reinterpret_cast(&dest[x]) & 15) != 0) && x < width; x++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_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++) + { + uint32_t rgba = source[x]; + dest[x] = (ANGLE_ROTL(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); + } + } + } +#else + // Ensure that this function is reported as not implemented for ARM builds because + // the instructions below are not present for that architecture. + UNIMPLEMENTED(); + return; +#endif +} + +} + diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp new file mode 100644 index 0000000000..12ee6a2b93 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp @@ -0,0 +1,503 @@ +// +// Copyright (c) 2015 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. +// + +// validationEGL.cpp: Validation functions for generic EGL entry point parameters + +#include "libANGLE/validationEGL.h" + +#include "libANGLE/Config.h" +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" + +#include + +namespace egl +{ + +Error ValidateDisplay(const Display *display) +{ + if (display == EGL_NO_DISPLAY) + { + return Error(EGL_BAD_DISPLAY); + } + + if (!display->isInitialized()) + { + return Error(EGL_NOT_INITIALIZED); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateSurface(const Display *display, Surface *surface) +{ + Error error = ValidateDisplay(display); + if (error.isError()) + { + return error; + } + + if (!display->isValidSurface(surface)) + { + return Error(EGL_BAD_SURFACE); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateConfig(const Display *display, const Config *config) +{ + Error error = ValidateDisplay(display); + if (error.isError()) + { + return error; + } + + if (!display->isValidConfig(config)) + { + return Error(EGL_BAD_CONFIG); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateContext(const Display *display, gl::Context *context) +{ + Error error = ValidateDisplay(display); + if (error.isError()) + { + return error; + } + + if (!display->isValidContext(context)) + { + return Error(EGL_BAD_CONTEXT); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, + const AttributeMap& attributes) +{ + Error error = ValidateConfig(display, configuration); + if (error.isError()) + { + return error; + } + + // Get the requested client version (default is 1) and check it is 2 or 3. + EGLint clientMajorVersion = 1; + EGLint clientMinorVersion = 0; + EGLint contextFlags = 0; + bool resetNotification = false; + bool robustAccess = false; + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_CONTEXT_CLIENT_VERSION: + clientMajorVersion = value; + break; + + case EGL_CONTEXT_MINOR_VERSION: + clientMinorVersion = value; + break; + + case EGL_CONTEXT_FLAGS_KHR: + contextFlags = value; + break; + + case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: + // Only valid for OpenGL (non-ES) contexts + return Error(EGL_BAD_ATTRIBUTE); + + case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: + if (!display->getExtensions().createContextRobustness) + { + return Error(EGL_BAD_ATTRIBUTE); + } + if (value != EGL_TRUE && value != EGL_FALSE) + { + return Error(EGL_BAD_ATTRIBUTE); + } + robustAccess = (value == EGL_TRUE); + break; + + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: + static_assert(EGL_LOSE_CONTEXT_ON_RESET_EXT == EGL_LOSE_CONTEXT_ON_RESET_KHR, "EGL extension enums not equal."); + static_assert(EGL_NO_RESET_NOTIFICATION_EXT == EGL_NO_RESET_NOTIFICATION_KHR, "EGL extension enums not equal."); + // same as EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, fall through + case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: + if (!display->getExtensions().createContextRobustness) + { + return Error(EGL_BAD_ATTRIBUTE); + } + if (value == EGL_LOSE_CONTEXT_ON_RESET_EXT) + { + resetNotification = true; + } + else if (value != EGL_NO_RESET_NOTIFICATION_EXT) + { + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + default: + return Error(EGL_BAD_ATTRIBUTE); + } + } + + if ((clientMajorVersion != 2 && clientMajorVersion != 3) || clientMinorVersion != 0) + { + return Error(EGL_BAD_CONFIG); + } + + if (clientMajorVersion == 3 && !(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR) && !(configuration->configCaveat & EGL_NON_CONFORMANT_CONFIG)) + { + return Error(EGL_BAD_CONFIG); + } + + // Note: EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR does not apply to ES + const EGLint validContextFlags = (EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR | + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR); + if ((contextFlags & ~validContextFlags) != 0) + { + return Error(EGL_BAD_ATTRIBUTE); + } + + if ((contextFlags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) > 0) + { + robustAccess = true; + } + + if (robustAccess) + { + // Unimplemented + return Error(EGL_BAD_CONFIG); + } + + if (shareContext) + { + // Shared context is invalid or is owned by another display + if (!display->isValidContext(shareContext)) + { + return Error(EGL_BAD_MATCH); + } + + if (shareContext->isResetNotificationEnabled() != resetNotification) + { + return Error(EGL_BAD_MATCH); + } + + if (shareContext->getClientVersion() != clientMajorVersion) + { + return Error(EGL_BAD_CONTEXT); + } + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWindowType window, + const AttributeMap& attributes) +{ + Error error = ValidateConfig(display, config); + if (error.isError()) + { + return error; + } + + if (!display->isValidNativeWindow(window)) + { + return Error(EGL_BAD_NATIVE_WINDOW); + } + + const DisplayExtensions &displayExtensions = display->getExtensions(); + + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_RENDER_BUFFER: + switch (value) + { + case EGL_BACK_BUFFER: + break; + case EGL_SINGLE_BUFFER: + return Error(EGL_BAD_MATCH); // Rendering directly to front buffer not supported + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + if (!displayExtensions.postSubBuffer) + { + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_WIDTH: + case EGL_HEIGHT: + if (!displayExtensions.windowFixedSize) + { + return Error(EGL_BAD_ATTRIBUTE); + } + if (value < 0) + { + return Error(EGL_BAD_PARAMETER); + } + break; + + case EGL_FIXED_SIZE_ANGLE: + if (!displayExtensions.windowFixedSize) + { + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_VG_COLORSPACE: + return Error(EGL_BAD_MATCH); + + case EGL_VG_ALPHA_FORMAT: + return Error(EGL_BAD_MATCH); + + default: + return Error(EGL_BAD_ATTRIBUTE); + } + } + + if (Display::hasExistingWindowSurface(window)) + { + return Error(EGL_BAD_ALLOC); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes) +{ + Error error = ValidateConfig(display, config); + if (error.isError()) + { + return error; + } + + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_WIDTH: + case EGL_HEIGHT: + if (value < 0) + { + return Error(EGL_BAD_PARAMETER); + } + break; + + case EGL_LARGEST_PBUFFER: + break; + + case EGL_TEXTURE_FORMAT: + switch (value) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_RGB: + case EGL_TEXTURE_RGBA: + break; + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_TEXTURE_TARGET: + switch (value) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_2D: + break; + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_MIPMAP_TEXTURE: + break; + + case EGL_VG_COLORSPACE: + break; + + case EGL_VG_ALPHA_FORMAT: + break; + + default: + return Error(EGL_BAD_ATTRIBUTE); + } + } + + if (!(config->surfaceType & EGL_PBUFFER_BIT)) + { + return Error(EGL_BAD_MATCH); + } + + const Caps &caps = display->getCaps(); + + EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + + if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || + (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) + { + return Error(EGL_BAD_MATCH); + } + + if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || + (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) + { + return Error(EGL_BAD_ATTRIBUTE); + } + + EGLint width = attributes.get(EGL_WIDTH, 0); + EGLint height = attributes.get(EGL_HEIGHT, 0); + if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) + { + return Error(EGL_BAD_MATCH); + } + + return Error(EGL_SUCCESS); +} + +Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, + Config *config, const AttributeMap& attributes) +{ + Error error = ValidateConfig(display, config); + if (error.isError()) + { + return error; + } + + const DisplayExtensions &displayExtensions = display->getExtensions(); + + switch (buftype) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + if (!displayExtensions.d3dShareHandleClientBuffer) + { + return Error(EGL_BAD_PARAMETER); + } + if (buffer == nullptr) + { + return Error(EGL_BAD_PARAMETER); + } + break; + + default: + return Error(EGL_BAD_PARAMETER); + } + + for (AttributeMap::const_iterator attributeIter = attributes.begin(); attributeIter != attributes.end(); attributeIter++) + { + EGLint attribute = attributeIter->first; + EGLint value = attributeIter->second; + + switch (attribute) + { + case EGL_WIDTH: + case EGL_HEIGHT: + if (!displayExtensions.d3dShareHandleClientBuffer) + { + return Error(EGL_BAD_PARAMETER); + } + if (value < 0) + { + return Error(EGL_BAD_PARAMETER); + } + break; + + case EGL_TEXTURE_FORMAT: + switch (value) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_RGB: + case EGL_TEXTURE_RGBA: + break; + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_TEXTURE_TARGET: + switch (value) + { + case EGL_NO_TEXTURE: + case EGL_TEXTURE_2D: + break; + default: + return Error(EGL_BAD_ATTRIBUTE); + } + break; + + case EGL_MIPMAP_TEXTURE: + break; + + default: + return Error(EGL_BAD_ATTRIBUTE); + } + } + + if (!(config->surfaceType & EGL_PBUFFER_BIT)) + { + return Error(EGL_BAD_MATCH); + } + + EGLenum textureFormat = attributes.get(EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE); + EGLenum textureTarget = attributes.get(EGL_TEXTURE_TARGET, EGL_NO_TEXTURE); + if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || + (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) + { + return Error(EGL_BAD_MATCH); + } + + if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) || + (textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE)) + { + return Error(EGL_BAD_ATTRIBUTE); + } + + if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) + { + EGLint width = attributes.get(EGL_WIDTH, 0); + EGLint height = attributes.get(EGL_HEIGHT, 0); + + if (width == 0 || height == 0) + { + return Error(EGL_BAD_ATTRIBUTE); + } + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) // On Windows Store, we know the originating texture came from D3D11, so bypass this check + const Caps &caps = display->getCaps(); + if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) + { + return Error(EGL_BAD_MATCH); + } +#endif + } + + return Error(EGL_SUCCESS); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.h b/src/3rdparty/angle/src/libANGLE/validationEGL.h new file mode 100644 index 0000000000..4daff791fd --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationEGL.h @@ -0,0 +1,49 @@ +// +// Copyright (c) 2015 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. +// + +// validationEGL.h: Validation functions for generic EGL entry point parameters + +#ifndef LIBANGLE_VALIDATIONEGL_H_ +#define LIBANGLE_VALIDATIONEGL_H_ + +#include "libANGLE/Error.h" + +#include + +namespace gl +{ +class Context; +} + +namespace egl +{ + +class AttributeMap; +struct Config; +class Display; +class Surface; + +// Object validation +Error ValidateDisplay(const Display *display); +Error ValidateSurface(const Display *display, Surface *surface); +Error ValidateConfig(const Display *display, const Config *config); +Error ValidateContext(const Display *display, gl::Context *context); + +// Entry point validation +Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, + const AttributeMap& attributes); + +Error ValidateCreateWindowSurface(Display *display, Config *config, EGLNativeWindowType window, + const AttributeMap& attributes); + +Error ValidateCreatePbufferSurface(Display *display, Config *config, const AttributeMap& attributes); +Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, EGLClientBuffer buffer, + Config *config, const AttributeMap& attributes); + + +} + +#endif // LIBANGLE_VALIDATIONEGL_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES.cpp b/src/3rdparty/angle/src/libANGLE/validationES.cpp new file mode 100644 index 0000000000..d267cbf2e6 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES.cpp @@ -0,0 +1,1882 @@ +// +// Copyright (c) 2013-2014 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. +// + +// validationES.h: Validation functions for generic OpenGL ES entry point parameters + +#include "libANGLE/validationES.h" +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES3.h" +#include "libANGLE/Context.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/FramebufferAttachment.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/Query.h" +#include "libANGLE/Program.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/TransformFeedback.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/renderer/BufferImpl.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +bool ValidCap(const Context *context, GLenum cap) +{ + switch (cap) + { + case GL_CULL_FACE: + case GL_POLYGON_OFFSET_FILL: + case GL_SAMPLE_ALPHA_TO_COVERAGE: + case GL_SAMPLE_COVERAGE: + case GL_SCISSOR_TEST: + case GL_STENCIL_TEST: + case GL_DEPTH_TEST: + case GL_BLEND: + case GL_DITHER: + return true; + case GL_PRIMITIVE_RESTART_FIXED_INDEX: + case GL_RASTERIZER_DISCARD: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidTextureTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + return true; + + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +// This function differs from ValidTextureTarget in that the target must be +// usable as the destination of a 2D operation-- so a cube face is valid, but +// GL_TEXTURE_CUBE_MAP is not. +// Note: duplicate of IsInternalTextureTarget +bool ValidTexture2DDestinationTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_TEXTURE_2D: + 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: + return true; + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_3D: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidFramebufferTarget(GLenum target) +{ + static_assert(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER, + "ANGLE framebuffer enums must equal the ES3 framebuffer enums."); + + switch (target) + { + case GL_FRAMEBUFFER: return true; + case GL_READ_FRAMEBUFFER: return true; + case GL_DRAW_FRAMEBUFFER: return true; + default: return false; + } +} + +bool ValidBufferTarget(const Context *context, GLenum target) +{ + switch (target) + { + case GL_ARRAY_BUFFER: + case GL_ELEMENT_ARRAY_BUFFER: + return true; + + case GL_PIXEL_PACK_BUFFER: + case GL_PIXEL_UNPACK_BUFFER: + return context->getExtensions().pixelBufferObject; + + case GL_COPY_READ_BUFFER: + case GL_COPY_WRITE_BUFFER: + case GL_TRANSFORM_FEEDBACK_BUFFER: + case GL_UNIFORM_BUFFER: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +bool ValidBufferParameter(const Context *context, GLenum pname) +{ + switch (pname) + { + case GL_BUFFER_USAGE: + case GL_BUFFER_SIZE: + return true; + + // GL_BUFFER_MAP_POINTER is a special case, and may only be + // queried with GetBufferPointerv + case GL_BUFFER_ACCESS_FLAGS: + case GL_BUFFER_MAPPED: + case GL_BUFFER_MAP_OFFSET: + case GL_BUFFER_MAP_LENGTH: + return (context->getClientVersion() >= 3); + + default: + return false; + } +} + +bool ValidMipLevel(const Context *context, GLenum target, GLint level) +{ + size_t maxDimension = 0; + switch (target) + { + case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break; + case GL_TEXTURE_CUBE_MAP: + 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: maxDimension = context->getCaps().maxCubeMapTextureSize; break; + case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break; + case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break; + default: UNREACHABLE(); + } + + return level <= gl::log2(maxDimension); +} + +bool ValidImageSize(const Context *context, GLenum target, GLint level, + GLsizei width, GLsizei height, GLsizei depth) +{ + if (level < 0 || width < 0 || height < 0 || depth < 0) + { + return false; + } + + if (!context->getExtensions().textureNPOT && + (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))) + { + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + return false; + } + + return true; +} + +bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height) +{ + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + if (!formatInfo.compressed) + { + return false; + } + + if (width < 0 || (static_cast(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) || + height < 0 || (static_cast(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0)) + { + return false; + } + + return true; +} + +bool ValidQueryType(const Context *context, GLenum queryType) +{ + static_assert(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT, "GL extension enums not equal."); + static_assert(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL extension enums not equal."); + + switch (queryType) + { + case GL_ANY_SAMPLES_PASSED: + case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: + return true; + case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: + return (context->getClientVersion() >= 3); + default: + return false; + } +} + +bool ValidProgram(Context *context, GLuint id) +{ + // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the + // error INVALID_VALUE if the provided name is not the name of either a shader or program object and + // INVALID_OPERATION if the provided name identifies an object that is not the expected type." + + if (context->getProgram(id) != NULL) + { + return true; + } + else if (context->getShader(id) != NULL) + { + // ID is the wrong type + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + // No shader/program object has this ID + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } +} + +bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment) +{ + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); + + if (colorAttachment >= context->getCaps().maxColorAttachments) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else + { + switch (attachment) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + case GL_DEPTH_STENCIL_ATTACHMENT: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + + return true; +} + +bool ValidateRenderbufferStorageParametersBase(gl::Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height) +{ + switch (target) + { + case GL_RENDERBUFFER: + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (width < 0 || height < 0 || samples < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (!formatCaps.renderable) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be + // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains + // only sized internal formats. + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + if (formatInfo.pixelBytes == 0) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (static_cast(std::max(width, height)) > context->getCaps().maxRenderbufferSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + GLuint handle = context->getState().getRenderbufferId(); + if (handle == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateRenderbufferStorageParametersANGLE(gl::Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height) +{ + ASSERT(samples == 0 || context->getExtensions().framebufferMultisample); + + // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal + // to MAX_SAMPLES_ANGLE (Context::getExtensions().maxSamples) otherwise GL_INVALID_VALUE is + // generated. + if (static_cast(samples) > context->getExtensions().maxSamples) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create + // the specified storage. This is different than ES 3.0 in which a sample number higher + // than the maximum sample number supported by this format generates a GL_INVALID_VALUE. + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (static_cast(samples) > formatCaps.getMaxSamples()) + { + context->recordError(Error(GL_OUT_OF_MEMORY)); + return false; + } + + return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height); +} + +bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer) +{ + if (!ValidFramebufferTarget(target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); + + if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + // [OpenGL ES 2.0.25] Section 4.4.3 page 112 + // [OpenGL ES 3.0.2] Section 4.4.2 page 201 + // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of + // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated. + if (renderbuffer != 0) + { + if (!context->getRenderbuffer(renderbuffer)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) +{ + if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || + dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() || + srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight()) + { + return true; + } + else if (context->getState().isScissorTestEnabled()) + { + const Rectangle &scissor = context->getState().getScissor(); + + return scissor.x > 0 || scissor.y > 0 || + scissor.width < writeBuffer->getWidth() || + scissor.height < writeBuffer->getHeight(); + } + else + { + return false; + } +} + +bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter, bool fromAngleExtension) +{ + switch (filter) + { + case GL_NEAREST: + break; + case GL_LINEAR: + if (fromAngleExtension) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (mask == 0) + { + // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no + // buffers are copied. + return false; + } + + if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)) + { + ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation."); + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the + // color buffer, leaving only nearest being unfiltered from above + if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id()) + { + if (fromAngleExtension) + { + ERR("Blits with the same source and destination framebuffer are not supported by this " + "implementation."); + } + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); + gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); + + if (!readFramebuffer || !drawFramebuffer) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (!readFramebuffer->checkStatus(context->getData())) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (!drawFramebuffer->checkStatus(context->getData())) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (drawFramebuffer->getSamples(context->getData()) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; + + if (mask & GL_COLOR_BUFFER_BIT) + { + gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer(); + gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer(); + + if (readColorBuffer && drawColorBuffer) + { + GLenum readInternalFormat = readColorBuffer->getInternalFormat(); + const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat); + + for (GLuint i = 0; i < context->getCaps().maxColorAttachments; i++) + { + if (drawFramebuffer->isEnabledColorAttachment(i)) + { + GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getInternalFormat(); + const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat); + + // The GL ES 3.0.2 spec (pg 193) states that: + // 1) If the read buffer is fixed point format, the draw buffer must be as well + // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well + // 3) If the read buffer is a signed integer format, the draw buffer must be as well + if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) && + !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + } + + if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (fromAngleExtension) + { + FramebufferAttachment *readColorAttachment = readFramebuffer->getReadColorbuffer(); + if (!readColorAttachment || + (!(readColorAttachment->type() == GL_TEXTURE && readColorAttachment->getTextureImageIndex()->type == GL_TEXTURE_2D) && + readColorAttachment->type() != GL_RENDERBUFFER && + readColorAttachment->type() != GL_FRAMEBUFFER_DEFAULT)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + for (GLuint colorAttachment = 0; colorAttachment < context->getCaps().maxColorAttachments; ++colorAttachment) + { + if (drawFramebuffer->isEnabledColorAttachment(colorAttachment)) + { + FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment); + ASSERT(attachment); + + if (!(attachment->type() == GL_TEXTURE && attachment->getTextureImageIndex()->type == GL_TEXTURE_2D) && + attachment->type() != GL_RENDERBUFFER && + attachment->type() != GL_FRAMEBUFFER_DEFAULT) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Return an error if the destination formats do not match + if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + } + + int readSamples = readFramebuffer->getSamples(context->getData()); + + if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + } + } + + GLenum masks[] = {GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT}; + GLenum attachments[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; + for (size_t i = 0; i < 2; i++) + { + if (mask & masks[i]) + { + gl::FramebufferAttachment *readBuffer = readFramebuffer->getAttachment(attachments[i]); + gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getAttachment(attachments[i]); + + if (readBuffer && drawBuffer) + { + if (readBuffer->getInternalFormat() != drawBuffer->getInternalFormat()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (readBuffer->getSamples() > 0 && !sameBounds) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (fromAngleExtension) + { + if (IsPartialBlit(context, readBuffer, drawBuffer, + srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) + { + ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); + context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted + return false; + } + + if (readBuffer->getSamples() != 0 || drawBuffer->getSamples() != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + } + } + } + + return true; +} + +bool ValidateGetVertexAttribParameters(Context *context, GLenum pname) +{ + switch (pname) + { + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: + case GL_VERTEX_ATTRIB_ARRAY_SIZE: + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: + case GL_VERTEX_ATTRIB_ARRAY_TYPE: + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: + case GL_CURRENT_VERTEX_ATTRIB: + return true; + + case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: + // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses + // the same constant. + static_assert(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE, + "ANGLE extension enums not equal to GL enums."); + return true; + + case GL_VERTEX_ATTRIB_ARRAY_INTEGER: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + return true; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } +} + +bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param) +{ + switch (pname) + { + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + default: break; + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + switch (param) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + case GL_TEXTURE_MIN_FILTER: + switch (param) + { + 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: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_MAG_FILTER: + switch (param) + { + case GL_NEAREST: + case GL_LINEAR: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_USAGE_ANGLE: + switch (param) + { + case GL_NONE: + case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // we assume the parameter passed to this validation method is truncated, not rounded + if (param < 1) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + return true; + + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + // any value is permissible + return true; + + case GL_TEXTURE_COMPARE_MODE: + // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 + switch (param) + { + case GL_NONE: + case GL_COMPARE_REF_TO_TEXTURE: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_COMPARE_FUNC: + // Acceptable function parameters from GLES 3.0.2 spec, table 3.17 + switch (param) + { + case GL_LEQUAL: + case GL_GEQUAL: + case GL_LESS: + case GL_GREATER: + case GL_EQUAL: + case GL_NOTEQUAL: + case GL_ALWAYS: + case GL_NEVER: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + switch (param) + { + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_ZERO: + case GL_ONE: + return true; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + if (param < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + return true; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } +} + +bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname) +{ + switch (pname) + { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + case GL_TEXTURE_COMPARE_MODE: + case GL_TEXTURE_COMPARE_FUNC: + return true; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } +} + +bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels) +{ + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + ASSERT(framebuffer); + + if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (context->getState().getReadFramebuffer()->id() != 0 && + framebuffer->getSamples(context->getData()) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const FramebufferAttachment *readBuffer = framebuffer->getReadColorbuffer(); + if (!readBuffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + GLenum currentFormat = framebuffer->getImplementationColorReadFormat(); + GLenum currentType = framebuffer->getImplementationColorReadType(); + GLenum currentInternalFormat = readBuffer->getInternalFormat(); + GLuint clientVersion = context->getClientVersion(); + + bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) : + ValidES3ReadFormatType(context, currentInternalFormat, format, type); + + if (!(currentFormat == format && currentType == type) && !validReadFormat) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + GLenum sizedInternalFormat = GetSizedInternalFormat(format, type); + const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat); + + GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment(), 0); + // sized query sanity check + if (bufSize) + { + int requiredSize = outputPitch * height; + if (requiredSize > *bufSize) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) +{ + if (!ValidQueryType(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (id == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // 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. + if (context->getState().isQueryActive()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + Query *queryObject = context->getQuery(id, true, target); + + // check that name was obtained with glGenQueries + if (!queryObject) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // check for type mismatch + if (queryObject->getType() != target) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateEndQuery(gl::Context *context, GLenum target) +{ + if (!ValidQueryType(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const Query *queryObject = context->getState().getActiveQuery(target); + + if (queryObject == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType, + GLint location, GLsizei count, LinkedUniform **uniformOut) +{ + if (count < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + gl::Program *program = context->getState().getProgram(); + if (!program) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (location == -1) + { + // Silently ignore the uniform command + return false; + } + + if (!program->isValidUniformLocation(location)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + LinkedUniform *uniform = program->getUniformByLocation(location); + + // attempting to write an array to a non-array uniform is an INVALID_OPERATION + if (uniform->elementCount() == 1 && count > 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + *uniformOut = uniform; + return true; +} + +bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count) +{ + // Check for ES3 uniform entry points + if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + LinkedUniform *uniform = NULL; + if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform)) + { + return false; + } + + GLenum targetBoolType = VariableBoolVectorType(uniformType); + bool samplerUniformCheck = (IsSamplerType(uniform->type) && uniformType == GL_INT); + if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count, + GLboolean transpose) +{ + // Check for ES3 uniform entry points + int rows = VariableRowCount(matrixType); + int cols = VariableColumnCount(matrixType); + if (rows != cols && context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (transpose != GL_FALSE && context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + LinkedUniform *uniform = NULL; + if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform)) + { + return false; + } + + if (uniform->type != matrixType) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams) +{ + if (!context->getQueryParameterInfo(pname, nativeType, numParams)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const Caps &caps = context->getCaps(); + + if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) + { + unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); + + if (colorAttachment >= caps.maxDrawBuffers) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + switch (pname) + { + case GL_TEXTURE_BINDING_2D: + case GL_TEXTURE_BINDING_CUBE_MAP: + case GL_TEXTURE_BINDING_3D: + case GL_TEXTURE_BINDING_2D_ARRAY: + if (context->getState().getActiveSampler() >= caps.maxCombinedTextureImageUnits) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + + case GL_IMPLEMENTATION_COLOR_READ_TYPE: + case GL_IMPLEMENTATION_COLOR_READ_FORMAT: + { + Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + ASSERT(framebuffer); + if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); + if (!attachment) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + break; + + default: + break; + } + + // pname is valid, but there are no parameters to return + if (numParams == 0) + { + return false; + } + + return true; +} + +bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border, GLenum *textureFormatOut) +{ + + if (!ValidTexture2DDestinationTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (std::numeric_limits::max() - xoffset < width || std::numeric_limits::max() - yoffset < height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (border != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidMipLevel(context, target, level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + GLuint maxDimension = 0; + switch (target) + { + case GL_TEXTURE_2D: + maxDimension = caps.max2DTextureSize; + 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: + maxDimension = caps.maxCubeMapTextureSize; + break; + + case GL_TEXTURE_2D_ARRAY: + maxDimension = caps.max2DTextureSize; + break; + + case GL_TEXTURE_3D: + maxDimension = caps.max3DTextureSize; + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (texture->isImmutable() && !isSubImage) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + + if (formatInfo.depthBits > 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (formatInfo.compressed && !ValidCompressedImageSize(context, internalformat, width, height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (isSubImage) + { + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level) || + static_cast(zoffset) >= texture->getDepth(target, level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else + { + if (IsCubeMapTextureTarget(target) && width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + int maxLevelDimension = (maxDimension >> level); + if (static_cast(width) > maxLevelDimension || static_cast(height) > maxLevelDimension) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + + *textureFormatOut = texture->getInternalFormat(target, level); + return true; +} + +static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount) +{ + switch (mode) + { + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (count < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + const State &state = context->getState(); + + // Check for mapped buffers + if (state.hasMappedBuffer(GL_ARRAY_BUFFER)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::DepthStencilState &depthStencilState = state.getDepthStencilState(); + if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask || + state.getStencilRef() != state.getStencilBackRef() || + depthStencilState.stencilMask != depthStencilState.stencilBackMask) + { + // Note: these separate values are not supported in WebGL, due to D3D's limitations. + // See Section 6.10 of the WebGL 1.0 spec + ERR("This ANGLE implementation does not support separate front/back stencil " + "writemasks, reference values, or stencil mask values."); + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Framebuffer *fbo = state.getDrawFramebuffer(); + if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + gl::Program *program = state.getProgram(); + if (!program) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!program->validateSamplers(NULL, context->getCaps())) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Buffer validations + const VertexArray *vao = state.getVertexArray(); + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex); + bool attribActive = (program->getSemanticIndex(attributeIndex) != -1); + if (attribActive && attrib.enabled) + { + gl::Buffer *buffer = attrib.buffer.get(); + + if (buffer) + { + GLint64 attribStride = static_cast(ComputeVertexAttributeStride(attrib)); + GLint64 maxVertexElement = 0; + + if (attrib.divisor > 0) + { + maxVertexElement = static_cast(primcount) / static_cast(attrib.divisor); + } + else + { + maxVertexElement = static_cast(maxVertex); + } + + GLint64 attribDataSize = maxVertexElement * attribStride; + + // [OpenGL ES 3.0.2] section 2.9.4 page 40: + // We can return INVALID_OPERATION if our vertex attribute does not have + // enough backing data. + if (attribDataSize > buffer->getSize()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else if (attrib.pointer == NULL) + { + // This is an application error that would normally result in a crash, + // but we catch it and return an error + context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer.")); + return false; + } + } + } + + // Uniform buffer validation + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++) + { + const gl::UniformBlock *uniformBlock = program->getUniformBlockByIndex(uniformBlockIndex); + GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex); + const gl::Buffer *uniformBuffer = state.getIndexedUniformBuffer(blockBinding); + + if (!uniformBuffer) + { + // undefined behaviour + context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer.")); + return false; + } + + size_t uniformBufferSize = state.getIndexedUniformBufferSize(blockBinding); + + if (uniformBufferSize == 0) + { + // Bind the whole buffer. + uniformBufferSize = uniformBuffer->getSize(); + } + + if (uniformBufferSize < uniformBlock->dataSize) + { + // undefined behaviour + context->recordError(Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small.")); + return false; + } + } + + // No-op if zero count + return (count > 0); +} + +bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + if (first < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + const State &state = context->getState(); + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() && + curTransformFeedback->getDrawMode() != mode) + { + // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode + // that does not match the current transform feedback object's draw mode (if transform feedback + // is active), (3.0.2, section 2.14, pg 86) + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!ValidateDrawBase(context, mode, count, count, primcount)) + { + return false; + } + + return true; +} + +bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + if (primcount < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidateDrawArrays(context, mode, first, count, primcount)) + { + return false; + } + + // No-op if zero primitive count + return (primcount > 0); +} + +static bool ValidateDrawInstancedANGLE(Context *context) +{ + // Verify there is at least one active attribute with a divisor of zero + const gl::State& state = context->getState(); + + gl::Program *program = state.getProgram(); + + const VertexArray *vao = state.getVertexArray(); + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex); + bool active = (program->getSemanticIndex(attributeIndex) != -1); + if (active && attrib.divisor == 0) + { + return true; + } + } + + context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute" + "has a divisor of zero.")); + return false; +} + +bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + if (!ValidateDrawInstancedANGLE(context)) + { + return false; + } + + return ValidateDrawArraysInstanced(context, mode, first, count, primcount); +} + +bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut) +{ + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + break; + case GL_UNSIGNED_INT: + if (!context->getExtensions().elementIndexUint) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const State &state = context->getState(); + + gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) + { + // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced + // while transform feedback is active, (3.0.2, section 2.14, pg 86) + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Check for mapped buffers + if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::VertexArray *vao = state.getVertexArray(); + gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer(); + if (!indices && !elementArrayBuffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (elementArrayBuffer) + { + const gl::Type &typeInfo = gl::GetTypeInfo(type); + + GLint64 offset = reinterpret_cast(indices); + GLint64 byteCount = static_cast(typeInfo.bytes) * static_cast(count)+offset; + + // check for integer overflows + if (static_cast(count) > (std::numeric_limits::max() / typeInfo.bytes) || + byteCount > static_cast(std::numeric_limits::max())) + { + context->recordError(Error(GL_OUT_OF_MEMORY)); + return false; + } + + // Check for reading past the end of the bound buffer object + if (byteCount > elementArrayBuffer->getSize()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else if (!indices) + { + // Catch this programming error here + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Use max index to validate if our vertex buffers are large enough for the pull. + // TODO: offer fast path, with disabled index validation. + // TODO: also disable index checking on back-ends that are robust to out-of-range accesses. + if (elementArrayBuffer) + { + uintptr_t offset = reinterpret_cast(indices); + if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut)) + { + rx::BufferImpl *bufferImpl = elementArrayBuffer->getImplementation(); + const uint8_t *dataPointer = NULL; + Error error = bufferImpl->getData(&dataPointer); + if (error.isError()) + { + context->recordError(error); + return false; + } + + const uint8_t *offsetPointer = dataPointer + offset; + *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count); + elementArrayBuffer->getIndexRangeCache()->addRange(type, offset, count, *indexRangeOut); + } + } + else + { + *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count); + } + + if (!ValidateDrawBase(context, mode, count, static_cast(indexRangeOut->end), primcount)) + { + return false; + } + + return true; +} + +bool ValidateDrawElementsInstanced(Context *context, + GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount, + rx::RangeUI *indexRangeOut) +{ + if (primcount < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut)) + { + return false; + } + + // No-op zero primitive count + return (primcount > 0); +} + +bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut) +{ + if (!ValidateDrawInstancedANGLE(context)) + { + return false; + } + + return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut); +} + +bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level) +{ + if (!ValidFramebufferTarget(target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (!ValidateAttachmentTarget(context, attachment)) + { + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + + if (tex == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (level < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + + const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); + + if (framebufferHandle == 0 || !framebuffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + // Attachments are required to be bound to level 0 in ES2 + if (context->getClientVersion() < 3 && level != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + ASSERT(tex); + + const gl::Caps &caps = context->getCaps(); + + switch (textarget) + { + case GL_TEXTURE_2D: + { + if (level > gl::log2(caps.max2DTextureSize)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + if (tex->getTarget() != GL_TEXTURE_2D) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + 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 (level > gl::log2(caps.maxCubeMapTextureSize)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(textarget, level)); + if (internalFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +bool ValidateGetUniformBase(Context *context, GLuint program, GLint location) +{ + if (program == 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidProgram(context, program)) + { + return false; + } + + gl::Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!programObject->isValidUniformLocation(location)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params) +{ + return ValidateGetUniformBase(context, program, location); +} + +bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params) +{ + return ValidateGetUniformBase(context, program, location); +} + +static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize) +{ + if (!ValidateGetUniformBase(context, program, location)) + { + return false; + } + + gl::Program *programObject = context->getProgram(program); + ASSERT(programObject); + + // sized queries -- ensure the provided buffer is large enough + LinkedUniform *uniform = programObject->getUniformByLocation(location); + size_t requiredBytes = VariableExternalSize(uniform->type); + if (static_cast(bufSize) < requiredBytes) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params) +{ + return ValidateSizedGetUniform(context, program, location, bufSize); +} + +bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params) +{ + return ValidateSizedGetUniform(context, program, location, bufSize); +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/validationES.h b/src/3rdparty/angle/src/libANGLE/validationES.h new file mode 100644 index 0000000000..b0ccd8eecc --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES.h @@ -0,0 +1,94 @@ +// +// Copyright (c) 2013 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. +// + +// validationES.h: Validation functions for generic OpenGL ES entry point parameters + +#ifndef LIBANGLE_VALIDATION_ES_H_ +#define LIBANGLE_VALIDATION_ES_H_ + +#include "common/mathutil.h" + +#include +#include + +namespace gl +{ + +class Context; + +bool ValidCap(const Context *context, GLenum cap); +bool ValidTextureTarget(const Context *context, GLenum target); +bool ValidTexture2DDestinationTarget(const Context *context, GLenum target); +bool ValidFramebufferTarget(GLenum target); +bool ValidBufferTarget(const Context *context, GLenum target); +bool ValidBufferParameter(const Context *context, GLenum pname); +bool ValidMipLevel(const Context *context, GLenum target, GLint level); +bool ValidImageSize(const Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth); +bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height); +bool ValidQueryType(const Context *context, GLenum queryType); +bool ValidProgram(Context *context, GLuint id); + +bool ValidateAttachmentTarget(Context *context, GLenum attachment); +bool ValidateRenderbufferStorageParametersBase(Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height); +bool ValidateRenderbufferStorageParametersANGLE(Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height); + +bool ValidateFramebufferRenderbufferParameters(Context *context, GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer); + +bool ValidateBlitFramebufferParameters(Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, + GLenum filter, bool fromAngleExtension); + +bool ValidateGetVertexAttribParameters(Context *context, GLenum pname); + +bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param); + +bool ValidateSamplerObjectParameter(Context *context, GLenum pname); + +bool ValidateReadPixelsParameters(Context *context, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels); + +bool ValidateBeginQuery(Context *context, GLenum target, GLuint id); +bool ValidateEndQuery(Context *context, GLenum target); + +bool ValidateUniform(Context *context, GLenum uniformType, GLint location, GLsizei count); +bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location, GLsizei count, + GLboolean transpose); + +bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams); + +bool ValidateCopyTexImageParametersBase(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border, GLenum *textureInternalFormatOut); + +bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); +bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); +bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); + +bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut); + +bool ValidateDrawElementsInstanced(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut); +bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut); + +bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level); +bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level); + +bool ValidateGetUniformBase(Context *context, GLuint program, GLint location); +bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params); +bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params); +bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params); +bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params); + +} + +#endif // LIBANGLE_VALIDATION_ES_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.cpp b/src/3rdparty/angle/src/libANGLE/validationES2.cpp new file mode 100644 index 0000000000..9eece1b54a --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES2.cpp @@ -0,0 +1,882 @@ +// +// Copyright (c) 2013-2014 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. +// + +// validationES2.cpp: Validation functions for OpenGL ES 2.0 entry point parameters + +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES.h" +#include "libANGLE/Context.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/FramebufferAttachment.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (!ValidImageSize(context, target, level, width, height, 1)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (level < 0 || xoffset < 0 || + std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!isSubImage && !isCompressed && internalformat != format) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + if (target == GL_TEXTURE_2D) + { + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else if (IsCubeMapTextureTarget(target)) + { + if (!isSubImage && width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || + static_cast(height) > (caps.maxCubeMapTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (isSubImage) + { + if (format != GL_NONE) + { + if (gl::GetSizedInternalFormat(format, type) != texture->getInternalFormat(target, level)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + else + { + if (texture->isImmutable()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + // Verify zero border + if (border != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat; + const InternalFormat &actualFormatInfo = GetInternalFormatInfo(actualInternalFormat); + + if (isCompressed != actualFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (isCompressed) + { + if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + switch (actualInternalFormat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + else + { + // 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: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // 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: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RED: + case GL_RG: + if (!context->getExtensions().textureRG) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_FLOAT: + case GL_HALF_FLOAT_OES: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + 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: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + 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: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_BGRA_EXT: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_SRGB_EXT: + case GL_SRGB_ALPHA_EXT: + if (!context->getExtensions().sRGB) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + 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: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_DEPTH_STENCIL_OES: + switch (type) + { + case GL_UNSIGNED_INT_24_8_OES: + break; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + switch (format) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + if (!context->getExtensions().depthTextures) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + if (target != GL_TEXTURE_2D) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + // OES_depth_texture supports loading depth data and multiple levels, + // but ANGLE_depth_texture does not + if (pixels != NULL || level != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + default: + break; + } + + if (type == GL_FLOAT) + { + if (!context->getExtensions().textureFloat) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + else if (type == GL_HALF_FLOAT_OES) + { + if (!context->getExtensions().textureHalfFloat) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + } + + return true; +} + + + +bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) +{ + GLenum textureInternalFormat = GL_NONE; + + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, + xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat)) + { + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat(); + const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat); + GLenum textureFormat = internalFormatInfo.format; + + // [OpenGL ES 2.0.24] table 3.9 + if (isSubImage) + { + switch (textureFormat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_LUMINANCE: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RED_EXT: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_R32F && + colorbufferFormat != GL_RG32F && + colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RG_EXT: + if (colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_RG32F && + colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_RGB32F && + colorbufferFormat != GL_RGBA32F) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_RGBA32F) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + 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: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_OES: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (internalFormatInfo.type == GL_FLOAT && + !context->getExtensions().textureFloat) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else + { + switch (internalformat) + { + case GL_ALPHA: + if (colorbufferFormat != GL_ALPHA8_EXT && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_LUMINANCE: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RED_EXT: + if (colorbufferFormat != GL_R8_EXT && + colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RG_EXT: + if (colorbufferFormat != GL_RG8_EXT && + colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_RGB: + if (colorbufferFormat != GL_RGB565 && + colorbufferFormat != GL_RGB8_OES && + colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + if (colorbufferFormat != GL_RGBA4 && + colorbufferFormat != GL_RGB5_A1 && + colorbufferFormat != GL_BGRA8_EXT && + colorbufferFormat != GL_RGBA8_OES && + colorbufferFormat != GL_BGR5_A1_ANGLEX) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (context->getExtensions().textureCompressionDXT3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (context->getExtensions().textureCompressionDXT5) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + 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->getExtensions().depthTextures) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + else + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + + // If width or height is zero, it is a no-op. Return false without setting an error. + return (width > 0 && height > 0); +} + +bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height) +{ + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (width < 1 || height < 1 || levels < 1) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (target == GL_TEXTURE_CUBE_MAP && width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + switch (target) + { + case GL_TEXTURE_2D: + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + case GL_TEXTURE_CUBE_MAP: + if (static_cast(width) > caps.maxCubeMapTextureSize || + static_cast(height) > caps.maxCubeMapTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (levels != 1 && !context->getExtensions().textureNPOT) + { + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + switch (internalformat) + { + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + if (!context->getExtensions().textureCompressionDXT1) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: + if (!context->getExtensions().textureCompressionDXT3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: + if (!context->getExtensions().textureCompressionDXT5) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_RGBA32F_EXT: + case GL_RGB32F_EXT: + case GL_ALPHA32F_EXT: + case GL_LUMINANCE32F_EXT: + case GL_LUMINANCE_ALPHA32F_EXT: + if (!context->getExtensions().textureFloat) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_RGBA16F_EXT: + case GL_RGB16F_EXT: + case GL_ALPHA16F_EXT: + case GL_LUMINANCE16F_EXT: + case GL_LUMINANCE_ALPHA16F_EXT: + if (!context->getExtensions().textureHalfFloat) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_R8_EXT: + case GL_RG8_EXT: + case GL_R16F_EXT: + case GL_RG16F_EXT: + case GL_R32F_EXT: + case GL_RG32F_EXT: + if (!context->getExtensions().textureRG) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT32_OES: + case GL_DEPTH24_STENCIL8_OES: + if (!context->getExtensions().depthTextures) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + if (target != GL_TEXTURE_2D) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + // ANGLE_depth_texture only supports 1-level textures + if (levels != 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + break; + default: + break; + } + + gl::Texture *texture = context->getTargetTexture(target); + if (!texture || texture->id() == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (texture->isImmutable()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +// check for combinations of format and type that are valid for ReadPixels +bool ValidES2ReadFormatType(Context *context, 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; + case GL_RG_EXT: + case GL_RED_EXT: + if (!context->getExtensions().textureRG) + { + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + + default: + return false; + } + return true; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/validationES2.h b/src/3rdparty/angle/src/libANGLE/validationES2.h new file mode 100644 index 0000000000..b9c1fd3bc4 --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES2.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2013 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. +// + +// validationES2.h: Validation functions for OpenGL ES 2.0 entry point parameters + +#ifndef LIBANGLE_VALIDATION_ES2_H_ +#define LIBANGLE_VALIDATION_ES2_H_ + +#include + +namespace gl +{ + +class Context; + +bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, const GLvoid *pixels); + +bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, + GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, + GLint border); + +bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height); + +bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type); + +} + +#endif // LIBANGLE_VALIDATION_ES2_H_ diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.cpp b/src/3rdparty/angle/src/libANGLE/validationES3.cpp new file mode 100644 index 0000000000..e141bb6ece --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES3.cpp @@ -0,0 +1,1282 @@ +// +// Copyright (c) 2013-2014 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. +// + +// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters + +#include "libANGLE/validationES3.h" +#include "libANGLE/validationES.h" +#include "libANGLE/Context.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/formatutils.h" +#include "libANGLE/FramebufferAttachment.h" + +#include "common/mathutil.h" +#include "common/utilities.h" + +namespace gl +{ + +struct ES3FormatCombination +{ + GLenum internalFormat; + GLenum format; + GLenum type; +}; + +bool operator<(const ES3FormatCombination& a, const ES3FormatCombination& b) +{ + return memcmp(&a, &b, sizeof(ES3FormatCombination)) < 0; +} + +typedef std::set ES3FormatCombinationSet; + +static inline void InsertES3FormatCombo(ES3FormatCombinationSet *set, GLenum internalFormat, GLenum format, GLenum type) +{ + ES3FormatCombination info; + info.internalFormat = internalFormat; + info.format = format; + info.type = type; + set->insert(info); +} + +ES3FormatCombinationSet BuildES3FormatSet() +{ + ES3FormatCombinationSet set; + + // Format combinations from ES 3.0.1 spec, table 3.2 + + // | Internal format | Format | Type | + // | | | | + InsertES3FormatCombo(&set, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 ); + InsertES3FormatCombo(&set, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV ); + InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV ); + InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 ); + InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_RGBA32F, GL_RGBA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT ); + InsertES3FormatCombo(&set, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT ); + InsertES3FormatCombo(&set, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV ); + InsertES3FormatCombo(&set, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB8_SNORM, GL_RGB, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 ); + InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV ); + InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV ); + InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_RGB32F, GL_RGB, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT ); + InsertES3FormatCombo(&set, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_RGB32I, GL_RGB_INTEGER, GL_INT ); + InsertES3FormatCombo(&set, GL_RG8, GL_RG, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RG8_SNORM, GL_RG, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_RG32F, GL_RG, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RG8I, GL_RG_INTEGER, GL_BYTE ); + InsertES3FormatCombo(&set, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_RG16I, GL_RG_INTEGER, GL_SHORT ); + InsertES3FormatCombo(&set, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_RG32I, GL_RG_INTEGER, GL_INT ); + InsertES3FormatCombo(&set, GL_R8, GL_RED, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_R8_SNORM, GL_RED, GL_BYTE ); + InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_R32F, GL_RED, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_R8I, GL_RED_INTEGER, GL_BYTE ); + InsertES3FormatCombo(&set, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_R16I, GL_RED_INTEGER, GL_SHORT ); + InsertES3FormatCombo(&set, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_R32I, GL_RED_INTEGER, GL_INT ); + + // Unsized formats + InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 ); + InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 ); + InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE ); + + // Depth stencil formats + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT ); + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 ); + InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); + + // From GL_EXT_sRGB + InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_SRGB8, GL_SRGB_EXT, GL_UNSIGNED_BYTE ); + + // From GL_OES_texture_float + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_FLOAT ); + + // From GL_OES_texture_half_float + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES ); + + // From GL_EXT_texture_format_BGRA8888 + InsertES3FormatCombo(&set, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); + + // From GL_EXT_texture_storage + // | Internal format | Format | Type | + // | | | | + InsertES3FormatCombo(&set, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT ); + InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT ); + InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES ); + + // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888 + InsertES3FormatCombo(&set, GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT); + InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); + InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT); + InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); + + // From GL_ANGLE_depth_texture + InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES ); + + // Compressed formats + // From ES 3.0.1 spec, table 3.16 + // | Internal format | Format | Type | + // | | | | + InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE); + + + // From GL_EXT_texture_compression_dxt1 + InsertES3FormatCombo(&set, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE); + InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE); + + // From GL_ANGLE_texture_compression_dxt3 + InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE); + + // From GL_ANGLE_texture_compression_dxt5 + InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE); + + return set; +} + +static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type) +{ + // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid + // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d) + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // The type and format are valid if any supported internal format has that type and format + bool formatSupported = false; + bool typeSupported = false; + + static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet(); + for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++) + { + if (i->format == format || i->type == type) + { + const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat); + bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions()); + if (supported && i->type == type) + { + typeSupported = true; + } + if (supported && i->format == format) + { + formatSupported = true; + } + + // Early-out if both type and format are supported now + if (typeSupported && formatSupported) + { + break; + } + } + } + + if (!typeSupported || !formatSupported) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // Check if this is a valid format combination to load texture data + ES3FormatCombination searchFormat; + searchFormat.internalFormat = internalFormat; + searchFormat.format = format; + searchFormat.type = type; + + if (es3FormatSet.find(searchFormat) == es3FormatSet.end()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return true; +} + +bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const GLvoid *pixels) +{ + if (!ValidTexture2DDestinationTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + // Validate image size + if (!ValidImageSize(context, target, level, width, height, depth)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + // Verify zero border + if (border != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (xoffset < 0 || yoffset < 0 || zoffset < 0 || + std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height || + std::numeric_limits::max() - zoffset < depth) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + switch (target) + { + case GL_TEXTURE_2D: + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + 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 (!isSubImage && width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(width) > (caps.maxCubeMapTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + + case GL_TEXTURE_3D: + if (static_cast(width) > (caps.max3DTextureSize >> level) || + static_cast(height) > (caps.max3DTextureSize >> level) || + static_cast(depth) > (caps.max3DTextureSize >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + + case GL_TEXTURE_2D_ARRAY: + if (static_cast(width) > (caps.max2DTextureSize >> level) || + static_cast(height) > (caps.max2DTextureSize >> level) || + static_cast(depth) > (caps.maxArrayTextureLayers >> level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + if (!texture) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (texture->isImmutable() && !isSubImage) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // Validate texture formats + GLenum actualInternalFormat = isSubImage ? texture->getInternalFormat(target, level) : internalformat; + const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat); + if (isCompressed) + { + if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (!actualFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (target == GL_TEXTURE_3D) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else + { + if (!ValidateTexImageFormatCombination(context, actualInternalFormat, format, type)) + { + return false; + } + + if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + // Validate sub image parameters + if (isSubImage) + { + if (isCompressed != actualFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (width == 0 || height == 0 || depth == 0) + { + return false; + } + + if (xoffset < 0 || yoffset < 0 || zoffset < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (std::numeric_limits::max() - xoffset < width || + std::numeric_limits::max() - yoffset < height || + std::numeric_limits::max() - zoffset < depth) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(xoffset + width) > texture->getWidth(target, level) || + static_cast(yoffset + height) > texture->getHeight(target, level) || + static_cast(zoffset + depth) > texture->getDepth(target, level)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + + // Check for pixel unpack buffer related API errors + gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER); + if (pixelUnpackBuffer != NULL) + { + // ...the data would be unpacked from the buffer object such that the memory reads required + // would exceed the data store size. + size_t widthSize = static_cast(width); + size_t heightSize = static_cast(height); + size_t depthSize = static_cast(depth); + GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type); + + size_t pixelBytes = static_cast(gl::GetInternalFormatInfo(sizedFormat).pixelBytes); + + if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) || + !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) || + !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes)) + { + // Overflow past the end of the buffer + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat); + size_t copyBytes = formatInfo.computeBlockSize(type, width, height); + size_t offset = reinterpret_cast(pixels); + + if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) || + ((offset + copyBytes) > static_cast(pixelUnpackBuffer->getSize()))) + { + // Overflow past the end of the buffer + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // ...data is not evenly divisible into the number of bytes needed to store in memory a datum + // indicated by type. + if (!isCompressed) + { + size_t dataBytesPerPixel = static_cast(gl::GetTypeInfo(type).bytes); + + if ((offset % dataBytesPerPixel) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + // ...the buffer object's data store is currently mapped. + if (pixelUnpackBuffer->isMapped()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +struct EffectiveInternalFormatInfo +{ + GLenum mEffectiveFormat; + GLenum mDestFormat; + GLuint mMinRedBits; + GLuint mMaxRedBits; + GLuint mMinGreenBits; + GLuint mMaxGreenBits; + GLuint mMinBlueBits; + GLuint mMaxBlueBits; + GLuint mMinAlphaBits; + GLuint mMaxAlphaBits; + + EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits, + GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits, + GLuint minAlphaBits, GLuint maxAlphaBits) + : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits), + mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits), + mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits), + mMaxAlphaBits(maxAlphaBits) {}; +}; + +typedef std::vector EffectiveInternalFormatList; + +static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList() +{ + EffectiveInternalFormatList list; + + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and + // linear source buffer component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | N/A | R | G | B | A | + list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2)); + + return list; +} + +static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList() +{ + EffectiveInternalFormatList list; + + // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and + // linear source buffer component sizes. + // | Source channel min/max sizes | + // Effective Internal Format | Dest Format | R | G | B | A | + list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_ALPHA, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, UINT_MAX)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4)); + list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1)); + list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8)); + + return list; +} + +static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat, + GLenum *outEffectiveFormat) +{ + const EffectiveInternalFormatList *list = NULL; + GLenum targetFormat = GL_NONE; + + if (destFormat.pixelBytes > 0) + { + static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList(); + list = &sizedList; + } + else + { + static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList(); + list = &unsizedList; + targetFormat = destFormat.format; + } + + for (size_t curFormat = 0; curFormat < list->size(); ++curFormat) + { + const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat); + if ((formatInfo.mDestFormat == targetFormat) && + (formatInfo.mMinRedBits <= srcFormat.redBits && formatInfo.mMaxRedBits >= srcFormat.redBits) && + (formatInfo.mMinGreenBits <= srcFormat.greenBits && formatInfo.mMaxGreenBits >= srcFormat.greenBits) && + (formatInfo.mMinBlueBits <= srcFormat.blueBits && formatInfo.mMaxBlueBits >= srcFormat.blueBits) && + (formatInfo.mMinAlphaBits <= srcFormat.alphaBits && formatInfo.mMaxAlphaBits >= srcFormat.alphaBits)) + { + *outEffectiveFormat = formatInfo.mEffectiveFormat; + return true; + } + } + + return false; +} + +struct CopyConversion +{ + GLenum mTextureFormat; + GLenum mFramebufferFormat; + + CopyConversion(GLenum textureFormat, GLenum framebufferFormat) + : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { } + + bool operator<(const CopyConversion& other) const + { + return memcmp(this, &other, sizeof(CopyConversion)) < 0; + } +}; + +typedef std::set CopyConversionSet; + +static CopyConversionSet BuildValidES3CopyTexImageCombinations() +{ + CopyConversionSet set; + + // From ES 3.0.1 spec, table 3.15 + set.insert(CopyConversion(GL_ALPHA, GL_RGBA)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RED)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RG)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RGB)); + set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA)); + set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA)); + set.insert(CopyConversion(GL_RED, GL_RED)); + set.insert(CopyConversion(GL_RED, GL_RG)); + set.insert(CopyConversion(GL_RED, GL_RGB)); + set.insert(CopyConversion(GL_RED, GL_RGBA)); + set.insert(CopyConversion(GL_RG, GL_RG)); + set.insert(CopyConversion(GL_RG, GL_RGB)); + set.insert(CopyConversion(GL_RG, GL_RGBA)); + set.insert(CopyConversion(GL_RGB, GL_RGB)); + set.insert(CopyConversion(GL_RGB, GL_RGBA)); + set.insert(CopyConversion(GL_RGBA, GL_RGBA)); + + // Necessary for ANGLE back-buffers + set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RED, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RG, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT)); + set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT)); + + set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER)); + set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER)); + set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER)); + + return set; +} + +static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle) +{ + const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat); + const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat); + + static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations(); + if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end()) + { + // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats + // must both be signed, unsigned, or fixed point and both source and destinations + // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed + // conversion between fixed and floating point. + + if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)) + { + return false; + } + + if (((textureInternalFormatInfo.componentType == GL_INT) != (framebufferInternalFormatInfo.componentType == GL_INT )) || + ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT))) + { + return false; + } + + if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || + textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED || + textureInternalFormatInfo.componentType == GL_FLOAT) && + !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || + framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED || + framebufferInternalFormatInfo.componentType == GL_FLOAT)) + { + return false; + } + + // GLES specification 3.0.3, sec 3.8.5, pg 139-140: + // The effective internal format of the source buffer is determined with the following rules applied in order: + // * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the + // effective internal format is the source buffer's sized internal format. + // * If the source buffer is a texture that was created with an unsized base internal format, then the + // effective internal format is the source image array's effective internal format, as specified by table + // 3.12, which is determined from the and that were used when the source image array was + // specified by TexImage*. + // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where + // Destination Internal Format matches internalformat and where the [source channel sizes] are consistent + // with the values of the source buffer's [channel sizes]. Table 3.17 is used if the + // FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING + // is SRGB. + const InternalFormat *sourceEffectiveFormat = NULL; + if (readBufferHandle != 0) + { + // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer + if (framebufferInternalFormatInfo.pixelBytes > 0) + { + sourceEffectiveFormat = &framebufferInternalFormatInfo; + } + else + { + // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format + // texture. We can use the same table we use when creating textures to get its effective sized format. + GLenum sizedInternalFormat = GetSizedInternalFormat(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type); + sourceEffectiveFormat = &GetInternalFormatInfo(sizedInternalFormat); + } + } + else + { + // The effective internal format must be derived from the source framebuffer's channel sizes. + // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17) + if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR) + { + GLenum effectiveFormat; + if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat)) + { + sourceEffectiveFormat = &GetInternalFormatInfo(effectiveFormat); + } + else + { + return false; + } + } + else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB) + { + // SRGB buffers can only be copied to sized format destinations according to table 3.18 + if ((textureInternalFormatInfo.pixelBytes > 0) && + (framebufferInternalFormatInfo.redBits >= 1 && framebufferInternalFormatInfo.redBits <= 8) && + (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) && + (framebufferInternalFormatInfo.blueBits >= 1 && framebufferInternalFormatInfo.blueBits <= 8) && + (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8)) + { + sourceEffectiveFormat = &GetInternalFormatInfo(GL_SRGB8_ALPHA8); + } + else + { + return false; + } + } + else + { + UNREACHABLE(); + return false; + } + } + + if (textureInternalFormatInfo.pixelBytes > 0) + { + // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized, + // component sizes of the source and destination formats must exactly match + if (textureInternalFormatInfo.redBits != sourceEffectiveFormat->redBits || + textureInternalFormatInfo.greenBits != sourceEffectiveFormat->greenBits || + textureInternalFormatInfo.blueBits != sourceEffectiveFormat->blueBits || + textureInternalFormatInfo.alphaBits != sourceEffectiveFormat->alphaBits) + { + return false; + } + } + + + return true; // A conversion function exists, and no rule in the specification has precluded conversion + // between these formats. + } + + return false; +} + +bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, + bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + GLenum textureInternalFormat; + if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, + xoffset, yoffset, zoffset, x, y, width, height, + border, &textureInternalFormat)) + { + return false; + } + + gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + + if (framebuffer->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (context->getState().getReadFramebuffer()->id() != 0 && + framebuffer->getSamples(context->getData()) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer(); + GLenum colorbufferInternalFormat = source->getInternalFormat(); + + if (isSubImage) + { + if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, + context->getState().getReadFramebuffer()->id())) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else + { + if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat, + context->getState().getReadFramebuffer()->id())) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + // If width or height is zero, it is a no-op. Return false without setting an error. + return (width > 0 && height > 0); +} + +bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth) +{ + if (width < 1 || height < 1 || depth < 1 || levels < 1) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Caps &caps = context->getCaps(); + + switch (target) + { + case GL_TEXTURE_2D: + { + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + case GL_TEXTURE_CUBE_MAP: + { + if (width != height) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(width) > caps.maxCubeMapTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + case GL_TEXTURE_3D: + { + if (static_cast(width) > caps.max3DTextureSize || + static_cast(height) > caps.max3DTextureSize || + static_cast(depth) > caps.max3DTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + if (static_cast(width) > caps.max2DTextureSize || + static_cast(height) > caps.max2DTextureSize || + static_cast(depth) > caps.maxArrayTextureLayers) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + gl::Texture *texture = context->getTargetTexture(target); + if (!texture || texture->id() == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (texture->isImmutable()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (formatInfo.pixelBytes == 0) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + return true; +} + +bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + if (layer < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) + { + return false; + } + + const gl::Caps &caps = context->getCaps(); + if (texture != 0) + { + gl::Texture *tex = context->getTexture(texture); + ASSERT(tex); + + switch (tex->getTarget()) + { + case GL_TEXTURE_2D_ARRAY: + { + if (level > gl::log2(caps.max2DTextureSize)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(layer) >= caps.maxArrayTextureLayers) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + case GL_TEXTURE_3D: + { + if (level > gl::log2(caps.max3DTextureSize)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + if (static_cast(layer) >= caps.max3DTextureSize) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(tex->getInternalFormat(tex->getTarget(), level)); + if (internalFormatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + + return true; +} + +bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type) +{ + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); + + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (internalFormat != GL_RGB10_A2) + { + return false; + } + break; + case GL_FLOAT: + if (internalFormatInfo.componentType != GL_FLOAT) + { + return false; + } + break; + default: + return false; + } + break; + case GL_RGBA_INTEGER: + switch (type) + { + case GL_INT: + if (internalFormatInfo.componentType != GL_INT) + { + return false; + } + break; + case GL_UNSIGNED_INT: + if (internalFormatInfo.componentType != GL_UNSIGNED_INT) + { + return false; + } + 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; + case GL_RG_EXT: + case GL_RED_EXT: + if (!context->getExtensions().textureRG) + { + return false; + } + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; + default: + return false; + } + return true; +} + +bool ValidateES3RenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height) +{ + if (!ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height)) + { + return false; + } + + //The ES3 spec(section 4.4.2) states that the internal format must be sized and not an integer format if samples is greater than zero. + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); + if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + // The behavior is different than the ANGLE version, which would generate a GL_OUT_OF_MEMORY. + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (static_cast(samples) > formatCaps.getMaxSamples()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return false; + } + + return true; +} + +bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GLsizei numAttachments, + const GLenum* attachments) +{ + bool defaultFramebuffer = false; + + switch (target) + { + case GL_DRAW_FRAMEBUFFER: + case GL_FRAMEBUFFER: + defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0; + break; + case GL_READ_FRAMEBUFFER: + defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0; + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + for (int i = 0; i < numAttachments; ++i) + { + if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) + { + if (defaultFramebuffer) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + + if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + } + else + { + switch (attachments[i]) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + case GL_DEPTH_STENCIL_ATTACHMENT: + if (defaultFramebuffer) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + case GL_COLOR: + case GL_DEPTH: + case GL_STENCIL: + if (!defaultFramebuffer) + { + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return false; + } + } + } + + return true; +} + +bool ValidateClearBuffer(Context *context) +{ + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer(); + if (!fbo || fbo->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + return true; +} + +bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params) +{ + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + return ValidateGetUniformBase(context, program, location); +} + +bool ValidateReadBuffer(Context *context, GLenum src) +{ + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } + + Framebuffer *readFBO = context->getState().getReadFramebuffer(); + + if (readFBO == nullptr) + { + context->recordError(gl::Error(GL_INVALID_OPERATION, "No active read framebuffer.")); + return false; + } + + if (src == GL_NONE) + { + return true; + } + + if (src != GL_BACK && (src < GL_COLOR_ATTACHMENT0 || src > GL_COLOR_ATTACHMENT15)) + { + context->recordError(gl::Error(GL_INVALID_ENUM, "Unknown enum for 'src' in ReadBuffer")); + return false; + } + + if (readFBO->id() == 0) + { + if (src != GL_BACK) + { + const char *errorMsg = "'src' must be GL_NONE or GL_BACK when reading from the default framebuffer."; + context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg)); + return false; + } + } + else + { + GLuint drawBuffer = static_cast(src - GL_COLOR_ATTACHMENT0); + + if (drawBuffer >= context->getCaps().maxDrawBuffers) + { + const char *errorMsg = "'src' is greater than MAX_DRAW_BUFFERS."; + context->recordError(gl::Error(GL_INVALID_OPERATION, errorMsg)); + return false; + } + } + + return true; +} + +} diff --git a/src/3rdparty/angle/src/libANGLE/validationES3.h b/src/3rdparty/angle/src/libANGLE/validationES3.h new file mode 100644 index 0000000000..517cb5d27f --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/validationES3.h @@ -0,0 +1,49 @@ +// +// Copyright (c) 2013 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. +// + +// validationES3.h: Validation functions for OpenGL ES 3.0 entry point parameters + +#ifndef LIBANGLE_VALIDATION_ES3_H_ +#define LIBANGLE_VALIDATION_ES3_H_ + +#include + +namespace gl +{ + +class Context; + +bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, + GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum format, GLenum type, const GLvoid *pixels); + +bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, + bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, + GLsizei width, GLsizei height, GLint border); + +bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth); + +bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer); + +bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type); + +bool ValidateES3RenderbufferStorageParameters(Context *context, GLenum target, GLsizei samples, + GLenum internalformat, GLsizei width, GLsizei height); + +bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GLsizei numAttachments, + const GLenum* attachments); + +bool ValidateClearBuffer(Context *context); + +bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params); + +bool ValidateReadBuffer(Context *context, GLenum mode); + +} + +#endif // LIBANGLE_VALIDATION_ES3_H_ diff --git a/src/3rdparty/angle/src/libEGL/AttributeMap.cpp b/src/3rdparty/angle/src/libEGL/AttributeMap.cpp deleted file mode 100644 index 28dd3d842e..0000000000 --- a/src/3rdparty/angle/src/libEGL/AttributeMap.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) 2014 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 "libEGL/AttributeMap.h" - -namespace egl -{ - -AttributeMap::AttributeMap() -{ -} - -AttributeMap::AttributeMap(const EGLint *attributes) -{ - for (const EGLint *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) - { - insert(curAttrib[0], curAttrib[1]); - } -} - -void AttributeMap::insert(EGLint key, EGLint value) -{ - mAttributes[key] = value; -} - -bool AttributeMap::contains(EGLint key) const -{ - return (mAttributes.find(key) != mAttributes.end()); -} - -EGLint AttributeMap::get(EGLint key, EGLint defaultValue) const -{ - std::map::const_iterator iter = mAttributes.find(key); - return (mAttributes.find(key) != mAttributes.end()) ? iter->second : defaultValue; -} - -} diff --git a/src/3rdparty/angle/src/libEGL/AttributeMap.h b/src/3rdparty/angle/src/libEGL/AttributeMap.h deleted file mode 100644 index f2f082fe21..0000000000 --- a/src/3rdparty/angle/src/libEGL/AttributeMap.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright (c) 2014 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 LIBEGL_ATTRIBUTEMAP_H_ -#define LIBEGL_ATTRIBUTEMAP_H_ - -#include - -#include - -namespace egl -{ - -class AttributeMap -{ - public: - AttributeMap(); - explicit AttributeMap(const EGLint *attributes); - - virtual void insert(EGLint key, EGLint value); - virtual bool contains(EGLint key) const; - virtual EGLint get(EGLint key, EGLint defaultValue) const; - - private: - std::map mAttributes; -}; - -} - -#endif // LIBEGL_ATTRIBUTEMAP_H_ diff --git a/src/3rdparty/angle/src/libEGL/Config.cpp b/src/3rdparty/angle/src/libEGL/Config.cpp deleted file mode 100644 index fdc41a95f0..0000000000 --- a/src/3rdparty/angle/src/libEGL/Config.cpp +++ /dev/null @@ -1,353 +0,0 @@ -// -// 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 "angle_gl.h" -#include - -#include "common/debug.h" - -using namespace std; - -namespace egl -{ -Config::Config(rx::ConfigDesc desc, EGLint minInterval, EGLint maxInterval, EGLint texWidth, EGLint texHeight) - : mRenderTargetFormat(desc.renderTargetFormat), mDepthStencilFormat(desc.depthStencilFormat), mMultiSample(desc.multiSample) -{ - mBindToTextureRGB = EGL_FALSE; - mBindToTextureRGBA = EGL_FALSE; - switch (desc.renderTargetFormat) - { - case GL_RGB5_A1: - mBufferSize = 16; - mRedSize = 5; - mGreenSize = 5; - mBlueSize = 5; - mAlphaSize = 1; - break; - case GL_BGR5_A1_ANGLEX: - mBufferSize = 16; - mRedSize = 5; - mGreenSize = 5; - mBlueSize = 5; - mAlphaSize = 1; - break; - case GL_RGBA8_OES: - mBufferSize = 32; - mRedSize = 8; - mGreenSize = 8; - mBlueSize = 8; - mAlphaSize = 8; - mBindToTextureRGBA = true; - break; - case GL_RGB565: - mBufferSize = 16; - mRedSize = 5; - mGreenSize = 6; - mBlueSize = 5; - mAlphaSize = 0; - break; - case GL_RGB8_OES: - mBufferSize = 32; - mRedSize = 8; - mGreenSize = 8; - mBlueSize = 8; - mAlphaSize = 0; - mBindToTextureRGB = true; - break; - case GL_BGRA8_EXT: - mBufferSize = 32; - mRedSize = 8; - mGreenSize = 8; - mBlueSize = 8; - mAlphaSize = 8; - mBindToTextureRGBA = true; - break; - default: - UNREACHABLE(); // Other formats should not be valid - } - - mLuminanceSize = 0; - mAlphaMaskSize = 0; - mColorBufferType = EGL_RGB_BUFFER; - mConfigCaveat = (desc.fastConfig) ? EGL_NONE : EGL_SLOW_CONFIG; - mConfigID = 0; - mConformant = EGL_OPENGL_ES2_BIT; - - switch (desc.depthStencilFormat) - { - case GL_NONE: - mDepthSize = 0; - mStencilSize = 0; - break; - case GL_DEPTH_COMPONENT32_OES: - mDepthSize = 32; - mStencilSize = 0; - break; - case GL_DEPTH24_STENCIL8_OES: - mDepthSize = 24; - mStencilSize = 8; - break; - case GL_DEPTH_COMPONENT24_OES: - mDepthSize = 24; - mStencilSize = 0; - break; - case GL_DEPTH_COMPONENT16: - mDepthSize = 16; - mStencilSize = 0; - 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 = desc.multiSample ? 1 : 0; - mSamples = desc.multiSample; - mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; - mTransparentType = EGL_NONE; - mTransparentRedValue = 0; - mTransparentGreenValue = 0; - mTransparentBlueValue = 0; - - if (desc.es3Capable) - { - mRenderableType |= EGL_OPENGL_ES3_BIT_KHR; - mConformant |= EGL_OPENGL_ES3_BIT_KHR; - } -} - -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(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, EGLint texWidth, EGLint texHeight) -{ - Config config(desc, minSwapInterval, maxSwapInterval, 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 deleted file mode 100644 index 98441142f4..0000000000 --- a/src/3rdparty/angle/src/libEGL/Config.h +++ /dev/null @@ -1,114 +0,0 @@ -// -// 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_ - -#include - -#include - -#include "libGLESv2/renderer/Renderer.h" -#include "common/angleutils.h" - -namespace egl -{ -class Display; - -class Config -{ - public: - Config(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, EGLint texWidth, EGLint texHeight); - - EGLConfig getHandle() const; - - const GLenum mRenderTargetFormat; - const GLenum mDepthStencilFormat; - const GLint 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(rx::ConfigDesc desc, EGLint minSwapInterval, EGLint maxSwapInterval, 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 deleted file mode 100644 index eea93b1d87..0000000000 --- a/src/3rdparty/angle/src/libEGL/Display.cpp +++ /dev/null @@ -1,648 +0,0 @@ -// -// Copyright (c) 2002-2014 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 -#include - -#include "common/debug.h" -#include "common/mathutil.h" -#include "libGLESv2/main.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/renderer/SwapChain.h" - -#include "libEGL/main.h" -#include "libEGL/Surface.h" - -namespace egl -{ - -typedef std::map DisplayMap; -static DisplayMap *GetDisplayMap() -{ - static DisplayMap displays; - return &displays; -} - -egl::Display *Display::getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap) -{ - Display *display = NULL; - - DisplayMap *displays = GetDisplayMap(); - DisplayMap::const_iterator iter = displays->find(displayId); - if (iter != displays->end()) - { - display = iter->second; - } - else - { - display = new egl::Display(displayId); - displays->insert(std::make_pair(displayId, display)); - } - - // Apply new attributes if the display is not initialized yet. - if (!display->isInitialized()) - { - display->setAttributes(attribMap); - } - - return display; -} - -Display::Display(EGLNativeDisplayType displayId) - : mDisplayId(displayId), - mAttributeMap(), - mRenderer(NULL) -{ -} - -Display::~Display() -{ - terminate(); - - DisplayMap *displays = GetDisplayMap(); - DisplayMap::iterator iter = displays->find(mDisplayId); - if (iter != displays->end()) - { - displays->erase(iter); - } -} - -void Display::setAttributes(const AttributeMap &attribMap) -{ - mAttributeMap = attribMap; -} - -Error Display::initialize() -{ - if (isInitialized()) - { - return Error(EGL_SUCCESS); - } - - mRenderer = glCreateRenderer(this, mDisplayId, mAttributeMap); - - if (!mRenderer) - { - terminate(); - return Error(EGL_NOT_INITIALIZED); - } - - //TODO(jmadill): should be part of caps? - EGLint minSwapInterval = mRenderer->getMinSwapInterval(); - EGLint maxSwapInterval = mRenderer->getMaxSwapInterval(); - EGLint maxTextureSize = mRenderer->getRendererCaps().max2DTextureSize; - - rx::ConfigDesc *descList; - int numConfigs = mRenderer->generateConfigs(&descList); - ConfigSet configSet; - - for (int i = 0; i < numConfigs; ++i) - { - configSet.add(descList[i], minSwapInterval, maxSwapInterval, maxTextureSize, maxTextureSize); - } - - // 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); - } - - mRenderer->deleteConfigs(descList); - descList = NULL; - - if (!isInitialized()) - { - terminate(); - return Error(EGL_NOT_INITIALIZED); - } - - initDisplayExtensionString(); - initVendorString(); - - return Error(EGL_SUCCESS); -} - -void Display::terminate() -{ - while (!mSurfaceSet.empty()) - { - destroySurface(*mSurfaceSet.begin()); - } - - while (!mContextSet.empty()) - { - destroyContext(*mContextSet.begin()); - } - - glDestroyRenderer(mRenderer); - mRenderer = NULL; - - mConfigSet.mSet.clear(); -} - -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; -} - - - -Error Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList, EGLSurface *outSurface) -{ - const Config *configuration = mConfigSet.get(config); - EGLint postSubBufferSupported = EGL_FALSE; - - EGLint width = 0; - EGLint height = 0; - EGLint fixedSize = 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); // Rendering directly to front buffer not supported - default: - return Error(EGL_BAD_ATTRIBUTE); - } - break; - case EGL_POST_SUB_BUFFER_SUPPORTED_NV: - postSubBufferSupported = attribList[1]; - break; - case EGL_WIDTH: - width = attribList[1]; - break; - case EGL_HEIGHT: - height = attribList[1]; - break; - case EGL_FIXED_SIZE_ANGLE: - fixedSize = attribList[1]; - break; - case EGL_VG_COLORSPACE: - return Error(EGL_BAD_MATCH); - case EGL_VG_ALPHA_FORMAT: - return Error(EGL_BAD_MATCH); - default: - return Error(EGL_BAD_ATTRIBUTE); - } - - attribList += 2; - } - } - - if (width < 0 || height < 0) - { - return Error(EGL_BAD_PARAMETER); - } - - if (!fixedSize) - { - width = -1; - height = -1; - } - - if (hasExistingWindowSurface(window)) - { - return Error(EGL_BAD_ALLOC); - } - - if (mRenderer->testDeviceLost(false)) - { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } - } - - Surface *surface = new Surface(this, configuration, window, fixedSize, width, height, postSubBufferSupported); - Error error = surface->initialize(); - if (error.isError()) - { - SafeDelete(surface); - return error; - } - - mSurfaceSet.insert(surface); - - *outSurface = surface; - return Error(EGL_SUCCESS); -} - -Error Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList, EGLSurface *outSurface) -{ - 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); - } - 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); - } - break; - case EGL_MIPMAP_TEXTURE: - if (attribList[1] != EGL_FALSE) - return Error(EGL_BAD_ATTRIBUTE); - break; - case EGL_VG_COLORSPACE: - return Error(EGL_BAD_MATCH); - case EGL_VG_ALPHA_FORMAT: - return Error(EGL_BAD_MATCH); - default: - return Error(EGL_BAD_ATTRIBUTE); - } - - attribList += 2; - } - } - - if (width < 0 || height < 0) - { - return Error(EGL_BAD_PARAMETER); - } - - if (width == 0 || height == 0) - { - return Error(EGL_BAD_ATTRIBUTE); - } - - if (textureFormat != EGL_NO_TEXTURE && !mRenderer->getRendererExtensions().textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) - { - return Error(EGL_BAD_MATCH); - } - - if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || - (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) - { - return Error(EGL_BAD_MATCH); - } - - if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT)) - { - return Error(EGL_BAD_MATCH); - } - - if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || - (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)) - { - return Error(EGL_BAD_ATTRIBUTE); - } - - if (mRenderer->testDeviceLost(false)) - { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } - } - - Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget); - Error error = surface->initialize(); - if (error.isError()) - { - SafeDelete(surface); - return error; - } - - mSurfaceSet.insert(surface); - - *outSurface = surface; - return Error(EGL_SUCCESS); -} - -Error Display::createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, - bool robustAccess, EGLContext *outContext) -{ - if (!mRenderer) - { - *outContext = EGL_NO_CONTEXT; - return Error(EGL_SUCCESS); - } - else if (mRenderer->testDeviceLost(false)) // Lost device - { - Error error = restoreLostDevice(); - if (error.isError()) - { - return error; - } - } - - //TODO(jmadill): shader model is not cross-platform - if (clientVersion > 2 && mRenderer->getMajorShaderModel() < 4) - { - return Error(EGL_BAD_CONFIG); - } - - gl::Context *context = glCreateContext(clientVersion, shareContext, mRenderer, notifyResets, robustAccess); - mContextSet.insert(context); - - *outContext = context; - return Error(EGL_SUCCESS); -} - -Error Display::restoreLostDevice() -{ - for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) - { - if ((*ctx)->isResetNotificationEnabled()) - { - // If reset notifications have been requested, application must delete all contexts first - return Error(EGL_CONTEXT_LOST); - } - } - - // Release surface resources to make the Reset() succeed - for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) - { - (*surface)->release(); - } - - if (!mRenderer->resetDevice()) - { - return Error(EGL_BAD_ALLOC); - } - - // Restore any surfaces that may have been lost - for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) - { - Error error = (*surface)->resetSwapChain(); - if (error.isError()) - { - return error; - } - } - - return Error(EGL_SUCCESS); -} - - -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(); - } -} - -void Display::recreateSwapChains() -{ - for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) - { - (*surface)->getSwapChain()->recreate(); - } -} - -bool Display::isInitialized() const -{ - return mRenderer != 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(EGLNativeWindowType window) -{ - for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) - { - if ((*surface)->getWindowHandle() == window) - { - return true; - } - } - - return false; -} - -std::string Display::generateClientExtensionString() -{ - std::vector extensions; - - extensions.push_back("EGL_EXT_client_extensions"); - - extensions.push_back("ANGLE_platform_angle"); - - if (supportsPlatformD3D()) - { - extensions.push_back("ANGLE_platform_angle_d3d"); - } - - if (supportsPlatformOpenGL()) - { - extensions.push_back("ANGLE_platform_angle_opengl"); - } - - std::ostringstream stream; - std::copy(extensions.begin(), extensions.end(), std::ostream_iterator(stream, " ")); - return stream.str(); -} - -void Display::initDisplayExtensionString() -{ - std::vector extensions; - - // Multi-vendor (EXT) extensions - extensions.push_back("EGL_EXT_create_context_robustness"); - - // ANGLE-specific extensions - if (mRenderer->getShareHandleSupport()) - { - extensions.push_back("EGL_ANGLE_d3d_share_handle_client_buffer"); - extensions.push_back("EGL_ANGLE_surface_d3d_texture_2d_share_handle"); - } - - extensions.push_back("EGL_ANGLE_query_surface_pointer"); - extensions.push_back("EGL_ANGLE_window_fixed_size"); - - if (mRenderer->getPostSubBufferSupport()) - { - extensions.push_back("EGL_NV_post_sub_buffer"); - } - -#if defined (ANGLE_TEST_CONFIG) - // TODO: complete support for the EGL_KHR_create_context extension - extensions.push_back("EGL_KHR_create_context"); -#endif - - std::ostringstream stream; - std::copy(extensions.begin(), extensions.end(), std::ostream_iterator(stream, " ")); - mDisplayExtensionString = stream.str(); -} - -const char *Display::getExtensionString(egl::Display *display) -{ - if (display != EGL_NO_DISPLAY) - { - return display->mDisplayExtensionString.c_str(); - } - else - { - static std::string clientExtensions = generateClientExtensionString(); - return clientExtensions.c_str(); - } -} - -bool Display::supportsPlatformD3D() -{ -#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) - return true; -#else - return false; -#endif -} - -bool Display::supportsPlatformOpenGL() -{ - return false; -} - -void Display::initVendorString() -{ - mVendorString = "Google Inc."; - - LUID adapterLuid = {0}; - - //TODO(jmadill): LUID is not cross-platform - if (mRenderer && mRenderer->getLUID(&adapterLuid)) - { - char adapterLuidString[64]; - sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); - - mVendorString += adapterLuidString; - } -} - -const char *Display::getVendorString() const -{ - return mVendorString.c_str(); -} - -} diff --git a/src/3rdparty/angle/src/libEGL/Display.h b/src/3rdparty/angle/src/libEGL/Display.h deleted file mode 100644 index b3ffcc84c5..0000000000 --- a/src/3rdparty/angle/src/libEGL/Display.h +++ /dev/null @@ -1,104 +0,0 @@ -// -// Copyright (c) 2002-2013 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_ - -#include -#include - -#include "libEGL/Error.h" -#include "libEGL/Config.h" -#include "libEGL/AttributeMap.h" - -namespace gl -{ -class Context; -} - -namespace egl -{ -class Surface; - -class Display -{ - public: - ~Display(); - - Error initialize(); - void terminate(); - - static egl::Display *getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap); - - static const char *getExtensionString(egl::Display *display); - - static bool supportsPlatformD3D(); - static bool supportsPlatformOpenGL(); - - bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); - bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value); - - Error createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList, EGLSurface *outSurface); - Error createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList, EGLSurface *outSurface); - Error createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, - bool robustAccess, EGLContext *outContext); - - 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(EGLNativeWindowType window); - - rx::Renderer *getRenderer() { return mRenderer; }; - - // exported methods must be virtual - virtual void notifyDeviceLost(); - virtual void recreateSwapChains(); - - const char *getExtensionString() const; - const char *getVendorString() const; - EGLNativeDisplayType getDisplayId() const { return mDisplayId; } - - private: - DISALLOW_COPY_AND_ASSIGN(Display); - - Display(EGLNativeDisplayType displayId); - - void setAttributes(const AttributeMap &attribMap); - - Error restoreLostDevice(); - - EGLNativeDisplayType mDisplayId; - AttributeMap mAttributeMap; - - typedef std::set SurfaceSet; - SurfaceSet mSurfaceSet; - - ConfigSet mConfigSet; - - typedef std::set ContextSet; - ContextSet mContextSet; - - rx::Renderer *mRenderer; - - static std::string generateClientExtensionString(); - - void initDisplayExtensionString(); - std::string mDisplayExtensionString; - - void initVendorString(); - std::string mVendorString; -}; -} - -#endif // LIBEGL_DISPLAY_H_ diff --git a/src/3rdparty/angle/src/libEGL/Error.cpp b/src/3rdparty/angle/src/libEGL/Error.cpp deleted file mode 100644 index df5f163d32..0000000000 --- a/src/3rdparty/angle/src/libEGL/Error.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// Error.cpp: Implements the egl::Error class which encapsulates an EGL error -// and optional error message. - -#include "libEGL/Error.h" - -#include "common/angleutils.h" - -#include - -namespace egl -{ - -Error::Error(EGLint errorCode) - : mCode(errorCode), - mMessage() -{ -} - -Error::Error(EGLint errorCode, const char *msg, ...) - : mCode(errorCode), - mMessage() -{ - va_list vararg; - va_start(vararg, msg); - mMessage = FormatString(msg, vararg); - va_end(vararg); -} - -Error::Error(const Error &other) - : mCode(other.mCode), - mMessage(other.mMessage) -{ -} - -Error &Error::operator=(const Error &other) -{ - mCode = other.mCode; - mMessage = other.mMessage; - return *this; -} - -} diff --git a/src/3rdparty/angle/src/libEGL/Error.h b/src/3rdparty/angle/src/libEGL/Error.h deleted file mode 100644 index 71805d2fb7..0000000000 --- a/src/3rdparty/angle/src/libEGL/Error.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2014 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. - -// Error.h: Defines the egl::Error class which encapsulates an EGL error -// and optional error message. - -#ifndef LIBEGL_ERROR_H_ -#define LIBEGL_ERROR_H_ - -#include - -#include - -namespace egl -{ - -class Error -{ - public: - explicit Error(EGLint errorCode); - Error(EGLint errorCode, const char *msg, ...); - Error(const Error &other); - Error &operator=(const Error &other); - - EGLint getCode() const { return mCode; } - bool isError() const { return (mCode != EGL_SUCCESS); } - - const std::string &getMessage() const { return mMessage; } - - private: - EGLint mCode; - std::string mMessage; -}; - -} - -#endif // LIBEGL_ERROR_H_ diff --git a/src/3rdparty/angle/src/libEGL/Surface.cpp b/src/3rdparty/angle/src/libEGL/Surface.cpp deleted file mode 100644 index b664a8530e..0000000000 --- a/src/3rdparty/angle/src/libEGL/Surface.cpp +++ /dev/null @@ -1,505 +0,0 @@ -// -// Copyright (c) 2002-2014 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 - -#include "libEGL/Surface.h" - -#include "common/debug.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/renderer/SwapChain.h" -#include "libGLESv2/main.h" - -#include "libEGL/main.h" -#include "libEGL/Display.h" - -#include "common/NativeWindow.h" - -//TODO(jmadill): phase this out -#include "libGLESv2/renderer/d3d/RendererD3D.h" - -namespace egl -{ - -Surface::Surface(Display *display, const Config *config, EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported) - : mDisplay(display), mConfig(config), mNativeWindow(window, display->getDisplayId()), mPostSubBufferSupported(postSubBufferSupported) -{ - //TODO(jmadill): MANGLE refactor. (note, can't call makeRendererD3D because of dll export issues) - mRenderer = static_cast(mDisplay->getRenderer()); - mSwapChain = 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; - mWidth = width; - mHeight = height; - mFixedWidth = mWidth; - mFixedHeight = mHeight; - setSwapInterval(1); - mFixedSize = fixedSize; - - subclassWindow(); -} - -Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType) - : mDisplay(display), mNativeWindow(NULL, NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) -{ - //TODO(jmadill): MANGLE refactor. (note, can't call makeRendererD3D because of dll export issues) - mRenderer = static_cast(mDisplay->getRenderer()); - mSwapChain = 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); - // This constructor is for offscreen surfaces, which are always fixed-size. - mFixedSize = EGL_TRUE; - mFixedWidth = mWidth; - mFixedHeight = mHeight; -} - -Surface::~Surface() -{ - unsubclassWindow(); - release(); -} - -Error Surface::initialize() -{ - if (mNativeWindow.getNativeWindow()) - { - if (!mNativeWindow.initialize()) - { - return Error(EGL_BAD_SURFACE); - } - } - - Error error = resetSwapChain(); - if (error.isError()) - { - return error; - } - - return Error(EGL_SUCCESS); -} - -void Surface::release() -{ - delete mSwapChain; - mSwapChain = NULL; - - if (mTexture) - { - mTexture->releaseTexImage(); - mTexture = NULL; - } -} - -Error Surface::resetSwapChain() -{ - ASSERT(!mSwapChain); - - int width; - int height; - - if (!mFixedSize) - { - RECT windowRect; - if (!mNativeWindow.getClientRect(&windowRect)) - { - ASSERT(false); - - return Error(EGL_BAD_SURFACE, "Could not retrieve the window dimensions"); - } - - width = windowRect.right - windowRect.left; - height = windowRect.bottom - windowRect.top; - } - else - { - // non-window surface - size is determined at creation - width = mWidth; - height = mHeight; - } - - mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, - mConfig->mRenderTargetFormat, - mConfig->mDepthStencilFormat); - if (!mSwapChain) - { - return Error(EGL_BAD_ALLOC); - } - - Error error = resetSwapChain(width, height); - if (error.isError()) - { - SafeDelete(mSwapChain); - return error; - } - - return Error(EGL_SUCCESS); -} - -Error Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight) -{ - ASSERT(mSwapChain); - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - backbufferWidth = std::max(1, backbufferWidth); - backbufferHeight = std::max(1, backbufferHeight); -#endif - EGLint status = mSwapChain->resize(backbufferWidth, backbufferHeight); - - if (status == EGL_CONTEXT_LOST) - { - mDisplay->notifyDeviceLost(); - return Error(status); - } - else if (status != EGL_SUCCESS) - { - return Error(status); - } - - mWidth = backbufferWidth; - mHeight = backbufferHeight; - - return Error(EGL_SUCCESS); -} - -Error Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) -{ - ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); - ASSERT(mSwapChain); - - EGLint status = mSwapChain->reset(std::max(1, backbufferWidth), std::max(1, backbufferHeight), mSwapInterval); - - if (status == EGL_CONTEXT_LOST) - { - mRenderer->notifyDeviceLost(); - return Error(status); - } - else if (status != EGL_SUCCESS) - { - return Error(status); - } - - mWidth = backbufferWidth; - mHeight = backbufferHeight; - mSwapIntervalDirty = false; - - return Error(EGL_SUCCESS); -} - -Error Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) -{ - if (!mSwapChain) - { - return Error(EGL_SUCCESS); - } - - if (x + width > abs(mWidth)) - { - width = abs(mWidth) - x; - } - - if (y + height > abs(mHeight)) - { - height = abs(mHeight) - y; - } - - if (width == 0 || height == 0) - { - return Error(EGL_SUCCESS); - } - - ASSERT(width > 0); - ASSERT(height > 0); - - EGLint status = mSwapChain->swapRect(x, y, width, height); - - if (status == EGL_CONTEXT_LOST) - { - mRenderer->notifyDeviceLost(); - return Error(status); - } - else if (status != EGL_SUCCESS) - { - return Error(status); - } - - checkForOutOfDateSwapChain(); - - return Error(EGL_SUCCESS); -} - -EGLNativeWindowType Surface::getWindowHandle() -{ - return mNativeWindow.getNativeWindow(); -} - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) -#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); -} -#endif - -void Surface::subclassWindow() -{ -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - HWND window = mNativeWindow.getNativeWindow(); - if (!window) - { - return; - } - - DWORD processId; - DWORD threadId = GetWindowThreadProcessId(window, &processId); - if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId()) - { - return; - } - - SetLastError(0); - LONG_PTR oldWndProc = SetWindowLongPtr(window, GWLP_WNDPROC, reinterpret_cast(SurfaceWindowProc)); - if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) - { - mWindowSubclassed = false; - return; - } - - SetProp(window, kSurfaceProperty, reinterpret_cast(this)); - SetProp(window, kParentWndProc, reinterpret_cast(oldWndProc)); - mWindowSubclassed = true; -#endif -} - -void Surface::unsubclassWindow() -{ - if(!mWindowSubclassed) - { - return; - } - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - HWND window = mNativeWindow.getNativeWindow(); - if (!window) - { - return; - } - - // un-subclass - LONG_PTR parentWndFunc = reinterpret_cast(GetProp(window, 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(window, GWLP_WNDPROC, parentWndFunc); - UNUSED_ASSERTION_VARIABLE(prevWndFunc); - ASSERT(prevWndFunc == reinterpret_cast(SurfaceWindowProc)); - } - - RemoveProp(window, kSurfaceProperty); - RemoveProp(window, kParentWndProc); -#endif - mWindowSubclassed = false; -} - -bool Surface::checkForOutOfDateSwapChain() -{ - RECT client; - int clientWidth = getWidth(); - int clientHeight = getHeight(); - bool sizeDirty = false; - if (!mFixedSize && !mNativeWindow.isIconic()) - { - // The window is automatically resized to 150x22 when it's minimized, but the swapchain shouldn't be resized - // because that's not a useful size to render to. - if (!mNativeWindow.getClientRect(&client)) - { - ASSERT(false); - return false; - } - - // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information. - clientWidth = client.right - client.left; - clientHeight = client.bottom - client.top; - sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); - } - - if (mFixedSize && (mWidth != mFixedWidth || mHeight != mFixedHeight)) - { - clientWidth = mFixedWidth; - clientHeight = mFixedHeight; - sizeDirty = true; - } - - bool wasDirty = (mSwapIntervalDirty || sizeDirty); - - if (mSwapIntervalDirty) - { - resetSwapChain(clientWidth, clientHeight); - } - else if (sizeDirty) - { - resizeSwapChain(clientWidth, clientHeight); - } - - if (wasDirty) - { - if (static_cast(getCurrentDrawSurface()) == this) - { - glMakeCurrent(glGetCurrentContext(), static_cast(getCurrentDisplay()), this); - } - - return true; - } - - return false; -} - -Error Surface::swap() -{ - return swapRect(0, 0, abs(mWidth), abs(mHeight)); -} - -Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) -{ - if (!mPostSubBufferSupported) - { - // Spec is not clear about how this should be handled. - return Error(EGL_SUCCESS); - } - - return swapRect(x, y, width, height); -} - -EGLint Surface::isPostSubBufferSupported() const -{ - return mPostSubBufferSupported; -} - -rx::SwapChain *Surface::getSwapChain() const -{ - return mSwapChain; -} - -void Surface::setSwapInterval(EGLint interval) -{ - if (mSwapInterval == interval) - { - return; - } - - mSwapInterval = interval; - mSwapInterval = std::max(mSwapInterval, mRenderer->getMinSwapInterval()); - mSwapInterval = std::min(mSwapInterval, mRenderer->getMaxSwapInterval()); - - mSwapIntervalDirty = true; -} - -EGLint Surface::getConfigID() const -{ - return mConfig->mConfigID; -} - -EGLint Surface::getWidth() const -{ - return mWidth; -} - -EGLint Surface::getHeight() const -{ - return mHeight; -} - -EGLint Surface::getPixelAspectRatio() const -{ - return mPixelAspectRatio; -} - -EGLenum Surface::getRenderBuffer() const -{ - return mRenderBuffer; -} - -EGLenum Surface::getSwapBehavior() const -{ - return mSwapBehavior; -} - -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; -} - -EGLint Surface::isFixedSize() const -{ - return mFixedSize; -} - -void Surface::setFixedWidth(EGLint width) -{ - mFixedWidth = width; -} - -void Surface::setFixedHeight(EGLint height) -{ - mFixedHeight = height; -} - -EGLenum Surface::getFormat() const -{ - return mConfig->mRenderTargetFormat; -} -} diff --git a/src/3rdparty/angle/src/libEGL/Surface.h b/src/3rdparty/angle/src/libEGL/Surface.h deleted file mode 100644 index 46382d06e1..0000000000 --- a/src/3rdparty/angle/src/libEGL/Surface.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2002-2014 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 LIBEGL_SURFACE_H_ -#define LIBEGL_SURFACE_H_ - -#include "libEGL/Error.h" - -#include - -#include "common/angleutils.h" -#include "common/NativeWindow.h" - -namespace gl -{ -class Texture2D; -} -namespace rx -{ -class SwapChain; -class RendererD3D; //TODO(jmadill): remove this -} - -namespace egl -{ -class Display; -class Config; - -class Surface -{ - public: - Surface(Display *display, const egl::Config *config, EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported); - Surface(Display *display, const egl::Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureTarget); - - virtual ~Surface(); - - Error initialize(); - void release(); - Error resetSwapChain(); - - EGLNativeWindowType getWindowHandle(); - Error swap(); - Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); - - virtual EGLint isPostSubBufferSupported() const; - - virtual rx::SwapChain *getSwapChain() const; - - void setSwapInterval(EGLint interval); - bool checkForOutOfDateSwapChain(); // Returns true if swapchain changed due to resize or interval update - - virtual EGLint getConfigID() const; - virtual EGLint getWidth() const; - virtual EGLint getHeight() const; - virtual EGLint getPixelAspectRatio() const; - virtual EGLenum getRenderBuffer() const; - virtual EGLenum getSwapBehavior() const; - virtual EGLenum getTextureFormat() const; - virtual EGLenum getTextureTarget() const; - virtual EGLenum getFormat() const; - - virtual void setBoundTexture(gl::Texture2D *texture); - virtual gl::Texture2D *getBoundTexture() const; - - EGLint isFixedSize() const; - void setFixedWidth(EGLint width); - void setFixedHeight(EGLint height); - - private: - DISALLOW_COPY_AND_ASSIGN(Surface); - - Display *const mDisplay; - rx::RendererD3D *mRenderer; - - HANDLE mShareHandle; - rx::SwapChain *mSwapChain; - - void subclassWindow(); - void unsubclassWindow(); - Error resizeSwapChain(int backbufferWidth, int backbufferHeight); - Error resetSwapChain(int backbufferWidth, int backbufferHeight); - Error swapRect(EGLint x, EGLint y, EGLint width, EGLint height); - - rx::NativeWindow mNativeWindow; // Handler for the 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 mFixedHeight; // Pending height of the surface - EGLint mFixedWidth; // Pending width of the 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; - EGLint mFixedSize; - - bool mSwapIntervalDirty; - gl::Texture2D *mTexture; -}; -} - -#endif // LIBEGL_SURFACE_H_ diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp index 68399d63a4..d09219e308 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL.cpp +++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp @@ -6,1258 +6,245 @@ // libEGL.cpp: Implements the exported EGL functions. -#undef EGLAPI -#define EGLAPI +#include "libGLESv2/entry_points_egl.h" +#include "libGLESv2/entry_points_egl_ext.h" -#include - -#include "common/debug.h" -#include "common/version.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/main.h" -#include "libGLESv2/renderer/SwapChain.h" -#if defined(ANGLE_ENABLE_D3D11) -# include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#endif - -#include "libEGL/main.h" -#include "libEGL/Display.h" -#include "libEGL/Surface.h" - -#include "common/NativeWindow.h" - -bool validateDisplay(egl::Display *display) +extern "C" { - if (display == EGL_NO_DISPLAY) - { - recordError(egl::Error(EGL_BAD_DISPLAY)); - return false; - } - - if (!display->isInitialized()) - { - recordError(egl::Error(EGL_NOT_INITIALIZED)); - return false; - } - return true; +EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + return egl::ChooseConfig(dpy, attrib_list, configs, config_size, num_config); } -bool validateConfig(egl::Display *display, EGLConfig config) +EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) { - if (!validateDisplay(display)) - { - return false; - } - - if (!display->isValidConfig(config)) - { - recordError(egl::Error(EGL_BAD_CONFIG)); - return false; - } - - return true; + return egl::CopyBuffers(dpy, surface, target); } -bool validateContext(egl::Display *display, gl::Context *context) +EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) { - if (!validateDisplay(display)) - { - return false; - } - - if (!display->isValidContext(context)) - { - recordError(egl::Error(EGL_BAD_CONTEXT)); - return false; - } - - return true; + return egl::CreateContext(dpy, config, share_context, attrib_list); } -bool validateSurface(egl::Display *display, egl::Surface *surface) +EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { - if (!validateDisplay(display)) - { - return false; - } - - if (!display->isValidSurface(surface)) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return false; - } - - return true; + return egl::CreatePbufferSurface(dpy, config, attrib_list); } -extern "C" -{ -EGLint __stdcall eglGetError(void) +EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) { - EVENT("()"); - - EGLint error = egl::getCurrentError(); - recordError(egl::Error(EGL_SUCCESS)); - return error; + return egl::CreatePixmapSurface(dpy, config, pixmap, attrib_list); } -EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id) +EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) { - EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id); - - return egl::Display::getDisplay(display_id, egl::AttributeMap()); + return egl::CreateWindowSurface(dpy, config, win, attrib_list); } -EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) +EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { - EVENT("(EGLenum platform = %d, void* native_display = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", - platform, native_display, attrib_list); - - switch (platform) - { - case EGL_PLATFORM_ANGLE_ANGLE: - break; - - default: - recordError(egl::Error(EGL_BAD_CONFIG)); - return EGL_NO_DISPLAY; - } - - EGLNativeDisplayType displayId = static_cast(native_display); - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - // Validate the display device context - if (WindowFromDC(displayId) == NULL) - { - recordError(egl::Error(EGL_SUCCESS)); - return EGL_NO_DISPLAY; - } -#endif - - EGLint platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; - bool majorVersionSpecified = false; - bool minorVersionSpecified = false; - bool requestedWARP = false; - - if (attrib_list) - { - for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2) - { - switch (curAttrib[0]) - { - case EGL_PLATFORM_ANGLE_TYPE_ANGLE: - switch (curAttrib[1]) - { - case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: - break; - - case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: - case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: - if (!egl::Display::supportsPlatformD3D()) - { - recordError(egl::Error(EGL_SUCCESS)); - return EGL_NO_DISPLAY; - } - break; - - case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: - case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: - if (!egl::Display::supportsPlatformOpenGL()) - { - recordError(egl::Error(EGL_SUCCESS)); - return EGL_NO_DISPLAY; - } - break; - - default: - recordError(egl::Error(EGL_SUCCESS)); - return EGL_NO_DISPLAY; - } - platformType = curAttrib[1]; - break; - - case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE: - if (curAttrib[1] != EGL_DONT_CARE) - { - majorVersionSpecified = true; - } - break; - - case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE: - if (curAttrib[1] != EGL_DONT_CARE) - { - minorVersionSpecified = true; - } - break; - - case EGL_PLATFORM_ANGLE_USE_WARP_ANGLE: - if (!egl::Display::supportsPlatformD3D()) - { - recordError(egl::Error(EGL_SUCCESS)); - return EGL_NO_DISPLAY; - } - - switch (curAttrib[1]) - { - case EGL_FALSE: - case EGL_TRUE: - break; - - default: - recordError(egl::Error(EGL_SUCCESS)); - return EGL_NO_DISPLAY; - } - - requestedWARP = (curAttrib[1] == EGL_TRUE); - break; - - default: - break; - } - } - } - - if (!majorVersionSpecified && minorVersionSpecified) - { - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_NO_DISPLAY; - } - - if (platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE && requestedWARP) - { - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_NO_DISPLAY; - } - - recordError(egl::Error(EGL_SUCCESS)); - return egl::Display::getDisplay(displayId, egl::AttributeMap(attrib_list)); + return egl::DestroyContext(dpy, ctx); } -EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)", - dpy, major, minor); - - if (dpy == EGL_NO_DISPLAY) - { - recordError(egl::Error(EGL_BAD_DISPLAY)); - return EGL_FALSE; - } - - egl::Display *display = static_cast(dpy); - - egl::Error error = display->initialize(); - if (error.isError()) - { - recordError(error); - return EGL_FALSE; - } - - if (major) *major = 1; - if (minor) *minor = 4; - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::DestroySurface(dpy, surface); } -EGLBoolean __stdcall eglTerminate(EGLDisplay dpy) +EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { - EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy); - - if (dpy == EGL_NO_DISPLAY) - { - recordError(egl::Error(EGL_BAD_DISPLAY)); - return EGL_FALSE; - } - - egl::Display *display = static_cast(dpy); - - display->terminate(); - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::GetConfigAttrib(dpy, config, attribute, value); } -const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name) +EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name); - - egl::Display *display = static_cast(dpy); - if (!(display == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) && !validateDisplay(display)) - { - return NULL; - } - - const char *result; - switch (name) - { - case EGL_CLIENT_APIS: - result = "OpenGL_ES"; - break; - case EGL_EXTENSIONS: - result = egl::Display::getExtensionString(display); - break; - case EGL_VENDOR: - result = display->getVendorString(); - break; - case EGL_VERSION: - result = "1.4 (ANGLE " ANGLE_VERSION_STRING ")"; - break; - default: - recordError(egl::Error(EGL_BAD_PARAMETER)); - return NULL; - } - - recordError(egl::Error(EGL_SUCCESS)); - return result; + return egl::GetConfigs(dpy, configs, config_size, num_config); } -EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) +EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void) { - 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); - - egl::Display *display = static_cast(dpy); - - if (!validateDisplay(display)) - { - return EGL_FALSE; - } - - if (!num_config) - { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - - const EGLint attribList[] = {EGL_NONE}; - - if (!display->getConfigs(configs, attribList, config_size, num_config)) - { - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; - } - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::GetCurrentDisplay(); } -EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw) { - 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); - - egl::Display *display = static_cast(dpy); - - if (!validateDisplay(display)) - { - return EGL_FALSE; - } - - if (!num_config) - { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - - const EGLint attribList[] = {EGL_NONE}; - - if (!attrib_list) - { - attrib_list = attribList; - } - - display->getConfigs(configs, attrib_list, config_size, num_config); - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::GetCurrentSurface(readdraw); } -EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", - dpy, config, attribute, value); - - egl::Display *display = static_cast(dpy); - - if (!validateConfig(display, config)) - { - return EGL_FALSE; - } - - if (!display->getConfigAttrib(config, attribute, value)) - { - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; - } - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::GetDisplay(display_id); } -EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) +EGLint EGLAPIENTRY eglGetError(void) { - 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); - - egl::Display *display = static_cast(dpy); - - if (!validateConfig(display, config)) - { - return EGL_NO_SURFACE; - } - - if (!rx::IsValidEGLNativeWindowType(win)) - { - recordError(egl::Error(EGL_BAD_NATIVE_WINDOW)); - return EGL_NO_SURFACE; - } - - EGLSurface surface = EGL_NO_SURFACE; - egl::Error error = display->createWindowSurface(win, config, attrib_list, &surface); - if (error.isError()) - { - recordError(error); - return EGL_NO_SURFACE; - } - - return surface; + return egl::GetError(); } -EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)", - dpy, config, attrib_list); - - egl::Display *display = static_cast(dpy); - - if (!validateConfig(display, config)) - { - return EGL_NO_SURFACE; - } - - EGLSurface surface = EGL_NO_SURFACE; - egl::Error error = display->createOffscreenSurface(config, NULL, attrib_list, &surface); - if (error.isError()) - { - recordError(error); - return EGL_NO_SURFACE; - } - - return surface; + return egl::Initialize(dpy, major, minor); } -EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) +EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { - 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); - - egl::Display *display = static_cast(dpy); - - if (!validateConfig(display, config)) - { - return EGL_NO_SURFACE; - } - - UNIMPLEMENTED(); // FIXME - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_NO_SURFACE; + return egl::MakeCurrent(dpy, draw, read, ctx); } -EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = static_cast(surface); - - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - if (surface == EGL_NO_SURFACE) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return EGL_FALSE; - } - - display->destroySurface((egl::Surface*)surface); - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::QueryContext(dpy, ctx, attribute, value); } -EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) +const char* EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", - dpy, surface, attribute, value); - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = (egl::Surface*)surface; - - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - if (surface == EGL_NO_SURFACE) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return EGL_FALSE; - } - - switch (attribute) - { - case EGL_VG_ALPHA_FORMAT: - UNIMPLEMENTED(); // FIXME - break; - case EGL_VG_COLORSPACE: - UNIMPLEMENTED(); // FIXME - break; - case EGL_CONFIG_ID: - *value = eglSurface->getConfigID(); - 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: - *value = eglSurface->getPixelAspectRatio(); - break; - case EGL_RENDER_BUFFER: - *value = eglSurface->getRenderBuffer(); - break; - case EGL_SWAP_BEHAVIOR: - *value = eglSurface->getSwapBehavior(); - break; - case EGL_TEXTURE_FORMAT: - *value = eglSurface->getTextureFormat(); - break; - case EGL_TEXTURE_TARGET: - *value = eglSurface->getTextureTarget(); - 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; - case EGL_FIXED_SIZE_ANGLE: - *value = eglSurface->isFixedSize(); - break; - default: - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; - } - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::QueryString(dpy, name); } -EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value) +EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) { - TRACE("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)", - dpy, surface, attribute, value); - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = (egl::Surface*)surface; - - switch (attribute) - { - case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: - { - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - if (surface == EGL_NO_SURFACE) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return EGL_FALSE; - } - - rx::SwapChain *swapchain = eglSurface->getSwapChain(); - *value = (void*) (swapchain ? swapchain->getShareHandle() : NULL); - } - break; -#if defined(ANGLE_ENABLE_D3D11) - case EGL_DEVICE_EXT: - { - if (!validateDisplay(display)) - { - return EGL_FALSE; - } - - rx::Renderer *renderer = display->getRenderer(); - if (!renderer) - { - *value = NULL; - break; - } - - if (renderer->getMajorShaderModel() < 4) - { - recordError(egl::Error(EGL_BAD_CONTEXT)); - return EGL_FALSE; - } - - *value = static_cast(renderer)->getDevice(); - } - break; -#endif - default: - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; - } - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::QuerySurface(dpy, surface, attribute, value); } -EGLBoolean __stdcall eglBindAPI(EGLenum api) +EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { - EVENT("(EGLenum api = 0x%X)", api); - - switch (api) - { - case EGL_OPENGL_API: - case EGL_OPENVG_API: - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; // Not supported by this implementation - case EGL_OPENGL_ES_API: - break; - default: - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - - egl::setCurrentAPI(api); - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::SwapBuffers(dpy, surface); } -EGLenum __stdcall eglQueryAPI(void) +EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy) { - EVENT("()"); - - EGLenum API = egl::getCurrentAPI(); - - recordError(egl::Error(EGL_SUCCESS)); - return API; + return egl::Terminate(dpy); } -EGLBoolean __stdcall eglWaitClient(void) +EGLBoolean EGLAPIENTRY eglWaitGL(void) { - EVENT("()"); - - UNIMPLEMENTED(); // FIXME - - recordError(egl::Error(EGL_SUCCESS)); - return 0; + return egl::WaitGL(); } -EGLBoolean __stdcall eglReleaseThread(void) +EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine) { - EVENT("()"); - - eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::WaitNative(engine); } -EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) +EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - 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); - - egl::Display *display = static_cast(dpy); - - if (!validateConfig(display, config)) - { - return EGL_NO_SURFACE; - } - - if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || !buffer) - { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_NO_SURFACE; - } - - EGLSurface surface = EGL_NO_SURFACE; - egl::Error error = display->createOffscreenSurface(config, (HANDLE)buffer, attrib_list, &surface); - if (error.isError()) - { - recordError(error); - return EGL_NO_SURFACE; - } - - return surface; + return egl::BindTexImage(dpy, surface, buffer); } -EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d)", - dpy, surface, attribute, value); - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = static_cast(surface); - - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - switch (attribute) - { - case EGL_WIDTH: - if (!eglSurface->isFixedSize() || !value) { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - eglSurface->setFixedWidth(value); - return EGL_TRUE; - case EGL_HEIGHT: - if (!eglSurface->isFixedSize() || !value) { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - eglSurface->setFixedHeight(value); - return EGL_TRUE; - default: - break; - } - - UNIMPLEMENTED(); // FIXME - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::ReleaseTexImage(dpy, surface, buffer); } -EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = static_cast(surface); - - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - if (buffer != EGL_BACK_BUFFER) - { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - - if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle()) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return EGL_FALSE; - } - - if (eglSurface->getBoundTexture()) - { - recordError(egl::Error(EGL_BAD_ACCESS)); - return EGL_FALSE; - } - - if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) - { - recordError(egl::Error(EGL_BAD_MATCH)); - return EGL_FALSE; - } - - if (!glBindTexImage(eglSurface)) - { - recordError(egl::Error(EGL_BAD_MATCH)); - return EGL_FALSE; - } - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::SurfaceAttrib(dpy, surface, attribute, value); } -EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = static_cast(surface); - - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - if (buffer != EGL_BACK_BUFFER) - { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - - if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle()) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return EGL_FALSE; - } - - if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) - { - recordError(egl::Error(EGL_BAD_MATCH)); - return EGL_FALSE; - } - - gl::Texture2D *texture = eglSurface->getBoundTexture(); - - if (texture) - { - texture->releaseTexImage(); - } - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::SwapInterval(dpy, interval); } -EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval) +EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval); - - egl::Display *display = static_cast(dpy); - - if (!validateDisplay(display)) - { - return EGL_FALSE; - } - - egl::Surface *draw_surface = static_cast(egl::getCurrentDrawSurface()); - - if (draw_surface == NULL) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return EGL_FALSE; - } - - draw_surface->setSwapInterval(interval); - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::BindAPI(api); } -EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) +EGLenum EGLAPIENTRY eglQueryAPI(void) { - 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); - - // Get the requested client version (default is 1) and check it is 2 or 3. - 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) - { - recordError(egl::Error(EGL_BAD_CONFIG)); // Unimplemented - return EGL_NO_CONTEXT; - // robust_access = true; - } - else if (attribute[1] != EGL_FALSE) - { - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return 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) - { - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_NO_CONTEXT; - } - break; - default: - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_NO_CONTEXT; - } - } - } - - if (client_version != 2 && client_version != 3) - { - recordError(egl::Error(EGL_BAD_CONFIG)); - return EGL_NO_CONTEXT; - } - - egl::Display *display = static_cast(dpy); - - if (share_context) - { - gl::Context* sharedGLContext = static_cast(share_context); - - if (sharedGLContext->isResetNotificationEnabled() != reset_notification) - { - recordError(egl::Error(EGL_BAD_MATCH)); - return EGL_NO_CONTEXT; - } - - if (sharedGLContext->getClientVersion() != client_version) - { - recordError(egl::Error(EGL_BAD_CONTEXT)); - return EGL_NO_CONTEXT; - } - - // Can not share contexts between displays - if (sharedGLContext->getRenderer() != display->getRenderer()) - { - recordError(egl::Error(EGL_BAD_MATCH)); - return EGL_NO_CONTEXT; - } - } - - if (!validateConfig(display, config)) - { - return EGL_NO_CONTEXT; - } - - EGLContext context = EGL_NO_CONTEXT; - egl::Error error = display->createContext(config, client_version, static_cast(share_context), - reset_notification, robust_access, &context); - if (error.isError()) - { - recordError(error); - return EGL_NO_CONTEXT; - } - - return context; + return egl::QueryAPI(); } -EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx); - - egl::Display *display = static_cast(dpy); - gl::Context *context = static_cast(ctx); - - if (!validateContext(display, context)) - { - return EGL_FALSE; - } - - if (ctx == EGL_NO_CONTEXT) - { - recordError(egl::Error(EGL_BAD_CONTEXT)); - return EGL_FALSE; - } - - display->destroyContext(context); - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::CreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list); } -EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) +EGLBoolean EGLAPIENTRY eglReleaseThread(void) { - 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); - - egl::Display *display = static_cast(dpy); - gl::Context *context = static_cast(ctx); - - bool noContext = (ctx == EGL_NO_CONTEXT); - bool noSurface = (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE); - if (noContext != noSurface) - { - recordError(egl::Error(EGL_BAD_MATCH)); - return EGL_FALSE; - } - - if (ctx != EGL_NO_CONTEXT && !validateContext(display, context)) - { - return EGL_FALSE; - } - - if (dpy != EGL_NO_DISPLAY && display->isInitialized()) - { - rx::Renderer *renderer = display->getRenderer(); - if (renderer->testDeviceLost(true)) - { - return EGL_FALSE; - } - - if (renderer->isDeviceLost()) - { - recordError(egl::Error(EGL_CONTEXT_LOST)); - 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)); - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::ReleaseThread(); } -EGLContext __stdcall eglGetCurrentContext(void) +EGLBoolean EGLAPIENTRY eglWaitClient(void) { - EVENT("()"); - - EGLContext context = glGetCurrentContext(); - - recordError(egl::Error(EGL_SUCCESS)); - return context; + return egl::WaitClient(); } -EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw) +EGLContext EGLAPIENTRY eglGetCurrentContext(void) { - EVENT("(EGLint readdraw = %d)", readdraw); - - if (readdraw == EGL_READ) - { - recordError(egl::Error(EGL_SUCCESS)); - return egl::getCurrentReadSurface(); - } - else if (readdraw == EGL_DRAW) - { - recordError(egl::Error(EGL_SUCCESS)); - return egl::getCurrentDrawSurface(); - } - else - { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_NO_SURFACE; - } + return egl::GetCurrentContext(); } -EGLDisplay __stdcall eglGetCurrentDisplay(void) +EGLSync EGLAPIENTRY eglCreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) { - EVENT("()"); - - EGLDisplay dpy = egl::getCurrentDisplay(); - - recordError(egl::Error(EGL_SUCCESS)); - return dpy; + return egl::CreateSync(dpy, type, attrib_list); } -EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) +EGLBoolean EGLAPIENTRY eglDestroySync(EGLDisplay dpy, EGLSync sync) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)", - dpy, ctx, attribute, value); - - egl::Display *display = static_cast(dpy); - gl::Context *context = static_cast(ctx); - - if (!validateContext(display, context)) - { - return EGL_FALSE; - } - - UNIMPLEMENTED(); // FIXME - - recordError(egl::Error(EGL_SUCCESS)); - return 0; + return egl::DestroySync(dpy, sync); } -EGLBoolean __stdcall eglWaitGL(void) +EGLint EGLAPIENTRY eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) { - EVENT("()"); - - UNIMPLEMENTED(); // FIXME - - recordError(egl::Error(EGL_SUCCESS)); - return 0; + return egl::ClientWaitSync(dpy, sync, flags, timeout); } -EGLBoolean __stdcall eglWaitNative(EGLint engine) +EGLBoolean EGLAPIENTRY eglGetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value) { - EVENT("(EGLint engine = %d)", engine); - - UNIMPLEMENTED(); // FIXME - - recordError(egl::Error(EGL_SUCCESS)); - return 0; + return egl::GetSyncAttrib(dpy, sync, attribute, value); } -EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +EGLImage EGLAPIENTRY eglCreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = (egl::Surface*)surface; - - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - if (display->getRenderer()->isDeviceLost()) - { - recordError(egl::Error(EGL_CONTEXT_LOST)); - return EGL_FALSE; - } - - if (surface == EGL_NO_SURFACE) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return EGL_FALSE; - } - - egl::Error error = eglSurface->swap(); - if (error.isError()) - { - recordError(error); - return EGL_FALSE; - } - - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; + return egl::CreateImage(dpy, ctx, target, buffer, attrib_list); } -EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) +EGLBoolean EGLAPIENTRY eglDestroyImage(EGLDisplay dpy, EGLImage image) { - EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p)", dpy, surface, target); - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = static_cast(surface); - - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - if (display->getRenderer()->isDeviceLost()) - { - recordError(egl::Error(EGL_CONTEXT_LOST)); - return EGL_FALSE; - } - - UNIMPLEMENTED(); // FIXME - - recordError(egl::Error(EGL_SUCCESS)); - return 0; + return egl::DestroyImage(dpy, image); } -EGLBoolean __stdcall eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height) +EGLDisplay EGLAPIENTRY eglGetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list) { - 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); - - if (x < 0 || y < 0 || width < 0 || height < 0) - { - recordError(egl::Error(EGL_BAD_PARAMETER)); - return EGL_FALSE; - } - - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = static_cast(surface); - - if (!validateSurface(display, eglSurface)) - { - return EGL_FALSE; - } - - if (display->getRenderer()->isDeviceLost()) - { - recordError(egl::Error(EGL_CONTEXT_LOST)); - return EGL_FALSE; - } - - if (surface == EGL_NO_SURFACE) - { - recordError(egl::Error(EGL_BAD_SURFACE)); - return EGL_FALSE; - } + return egl::GetPlatformDisplay(platform, native_display, attrib_list); +} - egl::Error error = eglSurface->postSubBuffer(x, y, width, height); - if (error.isError()) - { - recordError(error); - return EGL_FALSE; - } +EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list) +{ + return egl::CreatePlatformWindowSurface(dpy, config, native_window, attrib_list); +} - recordError(egl::Error(EGL_SUCCESS)); - return EGL_TRUE; +EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list) +{ + return egl::CreatePlatformPixmapSurface(dpy, config, native_pixmap, attrib_list); } -__eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname) +EGLBoolean EGLAPIENTRY eglWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) { - EVENT("(const char *procname = \"%s\")", procname); + return egl::WaitSync(dpy, sync, flags); +} - struct Extension - { - const char *name; - __eglMustCastToProperFunctionPointerType address; - }; +EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value) +{ + return egl::QuerySurfacePointerANGLE(dpy, surface, attribute, value); +} - static const Extension eglExtensions[] = - { - { "eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)eglQuerySurfacePointerANGLE }, - { "eglPostSubBufferNV", (__eglMustCastToProperFunctionPointerType)eglPostSubBufferNV }, - { "eglGetPlatformDisplayEXT", (__eglMustCastToProperFunctionPointerType)eglGetPlatformDisplayEXT }, - { "", NULL }, - }; +EGLBoolean EGLAPIENTRY eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height) +{ + return egl::PostSubBufferNV(dpy, surface, x, y, width, height); +} - for (unsigned int ext = 0; ext < ArraySize(eglExtensions); ext++) - { - if (strcmp(procname, eglExtensions[ext].name) == 0) - { - return (__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address; - } - } +EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) +{ + return egl::GetPlatformDisplayEXT(platform, native_display, attrib_list); +} - return glGetProcAddress(procname); +__eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *procname) +{ + return egl::GetProcAddress(procname); } + } diff --git a/src/3rdparty/angle/src/libEGL/libEGL.def b/src/3rdparty/angle/src/libEGL/libEGL.def index d7949d0354..823cba2f88 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL.def +++ b/src/3rdparty/angle/src/libEGL/libEGL.def @@ -39,3 +39,15 @@ EXPORTS eglGetPlatformDisplayEXT @35 eglQuerySurfacePointerANGLE @36 eglPostSubBufferNV @37 + + ; 1.5 entry points + eglCreateSync @38 + eglDestroySync @39 + eglClientWaitSync @40 + eglGetSyncAttrib @41 + eglCreateImage @42 + eglDestroyImage @43 + eglGetPlatformDisplay @44 + eglCreatePlatformWindowSurface @45 + eglCreatePlatformPixmapSurface @46 + eglWaitSync @47 diff --git a/src/3rdparty/angle/src/libEGL/libEGL.rc b/src/3rdparty/angle/src/libEGL/libEGL.rc deleted file mode 100644 index 65e0aa50c8..0000000000 --- a/src/3rdparty/angle/src/libEGL/libEGL.rc +++ /dev/null @@ -1,103 +0,0 @@ -// 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 ANGLE_MAJOR_VERSION,ANGLE_MINOR_VERSION,0,0 - PRODUCTVERSION ANGLE_MAJOR_VERSION,ANGLE_MINOR_VERSION,0,0 - 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", ANGLE_VERSION_STRING - VALUE "InternalName", "libEGL" - VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc." - VALUE "OriginalFilename", "libEGL.dll" - VALUE "PrivateBuild", ANGLE_VERSION_STRING - VALUE "ProductName", "ANGLE libEGL Dynamic Link Library" - VALUE "ProductVersion", ANGLE_VERSION_STRING - VALUE "Comments", "Build Date: " ANGLE_COMMIT_DATE - 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/libEGL_mingw32.def b/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def index 492ad4d0cf..6a771a54b8 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def +++ b/src/3rdparty/angle/src/libEGL/libEGL_mingw32.def @@ -39,3 +39,15 @@ EXPORTS eglGetPlatformDisplayEXT@12 @35 eglQuerySurfacePointerANGLE@16 @36 eglPostSubBufferNV@24 @37 + + ; 1.5 entry points + eglCreateSync @38 + eglDestroySync @39 + eglClientWaitSync @40 + eglGetSyncAttrib @41 + eglCreateImage @42 + eglDestroyImage @43 + eglGetPlatformDisplay @44 + eglCreatePlatformWindowSurface @45 + eglCreatePlatformPixmapSurface @46 + eglWaitSync @47 diff --git a/src/3rdparty/angle/src/libEGL/libEGLd.def b/src/3rdparty/angle/src/libEGL/libEGLd.def index 0ebd27d0e1..cab7dc9d24 100644 --- a/src/3rdparty/angle/src/libEGL/libEGLd.def +++ b/src/3rdparty/angle/src/libEGL/libEGLd.def @@ -39,3 +39,15 @@ EXPORTS eglGetPlatformDisplayEXT @35 eglQuerySurfacePointerANGLE @36 eglPostSubBufferNV @37 + + ; 1.5 entry points + eglCreateSync @38 + eglDestroySync @39 + eglClientWaitSync @40 + eglGetSyncAttrib @41 + eglCreateImage @42 + eglDestroyImage @43 + eglGetPlatformDisplay @44 + eglCreatePlatformWindowSurface @45 + eglCreatePlatformPixmapSurface @46 + eglWaitSync @47 diff --git a/src/3rdparty/angle/src/libEGL/main.cpp b/src/3rdparty/angle/src/libEGL/main.cpp deleted file mode 100644 index e88cad775f..0000000000 --- a/src/3rdparty/angle/src/libEGL/main.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// -// 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" -#include "common/tls.h" - -static TLSIndex currentTLS = TLS_OUT_OF_INDEXES; - -namespace egl -{ - -Current *AllocateCurrent() -{ - ASSERT(currentTLS != TLS_OUT_OF_INDEXES); - if (currentTLS == TLS_OUT_OF_INDEXES) - { - return NULL; - } - - Current *current = new 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; - - if (!SetTLSValue(currentTLS, current)) - { - ERR("Could not set thread local storage."); - return NULL; - } - - return current; -} - -void DeallocateCurrent() -{ - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - SafeDelete(current); - SetTLSValue(currentTLS, NULL); -} - -} - -#ifndef QT_OPENGL_ES_2_ANGLE_STATIC - -extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) -{ - switch (reason) - { - case DLL_PROCESS_ATTACH: - { -#if defined(ANGLE_ENABLE_DEBUG_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 = CreateTLSIndex(); - if (currentTLS == TLS_OUT_OF_INDEXES) - { - return FALSE; - } - -#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS - gl::InitializeDebugAnnotations(); -#endif - } - // Fall through to initialize index - case DLL_THREAD_ATTACH: - { - egl::AllocateCurrent(); - } - break; - case DLL_THREAD_DETACH: - { - egl::DeallocateCurrent(); - } - break; - case DLL_PROCESS_DETACH: - { - egl::DeallocateCurrent(); - DestroyTLSIndex(currentTLS); - -#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS - gl::UninitializeDebugAnnotations(); -#endif - } - break; - default: - break; - } - - return TRUE; -} - -#endif // !QT_OPENGL_ES_2_ANGLE_STATIC - -namespace egl -{ - -Current *GetCurrentData() -{ -#ifndef QT_OPENGL_ES_2_ANGLE_STATIC - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - - // ANGLE issue 488: when the dll is loaded after thread initialization, - // thread local storage (current) might not exist yet. - return (current ? current : AllocateCurrent()); -#else - // No precautions for thread safety taken as ANGLE is used single-threaded in Qt. - static Current current = { EGL_SUCCESS, EGL_OPENGL_ES_API, EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE }; - return ¤t; -#endif -} - -void recordError(const Error &error) -{ - Current *current = GetCurrentData(); - - current->error = error.getCode(); -} - -EGLint getCurrentError() -{ - Current *current = GetCurrentData(); - - return current->error; -} - -void setCurrentAPI(EGLenum API) -{ - Current *current = GetCurrentData(); - - current->API = API; -} - -EGLenum getCurrentAPI() -{ - Current *current = GetCurrentData(); - - return current->API; -} - -void setCurrentDisplay(EGLDisplay dpy) -{ - Current *current = GetCurrentData(); - - current->display = dpy; -} - -EGLDisplay getCurrentDisplay() -{ - Current *current = GetCurrentData(); - - return current->display; -} - -void setCurrentDrawSurface(EGLSurface surface) -{ - Current *current = GetCurrentData(); - - current->drawSurface = surface; -} - -EGLSurface getCurrentDrawSurface() -{ - Current *current = GetCurrentData(); - - return current->drawSurface; -} - -void setCurrentReadSurface(EGLSurface surface) -{ - Current *current = GetCurrentData(); - - current->readSurface = surface; -} - -EGLSurface getCurrentReadSurface() -{ - Current *current = GetCurrentData(); - - return current->readSurface; -} - -} diff --git a/src/3rdparty/angle/src/libEGL/main.h b/src/3rdparty/angle/src/libEGL/main.h deleted file mode 100644 index e5361a4a5e..0000000000 --- a/src/3rdparty/angle/src/libEGL/main.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// 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_ - -#include "libEGL/Error.h" - -#include -#include - -namespace egl -{ -struct Current -{ - EGLint error; - EGLenum API; - EGLDisplay display; - EGLSurface drawSurface; - EGLSurface readSurface; -}; - -void recordError(const Error &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(); - -} - -#endif // LIBEGL_MAIN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/BinaryStream.h b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h deleted file mode 100644 index 4f7f5f2c85..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/BinaryStream.h +++ /dev/null @@ -1,208 +0,0 @@ -// -// 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 "common/angleutils.h" -#include "common/mathutil.h" - -#include -#include -#include -#include - -namespace gl -{ - -class BinaryInputStream -{ - public: - BinaryInputStream(const void *data, size_t length) - { - mError = false; - mOffset = 0; - mData = static_cast(data); - mLength = length; - } - - // readInt will generate an error for bool types - template - IntT readInt() - { - int value; - read(&value); - return static_cast(value); - } - - template - void readInt(IntT *outValue) - { - *outValue = readInt(); - } - - bool readBool() - { - int value; - read(&value); - return (value > 0); - } - - void readBool(bool *outValue) - { - *outValue = readBool(); - } - - void readBytes(unsigned char outArray[], size_t count) - { - read(outArray, count); - } - - std::string readString() - { - std::string outString; - readString(&outString); - return outString; - } - - void readString(std::string *v) - { - size_t length; - readInt(&length); - - if (mError) - { - return; - } - - if (mOffset + length > mLength) - { - mError = true; - return; - } - - v->assign(reinterpret_cast(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; - } - - const uint8_t *data() - { - return mData; - } - - private: - DISALLOW_COPY_AND_ASSIGN(BinaryInputStream); - bool mError; - size_t mOffset; - const uint8_t *mData; - size_t mLength; - - template - void read(T *v, size_t num) - { - META_ASSERT(std::is_fundamental::value); - - 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); - } - -}; - -class BinaryOutputStream -{ - public: - BinaryOutputStream() - { - } - - // writeInt also handles bool types - template - void writeInt(IntT param) - { - ASSERT(rx::IsIntegerCastSafe(param)); - int intValue = static_cast(param); - write(&intValue, 1); - } - - void writeString(const std::string &v) - { - writeInt(v.length()); - write(v.c_str(), v.length()); - } - - void writeBytes(const unsigned char *bytes, size_t count) - { - write(bytes, count); - } - - 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; - - template - void write(const T *v, size_t num) - { - META_ASSERT(std::is_fundamental::value); - const char *asBytes = reinterpret_cast(v); - mData.insert(mData.end(), asBytes, asBytes + num * sizeof(T)); - } - -}; -} - -#endif // LIBGLESV2_BINARYSTREAM_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.cpp b/src/3rdparty/angle/src/libGLESv2/Buffer.cpp deleted file mode 100644 index 3b2a1a912a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Buffer.cpp +++ /dev/null @@ -1,128 +0,0 @@ -// -// Copyright (c) 2002-2014 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/renderer/BufferImpl.h" -#include "libGLESv2/renderer/Renderer.h" - -namespace gl -{ - -Buffer::Buffer(rx::BufferImpl *impl, GLuint id) - : RefCountObject(id), - mBuffer(impl), - mUsage(GL_DYNAMIC_DRAW), - mSize(0), - mAccessFlags(0), - mMapped(GL_FALSE), - mMapPointer(NULL), - mMapOffset(0), - mMapLength(0) -{ -} - -Buffer::~Buffer() -{ - SafeDelete(mBuffer); -} - -Error Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage) -{ - gl::Error error = mBuffer->setData(data, size, usage); - if (error.isError()) - { - return error; - } - - mIndexRangeCache.clear(); - mUsage = usage; - mSize = size; - - return error; -} - -Error Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset) -{ - gl::Error error = mBuffer->setSubData(data, size, offset); - if (error.isError()) - { - return error; - } - - mIndexRangeCache.invalidateRange(offset, size); - - return error; -} - -Error Buffer::copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) -{ - gl::Error error = mBuffer->copySubData(source->getImplementation(), sourceOffset, destOffset, size); - if (error.isError()) - { - return error; - } - - mIndexRangeCache.invalidateRange(destOffset, size); - - return error; -} - -Error Buffer::mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access) -{ - ASSERT(!mMapped); - ASSERT(offset + length <= mSize); - - Error error = mBuffer->map(offset, length, access, &mMapPointer); - if (error.isError()) - { - mMapPointer = NULL; - return error; - } - - mMapped = GL_TRUE; - mMapOffset = static_cast(offset); - mMapLength = static_cast(length); - mAccessFlags = static_cast(access); - - if ((access & GL_MAP_WRITE_BIT) > 0) - { - mIndexRangeCache.invalidateRange(offset, length); - } - - return error; -} - -Error Buffer::unmap() -{ - ASSERT(mMapped); - - Error error = mBuffer->unmap(); - if (error.isError()) - { - return error; - } - - mMapped = GL_FALSE; - mMapPointer = NULL; - mMapOffset = 0; - mMapLength = 0; - mAccessFlags = 0; - - return error; -} - -void Buffer::markTransformFeedbackUsage() -{ - // TODO: Only used by the DX11 backend. Refactor to a more appropriate place. - mBuffer->markTransformFeedbackUsage(); - mIndexRangeCache.clear(); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.h b/src/3rdparty/angle/src/libGLESv2/Buffer.h deleted file mode 100644 index daa862ca0d..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Buffer.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (c) 2002-2014 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 "libGLESv2/Error.h" - -#include "common/angleutils.h" -#include "common/RefCountObject.h" -#include "libGLESv2/renderer/IndexRangeCache.h" - -namespace rx -{ -class BufferImpl; -}; - -namespace gl -{ - -class Buffer : public RefCountObject -{ - public: - Buffer(rx::BufferImpl *impl, GLuint id); - - virtual ~Buffer(); - - Error bufferData(const void *data, GLsizeiptr size, GLenum usage); - Error bufferSubData(const void *data, GLsizeiptr size, GLintptr offset); - Error copyBufferSubData(Buffer* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); - Error mapRange(GLintptr offset, GLsizeiptr length, GLbitfield access); - Error unmap(); - - GLenum getUsage() const { return mUsage; } - GLint getAccessFlags() const { return mAccessFlags; } - GLboolean isMapped() const { return mMapped; } - GLvoid *getMapPointer() const { return mMapPointer; } - GLint64 getMapOffset() const { return mMapOffset; } - GLint64 getMapLength() const { return mMapLength; } - GLint64 getSize() const { return mSize; } - - rx::BufferImpl *getImplementation() const { return mBuffer; } - - void markTransformFeedbackUsage(); - - rx::IndexRangeCache *getIndexRangeCache() { return &mIndexRangeCache; } - const rx::IndexRangeCache *getIndexRangeCache() const { return &mIndexRangeCache; } - - private: - DISALLOW_COPY_AND_ASSIGN(Buffer); - - rx::BufferImpl *mBuffer; - - GLenum mUsage; - GLint64 mSize; - GLint mAccessFlags; - GLboolean mMapped; - GLvoid *mMapPointer; - GLint64 mMapOffset; - GLint64 mMapLength; - - rx::IndexRangeCache mIndexRangeCache; -}; - -} - -#endif // LIBGLESV2_BUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Caps.cpp b/src/3rdparty/angle/src/libGLESv2/Caps.cpp deleted file mode 100644 index 983800c0e6..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Caps.cpp +++ /dev/null @@ -1,425 +0,0 @@ -// -// Copyright (c) 2014 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 "libGLESv2/Caps.h" -#include "common/debug.h" -#include "common/angleutils.h" - -#include "angle_gl.h" - -#include -#include - -namespace gl -{ - -TextureCaps::TextureCaps() - : texturable(false), - filterable(false), - renderable(false), - sampleCounts() -{ -} - -GLuint TextureCaps::getMaxSamples() const -{ - return !sampleCounts.empty() ? *sampleCounts.rbegin() : 0; -} - -GLuint TextureCaps::getNearestSamples(GLuint requestedSamples) const -{ - if (requestedSamples == 0) - { - return 0; - } - - for (SupportedSampleSet::const_iterator i = sampleCounts.begin(); i != sampleCounts.end(); i++) - { - GLuint samples = *i; - if (samples >= requestedSamples) - { - return samples; - } - } - - return 0; -} - -void TextureCapsMap::insert(GLenum internalFormat, const TextureCaps &caps) -{ - mCapsMap.insert(std::make_pair(internalFormat, caps)); -} - -void TextureCapsMap::remove(GLenum internalFormat) -{ - InternalFormatToCapsMap::iterator i = mCapsMap.find(internalFormat); - if (i != mCapsMap.end()) - { - mCapsMap.erase(i); - } -} - -const TextureCaps &TextureCapsMap::get(GLenum internalFormat) const -{ - static TextureCaps defaultUnsupportedTexture; - InternalFormatToCapsMap::const_iterator iter = mCapsMap.find(internalFormat); - return (iter != mCapsMap.end()) ? iter->second : defaultUnsupportedTexture; -} - -TextureCapsMap::const_iterator TextureCapsMap::begin() const -{ - return mCapsMap.begin(); -} - -TextureCapsMap::const_iterator TextureCapsMap::end() const -{ - return mCapsMap.end(); -} - -size_t TextureCapsMap::size() const -{ - return mCapsMap.size(); -} - -Extensions::Extensions() - : elementIndexUint(false), - packedDepthStencil(false), - getProgramBinary(false), - rgb8rgba8(false), - textureFormatBGRA8888(false), - readFormatBGRA(false), - pixelBufferObject(false), - mapBuffer(false), - mapBufferRange(false), - textureHalfFloat(false), - textureHalfFloatLinear(false), - textureFloat(false), - textureFloatLinear(false), - textureRG(false), - textureCompressionDXT1(false), - textureCompressionDXT3(false), - textureCompressionDXT5(false), - depthTextures(false), - textureNPOT(false), - drawBuffers(false), - textureStorage(false), - textureFilterAnisotropic(false), - maxTextureAnisotropy(false), - occlusionQueryBoolean(false), - fence(false), - timerQuery(false), - robustness(false), - blendMinMax(false), - framebufferBlit(false), - framebufferMultisample(false), - instancedArrays(false), - packReverseRowOrder(false), - standardDerivatives(false), - shaderTextureLOD(false), - fragDepth(false), - textureUsage(false), - translatedShaderSource(false), - colorBufferFloat(false) -{ -} - -static void InsertExtensionString(const std::string &extension, bool supported, std::vector *extensionVector) -{ - if (supported) - { - extensionVector->push_back(extension); - } -} - -std::vector Extensions::getStrings() const -{ - std::vector extensionStrings; - - // | Extension name | Supported flag | Output vector | - InsertExtensionString("GL_OES_element_index_uint", elementIndexUint, &extensionStrings); - InsertExtensionString("GL_OES_packed_depth_stencil", packedDepthStencil, &extensionStrings); - InsertExtensionString("GL_OES_get_program_binary", getProgramBinary, &extensionStrings); - InsertExtensionString("GL_OES_rgb8_rgba8", rgb8rgba8, &extensionStrings); - InsertExtensionString("GL_EXT_texture_format_BGRA8888", textureFormatBGRA8888, &extensionStrings); - InsertExtensionString("GL_EXT_read_format_bgra", readFormatBGRA, &extensionStrings); - InsertExtensionString("GL_NV_pixel_buffer_object", pixelBufferObject, &extensionStrings); - InsertExtensionString("GL_OES_mapbuffer", mapBuffer, &extensionStrings); - InsertExtensionString("GL_EXT_map_buffer_range", mapBufferRange, &extensionStrings); - InsertExtensionString("GL_OES_texture_half_float", textureHalfFloat, &extensionStrings); - InsertExtensionString("GL_OES_texture_half_float_linear", textureHalfFloatLinear, &extensionStrings); - InsertExtensionString("GL_OES_texture_float", textureFloat, &extensionStrings); - InsertExtensionString("GL_OES_texture_float_linear", textureFloatLinear, &extensionStrings); - InsertExtensionString("GL_EXT_texture_rg", textureRG, &extensionStrings); - InsertExtensionString("GL_EXT_texture_compression_dxt1", textureCompressionDXT1, &extensionStrings); - InsertExtensionString("GL_ANGLE_texture_compression_dxt3", textureCompressionDXT3, &extensionStrings); - InsertExtensionString("GL_ANGLE_texture_compression_dxt5", textureCompressionDXT5, &extensionStrings); - InsertExtensionString("GL_EXT_sRGB", sRGB, &extensionStrings); - InsertExtensionString("GL_ANGLE_depth_texture", depthTextures, &extensionStrings); - InsertExtensionString("GL_EXT_texture_storage", textureStorage, &extensionStrings); - InsertExtensionString("GL_OES_texture_npot", textureNPOT, &extensionStrings); - InsertExtensionString("GL_EXT_draw_buffers", drawBuffers, &extensionStrings); - InsertExtensionString("GL_EXT_texture_filter_anisotropic", textureFilterAnisotropic, &extensionStrings); - InsertExtensionString("GL_EXT_occlusion_query_boolean", occlusionQueryBoolean, &extensionStrings); - InsertExtensionString("GL_NV_fence", fence, &extensionStrings); - InsertExtensionString("GL_ANGLE_timer_query", timerQuery, &extensionStrings); - InsertExtensionString("GL_EXT_robustness", robustness, &extensionStrings); - InsertExtensionString("GL_EXT_blend_minmax", blendMinMax, &extensionStrings); - InsertExtensionString("GL_ANGLE_framebuffer_blit", framebufferBlit, &extensionStrings); - InsertExtensionString("GL_ANGLE_framebuffer_multisample", framebufferMultisample, &extensionStrings); - InsertExtensionString("GL_ANGLE_instanced_arrays", instancedArrays, &extensionStrings); - InsertExtensionString("GL_ANGLE_pack_reverse_row_order", packReverseRowOrder, &extensionStrings); - InsertExtensionString("GL_OES_standard_derivatives", standardDerivatives, &extensionStrings); - InsertExtensionString("GL_EXT_shader_texture_lod", shaderTextureLOD, &extensionStrings); - InsertExtensionString("GL_EXT_frag_depth", fragDepth, &extensionStrings); - InsertExtensionString("GL_ANGLE_texture_usage", textureUsage, &extensionStrings); - InsertExtensionString("GL_ANGLE_translated_shader_source", translatedShaderSource, &extensionStrings); - InsertExtensionString("GL_EXT_color_buffer_float", colorBufferFloat, &extensionStrings); - - return extensionStrings; -} - -static bool GetFormatSupport(const TextureCapsMap &textureCaps, const std::vector &requiredFormats, - bool requiresTexturing, bool requiresFiltering, bool requiresRendering) -{ - for (size_t i = 0; i < requiredFormats.size(); i++) - { - const TextureCaps &cap = textureCaps.get(requiredFormats[i]); - - if (requiresTexturing && !cap.texturable) - { - return false; - } - - if (requiresFiltering && !cap.filterable) - { - return false; - } - - if (requiresRendering && !cap.renderable) - { - return false; - } - } - - return true; -} - -// Checks for GL_OES_rgb8_rgba8 support -static bool DetermineRGB8AndRGBA8TextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB8); - requiredFormats.push_back(GL_RGBA8); - - return GetFormatSupport(textureCaps, requiredFormats, true, true, true); -} - -// Checks for GL_EXT_texture_format_BGRA8888 support -static bool DetermineBGRA8TextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_BGRA8_EXT); - - return GetFormatSupport(textureCaps, requiredFormats, true, true, true); -} - -// Checks for GL_OES_texture_half_float support -static bool DetermineHalfFloatTextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB16F); - requiredFormats.push_back(GL_RGBA16F); - - return GetFormatSupport(textureCaps, requiredFormats, true, false, true); -} - -// Checks for GL_OES_texture_half_float_linear support -static bool DetermineHalfFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB16F); - requiredFormats.push_back(GL_RGBA16F); - - return GetFormatSupport(textureCaps, requiredFormats, true, true, false); -} - -// Checks for GL_OES_texture_float support -static bool DetermineFloatTextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB32F); - requiredFormats.push_back(GL_RGBA32F); - - return GetFormatSupport(textureCaps, requiredFormats, true, false, true); -} - -// Checks for GL_OES_texture_float_linear support -static bool DetermineFloatTextureFilteringSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_RGB32F); - requiredFormats.push_back(GL_RGBA32F); - - return GetFormatSupport(textureCaps, requiredFormats, true, true, false); -} - -// Checks for GL_EXT_texture_rg support -static bool DetermineRGTextureSupport(const TextureCapsMap &textureCaps, bool checkHalfFloatFormats, bool checkFloatFormats) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_R8); - requiredFormats.push_back(GL_RG8); - if (checkHalfFloatFormats) - { - requiredFormats.push_back(GL_R16F); - requiredFormats.push_back(GL_RG16F); - } - if (checkFloatFormats) - { - requiredFormats.push_back(GL_R32F); - requiredFormats.push_back(GL_RG32F); - } - - return GetFormatSupport(textureCaps, requiredFormats, true, true, false); -} - -// Check for GL_EXT_texture_compression_dxt1 -static bool DetermineDXT1TextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_COMPRESSED_RGB_S3TC_DXT1_EXT); - requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); - - return GetFormatSupport(textureCaps, requiredFormats, true, true, false); -} - -// Check for GL_ANGLE_texture_compression_dxt3 -static bool DetermineDXT3TextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); - - return GetFormatSupport(textureCaps, requiredFormats, true, true, false); -} - -// Check for GL_ANGLE_texture_compression_dxt5 -static bool DetermineDXT5TextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); - - return GetFormatSupport(textureCaps, requiredFormats, true, true, false); -} - -// Check for GL_ANGLE_texture_compression_dxt5 -static bool DetermineSRGBTextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFilterFormats; - requiredFilterFormats.push_back(GL_SRGB8); - requiredFilterFormats.push_back(GL_SRGB8_ALPHA8); - - std::vector requiredRenderFormats; - requiredRenderFormats.push_back(GL_SRGB8_ALPHA8); - - return GetFormatSupport(textureCaps, requiredFilterFormats, true, true, false) && - GetFormatSupport(textureCaps, requiredRenderFormats, true, false, true); -} - -// Check for GL_ANGLE_depth_texture -static bool DetermineDepthTextureSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_DEPTH_COMPONENT16); - requiredFormats.push_back(GL_DEPTH_COMPONENT32_OES); - requiredFormats.push_back(GL_DEPTH24_STENCIL8_OES); - - return GetFormatSupport(textureCaps, requiredFormats, true, true, true); -} - -// Check for GL_EXT_color_buffer_float -static bool DetermineColorBufferFloatSupport(const TextureCapsMap &textureCaps) -{ - std::vector requiredFormats; - requiredFormats.push_back(GL_R16F); - requiredFormats.push_back(GL_RG16F); - requiredFormats.push_back(GL_RGBA16F); - requiredFormats.push_back(GL_R32F); - requiredFormats.push_back(GL_RG32F); - requiredFormats.push_back(GL_RGBA32F); - requiredFormats.push_back(GL_R11F_G11F_B10F); - - return GetFormatSupport(textureCaps, requiredFormats, true, false, true); -} - -void Extensions::setTextureExtensionSupport(const TextureCapsMap &textureCaps) -{ - rgb8rgba8 = DetermineRGB8AndRGBA8TextureSupport(textureCaps); - textureFormatBGRA8888 = DetermineBGRA8TextureSupport(textureCaps); - textureHalfFloat = DetermineHalfFloatTextureSupport(textureCaps); - textureHalfFloatLinear = DetermineHalfFloatTextureFilteringSupport(textureCaps); - textureFloat = DetermineFloatTextureSupport(textureCaps); - textureFloatLinear = DetermineFloatTextureFilteringSupport(textureCaps); - textureRG = DetermineRGTextureSupport(textureCaps, textureHalfFloat, textureFloat); - textureCompressionDXT1 = DetermineDXT1TextureSupport(textureCaps); - textureCompressionDXT3 = DetermineDXT3TextureSupport(textureCaps); - textureCompressionDXT5 = DetermineDXT5TextureSupport(textureCaps); - sRGB = DetermineSRGBTextureSupport(textureCaps); - depthTextures = DetermineDepthTextureSupport(textureCaps); - colorBufferFloat = DetermineColorBufferFloatSupport(textureCaps); -} - -Caps::Caps() - : maxElementIndex(0), - max3DTextureSize(0), - max2DTextureSize(0), - maxArrayTextureLayers(0), - maxLODBias(0), - maxCubeMapTextureSize(0), - maxRenderbufferSize(0), - maxDrawBuffers(0), - maxColorAttachments(0), - maxViewportWidth(0), - maxViewportHeight(0), - minAliasedPointSize(0), - maxAliasedPointSize(0), - minAliasedLineWidth(0), - // Table 6.29 - maxElementsIndices(0), - maxElementsVertices(0), - maxServerWaitTimeout(0), - // Table 6.31 - maxVertexAttributes(0), - maxVertexUniformComponents(0), - maxVertexUniformVectors(0), - maxVertexUniformBlocks(0), - maxVertexOutputComponents(0), - maxVertexTextureImageUnits(0), - // Table 6.32 - maxFragmentUniformComponents(0), - maxFragmentUniformVectors(0), - maxFragmentUniformBlocks(0), - maxFragmentInputComponents(0), - maxTextureImageUnits(0), - minProgramTexelOffset(0), - maxProgramTexelOffset(0), - - maxUniformBufferBindings(0), - maxUniformBlockSize(0), - uniformBufferOffsetAlignment(0), - maxCombinedUniformBlocks(0), - maxCombinedVertexUniformComponents(0), - maxCombinedFragmentUniformComponents(0), - maxVaryingComponents(0), - maxVaryingVectors(0), - maxCombinedTextureImageUnits(0), - - maxTransformFeedbackInterleavedComponents(0), - maxTransformFeedbackSeparateAttributes(0), - maxTransformFeedbackSeparateComponents(0) -{ -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Caps.h b/src/3rdparty/angle/src/libGLESv2/Caps.h deleted file mode 100644 index a00e554176..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Caps.h +++ /dev/null @@ -1,273 +0,0 @@ -#ifndef LIBGLESV2_CAPS_H -#define LIBGLESV2_CAPS_H - -// -// Copyright (c) 2014 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 "angle_gl.h" - -#include -#include -#include -#include - -namespace gl -{ - -typedef std::set SupportedSampleSet; - -struct TextureCaps -{ - TextureCaps(); - - // Supports for basic texturing: glTexImage, glTexSubImage, etc - bool texturable; - - // Support for linear or anisotropic filtering - bool filterable; - - // Support for being used as a framebuffer attachment or renderbuffer format - bool renderable; - - SupportedSampleSet sampleCounts; - - // Get the maximum number of samples supported - GLuint getMaxSamples() const; - - // Get the number of supported samples that is at least as many as requested. Returns 0 if - // there are no sample counts available - GLuint getNearestSamples(GLuint requestedSamples) const; -}; - -class TextureCapsMap -{ - public: - typedef std::unordered_map::const_iterator const_iterator; - - void insert(GLenum internalFormat, const TextureCaps &caps); - void remove(GLenum internalFormat); - - const TextureCaps &get(GLenum internalFormat) const; - - const_iterator begin() const; - const_iterator end() const; - - size_t size() const; - - private: - typedef std::unordered_map InternalFormatToCapsMap; - InternalFormatToCapsMap mCapsMap; -}; - -struct Extensions -{ - Extensions(); - - // Generate a vector of supported extension strings - std::vector getStrings() const; - - // Set all texture related extension support based on the supported textures. - // Determines support for: - // GL_OES_rgb8_rgba8 - // GL_EXT_texture_format_BGRA8888 - // GL_OES_texture_half_float, GL_OES_texture_half_float_linear - // GL_OES_texture_float, GL_OES_texture_float_linear - // GL_EXT_texture_rg - // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3, GL_ANGLE_texture_compression_dxt5 - // GL_EXT_sRGB - // GL_ANGLE_depth_texture - // GL_EXT_color_buffer_float - void setTextureExtensionSupport(const TextureCapsMap &textureCaps); - - // ES2 Extension support - - // GL_OES_element_index_uint - bool elementIndexUint; - - // GL_OES_packed_depth_stencil - bool packedDepthStencil; - - // GL_OES_get_program_binary - bool getProgramBinary; - - // GL_OES_rgb8_rgba8 - // Implies that TextureCaps for GL_RGB8 and GL_RGBA8 exist - bool rgb8rgba8; - - // GL_EXT_texture_format_BGRA8888 - // Implies that TextureCaps for GL_BGRA8 exist - bool textureFormatBGRA8888; - - // GL_EXT_read_format_bgra - bool readFormatBGRA; - - // GL_NV_pixel_buffer_object - bool pixelBufferObject; - - // GL_OES_mapbuffer and GL_EXT_map_buffer_range - bool mapBuffer; - bool mapBufferRange; - - // GL_OES_texture_half_float and GL_OES_texture_half_float_linear - // Implies that TextureCaps for GL_RGB16F, GL_RGBA16F, GL_ALPHA32F_EXT, GL_LUMINANCE32F_EXT and - // GL_LUMINANCE_ALPHA32F_EXT exist - bool textureHalfFloat; - bool textureHalfFloatLinear; - - // GL_OES_texture_float and GL_OES_texture_float_linear - // Implies that TextureCaps for GL_RGB32F, GL_RGBA32F, GL_ALPHA16F_EXT, GL_LUMINANCE16F_EXT and - // GL_LUMINANCE_ALPHA16F_EXT exist - bool textureFloat; - bool textureFloatLinear; - - // GL_EXT_texture_rg - // Implies that TextureCaps for GL_R8, GL_RG8 (and floating point R/RG texture formats if floating point extensions - // are also present) exist - bool textureRG; - - // GL_EXT_texture_compression_dxt1, GL_ANGLE_texture_compression_dxt3 and GL_ANGLE_texture_compression_dxt5 - // Implies that TextureCaps for GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT - // GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE and GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE - bool textureCompressionDXT1; - bool textureCompressionDXT3; - bool textureCompressionDXT5; - - // GL_EXT_sRGB - // Implies that TextureCaps for GL_SRGB8_ALPHA8 and GL_SRGB8 exist - // TODO: Don't advertise this extension in ES3 - bool sRGB; - - // GL_ANGLE_depth_texture - bool depthTextures; - - // GL_EXT_texture_storage - bool textureStorage; - - // GL_OES_texture_npot - bool textureNPOT; - - // GL_EXT_draw_buffers - bool drawBuffers; - - // GL_EXT_texture_filter_anisotropic - bool textureFilterAnisotropic; - GLfloat maxTextureAnisotropy; - - // GL_EXT_occlusion_query_boolean - bool occlusionQueryBoolean; - - // GL_NV_fence - bool fence; - - // GL_ANGLE_timer_query - bool timerQuery; - - // GL_EXT_robustness - bool robustness; - - // GL_EXT_blend_minmax - bool blendMinMax; - - // GL_ANGLE_framebuffer_blit - bool framebufferBlit; - - // GL_ANGLE_framebuffer_multisample - bool framebufferMultisample; - GLuint maxSamples; - - // GL_ANGLE_instanced_arrays - bool instancedArrays; - - // GL_ANGLE_pack_reverse_row_order - bool packReverseRowOrder; - - // GL_OES_standard_derivatives - bool standardDerivatives; - - // GL_EXT_shader_texture_lod - bool shaderTextureLOD; - - // GL_EXT_frag_depth - bool fragDepth; - - // GL_ANGLE_texture_usage - bool textureUsage; - - // GL_ANGLE_translated_shader_source - bool translatedShaderSource; - - // ES3 Extension support - - // GL_EXT_color_buffer_float - bool colorBufferFloat; -}; - -struct Caps -{ - Caps(); - - // Table 6.28, implementation dependent values - GLuint64 maxElementIndex; - GLuint max3DTextureSize; - GLuint max2DTextureSize; - GLuint maxArrayTextureLayers; - GLfloat maxLODBias; - GLuint maxCubeMapTextureSize; - GLuint maxRenderbufferSize; - GLuint maxDrawBuffers; - GLuint maxColorAttachments; - GLuint maxViewportWidth; - GLuint maxViewportHeight; - GLfloat minAliasedPointSize; - GLfloat maxAliasedPointSize; - GLfloat minAliasedLineWidth; - GLfloat maxAliasedLineWidth; - - // Table 6.29, implementation dependent values (cont.) - GLuint maxElementsIndices; - GLuint maxElementsVertices; - std::vector compressedTextureFormats; - std::vector programBinaryFormats; - std::vector shaderBinaryFormats; - GLuint64 maxServerWaitTimeout; - - // Table 6.31, implementation dependent vertex shader limits - GLuint maxVertexAttributes; - GLuint maxVertexUniformComponents; - GLuint maxVertexUniformVectors; - GLuint maxVertexUniformBlocks; - GLuint maxVertexOutputComponents; - GLuint maxVertexTextureImageUnits; - - // Table 6.32, implementation dependent fragment shader limits - GLuint maxFragmentUniformComponents; - GLuint maxFragmentUniformVectors; - GLuint maxFragmentUniformBlocks; - GLuint maxFragmentInputComponents; - GLuint maxTextureImageUnits; - GLint minProgramTexelOffset; - GLint maxProgramTexelOffset; - - // Table 6.33, implementation dependent aggregate shader limits - GLuint maxUniformBufferBindings; - GLuint64 maxUniformBlockSize; - GLuint uniformBufferOffsetAlignment; - GLuint maxCombinedUniformBlocks; - GLuint64 maxCombinedVertexUniformComponents; - GLuint64 maxCombinedFragmentUniformComponents; - GLuint maxVaryingComponents; - GLuint maxVaryingVectors; - GLuint maxCombinedTextureImageUnits; - - // Table 6.34, implementation dependent transform feedback limits - GLuint maxTransformFeedbackInterleavedComponents; - GLuint maxTransformFeedbackSeparateAttributes; - GLuint maxTransformFeedbackSeparateComponents; -}; - -} - -#endif // LIBGLESV2_CAPS_H diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp deleted file mode 100644 index 3772da6f42..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Context.cpp +++ /dev/null @@ -1,1769 +0,0 @@ -// -// Copyright (c) 2002-2014 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 "common/utilities.h" -#include "common/platform.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/Fence.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/Program.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Query.h" -#include "libGLESv2/ResourceManager.h" -#include "libGLESv2/Sampler.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/TransformFeedback.h" -#include "libGLESv2/VertexArray.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/main.h" -#include "libGLESv2/validationES.h" -#include "libGLESv2/renderer/Renderer.h" - -#include "libEGL/Surface.h" - -#include -#include - -namespace gl -{ - -Context::Context(int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) - : mRenderer(renderer) -{ - ASSERT(robustAccess == false); // Unimplemented - - initCaps(clientVersion); - mState.initialize(mCaps, clientVersion); - - mClientVersion = clientVersion; - - mFenceNVHandleAllocator.setBaseHandle(0); - - if (shareContext != NULL) - { - mResourceManager = shareContext->mResourceManager; - mResourceManager->addRef(); - } - else - { - mResourceManager = new ResourceManager(mRenderer); - } - - // [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. - - Texture2D *zeroTexture2D = new Texture2D(mRenderer->createTexture(GL_TEXTURE_2D), 0); - mZeroTextures[GL_TEXTURE_2D].set(zeroTexture2D); - - TextureCubeMap *zeroTextureCube = new TextureCubeMap(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), 0); - mZeroTextures[GL_TEXTURE_CUBE_MAP].set(zeroTextureCube); - - if (mClientVersion >= 3) - { - // TODO: These could also be enabled via extension - Texture3D *zeroTexture3D = new Texture3D(mRenderer->createTexture(GL_TEXTURE_3D), 0); - mZeroTextures[GL_TEXTURE_3D].set(zeroTexture3D); - - Texture2DArray *zeroTexture2DArray = new Texture2DArray(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), 0); - mZeroTextures[GL_TEXTURE_2D_ARRAY].set(zeroTexture2DArray); - } - - mState.initializeZeroTextures(mZeroTextures); - - bindVertexArray(0); - bindArrayBuffer(0); - bindElementArrayBuffer(0); - - bindReadFramebuffer(0); - bindDrawFramebuffer(0); - bindRenderbuffer(0); - - bindGenericUniformBuffer(0); - for (unsigned int i = 0; i < mCaps.maxCombinedUniformBlocks; i++) - { - bindIndexedUniformBuffer(0, i, 0, -1); - } - - bindGenericTransformFeedbackBuffer(0); - for (unsigned int i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++) - { - bindIndexedTransformFeedbackBuffer(0, i, 0, -1); - } - - bindCopyReadBuffer(0); - bindCopyWriteBuffer(0); - bindPixelPackBuffer(0); - bindPixelUnpackBuffer(0); - - // [OpenGL ES 3.0.2] section 2.14.1 pg 85: - // In the initial state, a default transform feedback object is bound and treated as - // a transform feedback object with a name of zero. That object is bound any time - // BindTransformFeedback is called with id of zero - mTransformFeedbackZero.set(new TransformFeedback(mRenderer->createTransformFeedback(), 0)); - bindTransformFeedback(0); - - mHasBeenCurrent = false; - mContextLost = false; - mResetStatus = GL_NO_ERROR; - mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); - mRobustAccess = robustAccess; -} - -Context::~Context() -{ - GLuint currentProgram = mState.getCurrentProgramId(); - if (currentProgram != 0) - { - Program *programObject = mResourceManager->getProgram(currentProgram); - if (programObject) - { - programObject->release(); - } - currentProgram = 0; - } - mState.setCurrentProgram(0, NULL); - - while (!mFramebufferMap.empty()) - { - deleteFramebuffer(mFramebufferMap.begin()->first); - } - - while (!mFenceNVMap.empty()) - { - deleteFenceNV(mFenceNVMap.begin()->first); - } - - while (!mQueryMap.empty()) - { - deleteQuery(mQueryMap.begin()->first); - } - - while (!mVertexArrayMap.empty()) - { - deleteVertexArray(mVertexArrayMap.begin()->first); - } - - mTransformFeedbackZero.set(NULL); - while (!mTransformFeedbackMap.empty()) - { - deleteTransformFeedback(mTransformFeedbackMap.begin()->first); - } - - for (TextureMap::iterator i = mZeroTextures.begin(); i != mZeroTextures.end(); i++) - { - i->second.set(NULL); - } - mZeroTextures.clear(); - - if (mResourceManager) - { - mResourceManager->release(); - } -} - -void Context::makeCurrent(egl::Surface *surface) -{ - if (!mHasBeenCurrent) - { - initRendererString(); - initExtensionStrings(); - - mState.setViewportParams(0, 0, surface->getWidth(), surface->getHeight()); - mState.setScissorParams(0, 0, surface->getWidth(), surface->getHeight()); - - mHasBeenCurrent = true; - } - - // Wrap the existing swapchain resources into GL objects and assign them to the '0' names - rx::SwapChain *swapchain = surface->getSwapChain(); - - rx::RenderbufferImpl *colorbufferZero = mRenderer->createRenderbuffer(swapchain, false); - rx::RenderbufferImpl *depthStencilbufferZero = mRenderer->createRenderbuffer(swapchain, true); - Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero); - - setFramebufferZero(framebufferZero); -} - -// NOTE: this function should not assume that this context is current! -void Context::markContextLost() -{ - if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT) - mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT; - mContextLost = true; -} - -bool Context::isContextLost() -{ - return mContextLost; -} - -GLuint Context::createBuffer() -{ - return mResourceManager->createBuffer(); -} - -GLuint Context::createProgram() -{ - return mResourceManager->createProgram(); -} - -GLuint Context::createShader(GLenum type) -{ - return mResourceManager->createShader(getData(), type); -} - -GLuint Context::createTexture() -{ - return mResourceManager->createTexture(); -} - -GLuint Context::createRenderbuffer() -{ - return mResourceManager->createRenderbuffer(); -} - -GLsync Context::createFenceSync() -{ - GLuint handle = mResourceManager->createFenceSync(); - - return reinterpret_cast(handle); -} - -GLuint Context::createVertexArray() -{ - GLuint handle = mVertexArrayHandleAllocator.allocate(); - - // Although the spec states VAO state is not initialized until the object is bound, - // we create it immediately. The resulting behaviour is transparent to the application, - // since it's not currently possible to access the state until the object is bound. - VertexArray *vertexArray = new VertexArray(mRenderer->createVertexArray(), handle, MAX_VERTEX_ATTRIBS); - mVertexArrayMap[handle] = vertexArray; - return handle; -} - -GLuint Context::createSampler() -{ - return mResourceManager->createSampler(); -} - -GLuint Context::createTransformFeedback() -{ - GLuint handle = mTransformFeedbackAllocator.allocate(); - TransformFeedback *transformFeedback = new TransformFeedback(mRenderer->createTransformFeedback(), handle); - transformFeedback->addRef(); - mTransformFeedbackMap[handle] = transformFeedback; - return handle; -} - -// Returns an unused framebuffer name -GLuint Context::createFramebuffer() -{ - GLuint handle = mFramebufferHandleAllocator.allocate(); - - mFramebufferMap[handle] = NULL; - - return handle; -} - -GLuint Context::createFenceNV() -{ - GLuint handle = mFenceNVHandleAllocator.allocate(); - - mFenceNVMap[handle] = new FenceNV(mRenderer->createFenceNV()); - - 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::deleteFenceSync(GLsync fenceSync) -{ - // The spec specifies the underlying Fence object is not deleted until all current - // wait commands finish. However, since the name becomes invalid, we cannot query the fence, - // and since our API is currently designed for being called from a single thread, we can delete - // the fence immediately. - mResourceManager->deleteFenceSync(reinterpret_cast(fenceSync)); -} - -void Context::deleteVertexArray(GLuint vertexArray) -{ - VertexArrayMap::iterator vertexArrayObject = mVertexArrayMap.find(vertexArray); - - if (vertexArrayObject != mVertexArrayMap.end()) - { - detachVertexArray(vertexArray); - - mVertexArrayHandleAllocator.release(vertexArrayObject->first); - delete vertexArrayObject->second; - mVertexArrayMap.erase(vertexArrayObject); - } -} - -void Context::deleteSampler(GLuint sampler) -{ - if (mResourceManager->getSampler(sampler)) - { - detachSampler(sampler); - } - - mResourceManager->deleteSampler(sampler); -} - -void Context::deleteTransformFeedback(GLuint transformFeedback) -{ - TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(transformFeedback); - if (iter != mTransformFeedbackMap.end()) - { - detachTransformFeedback(transformFeedback); - mTransformFeedbackAllocator.release(transformFeedback); - iter->second->release(); - mTransformFeedbackMap.erase(iter); - } -} - -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::deleteFenceNV(GLuint fence) -{ - FenceNVMap::iterator fenceObject = mFenceNVMap.find(fence); - - if (fenceObject != mFenceNVMap.end()) - { - mFenceNVHandleAllocator.release(fenceObject->first); - delete fenceObject->second; - mFenceNVMap.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) const -{ - return mResourceManager->getShader(handle); -} - -Program *Context::getProgram(GLuint handle) const -{ - return mResourceManager->getProgram(handle); -} - -Texture *Context::getTexture(GLuint handle) const -{ - return mResourceManager->getTexture(handle); -} - -Renderbuffer *Context::getRenderbuffer(GLuint handle) -{ - return mResourceManager->getRenderbuffer(handle); -} - -FenceSync *Context::getFenceSync(GLsync handle) const -{ - return mResourceManager->getFenceSync(reinterpret_cast(handle)); -} - -VertexArray *Context::getVertexArray(GLuint handle) const -{ - VertexArrayMap::const_iterator vertexArray = mVertexArrayMap.find(handle); - - if (vertexArray == mVertexArrayMap.end()) - { - return NULL; - } - else - { - return vertexArray->second; - } -} - -Sampler *Context::getSampler(GLuint handle) const -{ - return mResourceManager->getSampler(handle); -} - -TransformFeedback *Context::getTransformFeedback(GLuint handle) const -{ - if (handle == 0) - { - return mTransformFeedbackZero.get(); - } - else - { - TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle); - return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL; - } -} - -bool Context::isSampler(GLuint samplerName) const -{ - return mResourceManager->isSampler(samplerName); -} - -void Context::bindArrayBuffer(unsigned int buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setArrayBufferBinding(getBuffer(buffer)); -} - -void Context::bindElementArrayBuffer(unsigned int buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.getVertexArray()->setElementArrayBuffer(getBuffer(buffer)); -} - -void Context::bindTexture(GLenum target, GLuint handle) -{ - Texture *texture = NULL; - - if (handle == 0) - { - texture = mZeroTextures[target].get(); - } - else - { - mResourceManager->checkTextureAllocation(handle, target); - texture = getTexture(handle); - } - - ASSERT(texture); - - mState.setSamplerTexture(target, texture); -} - -void Context::bindReadFramebuffer(GLuint framebuffer) -{ - if (!getFramebuffer(framebuffer)) - { - mFramebufferMap[framebuffer] = new Framebuffer(framebuffer); - } - - mState.setReadFramebufferBinding(getFramebuffer(framebuffer)); -} - -void Context::bindDrawFramebuffer(GLuint framebuffer) -{ - if (!getFramebuffer(framebuffer)) - { - mFramebufferMap[framebuffer] = new Framebuffer(framebuffer); - } - - mState.setDrawFramebufferBinding(getFramebuffer(framebuffer)); -} - -void Context::bindRenderbuffer(GLuint renderbuffer) -{ - mResourceManager->checkRenderbufferAllocation(renderbuffer); - - mState.setRenderbufferBinding(getRenderbuffer(renderbuffer)); -} - -void Context::bindVertexArray(GLuint vertexArray) -{ - if (!getVertexArray(vertexArray)) - { - VertexArray *vertexArrayObject = new VertexArray(mRenderer->createVertexArray(), vertexArray, MAX_VERTEX_ATTRIBS); - mVertexArrayMap[vertexArray] = vertexArrayObject; - } - - mState.setVertexArrayBinding(getVertexArray(vertexArray)); -} - -void Context::bindSampler(GLuint textureUnit, GLuint sampler) -{ - ASSERT(textureUnit < mCaps.maxCombinedTextureImageUnits); - mResourceManager->checkSamplerAllocation(sampler); - - mState.setSamplerBinding(textureUnit, getSampler(sampler)); -} - -void Context::bindGenericUniformBuffer(GLuint buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setGenericUniformBufferBinding(getBuffer(buffer)); -} - -void Context::bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setIndexedUniformBufferBinding(index, getBuffer(buffer), offset, size); -} - -void Context::bindGenericTransformFeedbackBuffer(GLuint buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setGenericTransformFeedbackBufferBinding(getBuffer(buffer)); -} - -void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setIndexedTransformFeedbackBufferBinding(index, getBuffer(buffer), offset, size); -} - -void Context::bindCopyReadBuffer(GLuint buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setCopyReadBufferBinding(getBuffer(buffer)); -} - -void Context::bindCopyWriteBuffer(GLuint buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setCopyWriteBufferBinding(getBuffer(buffer)); -} - -void Context::bindPixelPackBuffer(GLuint buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setPixelPackBufferBinding(getBuffer(buffer)); -} - -void Context::bindPixelUnpackBuffer(GLuint buffer) -{ - mResourceManager->checkBufferAllocation(buffer); - - mState.setPixelUnpackBufferBinding(getBuffer(buffer)); -} - -void Context::useProgram(GLuint program) -{ - GLuint priorProgramId = mState.getCurrentProgramId(); - Program *priorProgram = mResourceManager->getProgram(priorProgramId); - - if (priorProgramId != program) - { - mState.setCurrentProgram(program, mResourceManager->getProgram(program)); - - if (priorProgram) - { - priorProgram->release(); - } - } -} - -Error Context::linkProgram(GLuint program) -{ - Program *programObject = mResourceManager->getProgram(program); - - Error error = programObject->link(getData()); - if (error.isError()) - { - return error; - } - - // if the current program was relinked successfully we - // need to install the new executables - if (programObject->isLinked() && program == mState.getCurrentProgramId()) - { - mState.setCurrentProgramBinary(programObject->getProgramBinary()); - } - - return Error(GL_NO_ERROR); -} - -Error Context::setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length) -{ - Program *programObject = mResourceManager->getProgram(program); - - Error error = programObject->setProgramBinary(binaryFormat, binary, length); - if (error.isError()) - { - return error; - } - - // if the current program was reloaded successfully we - // need to install the new executables - if (programObject->isLinked() && program == mState.getCurrentProgramId()) - { - mState.setCurrentProgramBinary(programObject->getProgramBinary()); - } - - return Error(GL_NO_ERROR); -} - -void Context::bindTransformFeedback(GLuint transformFeedback) -{ - mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback)); -} - -Error Context::beginQuery(GLenum target, GLuint query) -{ - Query *queryObject = getQuery(query, true, target); - ASSERT(queryObject); - - // begin query - Error error = queryObject->begin(); - if (error.isError()) - { - return error; - } - - // set query as active for specified target only if begin succeeded - mState.setActiveQuery(target, queryObject); - - return Error(GL_NO_ERROR); -} - -Error Context::endQuery(GLenum target) -{ - Query *queryObject = mState.getActiveQuery(target); - ASSERT(queryObject); - - gl::Error error = queryObject->end(); - - // Always unbind the query, even if there was an error. This may delete the query object. - mState.setActiveQuery(target, NULL); - - return error; -} - -void Context::setFramebufferZero(Framebuffer *buffer) -{ - // First, check to see if the old default framebuffer - // was set for draw or read framebuffer, and change - // the bindings to point to the new one before deleting it. - if (mState.getDrawFramebuffer()->id() == 0) - { - mState.setDrawFramebufferBinding(buffer); - } - - if (mState.getReadFramebuffer()->id() == 0) - { - mState.setReadFramebufferBinding(buffer); - } - - delete mFramebufferMap[0]; - mFramebufferMap[0] = buffer; -} - -Framebuffer *Context::getFramebuffer(unsigned int handle) const -{ - FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle); - - if (framebuffer == mFramebufferMap.end()) - { - return NULL; - } - else - { - return framebuffer->second; - } -} - -FenceNV *Context::getFenceNV(unsigned int handle) -{ - FenceNVMap::iterator fence = mFenceNVMap.find(handle); - - if (fence == mFenceNVMap.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(mRenderer->createQuery(type), handle); - query->second->addRef(); - } - return query->second; - } -} - -Texture *Context::getTargetTexture(GLenum target) const -{ - if (!ValidTextureTarget(this, target)) - { - return NULL; - } - - switch (target) - { - case GL_TEXTURE_2D: return getTexture2D(); - case GL_TEXTURE_CUBE_MAP: return getTextureCubeMap(); - case GL_TEXTURE_3D: return getTexture3D(); - case GL_TEXTURE_2D_ARRAY: return getTexture2DArray(); - default: return NULL; - } -} - -Texture2D *Context::getTexture2D() const -{ - return static_cast(getSamplerTexture(mState.getActiveSampler(), GL_TEXTURE_2D)); -} - -TextureCubeMap *Context::getTextureCubeMap() const -{ - return static_cast(getSamplerTexture(mState.getActiveSampler(), GL_TEXTURE_CUBE_MAP)); -} - -Texture3D *Context::getTexture3D() const -{ - return static_cast(getSamplerTexture(mState.getActiveSampler(), GL_TEXTURE_3D)); -} - -Texture2DArray *Context::getTexture2DArray() const -{ - return static_cast(getSamplerTexture(mState.getActiveSampler(), GL_TEXTURE_2D_ARRAY)); -} - -Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const -{ - return mState.getSamplerTexture(sampler, type); -} - -void Context::getBooleanv(GLenum pname, GLboolean *params) -{ - switch (pname) - { - case GL_SHADER_COMPILER: *params = GL_TRUE; break; - case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break; - default: - mState.getBooleanv(pname, params); - break; - } -} - -void Context::getFloatv(GLenum pname, GLfloat *params) -{ - // Queries about context capabilities and maximums are answered by Context. - // Queries about current GL state values are answered by State. - switch (pname) - { - case GL_ALIASED_LINE_WIDTH_RANGE: - params[0] = mCaps.minAliasedLineWidth; - params[1] = mCaps.maxAliasedLineWidth; - break; - case GL_ALIASED_POINT_SIZE_RANGE: - params[0] = mCaps.minAliasedPointSize; - params[1] = mCaps.maxAliasedPointSize; - break; - case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: - ASSERT(mExtensions.textureFilterAnisotropic); - *params = mExtensions.maxTextureAnisotropy; - break; - default: - mState.getFloatv(pname, params); - break; - } -} - -void Context::getIntegerv(GLenum pname, GLint *params) -{ - // Queries about context capabilities and maximums are answered by Context. - // Queries about current GL state values are answered by State. - - switch (pname) - { - case GL_MAX_VERTEX_ATTRIBS: *params = mCaps.maxVertexAttributes; break; - case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = mCaps.maxVertexUniformVectors; break; - case GL_MAX_VERTEX_UNIFORM_COMPONENTS: *params = mCaps.maxVertexUniformComponents; break; - case GL_MAX_VARYING_VECTORS: *params = mCaps.maxVaryingVectors; break; - case GL_MAX_VARYING_COMPONENTS: *params = mCaps.maxVertexOutputComponents; break; - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = mCaps.maxCombinedTextureImageUnits; break; - case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxVertexTextureImageUnits; break; - case GL_MAX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxTextureImageUnits; break; - case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mCaps.maxFragmentUniformVectors; break; - case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mCaps.maxFragmentInputComponents; break; - case GL_MAX_RENDERBUFFER_SIZE: *params = mCaps.maxRenderbufferSize; break; - case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mCaps.maxColorAttachments; break; - case GL_MAX_DRAW_BUFFERS_EXT: *params = mCaps.maxDrawBuffers; break; - //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE - case GL_SUBPIXEL_BITS: *params = 4; break; - case GL_MAX_TEXTURE_SIZE: *params = mCaps.max2DTextureSize; break; - case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = mCaps.maxCubeMapTextureSize; break; - case GL_MAX_3D_TEXTURE_SIZE: *params = mCaps.max3DTextureSize; break; - case GL_MAX_ARRAY_TEXTURE_LAYERS: *params = mCaps.maxArrayTextureLayers; break; - case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: *params = mCaps.uniformBufferOffsetAlignment; break; - case GL_MAX_UNIFORM_BUFFER_BINDINGS: *params = mCaps.maxUniformBufferBindings; break; - case GL_MAX_VERTEX_UNIFORM_BLOCKS: *params = mCaps.maxVertexUniformBlocks; break; - case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: *params = mCaps.maxFragmentUniformBlocks; break; - case GL_MAX_COMBINED_UNIFORM_BLOCKS: *params = mCaps.maxCombinedTextureImageUnits; break; - case GL_MAJOR_VERSION: *params = mClientVersion; break; - case GL_MINOR_VERSION: *params = 0; break; - case GL_MAX_ELEMENTS_INDICES: *params = mCaps.maxElementsIndices; break; - case GL_MAX_ELEMENTS_VERTICES: *params = mCaps.maxElementsVertices; break; - case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: *params = mCaps.maxTransformFeedbackInterleavedComponents; break; - case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: *params = mCaps.maxTransformFeedbackSeparateAttributes; break; - case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: *params = mCaps.maxTransformFeedbackSeparateComponents; break; - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: *params = mCaps.compressedTextureFormats.size(); break; - case GL_MAX_SAMPLES_ANGLE: *params = mExtensions.maxSamples; break; - case GL_IMPLEMENTATION_COLOR_READ_TYPE: - case GL_IMPLEMENTATION_COLOR_READ_FORMAT: - { - GLenum internalFormat, format, type; - getCurrentReadFormatType(&internalFormat, &format, &type); - if (pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT) - *params = format; - else - *params = type; - } - break; - case GL_MAX_VIEWPORT_DIMS: - { - params[0] = mCaps.maxViewportWidth; - params[1] = mCaps.maxViewportHeight; - } - break; - case GL_COMPRESSED_TEXTURE_FORMATS: - std::copy(mCaps.compressedTextureFormats.begin(), mCaps.compressedTextureFormats.end(), params); - break; - case GL_RESET_NOTIFICATION_STRATEGY_EXT: - *params = mResetStrategy; - break; - case GL_NUM_SHADER_BINARY_FORMATS: - *params = mCaps.shaderBinaryFormats.size(); - break; - case GL_SHADER_BINARY_FORMATS: - std::copy(mCaps.shaderBinaryFormats.begin(), mCaps.shaderBinaryFormats.end(), params); - break; - case GL_NUM_PROGRAM_BINARY_FORMATS: - *params = mCaps.programBinaryFormats.size(); - break; - case GL_PROGRAM_BINARY_FORMATS: - std::copy(mCaps.programBinaryFormats.begin(), mCaps.programBinaryFormats.end(), params); - break; - case GL_NUM_EXTENSIONS: - *params = static_cast(mExtensionStrings.size()); - break; - default: - mState.getIntegerv(getData(), pname, params); - break; - } -} - -void Context::getInteger64v(GLenum pname, GLint64 *params) -{ - // Queries about context capabilities and maximums are answered by Context. - // Queries about current GL state values are answered by State. - switch (pname) - { - case GL_MAX_ELEMENT_INDEX: - *params = mCaps.maxElementIndex; - break; - case GL_MAX_UNIFORM_BLOCK_SIZE: - *params = mCaps.maxUniformBlockSize; - break; - case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: - *params = mCaps.maxCombinedVertexUniformComponents; - break; - case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: - *params = mCaps.maxCombinedFragmentUniformComponents; - break; - case GL_MAX_SERVER_WAIT_TIMEOUT: - *params = mCaps.maxServerWaitTimeout; - break; - default: - UNREACHABLE(); - break; - } -} - -bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) -{ - // Queries about context capabilities and maximums are answered by Context. - // Queries about current GL state values are answered by State. - // Indexed integer queries all refer to current state, so this function is a - // mere passthrough. - return mState.getIndexedIntegerv(target, index, data); -} - -bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) -{ - // Queries about context capabilities and maximums are answered by Context. - // Queries about current GL state values are answered by State. - // Indexed integer queries all refer to current state, so this function is a - // mere passthrough. - return mState.getIndexedInteger64v(target, index, data); -} - -bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams) -{ - if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) - { - *type = GL_INT; - *numParams = 1; - return true; - } - - // 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 = mCaps.compressedTextureFormats.size(); - } - return true; - case GL_PROGRAM_BINARY_FORMATS_OES: - { - *type = GL_INT; - *numParams = mCaps.programBinaryFormats.size(); - } - return true; - case GL_SHADER_BINARY_FORMATS: - { - *type = GL_INT; - *numParams = mCaps.shaderBinaryFormats.size(); - } - return true; - 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_MAX_COLOR_ATTACHMENTS_EXT: - case GL_MAX_DRAW_BUFFERS_EXT: - case GL_NUM_SHADER_BINARY_FORMATS: - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: - case GL_ARRAY_BUFFER_BINDING: - //case GL_FRAMEBUFFER_BINDING: // equivalent to DRAW_FRAMEBUFFER_BINDING_ANGLE - case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: - case GL_READ_FRAMEBUFFER_BINDING_ANGLE: - 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: - { - *type = GL_INT; - *numParams = 1; - } - return true; - case GL_MAX_SAMPLES_ANGLE: - { - if (mExtensions.framebufferMultisample) - { - *type = GL_INT; - *numParams = 1; - } - else - { - return false; - } - } - return true; - case GL_PIXEL_PACK_BUFFER_BINDING: - case GL_PIXEL_UNPACK_BUFFER_BINDING: - { - if (mExtensions.pixelBufferObject) - { - *type = GL_INT; - *numParams = 1; - } - else - { - return false; - } - } - return true; - case GL_MAX_VIEWPORT_DIMS: - { - *type = GL_INT; - *numParams = 2; - } - return true; - case GL_VIEWPORT: - case GL_SCISSOR_BOX: - { - *type = GL_INT; - *numParams = 4; - } - return true; - 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; - } - return true; - case GL_COLOR_WRITEMASK: - { - *type = GL_BOOL; - *numParams = 4; - } - return true; - 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; - } - return true; - case GL_ALIASED_LINE_WIDTH_RANGE: - case GL_ALIASED_POINT_SIZE_RANGE: - case GL_DEPTH_RANGE: - { - *type = GL_FLOAT; - *numParams = 2; - } - return true; - case GL_COLOR_CLEAR_VALUE: - case GL_BLEND_COLOR: - { - *type = GL_FLOAT; - *numParams = 4; - } - return true; - case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: - if (!mExtensions.maxTextureAnisotropy) - { - return false; - } - *type = GL_FLOAT; - *numParams = 1; - return true; - } - - if (mClientVersion < 3) - { - return false; - } - - // Check for ES3.0+ parameter names - switch (pname) - { - case GL_MAX_UNIFORM_BUFFER_BINDINGS: - case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: - case GL_UNIFORM_BUFFER_BINDING: - case GL_TRANSFORM_FEEDBACK_BINDING: - case GL_COPY_READ_BUFFER_BINDING: - case GL_COPY_WRITE_BUFFER_BINDING: - case GL_TEXTURE_BINDING_3D: - case GL_TEXTURE_BINDING_2D_ARRAY: - case GL_MAX_3D_TEXTURE_SIZE: - case GL_MAX_ARRAY_TEXTURE_LAYERS: - case GL_MAX_VERTEX_UNIFORM_BLOCKS: - case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: - case GL_MAX_COMBINED_UNIFORM_BLOCKS: - case GL_MAX_VARYING_COMPONENTS: - case GL_VERTEX_ARRAY_BINDING: - case GL_MAX_VERTEX_UNIFORM_COMPONENTS: - case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: - case GL_NUM_EXTENSIONS: - case GL_MAJOR_VERSION: - case GL_MINOR_VERSION: - case GL_MAX_ELEMENTS_INDICES: - case GL_MAX_ELEMENTS_VERTICES: - case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: - case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: - case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: - { - *type = GL_INT; - *numParams = 1; - } - return true; - - case GL_MAX_ELEMENT_INDEX: - case GL_MAX_UNIFORM_BLOCK_SIZE: - case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: - case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: - case GL_MAX_SERVER_WAIT_TIMEOUT: - { - *type = GL_INT_64_ANGLEX; - *numParams = 1; - } - return true; - - case GL_TRANSFORM_FEEDBACK_ACTIVE: - case GL_TRANSFORM_FEEDBACK_PAUSED: - { - *type = GL_BOOL; - *numParams = 1; - } - return true; - } - - return false; -} - -bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams) -{ - if (mClientVersion < 3) - { - return false; - } - - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - case GL_UNIFORM_BUFFER_BINDING: - { - *type = GL_INT; - *numParams = 1; - } - return true; - case GL_TRANSFORM_FEEDBACK_BUFFER_START: - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - case GL_UNIFORM_BUFFER_START: - case GL_UNIFORM_BUFFER_SIZE: - { - *type = GL_INT_64_ANGLEX; - *numParams = 1; - } - } - - return false; -} - -Error Context::clear(GLbitfield mask) -{ - if (mState.isRasterizerDiscardEnabled()) - { - return Error(GL_NO_ERROR); - } - - return mRenderer->clear(getData(), mask); -} - -Error Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values) -{ - if (mState.isRasterizerDiscardEnabled()) - { - return Error(GL_NO_ERROR); - } - - return mRenderer->clearBufferfv(getData(), buffer, drawbuffer, values); -} - -Error Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values) -{ - if (mState.isRasterizerDiscardEnabled()) - { - return Error(GL_NO_ERROR); - } - - return mRenderer->clearBufferuiv(getData(), buffer, drawbuffer, values); -} - -Error Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values) -{ - if (mState.isRasterizerDiscardEnabled()) - { - return Error(GL_NO_ERROR); - } - - return mRenderer->clearBufferiv(getData(), buffer, drawbuffer, values); -} - -Error Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) -{ - if (mState.isRasterizerDiscardEnabled()) - { - return Error(GL_NO_ERROR); - } - - return mRenderer->clearBufferfi(getData(), buffer, drawbuffer, depth, stencil); -} - -Error Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei *bufSize, void* pixels) -{ - return mRenderer->readPixels(getData(), x, y, width, height, format, type, bufSize, pixels); -} - -Error Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) -{ - return mRenderer->drawArrays(getData(), mode, first, count, instances); -} - -Error Context::drawElements(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei instances, - const rx::RangeUI &indexRange) -{ - return mRenderer->drawElements(getData(), mode, count, type, indices, instances, indexRange); -} - -// Implements glFlush when block is false, glFinish when block is true -Error Context::sync(bool block) -{ - return mRenderer->sync(block); -} - -void Context::recordError(const Error &error) -{ - if (error.isError()) - { - mErrors.insert(error.getCode()); - } -} - -// 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 (mErrors.empty()) - { - return GL_NO_ERROR; - } - else - { - GLenum error = *mErrors.begin(); - mErrors.erase(mErrors.begin()); - return error; - } -} - -GLenum Context::getResetStatus() -{ - //TODO(jmadill): needs MANGLE reworking - if (mResetStatus == GL_NO_ERROR && !mContextLost) - { - // mResetStatus will be set by the markContextLost callback - // in the case a notification is sent - mRenderer->testDeviceLost(true); - } - - GLenum status = mResetStatus; - - if (mResetStatus != GL_NO_ERROR) - { - ASSERT(mContextLost); - - if (mRenderer->testDeviceResettable()) - { - mResetStatus = GL_NO_ERROR; - } - } - - return status; -} - -bool Context::isResetNotificationEnabled() -{ - return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); -} - -int Context::getClientVersion() const -{ - return mClientVersion; -} - -const Caps &Context::getCaps() const -{ - return mCaps; -} - -const TextureCapsMap &Context::getTextureCaps() const -{ - return mTextureCaps; -} - -const Extensions &Context::getExtensions() const -{ - return mExtensions; -} - -void Context::getCurrentReadFormatType(GLenum *internalFormat, GLenum *format, GLenum *type) -{ - Framebuffer *framebuffer = mState.getReadFramebuffer(); - ASSERT(framebuffer && framebuffer->completeness(getData()) == GL_FRAMEBUFFER_COMPLETE); - - FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); - ASSERT(attachment); - - GLenum actualFormat = attachment->getActualFormat(); - const InternalFormat &actualFormatInfo = GetInternalFormatInfo(actualFormat); - - *internalFormat = actualFormat; - *format = actualFormatInfo.format; - *type = actualFormatInfo.type; -} - -void Context::detachTexture(GLuint texture) -{ - // Simple pass-through to State's detachTexture method, as textures do not require - // allocation map management either here or in the resource manager at detach time. - // Zero textures are held by the Context, and we don't attempt to request them from - // the State. - mState.detachTexture(mZeroTextures, texture); -} - -void Context::detachBuffer(GLuint buffer) -{ - // Buffer detachment is handled by Context, because the buffer must also be - // attached from any VAOs in existence, and Context holds the VAO map. - - // [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. - - mState.removeArrayBufferBinding(buffer); - - // mark as freed among the vertex array objects - for (auto vaoIt = mVertexArrayMap.begin(); vaoIt != mVertexArrayMap.end(); vaoIt++) - { - vaoIt->second->detachBuffer(buffer); - } -} - -void Context::detachFramebuffer(GLuint framebuffer) -{ - // Framebuffer detachment is handled by Context, because 0 is a valid - // Framebuffer object, and a pointer to it must be passed from Context - // to State at binding time. - - // [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.removeReadFramebufferBinding(framebuffer)) - { - bindReadFramebuffer(0); - } - - if (mState.removeDrawFramebufferBinding(framebuffer)) - { - bindDrawFramebuffer(0); - } -} - -void Context::detachRenderbuffer(GLuint renderbuffer) -{ - mState.detachRenderbuffer(renderbuffer); -} - -void Context::detachVertexArray(GLuint vertexArray) -{ - // Vertex array detachment is handled by Context, because 0 is a valid - // VAO, and a pointer to it must be passed from Context to State at - // binding time. - - // [OpenGL ES 3.0.2] section 2.10 page 43: - // If a vertex array object that is currently bound is deleted, the binding - // for that object reverts to zero and the default vertex array becomes current. - if (mState.removeVertexArrayBinding(vertexArray)) - { - bindVertexArray(0); - } -} - -void Context::detachTransformFeedback(GLuint transformFeedback) -{ - mState.detachTransformFeedback(transformFeedback); -} - -void Context::detachSampler(GLuint sampler) -{ - mState.detachSampler(sampler); -} - -void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) -{ - mState.getVertexArray()->setVertexAttribDivisor(index, divisor); -} - -void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param) -{ - mResourceManager->checkSamplerAllocation(sampler); - - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); - - switch (pname) - { - case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast(param)); break; - case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast(param)); break; - case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast(param)); break; - case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast(param)); break; - case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast(param)); break; - case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast(param)); break; - case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast(param)); break; - case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(static_cast(param)); break; - case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(static_cast(param)); break; - default: UNREACHABLE(); break; - } -} - -void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param) -{ - mResourceManager->checkSamplerAllocation(sampler); - - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); - - switch (pname) - { - case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround(param)); break; - case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround(param)); break; - case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround(param)); break; - case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround(param)); break; - case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround(param)); break; - case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break; - case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break; - case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(uiround(param)); break; - case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(uiround(param)); break; - default: UNREACHABLE(); break; - } -} - -GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname) -{ - mResourceManager->checkSamplerAllocation(sampler); - - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); - - switch (pname) - { - case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); - case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); - case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); - case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); - case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); - case GL_TEXTURE_MIN_LOD: return uiround(samplerObject->getMinLod()); - case GL_TEXTURE_MAX_LOD: return uiround(samplerObject->getMaxLod()); - case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); - case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); - default: UNREACHABLE(); return 0; - } -} - -GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname) -{ - mResourceManager->checkSamplerAllocation(sampler); - - Sampler *samplerObject = getSampler(sampler); - ASSERT(samplerObject); - - switch (pname) - { - case GL_TEXTURE_MIN_FILTER: return static_cast(samplerObject->getMinFilter()); - case GL_TEXTURE_MAG_FILTER: return static_cast(samplerObject->getMagFilter()); - case GL_TEXTURE_WRAP_S: return static_cast(samplerObject->getWrapS()); - case GL_TEXTURE_WRAP_T: return static_cast(samplerObject->getWrapT()); - case GL_TEXTURE_WRAP_R: return static_cast(samplerObject->getWrapR()); - case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod(); - case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod(); - case GL_TEXTURE_COMPARE_MODE: return static_cast(samplerObject->getComparisonMode()); - case GL_TEXTURE_COMPARE_FUNC: return static_cast(samplerObject->getComparisonFunc()); - default: UNREACHABLE(); return 0; - } -} - -void Context::initRendererString() -{ - std::ostringstream rendererString; - rendererString << "ANGLE ("; - rendererString << mRenderer->getRendererDescription(); - rendererString << ")"; - - mRendererString = MakeStaticString(rendererString.str()); -} - -const std::string &Context::getRendererString() const -{ - return mRendererString; -} - -void Context::initExtensionStrings() -{ - mExtensionStrings = mExtensions.getStrings(); - - std::ostringstream combinedStringStream; - std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator(combinedStringStream, " ")); - mExtensionString = combinedStringStream.str(); -} - -const std::string &Context::getExtensionString() const -{ - return mExtensionString; -} - -const std::string &Context::getExtensionString(size_t idx) const -{ - return mExtensionStrings[idx]; -} - -size_t Context::getExtensionStringCount() const -{ - return mExtensionStrings.size(); -} - -Error Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) -{ - return mRenderer->blitFramebuffer(getData(), srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter); -} - -void Context::releaseShaderCompiler() -{ - mRenderer->releaseShaderCompiler(); -} - -void Context::initCaps(GLuint clientVersion) -{ - mCaps = mRenderer->getRendererCaps(); - - mExtensions = mRenderer->getRendererExtensions(); - - if (clientVersion < 3) - { - // Disable ES3+ extensions - mExtensions.colorBufferFloat = false; - } - - if (clientVersion > 2) - { - // FIXME(geofflang): Don't support EXT_sRGB in non-ES2 contexts - //mExtensions.sRGB = false; - } - - // Apply implementation limits - mCaps.maxVertexAttributes = std::min(mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS); - mCaps.maxVertexUniformBlocks = std::min(mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS); - mCaps.maxVertexOutputComponents = std::min(mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); - - mCaps.maxFragmentInputComponents = std::min(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); - - GLuint maxSamples = 0; - mCaps.compressedTextureFormats.clear(); - - const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps(); - for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++) - { - GLenum format = i->first; - TextureCaps formatCaps = i->second; - - const InternalFormat &formatInfo = GetInternalFormatInfo(format); - - // Update the format caps based on the client version and extensions - formatCaps.texturable = formatInfo.textureSupport(clientVersion, mExtensions); - formatCaps.renderable = formatInfo.renderSupport(clientVersion, mExtensions); - formatCaps.filterable = formatInfo.filterSupport(clientVersion, mExtensions); - - // OpenGL ES does not support multisampling with integer formats - if (!formatInfo.renderSupport || formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT) - { - formatCaps.sampleCounts.clear(); - } - maxSamples = std::max(maxSamples, formatCaps.getMaxSamples()); - - if (formatCaps.texturable && formatInfo.compressed) - { - mCaps.compressedTextureFormats.push_back(format); - } - - mTextureCaps.insert(format, formatCaps); - } - - mExtensions.maxSamples = maxSamples; -} - -Data Context::getData() const -{ - return Data(mClientVersion, mState, mCaps, mTextureCaps, mExtensions, mResourceManager); -} - -} - -extern "C" -{ -gl::Context *glCreateContext(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) -{ - return new gl::Context(clientVersion, shareContext, renderer, 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 deleted file mode 100644 index 0699592d91..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Context.h +++ /dev/null @@ -1,291 +0,0 @@ -// -// Copyright (c) 2002-2014 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_ - -#include "common/angleutils.h" -#include "common/RefCountObject.h" -#include "libGLESv2/Caps.h" -#include "libGLESv2/Constants.h" -#include "libGLESv2/Data.h" -#include "libGLESv2/Error.h" -#include "libGLESv2/HandleAllocator.h" -#include "libGLESv2/VertexAttribute.h" -#include "libGLESv2/angletypes.h" - -#include "angle_gl.h" - -#include -#include -#include -#include -#include - -namespace rx -{ -class Renderer; -} - -namespace egl -{ -class Surface; -} - -namespace gl -{ -class Shader; -class Program; -class ProgramBinary; -class Texture; -class Texture2D; -class TextureCubeMap; -class Texture3D; -class Texture2DArray; -class Framebuffer; -class Renderbuffer; -class FenceNV; -class FenceSync; -class Query; -class ResourceManager; -class Buffer; -struct VertexAttribute; -class VertexArray; -class Sampler; -class TransformFeedback; - -class Context -{ - public: - Context(int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); - - virtual ~Context(); - - void makeCurrent(egl::Surface *surface); - - virtual void markContextLost(); - bool isContextLost(); - - // 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(); - GLuint createSampler(); - GLuint createTransformFeedback(); - GLsync createFenceSync(); - - void deleteBuffer(GLuint buffer); - void deleteShader(GLuint shader); - void deleteProgram(GLuint program); - void deleteTexture(GLuint texture); - void deleteRenderbuffer(GLuint renderbuffer); - void deleteSampler(GLuint sampler); - void deleteTransformFeedback(GLuint transformFeedback); - void deleteFenceSync(GLsync fenceSync); - - // Framebuffers are owned by the Context, so these methods do not pass through - GLuint createFramebuffer(); - void deleteFramebuffer(GLuint framebuffer); - - // NV Fences are owned by the Context. - GLuint createFenceNV(); - void deleteFenceNV(GLuint fence); - - // Queries are owned by the Context; - GLuint createQuery(); - void deleteQuery(GLuint query); - - // Vertex arrays are owned by the Context - GLuint createVertexArray(); - void deleteVertexArray(GLuint vertexArray); - - void bindArrayBuffer(GLuint buffer); - void bindElementArrayBuffer(GLuint buffer); - void bindTexture(GLenum target, GLuint handle); - void bindReadFramebuffer(GLuint framebuffer); - void bindDrawFramebuffer(GLuint framebuffer); - void bindRenderbuffer(GLuint renderbuffer); - void bindVertexArray(GLuint vertexArray); - void bindSampler(GLuint textureUnit, GLuint sampler); - void bindGenericUniformBuffer(GLuint buffer); - void bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); - void bindGenericTransformFeedbackBuffer(GLuint buffer); - void bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size); - void bindCopyReadBuffer(GLuint buffer); - void bindCopyWriteBuffer(GLuint buffer); - void bindPixelPackBuffer(GLuint buffer); - void bindPixelUnpackBuffer(GLuint buffer); - void useProgram(GLuint program); - Error linkProgram(GLuint program); - Error setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length); - void bindTransformFeedback(GLuint transformFeedback); - - Error beginQuery(GLenum target, GLuint query); - Error endQuery(GLenum target); - - void setFramebufferZero(Framebuffer *framebuffer); - - void setVertexAttribDivisor(GLuint index, GLuint divisor); - - void samplerParameteri(GLuint sampler, GLenum pname, GLint param); - void samplerParameterf(GLuint sampler, GLenum pname, GLfloat param); - GLint getSamplerParameteri(GLuint sampler, GLenum pname); - GLfloat getSamplerParameterf(GLuint sampler, GLenum pname); - - Buffer *getBuffer(GLuint handle); - FenceNV *getFenceNV(GLuint handle); - FenceSync *getFenceSync(GLsync handle) const; - Shader *getShader(GLuint handle) const; - Program *getProgram(GLuint handle) const; - Texture *getTexture(GLuint handle) const; - Framebuffer *getFramebuffer(GLuint handle) const; - Renderbuffer *getRenderbuffer(GLuint handle); - VertexArray *getVertexArray(GLuint handle) const; - Sampler *getSampler(GLuint handle) const; - Query *getQuery(GLuint handle, bool create, GLenum type); - TransformFeedback *getTransformFeedback(GLuint handle) const; - - Texture *getTargetTexture(GLenum target) const; - Texture2D *getTexture2D() const; - TextureCubeMap *getTextureCubeMap() const; - Texture3D *getTexture3D() const; - Texture2DArray *getTexture2DArray() const; - - Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; - - bool isSampler(GLuint samplerName) const; - - void getBooleanv(GLenum pname, GLboolean *params); - void getFloatv(GLenum pname, GLfloat *params); - void getIntegerv(GLenum pname, GLint *params); - void getInteger64v(GLenum pname, GLint64 *params); - - bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); - bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); - - bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams); - bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); - - Error clear(GLbitfield mask); - Error clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values); - Error clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values); - Error clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values); - Error clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); - - Error readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); - Error drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances); - Error drawElements(GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei instances, - const rx::RangeUI &indexRange); - Error sync(bool block); // flush/finish - - void recordError(const Error &error); - - GLenum getError(); - GLenum getResetStatus(); - virtual bool isResetNotificationEnabled(); - - virtual int getClientVersion() const; - - const Caps &getCaps() const; - const TextureCapsMap &getTextureCaps() const; - const Extensions &getExtensions() const; - - const std::string &getRendererString() const; - - const std::string &getExtensionString() const; - const std::string &getExtensionString(size_t idx) const; - size_t getExtensionStringCount() const; - - void getCurrentReadFormatType(GLenum *internalFormat, GLenum *format, GLenum *type); - - Error blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter); - - rx::Renderer *getRenderer() { return mRenderer; } - - State &getState() { return mState; } - const State &getState() const { return mState; } - - Data getData() const; - - void releaseShaderCompiler(); - - private: - DISALLOW_COPY_AND_ASSIGN(Context); - - void detachBuffer(GLuint buffer); - void detachTexture(GLuint texture); - void detachFramebuffer(GLuint framebuffer); - void detachRenderbuffer(GLuint renderbuffer); - void detachVertexArray(GLuint vertexArray); - void detachTransformFeedback(GLuint transformFeedback); - void detachSampler(GLuint sampler); - - void initRendererString(); - void initExtensionStrings(); - - void initCaps(GLuint clientVersion); - - // Caps to use for validation - Caps mCaps; - TextureCapsMap mTextureCaps; - Extensions mExtensions; - - rx::Renderer *const mRenderer; - State mState; - - int mClientVersion; - - TextureMap mZeroTextures; - - typedef std::unordered_map FramebufferMap; - FramebufferMap mFramebufferMap; - HandleAllocator mFramebufferHandleAllocator; - - typedef std::unordered_map FenceNVMap; - FenceNVMap mFenceNVMap; - HandleAllocator mFenceNVHandleAllocator; - - typedef std::unordered_map QueryMap; - QueryMap mQueryMap; - HandleAllocator mQueryHandleAllocator; - - typedef std::unordered_map VertexArrayMap; - VertexArrayMap mVertexArrayMap; - HandleAllocator mVertexArrayHandleAllocator; - - BindingPointer mTransformFeedbackZero; - typedef std::unordered_map TransformFeedbackMap; - TransformFeedbackMap mTransformFeedbackMap; - HandleAllocator mTransformFeedbackAllocator; - - std::string mRendererString; - std::string mExtensionString; - std::vector mExtensionStrings; - - // Recorded errors - typedef std::set ErrorSet; - ErrorSet mErrors; - - // Current/lost context flags - bool mHasBeenCurrent; - bool mContextLost; - GLenum mResetStatus; - GLenum mResetStrategy; - bool mRobustAccess; - - ResourceManager *mResourceManager; -}; -} - -#endif // INCLUDE_CONTEXT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Data.cpp b/src/3rdparty/angle/src/libGLESv2/Data.cpp deleted file mode 100644 index 3ddf591d77..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Data.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// Data.cpp: Container class for all GL relevant state, caps and objects - -#include "libGLESv2/Data.h" -#include "libGLESv2/ResourceManager.h" - -namespace gl -{ - -Data::Data(GLint clientVersionIn, const State &stateIn, const Caps &capsIn, - const TextureCapsMap &textureCapsIn, const Extensions &extensionsIn, - const ResourceManager *resourceManagerIn) - : clientVersion(clientVersionIn), - state(&stateIn), - caps(&capsIn), - textureCaps(&textureCapsIn), - extensions(&extensionsIn), - resourceManager(resourceManagerIn) -{} - -Data::~Data() -{ -} - -Data::Data(const Data &other) - : clientVersion(other.clientVersion), - state(other.state), - caps(other.caps), - textureCaps(other.textureCaps), - extensions(other.extensions), - resourceManager(other.resourceManager) -{ -} - -Data &Data::operator=(const Data &other) -{ - clientVersion = other.clientVersion; - state = other.state; - caps = other.caps; - textureCaps = other.textureCaps; - extensions = other.extensions; - resourceManager = other.resourceManager; - return *this; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Data.h b/src/3rdparty/angle/src/libGLESv2/Data.h deleted file mode 100644 index 9234403e13..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Data.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// Data.h: Container class for all GL relevant state, caps and objects - -#ifndef LIBGLESV2_DATA_H_ -#define LIBGLESV2_DATA_H_ - -#include "libGLESv2/State.h" - -namespace gl -{ - -struct Data -{ - public: - Data(GLint clientVersion, const State &state, const Caps &caps, - const TextureCapsMap &textureCaps, const Extensions &extensions, - const ResourceManager *resourceManager); - ~Data(); - - Data(const Data &other); - Data &operator=(const Data &other); - - GLint clientVersion; - const State *state; - const Caps *caps; - const TextureCapsMap *textureCaps; - const Extensions *extensions; - const ResourceManager *resourceManager; -}; - -} - -#endif // LIBGLESV2_DATA_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Error.cpp b/src/3rdparty/angle/src/libGLESv2/Error.cpp deleted file mode 100644 index cc7d17eb37..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Error.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// Error.cpp: Implements the gl::Error class which encapsulates an OpenGL error -// and optional error message. - -#include "libGLESv2/Error.h" - -#include "common/angleutils.h" - -#include - -namespace gl -{ - -Error::Error(GLenum errorCode) - : mCode(errorCode), - mMessage() -{ -} - -Error::Error(GLenum errorCode, const char *msg, ...) - : mCode(errorCode), - mMessage() -{ - va_list vararg; - va_start(vararg, msg); - mMessage = FormatString(msg, vararg); - va_end(vararg); -} - -Error::Error(const Error &other) - : mCode(other.mCode), - mMessage(other.mMessage) -{ -} - -Error &Error::operator=(const Error &other) -{ - mCode = other.mCode; - mMessage = other.mMessage; - return *this; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Error.h b/src/3rdparty/angle/src/libGLESv2/Error.h deleted file mode 100644 index b70b5a531c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Error.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2014 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. - -// Error.h: Defines the gl::Error class which encapsulates an OpenGL error -// and optional error message. - -#ifndef LIBGLESV2_ERROR_H_ -#define LIBGLESV2_ERROR_H_ - -#include "angle_gl.h" - -#include - -namespace gl -{ - -class Error -{ - public: - explicit Error(GLenum errorCode); - Error(GLenum errorCode, const char *msg, ...); - Error(const Error &other); - Error &operator=(const Error &other); - - GLenum getCode() const { return mCode; } - bool isError() const { return (mCode != GL_NO_ERROR); } - - const std::string &getMessage() const { return mMessage; } - - private: - GLenum mCode; - std::string mMessage; -}; - -} - -#endif // LIBGLESV2_ERROR_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.cpp b/src/3rdparty/angle/src/libGLESv2/Fence.cpp deleted file mode 100644 index 966a327de5..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Fence.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright (c) 2002-2013 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::FenceNV and gl::FenceSync classes, which support the GL_NV_fence -// extension and GLES3 sync objects. - -#include "libGLESv2/Fence.h" -#include "libGLESv2/renderer/FenceImpl.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/main.h" -#include "common/utilities.h" - -#include "angle_gl.h" - -namespace gl -{ - -FenceNV::FenceNV(rx::FenceNVImpl *impl) - : mFence(impl), - mIsSet(false), - mStatus(GL_FALSE), - mCondition(GL_NONE) -{ -} - -FenceNV::~FenceNV() -{ - SafeDelete(mFence); -} - -GLboolean FenceNV::isFence() const -{ - // GL_NV_fence spec: - // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. - return (mIsSet ? GL_TRUE : GL_FALSE); -} - -Error FenceNV::setFence(GLenum condition) -{ - Error error = mFence->set(); - if (error.isError()) - { - return error; - } - - mCondition = condition; - mStatus = GL_FALSE; - mIsSet = true; - - return Error(GL_NO_ERROR); -} - -Error FenceNV::testFence(GLboolean *outResult) -{ - // Flush the command buffer by default - Error error = mFence->test(true, &mStatus); - if (error.isError()) - { - return error; - } - - *outResult = mStatus; - return Error(GL_NO_ERROR); -} - -Error FenceNV::finishFence() -{ - ASSERT(mIsSet); - - return mFence->finishFence(&mStatus); -} - -FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id) - : RefCountObject(id), - mFence(impl), - mCondition(GL_NONE) -{ -} - -FenceSync::~FenceSync() -{ - SafeDelete(mFence); -} - -Error FenceSync::set(GLenum condition) -{ - Error error = mFence->set(); - if (error.isError()) - { - return error; - } - - mCondition = condition; - return Error(GL_NO_ERROR); -} - -Error FenceSync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) -{ - ASSERT(mCondition != GL_NONE); - return mFence->clientWait(flags, timeout, outResult); -} - -Error FenceSync::serverWait(GLbitfield flags, GLuint64 timeout) -{ - return mFence->serverWait(flags, timeout); -} - -Error FenceSync::getStatus(GLint *outResult) const -{ - return mFence->getStatus(outResult); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.h b/src/3rdparty/angle/src/libGLESv2/Fence.h deleted file mode 100644 index fd565e96a6..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Fence.h +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright (c) 2002-2013 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::FenceNV and gl::FenceSync classes, which support the GL_NV_fence -// extension and GLES3 sync objects. - -#ifndef LIBGLESV2_FENCE_H_ -#define LIBGLESV2_FENCE_H_ - -#include "libGLESv2/Error.h" - -#include "common/angleutils.h" -#include "common/RefCountObject.h" - -namespace rx -{ -class FenceNVImpl; -class FenceSyncImpl; -} - -namespace gl -{ - -class FenceNV -{ - public: - explicit FenceNV(rx::FenceNVImpl *impl); - virtual ~FenceNV(); - - GLboolean isFence() const; - Error setFence(GLenum condition); - Error testFence(GLboolean *outResult); - Error finishFence(); - - GLboolean getStatus() const { return mStatus; } - GLuint getCondition() const { return mCondition; } - - private: - DISALLOW_COPY_AND_ASSIGN(FenceNV); - - rx::FenceNVImpl *mFence; - - bool mIsSet; - - GLboolean mStatus; - GLenum mCondition; -}; - -class FenceSync : public RefCountObject -{ - public: - explicit FenceSync(rx::FenceSyncImpl *impl, GLuint id); - virtual ~FenceSync(); - - Error set(GLenum condition); - Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult); - Error serverWait(GLbitfield flags, GLuint64 timeout); - Error getStatus(GLint *outResult) const; - - GLuint getCondition() const { return mCondition; } - - private: - DISALLOW_COPY_AND_ASSIGN(FenceSync); - - rx::FenceSyncImpl *mFence; - - GLenum mCondition; -}; - -} - -#endif // LIBGLESV2_FENCE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp b/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp deleted file mode 100644 index 5bf7b3fce8..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.cpp +++ /dev/null @@ -1,2203 +0,0 @@ -// -// 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 deleted file mode 100644 index cf039bfc21..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Float16ToFloat32.py +++ /dev/null @@ -1,78 +0,0 @@ -# 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 " %#010x," % convertMantissa(i) -print "};\n" - -print "const static unsigned g_exponent[64] = {" -for i in range(0, 64): - print " %#010x," % convertExponent(i) -print "};\n" - -print "const static unsigned g_offset[64] = {" -for i in range(0, 64): - print " %#010x," % 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 deleted file mode 100644 index 3d57262e3c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp +++ /dev/null @@ -1,672 +0,0 @@ -// -// Copyright (c) 2002-2014 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/formatutils.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/RenderTarget.h" -#include "libGLESv2/renderer/RenderbufferImpl.h" -#include "libGLESv2/renderer/Workarounds.h" -#include "libGLESv2/renderer/d3d/TextureD3D.h" -#include "libGLESv2/renderer/d3d/RenderbufferD3D.h" - -#include "common/utilities.h" - -namespace rx -{ -// TODO: Move these functions, and the D3D-specific header inclusions above, -// to FramebufferD3D. -gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget **outRT) -{ - if (attachment->isTexture()) - { - gl::Texture *texture = attachment->getTexture(); - ASSERT(texture); - TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); - const gl::ImageIndex *index = attachment->getTextureImageIndex(); - ASSERT(index); - return textureD3D->getRenderTarget(*index, outRT); - } - else - { - gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); - ASSERT(renderbuffer); - RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation()); - *outRT = renderbufferD3D->getRenderTarget(); - return gl::Error(GL_NO_ERROR); - } -} - -// Note: RenderTarget serials should ideally be in the RenderTargets themselves. -unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment) -{ - if (attachment->isTexture()) - { - gl::Texture *texture = attachment->getTexture(); - ASSERT(texture); - TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); - const gl::ImageIndex *index = attachment->getTextureImageIndex(); - ASSERT(index); - return textureD3D->getRenderTargetSerial(*index); - } - - gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); - ASSERT(renderbuffer); - RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation()); - return renderbufferD3D->getRenderTargetSerial(); -} - -} - -namespace gl -{ - -Framebuffer::Framebuffer(GLuint id) - : mId(id), - mReadBufferState(GL_COLOR_ATTACHMENT0_EXT), - mDepthbuffer(NULL), - mStencilbuffer(NULL) -{ - for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - mColorbuffers[colorAttachment] = NULL; - mDrawBufferStates[colorAttachment] = GL_NONE; - } - mDrawBufferStates[0] = GL_COLOR_ATTACHMENT0_EXT; -} - -Framebuffer::~Framebuffer() -{ - for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - SafeDelete(mColorbuffers[colorAttachment]); - } - SafeDelete(mDepthbuffer); - SafeDelete(mStencilbuffer); -} - -void Framebuffer::detachTexture(GLuint textureId) -{ - for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - FramebufferAttachment *attachment = mColorbuffers[colorAttachment]; - - if (attachment && attachment->isTextureWithId(textureId)) - { - SafeDelete(mColorbuffers[colorAttachment]); - } - } - - if (mDepthbuffer && mDepthbuffer->isTextureWithId(textureId)) - { - SafeDelete(mDepthbuffer); - } - - if (mStencilbuffer && mStencilbuffer->isTextureWithId(textureId)) - { - SafeDelete(mStencilbuffer); - } -} - -void Framebuffer::detachRenderbuffer(GLuint renderbufferId) -{ - for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - FramebufferAttachment *attachment = mColorbuffers[colorAttachment]; - - if (attachment && attachment->isRenderbufferWithId(renderbufferId)) - { - SafeDelete(mColorbuffers[colorAttachment]); - } - } - - if (mDepthbuffer && mDepthbuffer->isRenderbufferWithId(renderbufferId)) - { - SafeDelete(mDepthbuffer); - } - - if (mStencilbuffer && mStencilbuffer->isRenderbufferWithId(renderbufferId)) - { - SafeDelete(mStencilbuffer); - } -} - -FramebufferAttachment *Framebuffer::getColorbuffer(unsigned int colorAttachment) const -{ - ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); - return mColorbuffers[colorAttachment]; -} - -FramebufferAttachment *Framebuffer::getDepthbuffer() const -{ - return mDepthbuffer; -} - -FramebufferAttachment *Framebuffer::getStencilbuffer() const -{ - return mStencilbuffer; -} - -FramebufferAttachment *Framebuffer::getDepthStencilBuffer() const -{ - return (hasValidDepthStencil() ? mDepthbuffer : NULL); -} - -FramebufferAttachment *Framebuffer::getDepthOrStencilbuffer() const -{ - FramebufferAttachment *depthstencilbuffer = mDepthbuffer; - - if (!depthstencilbuffer) - { - depthstencilbuffer = mStencilbuffer; - } - - return depthstencilbuffer; -} - -FramebufferAttachment *Framebuffer::getReadColorbuffer() const -{ - // Will require more logic if glReadBuffers is supported - return mColorbuffers[0]; -} - -GLenum Framebuffer::getReadColorbufferType() const -{ - // Will require more logic if glReadBuffers is supported - return (mColorbuffers[0] ? mColorbuffers[0]->type() : GL_NONE); -} - -FramebufferAttachment *Framebuffer::getFirstColorbuffer() const -{ - for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (mColorbuffers[colorAttachment]) - { - return mColorbuffers[colorAttachment]; - } - } - - return NULL; -} - -FramebufferAttachment *Framebuffer::getAttachment(GLenum attachment) const -{ - if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) - { - return getColorbuffer(attachment - GL_COLOR_ATTACHMENT0); - } - else - { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: - return getDepthbuffer(); - case GL_STENCIL_ATTACHMENT: - return getStencilbuffer(); - case GL_DEPTH_STENCIL_ATTACHMENT: - return getDepthStencilBuffer(); - default: - UNREACHABLE(); - return NULL; - } - } -} - -GLenum Framebuffer::getDrawBufferState(unsigned int colorAttachment) const -{ - return mDrawBufferStates[colorAttachment]; -} - -void Framebuffer::setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer) -{ - mDrawBufferStates[colorAttachment] = drawBuffer; -} - -bool Framebuffer::isEnabledColorAttachment(unsigned int colorAttachment) const -{ - return (mColorbuffers[colorAttachment] && mDrawBufferStates[colorAttachment] != GL_NONE); -} - -bool Framebuffer::hasEnabledColorAttachment() const -{ - for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (isEnabledColorAttachment(colorAttachment)) - { - return true; - } - } - - return false; -} - -bool Framebuffer::hasStencil() const -{ - return (mStencilbuffer && mStencilbuffer->getStencilSize() > 0); -} - -bool Framebuffer::usingExtendedDrawBuffers() const -{ - for (unsigned int colorAttachment = 1; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (isEnabledColorAttachment(colorAttachment)) - { - return true; - } - } - - return false; -} - -GLenum Framebuffer::completeness(const gl::Data &data) const -{ - int width = 0; - int height = 0; - unsigned int colorbufferSize = 0; - int samples = -1; - bool missingAttachment = true; - - for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - const FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment]; - - if (colorbuffer) - { - if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - GLenum internalformat = colorbuffer->getInternalFormat(); - const TextureCaps &formatCaps = data.textureCaps->get(internalformat); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (colorbuffer->isTexture()) - { - if (!formatCaps.renderable) - { - return GL_FRAMEBUFFER_UNSUPPORTED; - } - - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - else - { - if (!formatCaps.renderable || formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - - if (!missingAttachment) - { - // all color attachments must have the same width and height - if (colorbuffer->getWidth() != width || colorbuffer->getHeight() != height) - { - return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; - } - - // APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that - // all color attachments have the same number of samples for the FBO to be complete. - if (colorbuffer->getSamples() != samples) - { - return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; - } - - // in GLES 2.0, all color attachments attachments must have the same number of bitplanes - // in GLES 3.0, there is no such restriction - if (data.clientVersion < 3) - { - if (formatInfo.pixelBytes != colorbufferSize) - { - return GL_FRAMEBUFFER_UNSUPPORTED; - } - } - - // D3D11 does not allow for overlapping RenderTargetViews, so ensure uniqueness - for (unsigned int previousColorAttachment = 0; previousColorAttachment < colorAttachment; previousColorAttachment++) - { - const FramebufferAttachment *previousAttachment = mColorbuffers[previousColorAttachment]; - - if (previousAttachment && - (colorbuffer->id() == previousAttachment->id() && - colorbuffer->type() == previousAttachment->type())) - { - return GL_FRAMEBUFFER_UNSUPPORTED; - } - } - } - else - { - width = colorbuffer->getWidth(); - height = colorbuffer->getHeight(); - samples = colorbuffer->getSamples(); - colorbufferSize = formatInfo.pixelBytes; - missingAttachment = false; - } - } - } - - if (mDepthbuffer) - { - if (mDepthbuffer->getWidth() == 0 || mDepthbuffer->getHeight() == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - GLenum internalformat = mDepthbuffer->getInternalFormat(); - const TextureCaps &formatCaps = data.textureCaps->get(internalformat); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (mDepthbuffer->isTexture()) - { - // depth texture attachments require OES/ANGLE_depth_texture - if (!data.extensions->depthTextures) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - if (!formatCaps.renderable) - { - return GL_FRAMEBUFFER_UNSUPPORTED; - } - - if (formatInfo.depthBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - else - { - if (!formatCaps.renderable || formatInfo.depthBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - - if (missingAttachment) - { - width = mDepthbuffer->getWidth(); - height = mDepthbuffer->getHeight(); - samples = mDepthbuffer->getSamples(); - missingAttachment = false; - } - else if (width != mDepthbuffer->getWidth() || height != mDepthbuffer->getHeight()) - { - return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; - } - else if (samples != mDepthbuffer->getSamples()) - { - return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; - } - } - - if (mStencilbuffer) - { - if (mStencilbuffer->getWidth() == 0 || mStencilbuffer->getHeight() == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - GLenum internalformat = mStencilbuffer->getInternalFormat(); - const TextureCaps &formatCaps = data.textureCaps->get(internalformat); - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (mStencilbuffer->isTexture()) - { - // texture stencil attachments come along as part - // of OES_packed_depth_stencil + OES/ANGLE_depth_texture - if (!data.extensions->depthTextures) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - - if (!formatCaps.renderable) - { - return GL_FRAMEBUFFER_UNSUPPORTED; - } - - if (formatInfo.stencilBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - else - { - if (!formatCaps.renderable || formatInfo.stencilBits == 0) - { - return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; - } - } - - if (missingAttachment) - { - width = mStencilbuffer->getWidth(); - height = mStencilbuffer->getHeight(); - samples = mStencilbuffer->getSamples(); - missingAttachment = false; - } - else if (width != mStencilbuffer->getWidth() || height != mStencilbuffer->getHeight()) - { - return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; - } - else if (samples != mStencilbuffer->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 (mDepthbuffer && mStencilbuffer && !hasValidDepthStencil()) - { - 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; -} - -Error Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments) -{ - GLuint maxDimension = caps.maxRenderbufferSize; - return invalidateSub(numAttachments, attachments, 0, 0, maxDimension, maxDimension); -} - -Error Framebuffer::invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height) -{ - for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex) - { - GLenum attachmentTarget = attachments[attachIndex]; - - FramebufferAttachment *attachment = (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() - : getAttachment(attachmentTarget); - - if (attachment) - { - rx::RenderTarget *renderTarget = NULL; - Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); - if (error.isError()) - { - return error; - } - - renderTarget->invalidate(x, y, width, height); - } - } - - return Error(GL_NO_ERROR); -} - -DefaultFramebuffer::DefaultFramebuffer(rx::RenderbufferImpl *colorbuffer, rx::RenderbufferImpl *depthStencil) - : Framebuffer(0) -{ - Renderbuffer *colorRenderbuffer = new Renderbuffer(colorbuffer, 0); - mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer); - - Renderbuffer *depthStencilBuffer = new Renderbuffer(depthStencil, 0); - - // Make a new attachment objects to ensure we do not double-delete - // See angle issue 686 - mDepthbuffer = (depthStencilBuffer->getDepthSize() != 0 ? new RenderbufferAttachment(GL_DEPTH_ATTACHMENT, depthStencilBuffer) : NULL); - mStencilbuffer = (depthStencilBuffer->getStencilSize() != 0 ? new RenderbufferAttachment(GL_STENCIL_ATTACHMENT, depthStencilBuffer) : NULL); - - mDrawBufferStates[0] = GL_BACK; - mReadBufferState = GL_BACK; -} - -int Framebuffer::getSamples(const gl::Data &data) const -{ - if (completeness(data) == GL_FRAMEBUFFER_COMPLETE) - { - // for a complete framebuffer, all attachments must have the same sample count - // in this case return the first nonzero sample size - for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (mColorbuffers[colorAttachment]) - { - return mColorbuffers[colorAttachment]->getSamples(); - } - } - } - - return 0; -} - -bool Framebuffer::hasValidDepthStencil() const -{ - // A valid depth-stencil attachment has the same resource bound to both the - // depth and stencil attachment points. - return (mDepthbuffer && mStencilbuffer && - mDepthbuffer->type() == mStencilbuffer->type() && - mDepthbuffer->id() == mStencilbuffer->id()); -} - -ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const -{ - ColorbufferInfo colorbuffersForRender; - - for (size_t colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; ++colorAttachment) - { - GLenum drawBufferState = mDrawBufferStates[colorAttachment]; - FramebufferAttachment *colorbuffer = mColorbuffers[colorAttachment]; - - if (colorbuffer != NULL && drawBufferState != GL_NONE) - { - ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment)); - colorbuffersForRender.push_back(colorbuffer); - } - else if (!workarounds.mrtPerfWorkaround) - { - colorbuffersForRender.push_back(NULL); - } - } - - return colorbuffersForRender; -} - -void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex) -{ - setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex)); -} - -void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer) -{ - setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer)); -} - -void Framebuffer::setNULLAttachment(GLenum attachment) -{ - setAttachment(attachment, NULL); -} - -void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj) -{ - if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS)) - { - size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0; - SafeDelete(mColorbuffers[colorAttachment]); - mColorbuffers[colorAttachment] = attachmentObj; - } - else if (attachment == GL_DEPTH_ATTACHMENT) - { - SafeDelete(mDepthbuffer); - mDepthbuffer = attachmentObj; - } - else if (attachment == GL_STENCIL_ATTACHMENT) - { - SafeDelete(mStencilbuffer); - mStencilbuffer = attachmentObj; - } - else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) - { - SafeDelete(mDepthbuffer); - SafeDelete(mStencilbuffer); - - // ensure this is a legitimate depth+stencil format - if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0) - { - mDepthbuffer = attachmentObj; - - // Make a new attachment object to ensure we do not double-delete - // See angle issue 686 - if (attachmentObj->isTexture()) - { - mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(), - *attachmentObj->getTextureImageIndex()); - } - else - { - mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer()); - } - } - } - else - { - UNREACHABLE(); - } -} - -GLenum DefaultFramebuffer::completeness(const gl::Data &) const -{ - // The default framebuffer *must* always be complete, though it may not be - // subject to the same rules as application FBOs. ie, it could have 0x0 size. - return GL_FRAMEBUFFER_COMPLETE; -} - -FramebufferAttachment *DefaultFramebuffer::getAttachment(GLenum attachment) const -{ - switch (attachment) - { - case GL_COLOR: - case GL_BACK: - return getColorbuffer(0); - case GL_DEPTH: - return getDepthbuffer(); - case GL_STENCIL: - return getStencilbuffer(); - case GL_DEPTH_STENCIL: - return getDepthStencilBuffer(); - default: - UNREACHABLE(); - return NULL; - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.h b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h deleted file mode 100644 index d0fe8935ea..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Framebuffer.h +++ /dev/null @@ -1,126 +0,0 @@ -// -// Copyright (c) 2002-2013 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_ - -#include "libGLESv2/Error.h" - -#include "common/angleutils.h" -#include "common/RefCountObject.h" -#include "Constants.h" - -#include - -namespace rx -{ -class RenderbufferImpl; -struct Workarounds; -} - -namespace gl -{ -class FramebufferAttachment; -class Texture; -class Renderbuffer; -struct ImageIndex; -struct Caps; -struct Extensions; -class TextureCapsMap; -struct Data; - -typedef std::vector ColorbufferInfo; - -class Framebuffer -{ - public: - Framebuffer(GLuint id); - virtual ~Framebuffer(); - - GLuint id() const { return mId; } - - void setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex); - void setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer); - void setNULLAttachment(GLenum attachment); - - void detachTexture(GLuint texture); - void detachRenderbuffer(GLuint renderbuffer); - - FramebufferAttachment *getColorbuffer(unsigned int colorAttachment) const; - FramebufferAttachment *getDepthbuffer() const; - FramebufferAttachment *getStencilbuffer() const; - FramebufferAttachment *getDepthStencilBuffer() const; - FramebufferAttachment *getDepthOrStencilbuffer() const; - FramebufferAttachment *getReadColorbuffer() const; - GLenum getReadColorbufferType() const; - FramebufferAttachment *getFirstColorbuffer() const; - - virtual FramebufferAttachment *getAttachment(GLenum attachment) const; - - GLenum getDrawBufferState(unsigned int colorAttachment) const; - void setDrawBufferState(unsigned int colorAttachment, GLenum drawBuffer); - - bool isEnabledColorAttachment(unsigned int colorAttachment) const; - bool hasEnabledColorAttachment() const; - bool hasStencil() const; - int getSamples(const gl::Data &data) const; - bool usingExtendedDrawBuffers() const; - - virtual GLenum completeness(const gl::Data &data) const; - bool hasValidDepthStencil() const; - - Error invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments); - Error invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); - - // Use this method to retrieve the color buffer map when doing rendering. - // It will apply a workaround for poor shader performance on some systems - // by compacting the list to skip NULL values. - ColorbufferInfo getColorbuffersForRender(const rx::Workarounds &workarounds) const; - - protected: - GLuint mId; - - FramebufferAttachment *mColorbuffers[IMPLEMENTATION_MAX_DRAW_BUFFERS]; - GLenum mDrawBufferStates[IMPLEMENTATION_MAX_DRAW_BUFFERS]; - GLenum mReadBufferState; - - FramebufferAttachment *mDepthbuffer; - FramebufferAttachment *mStencilbuffer; - - private: - DISALLOW_COPY_AND_ASSIGN(Framebuffer); - - void setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj); -}; - -class DefaultFramebuffer : public Framebuffer -{ - public: - DefaultFramebuffer(rx::RenderbufferImpl *colorbuffer, rx::RenderbufferImpl *depthStencil); - - GLenum completeness(const gl::Data &data) const override; - virtual FramebufferAttachment *getAttachment(GLenum attachment) const; - - private: - DISALLOW_COPY_AND_ASSIGN(DefaultFramebuffer); -}; - -} - -namespace rx -{ -class RenderTarget; - -// TODO: place this in FramebufferD3D.h -gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget **outRT); -unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment); - -} - -#endif // LIBGLESV2_FRAMEBUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp deleted file mode 100644 index 894884a6d8..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp +++ /dev/null @@ -1,230 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// FramebufferAttachment.cpp: the gl::FramebufferAttachment class and its derived classes -// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. - -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/renderer/RenderTarget.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/d3d/TextureStorage.h" - -#include "common/utilities.h" - -namespace gl -{ - -////// FramebufferAttachment Implementation ////// - -FramebufferAttachment::FramebufferAttachment(GLenum binding) - : mBinding(binding) -{ -} - -FramebufferAttachment::~FramebufferAttachment() -{ -} - -GLuint FramebufferAttachment::getRedSize() const -{ - return (GetInternalFormatInfo(getInternalFormat()).redBits > 0) ? GetInternalFormatInfo(getActualFormat()).redBits : 0; -} - -GLuint FramebufferAttachment::getGreenSize() const -{ - return (GetInternalFormatInfo(getInternalFormat()).greenBits > 0) ? GetInternalFormatInfo(getActualFormat()).greenBits : 0; -} - -GLuint FramebufferAttachment::getBlueSize() const -{ - return (GetInternalFormatInfo(getInternalFormat()).blueBits > 0) ? GetInternalFormatInfo(getActualFormat()).blueBits : 0; -} - -GLuint FramebufferAttachment::getAlphaSize() const -{ - return (GetInternalFormatInfo(getInternalFormat()).alphaBits > 0) ? GetInternalFormatInfo(getActualFormat()).alphaBits : 0; -} - -GLuint FramebufferAttachment::getDepthSize() const -{ - return (GetInternalFormatInfo(getInternalFormat()).depthBits > 0) ? GetInternalFormatInfo(getActualFormat()).depthBits : 0; -} - -GLuint FramebufferAttachment::getStencilSize() const -{ - return (GetInternalFormatInfo(getInternalFormat()).stencilBits > 0) ? GetInternalFormatInfo(getActualFormat()).stencilBits : 0; -} - -GLenum FramebufferAttachment::getComponentType() const -{ - return GetInternalFormatInfo(getActualFormat()).componentType; -} - -GLenum FramebufferAttachment::getColorEncoding() const -{ - return GetInternalFormatInfo(getActualFormat()).colorEncoding; -} - -bool FramebufferAttachment::isTexture() const -{ - return (type() != GL_RENDERBUFFER); -} - -///// TextureAttachment Implementation //////// - -TextureAttachment::TextureAttachment(GLenum binding, Texture *texture, const ImageIndex &index) - : FramebufferAttachment(binding), - mIndex(index) -{ - mTexture.set(texture); -} - -TextureAttachment::~TextureAttachment() -{ - mTexture.set(NULL); -} - -GLsizei TextureAttachment::getSamples() const -{ - return 0; -} - -GLuint TextureAttachment::id() const -{ - return mTexture->id(); -} - -GLsizei TextureAttachment::getWidth() const -{ - return mTexture->getWidth(mIndex); -} - -GLsizei TextureAttachment::getHeight() const -{ - return mTexture->getHeight(mIndex); -} - -GLenum TextureAttachment::getInternalFormat() const -{ - return mTexture->getInternalFormat(mIndex); -} - -GLenum TextureAttachment::getActualFormat() const -{ - return mTexture->getActualFormat(mIndex); -} - -GLenum TextureAttachment::type() const -{ - return mIndex.type; -} - -GLint TextureAttachment::mipLevel() const -{ - return mIndex.mipIndex; -} - -GLint TextureAttachment::layer() const -{ - return mIndex.layerIndex; -} - -Texture *TextureAttachment::getTexture() -{ - return mTexture.get(); -} - -const ImageIndex *TextureAttachment::getTextureImageIndex() const -{ - return &mIndex; -} - -Renderbuffer *TextureAttachment::getRenderbuffer() -{ - UNREACHABLE(); - return NULL; -} - -////// RenderbufferAttachment Implementation ////// - -RenderbufferAttachment::RenderbufferAttachment(GLenum binding, Renderbuffer *renderbuffer) - : FramebufferAttachment(binding) -{ - ASSERT(renderbuffer); - mRenderbuffer.set(renderbuffer); -} - -RenderbufferAttachment::~RenderbufferAttachment() -{ - mRenderbuffer.set(NULL); -} - -GLsizei RenderbufferAttachment::getWidth() const -{ - return mRenderbuffer->getWidth(); -} - -GLsizei RenderbufferAttachment::getHeight() const -{ - return mRenderbuffer->getHeight(); -} - -GLenum RenderbufferAttachment::getInternalFormat() const -{ - return mRenderbuffer->getInternalFormat(); -} - -GLenum RenderbufferAttachment::getActualFormat() const -{ - return mRenderbuffer->getActualFormat(); -} - -GLsizei RenderbufferAttachment::getSamples() const -{ - return mRenderbuffer->getSamples(); -} - -GLuint RenderbufferAttachment::id() const -{ - return mRenderbuffer->id(); -} - -GLenum RenderbufferAttachment::type() const -{ - return GL_RENDERBUFFER; -} - -GLint RenderbufferAttachment::mipLevel() const -{ - return 0; -} - -GLint RenderbufferAttachment::layer() const -{ - return 0; -} - -Texture *RenderbufferAttachment::getTexture() -{ - UNREACHABLE(); - return NULL; -} - -const ImageIndex *RenderbufferAttachment::getTextureImageIndex() const -{ - UNREACHABLE(); - return NULL; -} - -Renderbuffer *RenderbufferAttachment::getRenderbuffer() -{ - return mRenderbuffer.get(); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h deleted file mode 100644 index 8d2dafa7ee..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h +++ /dev/null @@ -1,132 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// FramebufferAttachment.h: Defines the wrapper class gl::FramebufferAttachment, as well as the -// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. - -#ifndef LIBGLESV2_FRAMEBUFFERATTACHMENT_H_ -#define LIBGLESV2_FRAMEBUFFERATTACHMENT_H_ - -#include "common/angleutils.h" -#include "common/RefCountObject.h" -#include "Texture.h" - -#include "angle_gl.h" - -namespace gl -{ -class Renderbuffer; - -// FramebufferAttachment implements a GL framebuffer attachment. -// Attachments are "light" containers, which store pointers to ref-counted GL objects. -// We support GL texture (2D/3D/Cube/2D array) and renderbuffer object attachments. -// Note: Our old naming scheme used the term "Renderbuffer" for both GL renderbuffers and for -// framebuffer attachments, which confused their usage. - -class FramebufferAttachment -{ - public: - explicit FramebufferAttachment(GLenum binding); - virtual ~FramebufferAttachment(); - - // Helper methods - GLuint getRedSize() const; - GLuint getGreenSize() const; - GLuint getBlueSize() const; - GLuint getAlphaSize() const; - GLuint getDepthSize() const; - GLuint getStencilSize() const; - GLenum getComponentType() const; - GLenum getColorEncoding() const; - bool isTexture() const; - - bool isTextureWithId(GLuint textureId) const { return isTexture() && id() == textureId; } - bool isRenderbufferWithId(GLuint renderbufferId) const { return !isTexture() && id() == renderbufferId; } - - GLenum getBinding() const { return mBinding; } - - // Child class interface - virtual GLsizei getWidth() const = 0; - virtual GLsizei getHeight() const = 0; - virtual GLenum getInternalFormat() const = 0; - virtual GLenum getActualFormat() const = 0; - virtual GLsizei getSamples() const = 0; - - virtual GLuint id() const = 0; - virtual GLenum type() const = 0; - virtual GLint mipLevel() const = 0; - virtual GLint layer() const = 0; - - virtual Texture *getTexture() = 0; - virtual const ImageIndex *getTextureImageIndex() const = 0; - virtual Renderbuffer *getRenderbuffer() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(FramebufferAttachment); - - GLenum mBinding; -}; - -class TextureAttachment : public FramebufferAttachment -{ - public: - TextureAttachment(GLenum binding, Texture *texture, const ImageIndex &index); - virtual ~TextureAttachment(); - - virtual GLsizei getSamples() const; - virtual GLuint id() const; - - virtual GLsizei getWidth() const; - virtual GLsizei getHeight() const; - virtual GLenum getInternalFormat() const; - virtual GLenum getActualFormat() const; - - virtual GLenum type() const; - virtual GLint mipLevel() const; - virtual GLint layer() const; - - virtual Texture *getTexture(); - virtual const ImageIndex *getTextureImageIndex() const; - virtual Renderbuffer *getRenderbuffer(); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureAttachment); - - BindingPointer mTexture; - ImageIndex mIndex; -}; - -class RenderbufferAttachment : public FramebufferAttachment -{ - public: - RenderbufferAttachment(GLenum binding, Renderbuffer *renderbuffer); - - virtual ~RenderbufferAttachment(); - - virtual GLsizei getWidth() const; - virtual GLsizei getHeight() const; - virtual GLenum getInternalFormat() const; - virtual GLenum getActualFormat() const; - virtual GLsizei getSamples() const; - - virtual GLuint id() const; - virtual GLenum type() const; - virtual GLint mipLevel() const; - virtual GLint layer() const; - - virtual Texture *getTexture(); - virtual const ImageIndex *getTextureImageIndex() const; - virtual Renderbuffer *getRenderbuffer(); - - private: - DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment); - - BindingPointer mRenderbuffer; -}; - -} - -#endif // LIBGLESV2_FRAMEBUFFERATTACHMENT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp b/src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp deleted file mode 100644 index c498f8a178..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/HandleAllocator.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// -// 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 deleted file mode 100644 index a89cc86775..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/HandleAllocator.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// 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_ - -#include "common/angleutils.h" - -#include "angle_gl.h" - -#include - -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/ImageIndex.cpp b/src/3rdparty/angle/src/libGLESv2/ImageIndex.cpp deleted file mode 100644 index b45cd9c169..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/ImageIndex.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// -// Copyright 2014 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. -// - -// ImageIndex.cpp: Implementation for ImageIndex methods. - -#include "libGLESv2/ImageIndex.h" -#include "libGLESv2/Texture.h" -#include "common/utilities.h" - -namespace gl -{ - -ImageIndex::ImageIndex(const ImageIndex &other) - : type(other.type), - mipIndex(other.mipIndex), - layerIndex(other.layerIndex) -{} - -ImageIndex &ImageIndex::operator=(const ImageIndex &other) -{ - type = other.type; - mipIndex = other.mipIndex; - layerIndex = other.layerIndex; - return *this; -} - -ImageIndex ImageIndex::Make2D(GLint mipIndex) -{ - return ImageIndex(GL_TEXTURE_2D, mipIndex, ENTIRE_LEVEL); -} - -ImageIndex ImageIndex::MakeCube(GLenum target, GLint mipIndex) -{ - ASSERT(gl::IsCubemapTextureTarget(target)); - return ImageIndex(target, mipIndex, TextureCubeMap::targetToLayerIndex(target)); -} - -ImageIndex ImageIndex::Make2DArray(GLint mipIndex, GLint layerIndex) -{ - return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex); -} - -ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex) -{ - return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex); -} - -ImageIndex ImageIndex::MakeInvalid() -{ - return ImageIndex(GL_NONE, -1, -1); -} - -ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn) - : type(typeIn), - mipIndex(mipIndexIn), - layerIndex(layerIndexIn) -{} - -ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) -{ - return ImageIndexIterator(GL_TEXTURE_2D, rx::Range(minMip, maxMip), - rx::Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL); -} - -ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) -{ - return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, rx::Range(minMip, maxMip), rx::Range(0, 6), NULL); -} - -ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, - GLint minLayer, GLint maxLayer) -{ - return ImageIndexIterator(GL_TEXTURE_3D, rx::Range(minMip, maxMip), rx::Range(minLayer, maxLayer), NULL); -} - -ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, - const GLsizei *layerCounts) -{ - return ImageIndexIterator(GL_TEXTURE_2D_ARRAY, rx::Range(minMip, maxMip), - rx::Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); -} - -ImageIndexIterator::ImageIndexIterator(GLenum type, const rx::Range &mipRange, - const rx::Range &layerRange, const GLsizei *layerCounts) - : mType(type), - mMipRange(mipRange), - mLayerRange(layerRange), - mLayerCounts(layerCounts), - mCurrentMip(mipRange.start), - mCurrentLayer(layerRange.start) -{} - -GLint ImageIndexIterator::maxLayer() const -{ - return (mLayerCounts ? static_cast(mLayerCounts[mCurrentMip]) : mLayerRange.end); -} - -ImageIndex ImageIndexIterator::next() -{ - ASSERT(hasNext()); - - ImageIndex value = current(); - - // Iterate layers in the inner loop for now. We can add switchable - // layer or mip iteration if we need it. - - if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL) - { - if (mCurrentLayer < maxLayer()-1) - { - mCurrentLayer++; - } - else if (mCurrentMip < mMipRange.end-1) - { - mCurrentMip++; - mCurrentLayer = mLayerRange.start; - } - } - else if (mCurrentMip < mMipRange.end-1) - { - mCurrentMip++; - mCurrentLayer = mLayerRange.start; - } - - return value; -} - -ImageIndex ImageIndexIterator::current() const -{ - ImageIndex value(mType, mCurrentMip, mCurrentLayer); - - if (mType == GL_TEXTURE_CUBE_MAP) - { - value.type = TextureCubeMap::layerIndexToTarget(mCurrentLayer); - } - - return value; -} - -bool ImageIndexIterator::hasNext() const -{ - return (mCurrentMip < mMipRange.end || mCurrentLayer < maxLayer()); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/ImageIndex.h b/src/3rdparty/angle/src/libGLESv2/ImageIndex.h deleted file mode 100644 index 8bb14fd555..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/ImageIndex.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright 2014 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. -// - -// ImageIndex.h: A helper struct for indexing into an Image array - -#ifndef LIBGLESV2_IMAGE_INDEX_H_ -#define LIBGLESV2_IMAGE_INDEX_H_ - -#include "angle_gl.h" -#include "common/mathutil.h" - -namespace gl -{ - -struct ImageIndex -{ - GLenum type; - GLint mipIndex; - GLint layerIndex; - - ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn); - ImageIndex(const ImageIndex &other); - ImageIndex &operator=(const ImageIndex &other); - - bool hasLayer() const { return layerIndex != ENTIRE_LEVEL; } - - static ImageIndex Make2D(GLint mipIndex); - static ImageIndex MakeCube(GLenum target, GLint mipIndex); - static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex); - static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL); - static ImageIndex MakeInvalid(); - - static const GLint ENTIRE_LEVEL = static_cast(-1); -}; - -class ImageIndexIterator -{ - public: - static ImageIndexIterator Make2D(GLint minMip, GLint maxMip); - static ImageIndexIterator MakeCube(GLint minMip, GLint maxMip); - static ImageIndexIterator Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer); - static ImageIndexIterator Make2DArray(GLint minMip, GLint maxMip, const GLsizei *layerCounts); - - ImageIndex next(); - ImageIndex current() const; - bool hasNext() const; - - private: - - ImageIndexIterator(GLenum type, const rx::Range &mipRange, - const rx::Range &layerRange, const GLsizei *layerCounts); - - GLint maxLayer() const; - - GLenum mType; - rx::Range mMipRange; - rx::Range mLayerRange; - const GLsizei *mLayerCounts; - GLint mCurrentMip; - GLint mCurrentLayer; -}; - -} - -#endif // LIBGLESV2_IMAGE_INDEX_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Program.cpp b/src/3rdparty/angle/src/libGLESv2/Program.cpp deleted file mode 100644 index 3faa8c56f6..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Program.cpp +++ /dev/null @@ -1,668 +0,0 @@ -// -// Copyright (c) 2002-2014 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 "libGLESv2/ResourceManager.h" -#include "libGLESv2/renderer/Renderer.h" - -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", msg.c_str()); -} - -void InfoLog::append(const char *format, ...) -{ - if (!format) - { - return; - } - - va_list vararg; - va_start(vararg, format); - size_t infoLength = vsnprintf(NULL, 0, format, vararg); - va_end(vararg); - - char *logPointer = NULL; - - if (!mInfoLog) - { - mInfoLog = new char[infoLength + 2]; - logPointer = mInfoLog; - } - else - { - size_t currentlogLength = strlen(mInfoLog); - char *newLog = new char[currentlogLength + infoLength + 2]; - strcpy(newLog, mInfoLog); - - delete[] mInfoLog; - mInfoLog = newLog; - - logPointer = mInfoLog + currentlogLength; - } - - va_start(vararg, format); - vsnprintf(logPointer, infoLength, format, vararg); - va_end(vararg); - - logPointer[infoLength] = 0; - strcpy(logPointer + infoLength, "\n"); -} - -void InfoLog::reset() -{ - if (mInfoLog) - { - delete [] mInfoLog; - mInfoLog = NULL; - } -} - -Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle) -{ - mFragmentShader = NULL; - mVertexShader = NULL; - mProgramBinary.set(NULL); - mDeleteStatus = false; - mLinked = false; - mRefCount = 0; - mRenderer = renderer; - - resetUniformBlockBindings(); -} - -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 = shader; - mVertexShader->addRef(); - } - else if (shader->getType() == GL_FRAGMENT_SHADER) - { - if (mFragmentShader) - { - return false; - } - - mFragmentShader = 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 -Error Program::link(const Data &data) -{ - unlink(false); - - mInfoLog.reset(); - resetUniformBlockBindings(); - - mProgramBinary.set(new ProgramBinary(mRenderer->createProgram())); - LinkResult result = mProgramBinary->link(data, mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader, - mTransformFeedbackVaryings, mTransformFeedbackBufferMode); - if (result.error.isError()) - { - return result.error; - } - - mLinked = result.linkSuccess; - return gl::Error(GL_NO_ERROR); -} - -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() const -{ - return mProgramBinary.get(); -} - -Error Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length) -{ - unlink(false); - - mInfoLog.reset(); - - mProgramBinary.set(new ProgramBinary(mRenderer->createProgram())); - LinkResult result = mProgramBinary->load(mInfoLog, binaryFormat, binary, length); - if (result.error.isError()) - { - mProgramBinary.set(NULL); - return result.error; - } - - mLinked = result.linkSuccess; - return Error(GL_NO_ERROR); -} - -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(const Caps &caps) -{ - mInfoLog.reset(); - - ProgramBinary *programBinary = getProgramBinary(); - if (isLinked() && programBinary) - { - programBinary->validate(mInfoLog, caps); - } - 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; - } -} - -GLint Program::getActiveUniformBlockCount() -{ - ProgramBinary *programBinary = getProgramBinary(); - if (programBinary) - { - return static_cast(programBinary->getActiveUniformBlockCount()); - } - else - { - return 0; - } -} - -GLint Program::getActiveUniformBlockMaxLength() -{ - ProgramBinary *programBinary = getProgramBinary(); - if (programBinary) - { - return static_cast(programBinary->getActiveUniformBlockMaxLength()); - } - else - { - return 0; - } -} - -void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding) -{ - mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding; -} - -GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const -{ - return mUniformBlockBindings[uniformBlockIndex]; -} - -void Program::resetUniformBlockBindings() -{ - for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++) - { - mUniformBlockBindings[blockId] = 0; - } -} - -void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode) -{ - mTransformFeedbackVaryings.resize(count); - for (GLsizei i = 0; i < count; i++) - { - mTransformFeedbackVaryings[i] = varyings[i]; - } - - mTransformFeedbackBufferMode = bufferMode; -} - -void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const -{ - ProgramBinary *programBinary = getProgramBinary(); - if (programBinary && index < programBinary->getTransformFeedbackVaryingCount()) - { - const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(index); - GLsizei lastNameIdx = std::min(bufSize - 1, static_cast(varying.name.length())); - if (length) - { - *length = lastNameIdx; - } - if (size) - { - *size = varying.size; - } - if (type) - { - *type = varying.type; - } - if (name) - { - memcpy(name, varying.name.c_str(), lastNameIdx); - name[lastNameIdx] = '\0'; - } - } -} - -GLsizei Program::getTransformFeedbackVaryingCount() const -{ - ProgramBinary *programBinary = getProgramBinary(); - if (programBinary) - { - return static_cast(programBinary->getTransformFeedbackVaryingCount()); - } - else - { - return 0; - } -} - -GLsizei Program::getTransformFeedbackVaryingMaxLength() const -{ - ProgramBinary *programBinary = getProgramBinary(); - if (programBinary) - { - GLsizei maxSize = 0; - for (size_t i = 0; i < programBinary->getTransformFeedbackVaryingCount(); i++) - { - const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(i); - maxSize = std::max(maxSize, static_cast(varying.name.length() + 1)); - } - - return maxSize; - } - else - { - return 0; - } -} - -GLenum Program::getTransformFeedbackBufferMode() const -{ - ProgramBinary *programBinary = getProgramBinary(); - if (programBinary) - { - return programBinary->getTransformFeedbackBufferMode(); - } - else - { - return mTransformFeedbackBufferMode; - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Program.h b/src/3rdparty/angle/src/libGLESv2/Program.h deleted file mode 100644 index b92349eeef..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Program.h +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (c) 2002-2014 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 "common/angleutils.h" -#include "common/RefCountObject.h" -#include "libGLESv2/Constants.h" -#include "libGLESv2/ProgramBinary.h" - -#include - -#include -#include -#include - -namespace rx -{ -class Renderer; -} - -namespace gl -{ -struct Caps; -struct Data; -class ResourceManager; -class Shader; - -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(rx::Renderer *renderer, ResourceManager *manager, GLuint handle); - - ~Program(); - - bool attachShader(Shader *shader); - bool detachShader(Shader *shader); - int getAttachedShadersCount() const; - - void bindAttributeLocation(GLuint index, const char *name); - - Error link(const Data &data); - bool isLinked(); - Error setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length); - ProgramBinary *getProgramBinary() const; - - 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(); - - GLint getActiveUniformBlockCount(); - GLint getActiveUniformBlockMaxLength(); - - void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding); - GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const; - - void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode); - void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const; - GLsizei getTransformFeedbackVaryingCount() const; - GLsizei getTransformFeedbackVaryingMaxLength() const; - GLenum getTransformFeedbackBufferMode() const; - - void addRef(); - void release(); - unsigned int getRefCount() const; - void flagForDeletion(); - bool isFlaggedForDeletion() const; - - void validate(const Caps &caps); - bool isValidated() const; - - GLint getProgramBinaryLength() const; - - private: - DISALLOW_COPY_AND_ASSIGN(Program); - - void unlink(bool destroy = false); - void resetUniformBlockBindings(); - - Shader *mFragmentShader; - Shader *mVertexShader; - - AttributeBindings mAttributeBindings; - - GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; - - std::vector mTransformFeedbackVaryings; - GLuint mTransformFeedbackBufferMode; - - 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; - rx::Renderer *mRenderer; - 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 deleted file mode 100644 index 6d64b38b56..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp +++ /dev/null @@ -1,1233 +0,0 @@ -// -// Copyright (c) 2002-2014 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/ProgramBinary.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/renderer/ShaderExecutable.h" - -#include "common/debug.h" -#include "common/version.h" -#include "common/utilities.h" -#include "common/platform.h" - -#include "libGLESv2/main.h" -#include "libGLESv2/Shader.h" -#include "libGLESv2/Program.h" -#include "libGLESv2/renderer/ProgramImpl.h" -#include "libGLESv2/renderer/d3d/ShaderD3D.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/Buffer.h" -#include "common/blocklayout.h" -#include "common/features.h" - -namespace gl -{ - -namespace -{ - -unsigned int ParseAndStripArrayIndex(std::string* name) -{ - unsigned int subscript = GL_INVALID_INDEX; - - // 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); - } - - return subscript; -} - -} - -VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) - : name(name), element(element), index(index) -{ -} - -LinkedVarying::LinkedVarying() -{ -} - -LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, - unsigned int semanticIndex, unsigned int semanticIndexCount) - : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount) -{ -} - -LinkResult::LinkResult(bool linkSuccess, const Error &error) - : linkSuccess(linkSuccess), - error(error) -{ -} - -unsigned int ProgramBinary::mCurrentSerial = 1; - -ProgramBinary::ProgramBinary(rx::ProgramImpl *impl) - : RefCountObject(0), - mProgram(impl), - mValidated(false), - mSerial(issueSerial()) -{ - ASSERT(impl); - - for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) - { - mSemanticIndex[index] = -1; - } -} - -ProgramBinary::~ProgramBinary() -{ - reset(); - SafeDelete(mProgram); -} - -unsigned int ProgramBinary::getSerial() const -{ - return mSerial; -} - -unsigned int ProgramBinary::issueSerial() -{ - return mCurrentSerial++; -} - -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) -{ - return mProgram->getUsedSamplerRange(type); -} - -bool ProgramBinary::usesPointSize() const -{ - return mProgram->usesPointSize(); -} - -GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps) -{ - return mProgram->getSamplerMapping(type, samplerIndex, caps); -} - -GLenum ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex) -{ - return mProgram->getSamplerTextureType(type, samplerIndex); -} - -GLint ProgramBinary::getUniformLocation(std::string name) -{ - return mProgram->getUniformLocation(name); -} - -GLuint ProgramBinary::getUniformIndex(std::string name) -{ - return mProgram->getUniformIndex(name); -} - -GLuint ProgramBinary::getUniformBlockIndex(std::string name) -{ - return mProgram->getUniformBlockIndex(name); -} - -UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex) -{ - return mProgram->getUniformBlockByIndex(blockIndex); -} - -GLint ProgramBinary::getFragDataLocation(const char *name) const -{ - std::string baseName(name); - unsigned int arrayIndex; - arrayIndex = ParseAndStripArrayIndex(&baseName); - - for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++) - { - const VariableLocation &outputVariable = locationIt->second; - - if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element)) - { - return static_cast(locationIt->first); - } - } - - return -1; -} - -size_t ProgramBinary::getTransformFeedbackVaryingCount() const -{ - return mProgram->getTransformFeedbackLinkedVaryings().size(); -} - -const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const -{ - return mProgram->getTransformFeedbackLinkedVaryings()[idx]; -} - -GLenum ProgramBinary::getTransformFeedbackBufferMode() const -{ - return mProgram->getTransformFeedbackBufferMode(); -} - -void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) { - mProgram->setUniform1fv(location, count, v); -} - -void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) { - mProgram->setUniform2fv(location, count, v); -} - -void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) { - mProgram->setUniform3fv(location, count, v); -} - -void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) { - mProgram->setUniform4fv(location, count, v); -} - -void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) { - mProgram->setUniform1iv(location, count, v); -} - -void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) { - mProgram->setUniform2iv(location, count, v); -} - -void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) { - mProgram->setUniform3iv(location, count, v); -} - -void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) { - mProgram->setUniform4iv(location, count, v); -} - -void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) { - mProgram->setUniform1uiv(location, count, v); -} - -void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) { - mProgram->setUniform2uiv(location, count, v); -} - -void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) { - mProgram->setUniform3uiv(location, count, v); -} - -void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) { - mProgram->setUniform4uiv(location, count, v); -} - -void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix2fv(location, count, transpose, v); -} - -void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix3fv(location, count, transpose, v); -} - -void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix4fv(location, count, transpose, v); -} - -void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix2x3fv(location, count, transpose, v); -} - -void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix2x4fv(location, count, transpose, v); -} - -void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix3x2fv(location, count, transpose, v); -} - -void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix3x4fv(location, count, transpose, v); -} - -void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix4x2fv(location, count, transpose, v); -} - -void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { - mProgram->setUniformMatrix4x3fv(location, count, transpose, v); -} - -void ProgramBinary::getUniformfv(GLint location, GLfloat *v) { - mProgram->getUniformfv(location, v); -} - -void ProgramBinary::getUniformiv(GLint location, GLint *v) { - mProgram->getUniformiv(location, v); -} - -void ProgramBinary::getUniformuiv(GLint location, GLuint *v) { - mProgram->getUniformuiv(location, v); -} - -void ProgramBinary::updateSamplerMapping() -{ - return mProgram->updateSamplerMapping(); -} - -// Applies all the uniforms set for this program object to the renderer -Error ProgramBinary::applyUniforms() -{ - return mProgram->applyUniforms(); -} - -Error ProgramBinary::applyUniformBuffers(const std::vector boundBuffers, const Caps &caps) -{ - return mProgram->applyUniformBuffers(boundBuffers, caps); -} - -bool ProgramBinary::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader) -{ - std::vector &fragmentVaryings = fragmentShader->getVaryings(); - std::vector &vertexVaryings = vertexShader->getVaryings(); - - for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++) - { - PackedVarying *input = &fragmentVaryings[fragVaryingIndex]; - bool matched = false; - - // Built-in varyings obey special rules - if (input->isBuiltIn()) - { - continue; - } - - for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) - { - PackedVarying *output = &vertexVaryings[vertVaryingIndex]; - if (output->name == input->name) - { - if (!linkValidateVaryings(infoLog, output->name, *input, *output)) - { - return false; - } - - output->registerIndex = input->registerIndex; - output->columnIndex = input->columnIndex; - - matched = true; - break; - } - } - - // We permit unmatched, unreferenced varyings - if (!matched && input->staticUse) - { - infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str()); - return false; - } - } - - return true; -} - -LinkResult ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length) -{ -#if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_DISABLED - return LinkResult(false, Error(GL_NO_ERROR)); -#else - ASSERT(binaryFormat == mProgram->getBinaryFormat()); - - reset(); - - BinaryInputStream stream(binary, length); - - GLenum format = stream.readInt(); - if (format != mProgram->getBinaryFormat()) - { - infoLog.append("Invalid program binary format."); - return LinkResult(false, Error(GL_NO_ERROR)); - } - - int majorVersion = stream.readInt(); - int minorVersion = stream.readInt(); - if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) - { - infoLog.append("Invalid program binary version."); - return LinkResult(false, Error(GL_NO_ERROR)); - } - - unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; - stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE); - if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) - { - infoLog.append("Invalid program binary version."); - return LinkResult(false, Error(GL_NO_ERROR)); - } - - int compileFlags = stream.readInt(); - if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) - { - infoLog.append("Mismatched compilation flags."); - return LinkResult(false, Error(GL_NO_ERROR)); - } - - for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) - { - stream.readInt(&mLinkedAttribute[i].type); - stream.readString(&mLinkedAttribute[i].name); - stream.readInt(&mProgram->getShaderAttributes()[i].type); - stream.readString(&mProgram->getShaderAttributes()[i].name); - stream.readInt(&mSemanticIndex[i]); - } - - initAttributesByLayout(); - - LinkResult result = mProgram->load(infoLog, &stream); - if (result.error.isError() || !result.linkSuccess) - { - return result; - } - - return LinkResult(true, Error(GL_NO_ERROR)); -#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED -} - -Error ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) -{ - if (binaryFormat) - { - *binaryFormat = mProgram->getBinaryFormat(); - } - - BinaryOutputStream stream; - - stream.writeInt(mProgram->getBinaryFormat()); - stream.writeInt(ANGLE_MAJOR_VERSION); - stream.writeInt(ANGLE_MINOR_VERSION); - stream.writeBytes(reinterpret_cast(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE); - stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL); - - for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) - { - stream.writeInt(mLinkedAttribute[i].type); - stream.writeString(mLinkedAttribute[i].name); - stream.writeInt(mProgram->getShaderAttributes()[i].type); - stream.writeString(mProgram->getShaderAttributes()[i].name); - stream.writeInt(mSemanticIndex[i]); - } - - mProgram->save(&stream); - - GLsizei streamLength = stream.length(); - const void *streamData = stream.data(); - - if (streamLength > bufSize) - { - if (length) - { - *length = 0; - } - - // TODO: This should be moved to the validation layer but computing the size of the binary before saving - // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate - // sizes and then copy it. - return Error(GL_INVALID_OPERATION); - } - - if (binary) - { - char *ptr = (char*) binary; - - memcpy(ptr, streamData, streamLength); - ptr += streamLength; - - ASSERT(ptr - streamLength == binary); - } - - if (length) - { - *length = streamLength; - } - - return Error(GL_NO_ERROR); -} - -GLint ProgramBinary::getLength() -{ - GLint length; - Error error = save(NULL, NULL, INT_MAX, &length); - if (error.isError()) - { - return 0; - } - - return length; -} - -LinkResult ProgramBinary::link(const Data &data, InfoLog &infoLog, const AttributeBindings &attributeBindings, - Shader *fragmentShader, Shader *vertexShader, - const std::vector &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode) -{ - if (!fragmentShader || !fragmentShader->isCompiled()) - { - return LinkResult(false, Error(GL_NO_ERROR)); - } - ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER); - - if (!vertexShader || !vertexShader->isCompiled()) - { - return LinkResult(false, Error(GL_NO_ERROR)); - } - ASSERT(vertexShader->getType() == GL_VERTEX_SHADER); - - reset(); - - int registers; - std::vector linkedVaryings; - LinkResult result = mProgram->link(data, infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode, - ®isters, &linkedVaryings, &mOutputVariables); - if (result.error.isError() || !result.linkSuccess) - { - return result; - } - - if (!linkAttributes(infoLog, attributeBindings, vertexShader)) - { - return LinkResult(false, Error(GL_NO_ERROR)); - } - - if (!mProgram->linkUniforms(infoLog, *vertexShader, *fragmentShader, *data.caps)) - { - return LinkResult(false, Error(GL_NO_ERROR)); - } - - if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, *data.caps)) - { - return LinkResult(false, Error(GL_NO_ERROR)); - } - - if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings, - transformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps)) - { - return LinkResult(false, Error(GL_NO_ERROR)); - } - - // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called, - // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling. - result = mProgram->compileProgramExecutables(infoLog, fragmentShader, vertexShader, registers); - if (result.error.isError() || !result.linkSuccess) - { - infoLog.append("Failed to create D3D shaders."); - reset(); - return result; - } - - return LinkResult(true, Error(GL_NO_ERROR)); -} - -bool ProgramBinary::linkUniformBlocks(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, - const gl::Caps &caps) -{ - const std::vector &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(); - const std::vector &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(); - - // Check that interface blocks defined in the vertex and fragment shaders are identical - typedef std::map UniformBlockMap; - UniformBlockMap linkedUniformBlocks; - - for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex]; - linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; - } - - for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex]; - UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); - if (entry != linkedUniformBlocks.end()) - { - const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; - if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) - { - return false; - } - } - } - - for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex]; - - // Note: shared and std140 layouts are always considered active - if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) - { - if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps)) - { - return false; - } - } - } - - for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex]; - - // Note: shared and std140 layouts are always considered active - if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) - { - if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps)) - { - return false; - } - } - } - - return true; -} - -bool ProgramBinary::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, - const sh::InterfaceBlock &fragmentInterfaceBlock) -{ - const char* blockName = vertexInterfaceBlock.name.c_str(); - - // validate blocks for the same member types - if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size()) - { - infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName); - return false; - } - - if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize) - { - infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName); - return false; - } - - if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) - { - infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName); - return false; - } - - const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size(); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++) - { - const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex]; - const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex]; - - if (vertexMember.name != fragmentMember.name) - { - infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')", - blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str()); - return false; - } - - std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; - if (!gl::ProgramBinary::linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember)) - { - return false; - } - } - - return true; -} - -// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices -bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader) -{ - const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); - - unsigned int usedLocations = 0; - const std::vector &shaderAttributes = vertexShader->getActiveAttributes(); - - // Link attributes that have a binding location - for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) - { - const sh::Attribute &attribute = shaderAttributes[attributeIndex]; - - ASSERT(attribute.staticUse); - - const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; - - mProgram->getShaderAttributes()[attributeIndex] = attribute; - - if (location != -1) // Set by glBindAttribLocation or by location layout qualifier - { - const int rows = VariableRegisterCount(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 row = 0; row < rows; row++) - { - const int rowLocation = location + row; - sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation]; - - // In GLSL 3.00, attribute aliasing produces a link error - // In GLSL 1.00, attribute aliasing is allowed - if (mProgram->getShaderVersion() >= 300) - { - if (!linkedAttribute.name.empty()) - { - infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation); - return false; - } - } - - linkedAttribute = attribute; - usedLocations |= 1 << rowLocation; - } - } - } - - // Link attributes that don't have a binding location - for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) - { - const sh::Attribute &attribute = shaderAttributes[attributeIndex]; - - ASSERT(attribute.staticUse); - - const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; - - if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier - { - int rows = VariableRegisterCount(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 = vertexShaderD3D->getSemanticIndex(mLinkedAttribute[attributeIndex].name); - int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type); - - for (int r = 0; r < rows; r++) - { - mSemanticIndex[attributeIndex++] = index++; - } - } - - initAttributesByLayout(); - - return true; -} - -bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable, - const sh::ShaderVariable &fragmentVariable, bool validatePrecision) -{ - if (vertexVariable.type != fragmentVariable.type) - { - infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str()); - return false; - } - if (vertexVariable.arraySize != fragmentVariable.arraySize) - { - infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str()); - return false; - } - if (validatePrecision && vertexVariable.precision != fragmentVariable.precision) - { - infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str()); - return false; - } - - if (vertexVariable.fields.size() != fragmentVariable.fields.size()) - { - infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str()); - return false; - } - const unsigned int numMembers = vertexVariable.fields.size(); - for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++) - { - const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex]; - const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex]; - - if (vertexMember.name != fragmentMember.name) - { - infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')", - memberIndex, variableName.c_str(), - vertexMember.name.c_str(), fragmentMember.name.c_str()); - return false; - } - - const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." + - vertexMember.name + "'"; - - if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision)) - { - return false; - } - } - - return true; -} - -bool ProgramBinary::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform) -{ - if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) - { - return false; - } - - return true; -} - -bool ProgramBinary::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying) -{ - if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false)) - { - return false; - } - - if (vertexVarying.interpolation != fragmentVarying.interpolation) - { - infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str()); - return false; - } - - return true; -} - -bool ProgramBinary::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform) -{ - if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true)) - { - return false; - } - - if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout) - { - infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str()); - return false; - } - - return true; -} - -bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector &linkedVaryings, - const std::vector &transformFeedbackVaryingNames, - GLenum transformFeedbackBufferMode, - std::vector *outTransformFeedbackLinkedVaryings, - const Caps &caps) const -{ - size_t totalComponents = 0; - - // Gather the linked varyings that are used for transform feedback, they should all exist. - outTransformFeedbackLinkedVaryings->clear(); - for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++) - { - bool found = false; - for (size_t j = 0; j < linkedVaryings.size(); j++) - { - if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name) - { - for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++) - { - if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name) - { - infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str()); - return false; - } - } - - size_t componentCount = linkedVaryings[j].semanticIndexCount * 4; - if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS && - componentCount > caps.maxTransformFeedbackSeparateComponents) - { - infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).", - linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents); - return false; - } - - totalComponents += componentCount; - - outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]); - found = true; - break; - } - } - - // All transform feedback varyings are expected to exist since packVaryings checks for them. - ASSERT(found); - } - - if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents) - { - infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).", - totalComponents, caps.maxTransformFeedbackInterleavedComponents); - return false; - } - - return true; -} - -bool ProgramBinary::isValidated() const -{ - return mValidated; -} - -void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const -{ - // 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() const -{ - int count = 0; - - for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) - { - if (!mLinkedAttribute[attributeIndex].name.empty()) - { - count++; - } - } - - return count; -} - -GLint ProgramBinary::getActiveAttributeMaxLength() const -{ - 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) const -{ - ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount() - - if (bufsize > 0) - { - std::string string = mProgram->getUniforms()[index]->name; - - if (mProgram->getUniforms()[index]->isArray()) - { - string += "[0]"; - } - - strncpy(name, string.c_str(), bufsize); - name[bufsize - 1] = '\0'; - - if (length) - { - *length = strlen(name); - } - } - - *size = mProgram->getUniforms()[index]->elementCount(); - - *type = mProgram->getUniforms()[index]->type; -} - -GLint ProgramBinary::getActiveUniformCount() const -{ - return mProgram->getUniforms().size(); -} - -GLint ProgramBinary::getActiveUniformMaxLength() const -{ - int maxLength = 0; - - unsigned int numUniforms = mProgram->getUniforms().size(); - for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) - { - if (!mProgram->getUniforms()[uniformIndex]->name.empty()) - { - int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1); - if (mProgram->getUniforms()[uniformIndex]->isArray()) - { - length += 3; // Counting in "[0]". - } - maxLength = std::max(length, maxLength); - } - } - - return maxLength; -} - -GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const -{ - const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index]; - - switch (pname) - { - case GL_UNIFORM_TYPE: return static_cast(uniform.type); - case GL_UNIFORM_SIZE: return static_cast(uniform.elementCount()); - case GL_UNIFORM_NAME_LENGTH: return static_cast(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0)); - case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex; - - case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset; - case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride; - case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride; - case GL_UNIFORM_IS_ROW_MAJOR: return static_cast(uniform.blockInfo.isRowMajorMatrix); - - default: - UNREACHABLE(); - break; - } - return 0; -} - -bool ProgramBinary::isValidUniformLocation(GLint location) const -{ - ASSERT(rx::IsIntegerCastSafe(mProgram->getUniformIndices().size())); - return (location >= 0 && location < static_cast(mProgram->getUniformIndices().size())); -} - -LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const -{ - return mProgram->getUniformByLocation(location); -} - -LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const -{ - return mProgram->getUniformByName(name); -} - -void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const -{ - ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount() - - const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; - - if (bufSize > 0) - { - std::string string = uniformBlock.name; - - if (uniformBlock.isArrayElement()) - { - string += ArrayString(uniformBlock.elementIndex); - } - - strncpy(uniformBlockName, string.c_str(), bufSize); - uniformBlockName[bufSize - 1] = '\0'; - - if (length) - { - *length = strlen(uniformBlockName); - } - } -} - -void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const -{ - ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount() - - const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; - - switch (pname) - { - case GL_UNIFORM_BLOCK_DATA_SIZE: - *params = static_cast(uniformBlock.dataSize); - break; - case GL_UNIFORM_BLOCK_NAME_LENGTH: - *params = static_cast(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0)); - break; - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: - *params = static_cast(uniformBlock.memberUniformIndexes.size()); - break; - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: - { - for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) - { - params[blockMemberIndex] = static_cast(uniformBlock.memberUniformIndexes[blockMemberIndex]); - } - } - break; - case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: - *params = static_cast(uniformBlock.isReferencedByVertexShader()); - break; - case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: - *params = static_cast(uniformBlock.isReferencedByFragmentShader()); - break; - default: UNREACHABLE(); - } -} - -GLuint ProgramBinary::getActiveUniformBlockCount() const -{ - return mProgram->getUniformBlocks().size(); -} - -GLuint ProgramBinary::getActiveUniformBlockMaxLength() const -{ - unsigned int maxLength = 0; - - unsigned int numUniformBlocks = mProgram->getUniformBlocks().size(); - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++) - { - const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; - if (!uniformBlock.name.empty()) - { - const unsigned int length = uniformBlock.name.length() + 1; - - // Counting in "[0]". - const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0); - - maxLength = std::max(length + arrayLength, maxLength); - } - } - - return maxLength; -} - -void ProgramBinary::validate(InfoLog &infoLog, const Caps &caps) -{ - applyUniforms(); - if (!validateSamplers(&infoLog, caps)) - { - mValidated = false; - } - else - { - mValidated = true; - } -} - -bool ProgramBinary::validateSamplers(InfoLog *infoLog, const Caps &caps) -{ - return mProgram->validateSamplers(infoLog, caps); -} - -struct AttributeSorter -{ - AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS]) - : originalIndices(semanticIndices) - { - } - - bool operator()(int a, int b) - { - if (originalIndices[a] == -1) return false; - if (originalIndices[b] == -1) return true; - return (originalIndices[a] < originalIndices[b]); - } - - const int (&originalIndices)[MAX_VERTEX_ATTRIBS]; -}; - -void ProgramBinary::initAttributesByLayout() -{ - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) - { - mAttributesByLayout[i] = i; - } - - std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex)); -} - -void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const -{ - rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS]; - - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) - { - oldTranslatedAttributes[i] = attributes[i]; - } - - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) - { - int oldIndex = mAttributesByLayout[i]; - sortedSemanticIndices[i] = oldIndex; - attributes[i] = oldTranslatedAttributes[oldIndex]; - } -} - -void ProgramBinary::reset() -{ - mOutputVariables.clear(); - - mProgram->reset(); - - mValidated = false; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h deleted file mode 100644 index 3142d66c6d..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h +++ /dev/null @@ -1,237 +0,0 @@ -// -// Copyright (c) 2002-2014 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_ - -#include "common/RefCountObject.h" -#include "angletypes.h" -#include "common/mathutil.h" -#include "libGLESv2/Uniform.h" -#include "libGLESv2/Shader.h" -#include "libGLESv2/Constants.h" -#include "libGLESv2/renderer/d3d/VertexDataManager.h" -#include "libGLESv2/renderer/d3d/DynamicHLSL.h" - -#include "angle_gl.h" - -#include -#include - -namespace sh -{ -class HLSLBlockEncoder; -} - -#include -#include -#include - -#include -#include - -namespace rx -{ -class ShaderExecutable; -struct TranslatedAttribute; -class UniformStorage; -class ProgramImpl; -} - -namespace gl -{ -struct Caps; -class Shader; -class InfoLog; -class AttributeBindings; -class Buffer; -class Framebuffer; -struct Data; - -// Struct used for correlating uniforms/elements of uniform arrays to handles -struct VariableLocation -{ - VariableLocation() - { - } - - VariableLocation(const std::string &name, unsigned int element, unsigned int index); - - std::string name; - unsigned int element; - unsigned int index; -}; - -struct LinkedVarying -{ - LinkedVarying(); - LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName, - unsigned int semanticIndex, unsigned int semanticIndexCount); - - // Original GL name - std::string name; - - GLenum type; - GLsizei size; - - // DirectX semantic information - std::string semanticName; - unsigned int semanticIndex; - unsigned int semanticIndexCount; -}; - -struct LinkResult -{ - bool linkSuccess; - Error error; - - LinkResult(bool linkSuccess, const Error &error); -}; - -// This is the result of linking a program. It is the state that would be passed to ProgramBinary. -class ProgramBinary : public RefCountObject -{ - public: - explicit ProgramBinary(rx::ProgramImpl *impl); - ~ProgramBinary(); - - rx::ProgramImpl *getImplementation() { return mProgram; } - const rx::ProgramImpl *getImplementation() const { return mProgram; } - - GLuint getAttributeLocation(const char *name); - int getSemanticIndex(int attributeIndex); - - GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps); - GLenum getSamplerTextureType(SamplerType type, unsigned int samplerIndex); - GLint getUsedSamplerRange(SamplerType type); - bool usesPointSize() const; - - GLint getUniformLocation(std::string name); - GLuint getUniformIndex(std::string name); - GLuint getUniformBlockIndex(std::string name); - void setUniform1fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform1iv(GLint location, GLsizei count, const GLint *v); - void setUniform2iv(GLint location, GLsizei count, const GLint *v); - void setUniform3iv(GLint location, GLsizei count, const GLint *v); - void setUniform4iv(GLint location, GLsizei count, const GLint *v); - void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); - void setUniform2uiv(GLint location, GLsizei count, const GLuint *v); - void setUniform3uiv(GLint location, GLsizei count, const GLuint *v); - void setUniform4uiv(GLint location, GLsizei count, const GLuint *v); - void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - - void getUniformfv(GLint location, GLfloat *params); - void getUniformiv(GLint location, GLint *params); - void getUniformuiv(GLint location, GLuint *params); - - Error applyUniforms(); - Error applyUniformBuffers(const std::vector boundBuffers, const Caps &caps); - - LinkResult load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length); - Error save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length); - GLint getLength(); - - LinkResult link(const Data &data, InfoLog &infoLog, const AttributeBindings &attributeBindings, - Shader *fragmentShader, Shader *vertexShader, - const std::vector &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode); - - void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; - GLint getActiveAttributeCount() const; - GLint getActiveAttributeMaxLength() const; - - void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; - GLint getActiveUniformCount() const; - GLint getActiveUniformMaxLength() const; - GLint getActiveUniformi(GLuint index, GLenum pname) const; - bool isValidUniformLocation(GLint location) const; - LinkedUniform *getUniformByLocation(GLint location) const; - LinkedUniform *getUniformByName(const std::string &name) const; - - void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const; - void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const; - GLuint getActiveUniformBlockCount() const; - GLuint getActiveUniformBlockMaxLength() const; - UniformBlock *getUniformBlockByIndex(GLuint blockIndex); - - GLint getFragDataLocation(const char *name) const; - - size_t getTransformFeedbackVaryingCount() const; - const LinkedVarying &getTransformFeedbackVarying(size_t idx) const; - GLenum getTransformFeedbackBufferMode() const; - - void validate(InfoLog &infoLog, const Caps &caps); - bool validateSamplers(InfoLog *infoLog, const Caps &caps); - bool isValidated() const; - void updateSamplerMapping(); - - unsigned int getSerial() const; - - void initAttributesByLayout(); - void sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const; - - static bool linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader); - static bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform); - static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform); - - private: - DISALLOW_COPY_AND_ASSIGN(ProgramBinary); - - void reset(); - - bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader); - bool linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps); - bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, - const sh::InterfaceBlock &fragmentInterfaceBlock); - - static bool linkValidateVariablesBase(InfoLog &infoLog, - const std::string &variableName, - const sh::ShaderVariable &vertexVariable, - const sh::ShaderVariable &fragmentVariable, - bool validatePrecision); - - static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying); - bool gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector &linkedVaryings, - const std::vector &transformFeedbackVaryingNames, - GLenum transformFeedbackBufferMode, - std::vector *outTransformFeedbackLinkedVaryings, - const Caps &caps) const; - bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps); - void defineOutputVariables(Shader *fragmentShader); - - rx::ProgramImpl *mProgram; - - sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; - int mSemanticIndex[MAX_VERTEX_ATTRIBS]; - int mAttributesByLayout[MAX_VERTEX_ATTRIBS]; - - std::map mOutputVariables; - - 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 deleted file mode 100644 index 4ee3525509..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Query.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// 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/renderer/QueryImpl.h" - -namespace gl -{ -Query::Query(rx::QueryImpl *impl, GLuint id) - : RefCountObject(id), - mQuery(impl) -{ -} - -Query::~Query() -{ - SafeDelete(mQuery); -} - -Error Query::begin() -{ - return mQuery->begin(); -} - -Error Query::end() -{ - return mQuery->end(); -} - -Error Query::getResult(GLuint *params) -{ - return mQuery->getResult(params); -} - -Error Query::isResultAvailable(GLuint *available) -{ - return mQuery->isResultAvailable(available); -} - -GLenum Query::getType() const -{ - return mQuery->getType(); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Query.h b/src/3rdparty/angle/src/libGLESv2/Query.h deleted file mode 100644 index a7ec404f85..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Query.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// 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_ - -#include "libGLESv2/Error.h" -#include "common/angleutils.h" -#include "common/RefCountObject.h" - -#include "angle_gl.h" - -namespace rx -{ -class QueryImpl; -} - -namespace gl -{ - -class Query : public RefCountObject -{ - public: - Query(rx::QueryImpl *impl, GLuint id); - virtual ~Query(); - - Error begin(); - Error end(); - - Error getResult(GLuint *params); - Error isResultAvailable(GLuint *available); - - GLenum getType() const; - - private: - DISALLOW_COPY_AND_ASSIGN(Query); - - rx::QueryImpl *mQuery; -}; - -} - -#endif // LIBGLESV2_QUERY_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp deleted file mode 100644 index 911a389dfa..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// -// 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. -// - -// Renderbuffer.cpp: Implements the renderer-agnostic gl::Renderbuffer class, -// GL renderbuffer objects and related functionality. -// [OpenGL ES 2.0.24] section 4.4.3 page 108. - -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/renderer/RenderTarget.h" -#include "libGLESv2/renderer/RenderbufferImpl.h" - -#include "common/utilities.h" - -namespace gl -{ -Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id) - : RefCountObject(id), - mRenderbuffer(impl) -{ - ASSERT(mRenderbuffer); - - mWidth = mRenderbuffer->getWidth(); - mHeight = mRenderbuffer->getHeight(); - mInternalFormat = mRenderbuffer->getInternalFormat(); - mActualFormat = mRenderbuffer->getActualFormat(); - mSamples = mRenderbuffer->getSamples(); -} - -Renderbuffer::~Renderbuffer() -{ - SafeDelete(mRenderbuffer); -} - -Error Renderbuffer::setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) -{ - Error error = mRenderbuffer->setStorage(width, height, internalformat, samples); - if (error.isError()) - { - return error; - } - - mWidth = width; - mHeight = height; - mInternalFormat = internalformat; - mSamples = samples; - mActualFormat = mRenderbuffer->getActualFormat(); - - return Error(GL_NO_ERROR); -} - -rx::RenderbufferImpl *Renderbuffer::getImplementation() -{ - ASSERT(mRenderbuffer); - return mRenderbuffer; -} - -GLsizei Renderbuffer::getWidth() const -{ - return mWidth; -} - -GLsizei Renderbuffer::getHeight() const -{ - return mHeight; -} - -GLenum Renderbuffer::getInternalFormat() const -{ - return mInternalFormat; -} - -GLenum Renderbuffer::getActualFormat() const -{ - return mActualFormat; -} - -GLsizei Renderbuffer::getSamples() const -{ - return mSamples; -} - -GLuint Renderbuffer::getRedSize() const -{ - return GetInternalFormatInfo(getActualFormat()).redBits; -} - -GLuint Renderbuffer::getGreenSize() const -{ - return GetInternalFormatInfo(getActualFormat()).greenBits; -} - -GLuint Renderbuffer::getBlueSize() const -{ - return GetInternalFormatInfo(getActualFormat()).blueBits; -} - -GLuint Renderbuffer::getAlphaSize() const -{ - return GetInternalFormatInfo(getActualFormat()).alphaBits; -} - -GLuint Renderbuffer::getDepthSize() const -{ - return GetInternalFormatInfo(getActualFormat()).depthBits; -} - -GLuint Renderbuffer::getStencilSize() const -{ - return GetInternalFormatInfo(getActualFormat()).stencilBits; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h deleted file mode 100644 index e9f12af3ce..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h +++ /dev/null @@ -1,71 +0,0 @@ -// -// 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 renderer-agnostic container class gl::Renderbuffer. -// 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_ - -#include "angle_gl.h" - -#include "libGLESv2/Error.h" - -#include "common/angleutils.h" -#include "common/RefCountObject.h" - -namespace rx -{ -class RenderbufferImpl; -} - -namespace gl -{ -class FramebufferAttachment; - -// A GL renderbuffer object is usually used as a depth or stencil buffer attachment -// for a framebuffer object. The renderbuffer itself is a distinct GL object, see -// FramebufferAttachment and Framebuffer for how they are applied to an FBO via an -// attachment point. - -class Renderbuffer : public RefCountObject -{ - public: - Renderbuffer(rx::RenderbufferImpl *impl, GLuint id); - virtual ~Renderbuffer(); - - Error setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples); - - rx::RenderbufferImpl *getImplementation(); - - GLsizei getWidth() const; - GLsizei getHeight() const; - GLenum getInternalFormat() const; - GLenum getActualFormat() const; - GLsizei getSamples() const; - GLuint getRedSize() const; - GLuint getGreenSize() const; - GLuint getBlueSize() const; - GLuint getAlphaSize() const; - GLuint getDepthSize() const; - GLuint getStencilSize() const; - - private: - DISALLOW_COPY_AND_ASSIGN(Renderbuffer); - - rx::RenderbufferImpl *mRenderbuffer; - - GLsizei mWidth; - GLsizei mHeight; - GLenum mInternalFormat; - GLenum mActualFormat; - GLsizei mSamples; -}; - -} - -#endif // LIBGLESV2_RENDERBUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp deleted file mode 100644 index 38d53cad81..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp +++ /dev/null @@ -1,427 +0,0 @@ -// -// Copyright (c) 2002-2013 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" -#include "libGLESv2/Sampler.h" -#include "libGLESv2/Fence.h" -#include "libGLESv2/renderer/Renderer.h" - -namespace gl -{ -ResourceManager::ResourceManager(rx::Renderer *renderer) - : mRenderer(renderer), - 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); - } - - while (!mSamplerMap.empty()) - { - deleteSampler(mSamplerMap.begin()->first); - } - - while (!mFenceSyncMap.empty()) - { - deleteFenceSync(mFenceSyncMap.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(const gl::Data &data, GLenum type) -{ - GLuint handle = mProgramShaderHandleAllocator.allocate(); - - if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER) - { - mShaderMap[handle] = new Shader(this, mRenderer->createShader(data, type), type, handle); - } - else UNREACHABLE(); - - return handle; -} - -// Returns an unused program/shader name -GLuint ResourceManager::createProgram() -{ - GLuint handle = mProgramShaderHandleAllocator.allocate(); - - mProgramMap[handle] = new Program(mRenderer, 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; -} - -// Returns an unused sampler name -GLuint ResourceManager::createSampler() -{ - GLuint handle = mSamplerHandleAllocator.allocate(); - - mSamplerMap[handle] = NULL; - - return handle; -} - -// Returns the next unused fence name, and allocates the fence -GLuint ResourceManager::createFenceSync() -{ - GLuint handle = mFenceSyncHandleAllocator.allocate(); - - FenceSync *fenceSync = new FenceSync(mRenderer->createFenceSync(), handle); - fenceSync->addRef(); - mFenceSyncMap[handle] = fenceSync; - - 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); - } -} - -void ResourceManager::deleteSampler(GLuint sampler) -{ - auto samplerObject = mSamplerMap.find(sampler); - - if (samplerObject != mSamplerMap.end()) - { - mSamplerHandleAllocator.release(samplerObject->first); - if (samplerObject->second) samplerObject->second->release(); - mSamplerMap.erase(samplerObject); - } -} - -void ResourceManager::deleteFenceSync(GLuint fenceSync) -{ - auto fenceObjectIt = mFenceSyncMap.find(fenceSync); - - if (fenceObjectIt != mFenceSyncMap.end()) - { - mFenceSyncHandleAllocator.release(fenceObjectIt->first); - if (fenceObjectIt->second) fenceObjectIt->second->release(); - mFenceSyncMap.erase(fenceObjectIt); - } -} - -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) const -{ - ProgramMap::const_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; - } -} - -Sampler *ResourceManager::getSampler(unsigned int handle) -{ - auto sampler = mSamplerMap.find(handle); - - if (sampler == mSamplerMap.end()) - { - return NULL; - } - else - { - return sampler->second; - } -} - -FenceSync *ResourceManager::getFenceSync(unsigned int handle) -{ - auto fenceObjectIt = mFenceSyncMap.find(handle); - - if (fenceObjectIt == mFenceSyncMap.end()) - { - return NULL; - } - else - { - return fenceObjectIt->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(mRenderer->createBuffer(), buffer); - mBufferMap[buffer] = bufferObject; - bufferObject->addRef(); - } -} - -void ResourceManager::checkTextureAllocation(GLuint texture, GLenum type) -{ - if (!getTexture(texture) && texture != 0) - { - Texture *textureObject; - - if (type == GL_TEXTURE_2D) - { - textureObject = new Texture2D(mRenderer->createTexture(GL_TEXTURE_2D), texture); - } - else if (type == GL_TEXTURE_CUBE_MAP) - { - textureObject = new TextureCubeMap(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), texture); - } - else if (type == GL_TEXTURE_3D) - { - textureObject = new Texture3D(mRenderer->createTexture(GL_TEXTURE_3D), texture); - } - else if (type == GL_TEXTURE_2D_ARRAY) - { - textureObject = new Texture2DArray(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), texture); - } - else - { - UNREACHABLE(); - return; - } - - mTextureMap[texture] = textureObject; - textureObject->addRef(); - } -} - -void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer) -{ - if (renderbuffer != 0 && !getRenderbuffer(renderbuffer)) - { - Renderbuffer *renderbufferObject = new Renderbuffer(mRenderer->createRenderbuffer(), renderbuffer); - mRenderbufferMap[renderbuffer] = renderbufferObject; - renderbufferObject->addRef(); - } -} - -void ResourceManager::checkSamplerAllocation(GLuint sampler) -{ - if (sampler != 0 && !getSampler(sampler)) - { - Sampler *samplerObject = new Sampler(sampler); - mSamplerMap[sampler] = samplerObject; - samplerObject->addRef(); - } -} - -bool ResourceManager::isSampler(GLuint sampler) -{ - return mSamplerMap.find(sampler) != mSamplerMap.end(); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.h b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h deleted file mode 100644 index acad29b51d..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/ResourceManager.h +++ /dev/null @@ -1,115 +0,0 @@ -// -// Copyright (c) 2002-2013 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_ - -#include "common/angleutils.h" -#include "libGLESv2/angletypes.h" -#include "libGLESv2/HandleAllocator.h" - -#include "angle_gl.h" - -#include - -namespace rx -{ -class Renderer; -} - -namespace gl -{ -class Buffer; -class Shader; -class Program; -class Texture; -class Renderbuffer; -class Sampler; -class FenceSync; -struct Data; - -class ResourceManager -{ - public: - explicit ResourceManager(rx::Renderer *renderer); - ~ResourceManager(); - - void addRef(); - void release(); - - GLuint createBuffer(); - GLuint createShader(const gl::Data &data, GLenum type); - GLuint createProgram(); - GLuint createTexture(); - GLuint createRenderbuffer(); - GLuint createSampler(); - GLuint createFenceSync(); - - void deleteBuffer(GLuint buffer); - void deleteShader(GLuint shader); - void deleteProgram(GLuint program); - void deleteTexture(GLuint texture); - void deleteRenderbuffer(GLuint renderbuffer); - void deleteSampler(GLuint sampler); - void deleteFenceSync(GLuint fenceSync); - - Buffer *getBuffer(GLuint handle); - Shader *getShader(GLuint handle); - Program *getProgram(GLuint handle) const; - Texture *getTexture(GLuint handle); - Renderbuffer *getRenderbuffer(GLuint handle); - Sampler *getSampler(GLuint handle); - FenceSync *getFenceSync(GLuint handle); - - void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer); - - void checkBufferAllocation(unsigned int buffer); - void checkTextureAllocation(GLuint texture, GLenum type); - void checkRenderbufferAllocation(GLuint renderbuffer); - void checkSamplerAllocation(GLuint sampler); - - bool isSampler(GLuint sampler); - - private: - DISALLOW_COPY_AND_ASSIGN(ResourceManager); - - rx::Renderer *mRenderer; - std::size_t mRefCount; - - typedef std::unordered_map BufferMap; - BufferMap mBufferMap; - HandleAllocator mBufferHandleAllocator; - - typedef std::unordered_map ShaderMap; - ShaderMap mShaderMap; - - typedef std::unordered_map ProgramMap; - ProgramMap mProgramMap; - HandleAllocator mProgramShaderHandleAllocator; - - typedef std::unordered_map TextureMap; - TextureMap mTextureMap; - HandleAllocator mTextureHandleAllocator; - - typedef std::unordered_map RenderbufferMap; - RenderbufferMap mRenderbufferMap; - HandleAllocator mRenderbufferHandleAllocator; - - typedef std::unordered_map SamplerMap; - SamplerMap mSamplerMap; - HandleAllocator mSamplerHandleAllocator; - - typedef std::unordered_map FenceMap; - FenceMap mFenceSyncMap; - HandleAllocator mFenceSyncHandleAllocator; -}; - -} - -#endif // LIBGLESV2_RESOURCEMANAGER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Sampler.cpp b/src/3rdparty/angle/src/libGLESv2/Sampler.cpp deleted file mode 100644 index b906e65557..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Sampler.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Sampler.cpp : Implements the Sampler class, which represents a GLES 3 -// sampler object. Sampler objects store some state needed to sample textures. - -#include "libGLESv2/Sampler.h" -#include "libGLESv2/angletypes.h" - -namespace gl -{ - -Sampler::Sampler(GLuint id) - : RefCountObject(id), - mMinFilter(GL_NEAREST_MIPMAP_LINEAR), - mMagFilter(GL_LINEAR), - mWrapS(GL_REPEAT), - mWrapT(GL_REPEAT), - mWrapR(GL_REPEAT), - mMinLod(-1000.0f), - mMaxLod(1000.0f), - mComparisonMode(GL_NONE), - mComparisonFunc(GL_LEQUAL) -{ -} - -void Sampler::getState(SamplerState *samplerState) const -{ - samplerState->minFilter = mMinFilter; - samplerState->magFilter = mMagFilter; - samplerState->wrapS = mWrapS; - samplerState->wrapT = mWrapT; - samplerState->wrapR = mWrapR; - samplerState->minLod = mMinLod; - samplerState->maxLod = mMaxLod; - samplerState->compareMode = mComparisonMode; - samplerState->compareFunc = mComparisonFunc; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Sampler.h b/src/3rdparty/angle/src/libGLESv2/Sampler.h deleted file mode 100644 index 257bc25d22..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Sampler.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Sampler.h : Defines the Sampler class, which represents a GLES 3 -// sampler object. Sampler objects store some state needed to sample textures. - -#ifndef LIBGLESV2_SAMPLER_H_ -#define LIBGLESV2_SAMPLER_H_ - -#include "common/RefCountObject.h" - -namespace gl -{ -struct SamplerState; - -class Sampler : public RefCountObject -{ - public: - Sampler(GLuint id); - - void setMinFilter(GLenum minFilter) { mMinFilter = minFilter; } - void setMagFilter(GLenum magFilter) { mMagFilter = magFilter; } - void setWrapS(GLenum wrapS) { mWrapS = wrapS; } - void setWrapT(GLenum wrapT) { mWrapT = wrapT; } - void setWrapR(GLenum wrapR) { mWrapR = wrapR; } - void setMinLod(GLfloat minLod) { mMinLod = minLod; } - void setMaxLod(GLfloat maxLod) { mMaxLod = maxLod; } - void setComparisonMode(GLenum comparisonMode) { mComparisonMode = comparisonMode; } - void setComparisonFunc(GLenum comparisonFunc) { mComparisonFunc = comparisonFunc; } - - GLenum getMinFilter() const { return mMinFilter; } - GLenum getMagFilter() const { return mMagFilter; } - GLenum getWrapS() const { return mWrapS; } - GLenum getWrapT() const { return mWrapT; } - GLenum getWrapR() const { return mWrapR; } - GLfloat getMinLod() const { return mMinLod; } - GLfloat getMaxLod() const { return mMaxLod; } - GLenum getComparisonMode() const { return mComparisonMode; } - GLenum getComparisonFunc() const { return mComparisonFunc; } - - void getState(SamplerState *samplerState) const; - - private: - GLenum mMinFilter; - GLenum mMagFilter; - GLenum mWrapS; - GLenum mWrapT; - GLenum mWrapR; - GLfloat mMinLod; - GLfloat mMaxLod; - GLenum mComparisonMode; - GLenum mComparisonFunc; -}; - -} - -#endif // LIBGLESV2_SAMPLER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp deleted file mode 100644 index 024ef8fb7c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Shader.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// -// Copyright (c) 2002-2014 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 "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/ShaderImpl.h" -#include "libGLESv2/Constants.h" -#include "libGLESv2/ResourceManager.h" - -#include "common/utilities.h" - -#include "GLSLANG/ShaderLang.h" - -#include - -namespace gl -{ - -Shader::Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLuint handle) - : mShader(impl), - mType(type), - mHandle(handle), - mResourceManager(manager), - mRefCount(0), - mDeleteStatus(false), - mCompiled(false) -{ - ASSERT(impl); -} - -Shader::~Shader() -{ - SafeDelete(mShader); -} - -GLuint Shader::getHandle() const -{ - return mHandle; -} - -void Shader::setSource(GLsizei count, const char *const *string, const GLint *length) -{ - std::ostringstream stream; - - for (int i = 0; i < count; i++) - { - if (length == nullptr || length[i] < 0) - { - stream.write(string[i], strlen(string[i])); - } - else - { - stream.write(string[i], length[i]); - } - } - - mSource = stream.str(); -} - -int Shader::getInfoLogLength() const -{ - return mShader->getInfoLog().empty() ? 0 : (mShader->getInfoLog().length() + 1); -} - -void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const -{ - int index = 0; - - if (bufSize > 0) - { - index = std::min(bufSize - 1, static_cast(mShader->getInfoLog().length())); - memcpy(infoLog, mShader->getInfoLog().c_str(), index); - - infoLog[index] = '\0'; - } - - if (length) - { - *length = index; - } -} - -int Shader::getSourceLength() const -{ - return mSource.empty() ? 0 : (mSource.length() + 1); -} - -int Shader::getTranslatedSourceLength() const -{ - return mShader->getTranslatedSource().empty() ? 0 : (mShader->getTranslatedSource().length() + 1); -} - -void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer) -{ - int index = 0; - - if (bufSize > 0) - { - index = std::min(bufSize - 1, static_cast(source.length())); - memcpy(buffer, source.c_str(), index); - - buffer[index] = '\0'; - } - - if (length) - { - *length = index; - } -} - -void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const -{ - getSourceImpl(mSource, bufSize, length, buffer); -} - -void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const -{ - getSourceImpl(mShader->getTranslatedSource(), bufSize, length, buffer); -} - -void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const -{ - std::string debugInfo(mShader->getDebugInfo()); - getSourceImpl(debugInfo, bufSize, length, buffer); -} - -void Shader::compile(const gl::Data &data) -{ - mCompiled = mShader->compile(data, mSource); -} - -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; -} - -const std::vector &Shader::getVaryings() const -{ - return mShader->getVaryings(); -} - -const std::vector &Shader::getUniforms() const -{ - return mShader->getUniforms(); -} - -const std::vector &Shader::getInterfaceBlocks() const -{ - return mShader->getInterfaceBlocks(); -} - -const std::vector &Shader::getActiveAttributes() const -{ - return mShader->getActiveAttributes(); -} - -const std::vector &Shader::getActiveOutputVariables() const -{ - return mShader->getActiveOutputVariables(); -} - -std::vector &Shader::getVaryings() -{ - return mShader->getVaryings(); -} - -std::vector &Shader::getUniforms() -{ - return mShader->getUniforms(); -} - -std::vector &Shader::getInterfaceBlocks() -{ - return mShader->getInterfaceBlocks(); -} - -std::vector &Shader::getActiveAttributes() -{ - return mShader->getActiveAttributes(); -} - -std::vector &Shader::getActiveOutputVariables() -{ - return mShader->getActiveOutputVariables(); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.h b/src/3rdparty/angle/src/libGLESv2/Shader.h deleted file mode 100644 index 904217dab8..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Shader.h +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (c) 2002-2013 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_ - - -#include -#include -#include - -#include "angle_gl.h" -#include - -#include "common/angleutils.h" -#include "libGLESv2/angletypes.h" - -namespace rx -{ -class ShaderImpl; -} - -namespace gl -{ -class ResourceManager; -struct Data; - -struct PackedVarying : public sh::Varying -{ - unsigned int registerIndex; // Assigned during link - unsigned int columnIndex; // Assigned during link, defaults to 0 - - PackedVarying(const sh::Varying &varying) - : sh::Varying(varying), - registerIndex(GL_INVALID_INDEX), - columnIndex(0) - {} - - bool registerAssigned() const { return registerIndex != GL_INVALID_INDEX; } - bool isBuiltIn() const { return name.compare(0, 3, "gl_") == 0; } - - void resetRegisterAssignment() - { - registerIndex = GL_INVALID_INDEX; - } -}; - -class Shader -{ - public: - Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLuint handle); - - virtual ~Shader(); - - GLenum getType() const { return mType; } - GLuint getHandle() const; - - rx::ShaderImpl *getImplementation() { return mShader; } - const rx::ShaderImpl *getImplementation() const { return mShader; } - - void deleteSource(); - void setSource(GLsizei count, const char *const *string, const GLint *length); - int getInfoLogLength() const; - void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const; - int getSourceLength() const; - void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const; - int getTranslatedSourceLength() const; - void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const; - void getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const; - - void compile(const gl::Data &data); - bool isCompiled() const { return mCompiled; } - - void addRef(); - void release(); - unsigned int getRefCount() const; - bool isFlaggedForDeletion() const; - void flagForDeletion(); - - const std::vector &getVaryings() const; - const std::vector &getUniforms() const; - const std::vector &getInterfaceBlocks() const; - const std::vector &getActiveAttributes() const; - const std::vector &getActiveOutputVariables() const; - - std::vector &getVaryings(); - std::vector &getUniforms(); - std::vector &getInterfaceBlocks(); - std::vector &getActiveAttributes(); - std::vector &getActiveOutputVariables(); - - private: - DISALLOW_COPY_AND_ASSIGN(Shader); - - static void getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer); - - rx::ShaderImpl *mShader; - const GLuint mHandle; - const GLenum mType; - std::string mSource; - 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 - bool mCompiled; // Indicates if this shader has been successfully compiled - - ResourceManager *mResourceManager; -}; - -} - -#endif // LIBGLESV2_SHADER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/State.cpp b/src/3rdparty/angle/src/libGLESv2/State.cpp deleted file mode 100644 index b5b62f5848..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/State.cpp +++ /dev/null @@ -1,1464 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// State.cpp: Implements the State class, encapsulating raw GL state. - -#include "libGLESv2/State.h" - -#include "libGLESv2/Context.h" -#include "libGLESv2/Caps.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/Query.h" -#include "libGLESv2/VertexArray.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/renderer/RenderTarget.h" - -namespace gl -{ - -State::State() -{ - mMaxDrawBuffers = 0; - mMaxCombinedTextureImageUnits = 0; -} - -State::~State() -{ - reset(); -} - -void State::initialize(const Caps& caps, GLuint clientVersion) -{ - mMaxDrawBuffers = caps.maxDrawBuffers; - mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; - - setClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - mDepthClearValue = 1.0f; - mStencilClearValue = 0; - - mRasterizer.rasterizerDiscard = false; - mRasterizer.cullFace = false; - mRasterizer.cullMode = GL_BACK; - mRasterizer.frontFace = GL_CCW; - mRasterizer.polygonOffsetFill = false; - mRasterizer.polygonOffsetFactor = 0.0f; - mRasterizer.polygonOffsetUnits = 0.0f; - mRasterizer.pointDrawMode = false; - mRasterizer.multiSample = false; - mScissorTest = false; - mScissor.x = 0; - mScissor.y = 0; - mScissor.width = 0; - mScissor.height = 0; - - mBlend.blend = false; - mBlend.sourceBlendRGB = GL_ONE; - mBlend.sourceBlendAlpha = GL_ONE; - mBlend.destBlendRGB = GL_ZERO; - mBlend.destBlendAlpha = GL_ZERO; - mBlend.blendEquationRGB = GL_FUNC_ADD; - mBlend.blendEquationAlpha = GL_FUNC_ADD; - mBlend.sampleAlphaToCoverage = false; - mBlend.dither = true; - - mBlendColor.red = 0; - mBlendColor.green = 0; - mBlendColor.blue = 0; - mBlendColor.alpha = 0; - - mDepthStencil.depthTest = false; - mDepthStencil.depthFunc = GL_LESS; - mDepthStencil.depthMask = true; - mDepthStencil.stencilTest = false; - mDepthStencil.stencilFunc = GL_ALWAYS; - mDepthStencil.stencilMask = -1; - mDepthStencil.stencilWritemask = -1; - mDepthStencil.stencilBackFunc = GL_ALWAYS; - mDepthStencil.stencilBackMask = -1; - mDepthStencil.stencilBackWritemask = -1; - mDepthStencil.stencilFail = GL_KEEP; - mDepthStencil.stencilPassDepthFail = GL_KEEP; - mDepthStencil.stencilPassDepthPass = GL_KEEP; - mDepthStencil.stencilBackFail = GL_KEEP; - mDepthStencil.stencilBackPassDepthFail = GL_KEEP; - mDepthStencil.stencilBackPassDepthPass = GL_KEEP; - - mStencilRef = 0; - mStencilBackRef = 0; - - mSampleCoverage = false; - mSampleCoverageValue = 1.0f; - mSampleCoverageInvert = false; - mGenerateMipmapHint = GL_DONT_CARE; - mFragmentShaderDerivativeHint = GL_DONT_CARE; - - mLineWidth = 1.0f; - - mViewport.x = 0; - mViewport.y = 0; - mViewport.width = 0; - mViewport.height = 0; - mNearZ = 0.0f; - mFarZ = 1.0f; - - mBlend.colorMaskRed = true; - mBlend.colorMaskGreen = true; - mBlend.colorMaskBlue = true; - mBlend.colorMaskAlpha = true; - - mActiveSampler = 0; - - const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - mVertexAttribCurrentValues.resize(caps.maxVertexAttributes); - for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); ++attribIndex) - { - mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); - } - - mUniformBuffers.resize(caps.maxCombinedUniformBlocks); - mTransformFeedbackBuffers.resize(caps.maxTransformFeedbackSeparateAttributes); - - mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits); - mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits); - if (clientVersion >= 3) - { - // TODO: These could also be enabled via extension - mSamplerTextures[GL_TEXTURE_2D_ARRAY].resize(caps.maxCombinedTextureImageUnits); - mSamplerTextures[GL_TEXTURE_3D].resize(caps.maxCombinedTextureImageUnits); - } - - mSamplers.resize(caps.maxCombinedTextureImageUnits); - - mActiveQueries[GL_ANY_SAMPLES_PASSED].set(NULL); - mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(NULL); - mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(NULL); - - mCurrentProgramId = 0; - mCurrentProgramBinary.set(NULL); - - mReadFramebuffer = NULL; - mDrawFramebuffer = NULL; -} - -void State::reset() -{ - for (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) - { - TextureBindingVector &textureVector = bindingVec->second; - for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) - { - textureVector[textureIdx].set(NULL); - } - } - for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++) - { - mSamplers[samplerIdx].set(NULL); - } - - mArrayBuffer.set(NULL); - mRenderbuffer.set(NULL); - - mTransformFeedback.set(NULL); - - for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++) - { - i->second.set(NULL); - } - - mGenericUniformBuffer.set(NULL); - mGenericTransformFeedbackBuffer.set(NULL); - for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr) - { - bufItr->set(NULL); - } - - for (BufferVector::iterator bufItr = mTransformFeedbackBuffers.begin(); bufItr != mTransformFeedbackBuffers.end(); ++bufItr) - { - bufItr->set(NULL); - } - - mCopyReadBuffer.set(NULL); - mCopyWriteBuffer.set(NULL); - - mPack.pixelBuffer.set(NULL); - mUnpack.pixelBuffer.set(NULL); -} - -const RasterizerState &State::getRasterizerState() const -{ - return mRasterizer; -} - -const BlendState &State::getBlendState() const -{ - return mBlend; -} - -const DepthStencilState &State::getDepthStencilState() const -{ - return mDepthStencil; -} - -void State::setClearColor(float red, float green, float blue, float alpha) -{ - mColorClearValue.red = red; - mColorClearValue.green = green; - mColorClearValue.blue = blue; - mColorClearValue.alpha = alpha; -} - -void State::setClearDepth(float depth) -{ - mDepthClearValue = depth; -} - -void State::setClearStencil(int stencil) -{ - mStencilClearValue = stencil; -} - -ClearParameters State::getClearParameters(GLbitfield mask) const -{ - ClearParameters clearParams = { 0 }; - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - clearParams.clearColor[i] = false; - } - clearParams.colorFClearValue = mColorClearValue; - clearParams.colorClearType = GL_FLOAT; - clearParams.colorMaskRed = mBlend.colorMaskRed; - clearParams.colorMaskGreen = mBlend.colorMaskGreen; - clearParams.colorMaskBlue = mBlend.colorMaskBlue; - clearParams.colorMaskAlpha = mBlend.colorMaskAlpha; - clearParams.clearDepth = false; - clearParams.depthClearValue = mDepthClearValue; - clearParams.clearStencil = false; - clearParams.stencilClearValue = mStencilClearValue; - clearParams.stencilWriteMask = mDepthStencil.stencilWritemask; - clearParams.scissorEnabled = mScissorTest; - clearParams.scissor = mScissor; - - const Framebuffer *framebufferObject = getDrawFramebuffer(); - if (mask & GL_COLOR_BUFFER_BIT) - { - if (framebufferObject->hasEnabledColorAttachment()) - { - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - clearParams.clearColor[i] = true; - } - } - } - - if (mask & GL_DEPTH_BUFFER_BIT) - { - if (mDepthStencil.depthMask && framebufferObject->getDepthbuffer() != NULL) - { - clearParams.clearDepth = true; - } - } - - if (mask & GL_STENCIL_BUFFER_BIT) - { - if (framebufferObject->getStencilbuffer() != NULL) - { - GLenum stencilActualFormat = framebufferObject->getStencilbuffer()->getActualFormat(); - if (GetInternalFormatInfo(stencilActualFormat).stencilBits > 0) - { - clearParams.clearStencil = true; - } - } - } - - return clearParams; -} - -void State::setColorMask(bool red, bool green, bool blue, bool alpha) -{ - mBlend.colorMaskRed = red; - mBlend.colorMaskGreen = green; - mBlend.colorMaskBlue = blue; - mBlend.colorMaskAlpha = alpha; -} - -void State::setDepthMask(bool mask) -{ - mDepthStencil.depthMask = mask; -} - -bool State::isRasterizerDiscardEnabled() const -{ - return mRasterizer.rasterizerDiscard; -} - -void State::setRasterizerDiscard(bool enabled) -{ - mRasterizer.rasterizerDiscard = enabled; -} - -bool State::isCullFaceEnabled() const -{ - return mRasterizer.cullFace; -} - -void State::setCullFace(bool enabled) -{ - mRasterizer.cullFace = enabled; -} - -void State::setCullMode(GLenum mode) -{ - mRasterizer.cullMode = mode; -} - -void State::setFrontFace(GLenum front) -{ - mRasterizer.frontFace = front; -} - -bool State::isDepthTestEnabled() const -{ - return mDepthStencil.depthTest; -} - -void State::setDepthTest(bool enabled) -{ - mDepthStencil.depthTest = enabled; -} - -void State::setDepthFunc(GLenum depthFunc) -{ - mDepthStencil.depthFunc = depthFunc; -} - -void State::setDepthRange(float zNear, float zFar) -{ - mNearZ = zNear; - mFarZ = zFar; -} - -void State::getDepthRange(float *zNear, float *zFar) const -{ - *zNear = mNearZ; - *zFar = mFarZ; -} - -bool State::isBlendEnabled() const -{ - return mBlend.blend; -} - -void State::setBlend(bool enabled) -{ - mBlend.blend = enabled; -} - -void State::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha) -{ - mBlend.sourceBlendRGB = sourceRGB; - mBlend.destBlendRGB = destRGB; - mBlend.sourceBlendAlpha = sourceAlpha; - mBlend.destBlendAlpha = destAlpha; -} - -void State::setBlendColor(float red, float green, float blue, float alpha) -{ - mBlendColor.red = red; - mBlendColor.green = green; - mBlendColor.blue = blue; - mBlendColor.alpha = alpha; -} - -void State::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation) -{ - mBlend.blendEquationRGB = rgbEquation; - mBlend.blendEquationAlpha = alphaEquation; -} - -const ColorF &State::getBlendColor() const -{ - return mBlendColor; -} - -bool State::isStencilTestEnabled() const -{ - return mDepthStencil.stencilTest; -} - -void State::setStencilTest(bool enabled) -{ - mDepthStencil.stencilTest = enabled; -} - -void State::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask) -{ - mDepthStencil.stencilFunc = stencilFunc; - mStencilRef = (stencilRef > 0) ? stencilRef : 0; - mDepthStencil.stencilMask = stencilMask; -} - -void State::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask) -{ - mDepthStencil.stencilBackFunc = stencilBackFunc; - mStencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0; - mDepthStencil.stencilBackMask = stencilBackMask; -} - -void State::setStencilWritemask(GLuint stencilWritemask) -{ - mDepthStencil.stencilWritemask = stencilWritemask; -} - -void State::setStencilBackWritemask(GLuint stencilBackWritemask) -{ - mDepthStencil.stencilBackWritemask = stencilBackWritemask; -} - -void State::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass) -{ - mDepthStencil.stencilFail = stencilFail; - mDepthStencil.stencilPassDepthFail = stencilPassDepthFail; - mDepthStencil.stencilPassDepthPass = stencilPassDepthPass; -} - -void State::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass) -{ - mDepthStencil.stencilBackFail = stencilBackFail; - mDepthStencil.stencilBackPassDepthFail = stencilBackPassDepthFail; - mDepthStencil.stencilBackPassDepthPass = stencilBackPassDepthPass; -} - -GLint State::getStencilRef() const -{ - return mStencilRef; -} - -GLint State::getStencilBackRef() const -{ - return mStencilBackRef; -} - -bool State::isPolygonOffsetFillEnabled() const -{ - return mRasterizer.polygonOffsetFill; -} - -void State::setPolygonOffsetFill(bool enabled) -{ - mRasterizer.polygonOffsetFill = enabled; -} - -void State::setPolygonOffsetParams(GLfloat factor, GLfloat units) -{ - // An application can pass NaN values here, so handle this gracefully - mRasterizer.polygonOffsetFactor = factor != factor ? 0.0f : factor; - mRasterizer.polygonOffsetUnits = units != units ? 0.0f : units; -} - -bool State::isSampleAlphaToCoverageEnabled() const -{ - return mBlend.sampleAlphaToCoverage; -} - -void State::setSampleAlphaToCoverage(bool enabled) -{ - mBlend.sampleAlphaToCoverage = enabled; -} - -bool State::isSampleCoverageEnabled() const -{ - return mSampleCoverage; -} - -void State::setSampleCoverage(bool enabled) -{ - mSampleCoverage = enabled; -} - -void State::setSampleCoverageParams(GLclampf value, bool invert) -{ - mSampleCoverageValue = value; - mSampleCoverageInvert = invert; -} - -void State::getSampleCoverageParams(GLclampf *value, bool *invert) const -{ - ASSERT(value != NULL && invert != NULL); - - *value = mSampleCoverageValue; - *invert = mSampleCoverageInvert; -} - -bool State::isScissorTestEnabled() const -{ - return mScissorTest; -} - -void State::setScissorTest(bool enabled) -{ - mScissorTest = enabled; -} - -void State::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height) -{ - mScissor.x = x; - mScissor.y = y; - mScissor.width = width; - mScissor.height = height; -} - -const Rectangle &State::getScissor() const -{ - return mScissor; -} - -bool State::isDitherEnabled() const -{ - return mBlend.dither; -} - -void State::setDither(bool enabled) -{ - mBlend.dither = enabled; -} - -void State::setEnableFeature(GLenum feature, bool enabled) -{ - switch (feature) - { - case GL_CULL_FACE: setCullFace(enabled); break; - case GL_POLYGON_OFFSET_FILL: setPolygonOffsetFill(enabled); break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: setSampleAlphaToCoverage(enabled); break; - case GL_SAMPLE_COVERAGE: setSampleCoverage(enabled); break; - case GL_SCISSOR_TEST: setScissorTest(enabled); break; - case GL_STENCIL_TEST: setStencilTest(enabled); break; - case GL_DEPTH_TEST: setDepthTest(enabled); break; - case GL_BLEND: setBlend(enabled); break; - case GL_DITHER: setDither(enabled); break; - case GL_PRIMITIVE_RESTART_FIXED_INDEX: UNIMPLEMENTED(); break; - case GL_RASTERIZER_DISCARD: setRasterizerDiscard(enabled); break; - default: UNREACHABLE(); - } -} - -bool State::getEnableFeature(GLenum feature) -{ - switch (feature) - { - case GL_CULL_FACE: return isCullFaceEnabled(); - case GL_POLYGON_OFFSET_FILL: return isPolygonOffsetFillEnabled(); - case GL_SAMPLE_ALPHA_TO_COVERAGE: return isSampleAlphaToCoverageEnabled(); - case GL_SAMPLE_COVERAGE: return isSampleCoverageEnabled(); - case GL_SCISSOR_TEST: return isScissorTestEnabled(); - case GL_STENCIL_TEST: return isStencilTestEnabled(); - case GL_DEPTH_TEST: return isDepthTestEnabled(); - case GL_BLEND: return isBlendEnabled(); - case GL_DITHER: return isDitherEnabled(); - case GL_PRIMITIVE_RESTART_FIXED_INDEX: UNIMPLEMENTED(); return false; - case GL_RASTERIZER_DISCARD: return isRasterizerDiscardEnabled(); - default: UNREACHABLE(); return false; - } -} - -void State::setLineWidth(GLfloat width) -{ - mLineWidth = width; -} - -void State::setGenerateMipmapHint(GLenum hint) -{ - mGenerateMipmapHint = hint; -} - -void State::setFragmentShaderDerivativeHint(GLenum hint) -{ - mFragmentShaderDerivativeHint = 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 State::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height) -{ - mViewport.x = x; - mViewport.y = y; - mViewport.width = width; - mViewport.height = height; -} - -const Rectangle &State::getViewport() const -{ - return mViewport; -} - -void State::setActiveSampler(unsigned int active) -{ - mActiveSampler = active; -} - -unsigned int State::getActiveSampler() const -{ - return mActiveSampler; -} - -void State::setSamplerTexture(GLenum type, Texture *texture) -{ - mSamplerTextures[type][mActiveSampler].set(texture); -} - -Texture *State::getSamplerTexture(unsigned int sampler, GLenum type) const -{ - return mSamplerTextures.at(type)[sampler].get(); -} - -GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const -{ - return mSamplerTextures.at(type)[sampler].id(); -} - -void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) -{ - // Textures have a detach method on State rather than a simple - // removeBinding, because the zero/null texture objects are managed - // separately, and don't have to go through the Context's maps or - // the ResourceManager. - - // [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 (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) - { - GLenum textureType = bindingVec->first; - TextureBindingVector &textureVector = bindingVec->second; - for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) - { - BindingPointer &binding = textureVector[textureIdx]; - if (binding.id() == texture) - { - // Zero textures are the "default" textures instead of NULL - binding.set(zeroTextures.at(textureType).get()); - } - } - } - - // [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 Texture2DAttachment had been called, with a texture of 0, for each attachment point to which this - // image was attached in the currently bound framebuffer. - - if (mReadFramebuffer) - { - mReadFramebuffer->detachTexture(texture); - } - - if (mDrawFramebuffer) - { - mDrawFramebuffer->detachTexture(texture); - } -} - -void State::initializeZeroTextures(const TextureMap &zeroTextures) -{ - for (TextureMap::const_iterator i = zeroTextures.begin(); i != zeroTextures.end(); i++) - { - TextureBindingVector &samplerTextureArray = mSamplerTextures[i->first]; - - for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) - { - samplerTextureArray[textureUnit].set(i->second.get()); - } - } -} - -void State::setSamplerBinding(GLuint textureUnit, Sampler *sampler) -{ - mSamplers[textureUnit].set(sampler); -} - -GLuint State::getSamplerId(GLuint textureUnit) const -{ - ASSERT(textureUnit < mSamplers.size()); - return mSamplers[textureUnit].id(); -} - -Sampler *State::getSampler(GLuint textureUnit) const -{ - return mSamplers[textureUnit].get(); -} - -void State::detachSampler(GLuint sampler) -{ - // [OpenGL ES 3.0.2] section 3.8.2 pages 123-124: - // If a sampler object that is currently bound to one or more texture units is - // deleted, it is as though BindSampler is called once for each texture unit to - // which the sampler is bound, with unit set to the texture unit and sampler set to zero. - for (size_t textureUnit = 0; textureUnit < mSamplers.size(); textureUnit++) - { - BindingPointer &samplerBinding = mSamplers[textureUnit]; - if (samplerBinding.id() == sampler) - { - samplerBinding.set(NULL); - } - } -} - -void State::setRenderbufferBinding(Renderbuffer *renderbuffer) -{ - mRenderbuffer.set(renderbuffer); -} - -GLuint State::getRenderbufferId() const -{ - return mRenderbuffer.id(); -} - -Renderbuffer *State::getCurrentRenderbuffer() -{ - return mRenderbuffer.get(); -} - -void State::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 (mRenderbuffer.id() == renderbuffer) - { - mRenderbuffer.set(NULL); - } - - // [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 = mReadFramebuffer; - Framebuffer *drawFramebuffer = mDrawFramebuffer; - - if (readFramebuffer) - { - readFramebuffer->detachRenderbuffer(renderbuffer); - } - - if (drawFramebuffer && drawFramebuffer != readFramebuffer) - { - drawFramebuffer->detachRenderbuffer(renderbuffer); - } - -} - -void State::setReadFramebufferBinding(Framebuffer *framebuffer) -{ - mReadFramebuffer = framebuffer; -} - -void State::setDrawFramebufferBinding(Framebuffer *framebuffer) -{ - mDrawFramebuffer = framebuffer; -} - -Framebuffer *State::getTargetFramebuffer(GLenum target) const -{ - switch (target) - { - case GL_READ_FRAMEBUFFER_ANGLE: return mReadFramebuffer; - case GL_DRAW_FRAMEBUFFER_ANGLE: - case GL_FRAMEBUFFER: return mDrawFramebuffer; - default: UNREACHABLE(); return NULL; - } -} - -Framebuffer *State::getReadFramebuffer() -{ - return mReadFramebuffer; -} - -Framebuffer *State::getDrawFramebuffer() -{ - return mDrawFramebuffer; -} - -const Framebuffer *State::getReadFramebuffer() const -{ - return mReadFramebuffer; -} - -const Framebuffer *State::getDrawFramebuffer() const -{ - return mDrawFramebuffer; -} - -bool State::removeReadFramebufferBinding(GLuint framebuffer) -{ - if (mReadFramebuffer->id() == framebuffer) - { - mReadFramebuffer = NULL; - return true; - } - - return false; -} - -bool State::removeDrawFramebufferBinding(GLuint framebuffer) -{ - if (mDrawFramebuffer->id() == framebuffer) - { - mDrawFramebuffer = NULL; - return true; - } - - return false; -} - -void State::setVertexArrayBinding(VertexArray *vertexArray) -{ - mVertexArray = vertexArray; -} - -GLuint State::getVertexArrayId() const -{ - ASSERT(mVertexArray != NULL); - return mVertexArray->id(); -} - -VertexArray *State::getVertexArray() const -{ - ASSERT(mVertexArray != NULL); - return mVertexArray; -} - -bool State::removeVertexArrayBinding(GLuint vertexArray) -{ - if (mVertexArray->id() == vertexArray) - { - mVertexArray = NULL; - return true; - } - - return false; -} - -void State::setCurrentProgram(GLuint programId, Program *newProgram) -{ - mCurrentProgramId = programId; // set new ID before trying to delete program binary; otherwise it will only be flagged for deletion - mCurrentProgramBinary.set(NULL); - - if (newProgram) - { - newProgram->addRef(); - mCurrentProgramBinary.set(newProgram->getProgramBinary()); - } -} - -void State::setCurrentProgramBinary(ProgramBinary *binary) -{ - mCurrentProgramBinary.set(binary); -} - -GLuint State::getCurrentProgramId() const -{ - return mCurrentProgramId; -} - -ProgramBinary *State::getCurrentProgramBinary() const -{ - return mCurrentProgramBinary.get(); -} - -void State::setTransformFeedbackBinding(TransformFeedback *transformFeedback) -{ - mTransformFeedback.set(transformFeedback); -} - -TransformFeedback *State::getCurrentTransformFeedback() const -{ - return mTransformFeedback.get(); -} - -void State::detachTransformFeedback(GLuint transformFeedback) -{ - if (mTransformFeedback.id() == transformFeedback) - { - mTransformFeedback.set(NULL); - } -} - -bool State::isQueryActive() const -{ - for (State::ActiveQueryMap::const_iterator i = mActiveQueries.begin(); - i != mActiveQueries.end(); i++) - { - if (i->second.get() != NULL) - { - return true; - } - } - - return false; -} - -void State::setActiveQuery(GLenum target, Query *query) -{ - mActiveQueries[target].set(query); -} - -GLuint State::getActiveQueryId(GLenum target) const -{ - const Query *query = getActiveQuery(target); - return (query ? query->id() : 0u); -} - -Query *State::getActiveQuery(GLenum target) const -{ - // All query types should already exist in the activeQueries map - ASSERT(mActiveQueries.find(target) != mActiveQueries.end()); - - return mActiveQueries.at(target).get(); -} - -void State::setArrayBufferBinding(Buffer *buffer) -{ - mArrayBuffer.set(buffer); -} - -GLuint State::getArrayBufferId() const -{ - return mArrayBuffer.id(); -} - -bool State::removeArrayBufferBinding(GLuint buffer) -{ - if (mArrayBuffer.id() == buffer) - { - mArrayBuffer.set(NULL); - return true; - } - - return false; -} - -void State::setGenericUniformBufferBinding(Buffer *buffer) -{ - mGenericUniformBuffer.set(buffer); -} - -void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) -{ - mUniformBuffers[index].set(buffer, offset, size); -} - -GLuint State::getIndexedUniformBufferId(GLuint index) const -{ - ASSERT(static_cast(index) < mUniformBuffers.size()); - - return mUniformBuffers[index].id(); -} - -Buffer *State::getIndexedUniformBuffer(GLuint index) const -{ - ASSERT(static_cast(index) < mUniformBuffers.size()); - - return mUniformBuffers[index].get(); -} - -void State::setGenericTransformFeedbackBufferBinding(Buffer *buffer) -{ - mGenericTransformFeedbackBuffer.set(buffer); -} - -void State::setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size) -{ - mTransformFeedbackBuffers[index].set(buffer, offset, size); -} - -GLuint State::getIndexedTransformFeedbackBufferId(GLuint index) const -{ - ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); - - return mTransformFeedbackBuffers[index].id(); -} - -Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const -{ - ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); - - return mTransformFeedbackBuffers[index].get(); -} - -GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const -{ - ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); - - return mTransformFeedbackBuffers[index].getOffset(); -} - -size_t State::getTransformFeedbackBufferIndexRange() const -{ - return mTransformFeedbackBuffers.size(); -} - -void State::setCopyReadBufferBinding(Buffer *buffer) -{ - mCopyReadBuffer.set(buffer); -} - -void State::setCopyWriteBufferBinding(Buffer *buffer) -{ - mCopyWriteBuffer.set(buffer); -} - -void State::setPixelPackBufferBinding(Buffer *buffer) -{ - mPack.pixelBuffer.set(buffer); -} - -void State::setPixelUnpackBufferBinding(Buffer *buffer) -{ - mUnpack.pixelBuffer.set(buffer); -} - -Buffer *State::getTargetBuffer(GLenum target) const -{ - switch (target) - { - case GL_ARRAY_BUFFER: return mArrayBuffer.get(); - case GL_COPY_READ_BUFFER: return mCopyReadBuffer.get(); - case GL_COPY_WRITE_BUFFER: return mCopyWriteBuffer.get(); - case GL_ELEMENT_ARRAY_BUFFER: return getVertexArray()->getElementArrayBuffer(); - case GL_PIXEL_PACK_BUFFER: return mPack.pixelBuffer.get(); - case GL_PIXEL_UNPACK_BUFFER: return mUnpack.pixelBuffer.get(); - case GL_TRANSFORM_FEEDBACK_BUFFER: return mGenericTransformFeedbackBuffer.get(); - case GL_UNIFORM_BUFFER: return mGenericUniformBuffer.get(); - default: UNREACHABLE(); return NULL; - } -} - -void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) -{ - getVertexArray()->enableAttribute(attribNum, enabled); -} - -void State::setVertexAttribf(GLuint index, const GLfloat values[4]) -{ - ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); - mVertexAttribCurrentValues[index].setFloatValues(values); -} - -void State::setVertexAttribu(GLuint index, const GLuint values[4]) -{ - ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); - mVertexAttribCurrentValues[index].setUnsignedIntValues(values); -} - -void State::setVertexAttribi(GLuint index, const GLint values[4]) -{ - ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); - mVertexAttribCurrentValues[index].setIntValues(values); -} - -void State::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized, - bool pureInteger, GLsizei stride, const void *pointer) -{ - getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer); -} - -const VertexAttribute &State::getVertexAttribState(unsigned int attribNum) const -{ - return getVertexArray()->getVertexAttribute(attribNum); -} - -const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const -{ - ASSERT(static_cast(attribNum) < mVertexAttribCurrentValues.size()); - return mVertexAttribCurrentValues[attribNum]; -} - -const void *State::getVertexAttribPointer(unsigned int attribNum) const -{ - return getVertexArray()->getVertexAttribute(attribNum).pointer; -} - -void State::setPackAlignment(GLint alignment) -{ - mPack.alignment = alignment; -} - -GLint State::getPackAlignment() const -{ - return mPack.alignment; -} - -void State::setPackReverseRowOrder(bool reverseRowOrder) -{ - mPack.reverseRowOrder = reverseRowOrder; -} - -bool State::getPackReverseRowOrder() const -{ - return mPack.reverseRowOrder; -} - -const PixelPackState &State::getPackState() const -{ - return mPack; -} - -void State::setUnpackAlignment(GLint alignment) -{ - mUnpack.alignment = alignment; -} - -GLint State::getUnpackAlignment() const -{ - return mUnpack.alignment; -} - -const PixelUnpackState &State::getUnpackState() const -{ - return mUnpack; -} - -void State::getBooleanv(GLenum pname, GLboolean *params) -{ - switch (pname) - { - case GL_SAMPLE_COVERAGE_INVERT: *params = mSampleCoverageInvert; break; - case GL_DEPTH_WRITEMASK: *params = mDepthStencil.depthMask; break; - case GL_COLOR_WRITEMASK: - params[0] = mBlend.colorMaskRed; - params[1] = mBlend.colorMaskGreen; - params[2] = mBlend.colorMaskBlue; - params[3] = mBlend.colorMaskAlpha; - break; - case GL_CULL_FACE: *params = mRasterizer.cullFace; break; - case GL_POLYGON_OFFSET_FILL: *params = mRasterizer.polygonOffsetFill; break; - case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mBlend.sampleAlphaToCoverage; break; - case GL_SAMPLE_COVERAGE: *params = mSampleCoverage; break; - case GL_SCISSOR_TEST: *params = mScissorTest; break; - case GL_STENCIL_TEST: *params = mDepthStencil.stencilTest; break; - case GL_DEPTH_TEST: *params = mDepthStencil.depthTest; break; - case GL_BLEND: *params = mBlend.blend; break; - case GL_DITHER: *params = mBlend.dither; break; - case GL_TRANSFORM_FEEDBACK_ACTIVE: *params = getCurrentTransformFeedback()->isStarted(); break; - case GL_TRANSFORM_FEEDBACK_PAUSED: *params = getCurrentTransformFeedback()->isPaused(); break; - default: - UNREACHABLE(); - break; - } -} - -void State::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 = mLineWidth; break; - case GL_SAMPLE_COVERAGE_VALUE: *params = mSampleCoverageValue; break; - case GL_DEPTH_CLEAR_VALUE: *params = mDepthClearValue; break; - case GL_POLYGON_OFFSET_FACTOR: *params = mRasterizer.polygonOffsetFactor; break; - case GL_POLYGON_OFFSET_UNITS: *params = mRasterizer.polygonOffsetUnits; break; - case GL_DEPTH_RANGE: - params[0] = mNearZ; - params[1] = mFarZ; - break; - case GL_COLOR_CLEAR_VALUE: - params[0] = mColorClearValue.red; - params[1] = mColorClearValue.green; - params[2] = mColorClearValue.blue; - params[3] = mColorClearValue.alpha; - break; - case GL_BLEND_COLOR: - params[0] = mBlendColor.red; - params[1] = mBlendColor.green; - params[2] = mBlendColor.blue; - params[3] = mBlendColor.alpha; - break; - default: - UNREACHABLE(); - break; - } -} - -void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) -{ - if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) - { - unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT); - ASSERT(colorAttachment < mMaxDrawBuffers); - Framebuffer *framebuffer = mDrawFramebuffer; - *params = framebuffer->getDrawBufferState(colorAttachment); - return; - } - - // 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 - // State::getFloatv. - switch (pname) - { - case GL_ARRAY_BUFFER_BINDING: *params = mArrayBuffer.id(); break; - case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = getVertexArray()->getElementArrayBufferId(); break; - //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE - case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mDrawFramebuffer->id(); break; - case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mReadFramebuffer->id(); break; - case GL_RENDERBUFFER_BINDING: *params = mRenderbuffer.id(); break; - case GL_VERTEX_ARRAY_BINDING: *params = mVertexArray->id(); break; - case GL_CURRENT_PROGRAM: *params = mCurrentProgramId; break; - case GL_PACK_ALIGNMENT: *params = mPack.alignment; break; - case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mPack.reverseRowOrder; break; - case GL_UNPACK_ALIGNMENT: *params = mUnpack.alignment; break; - case GL_GENERATE_MIPMAP_HINT: *params = mGenerateMipmapHint; break; - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mFragmentShaderDerivativeHint; break; - case GL_ACTIVE_TEXTURE: *params = (mActiveSampler + GL_TEXTURE0); break; - case GL_STENCIL_FUNC: *params = mDepthStencil.stencilFunc; break; - case GL_STENCIL_REF: *params = mStencilRef; break; - case GL_STENCIL_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilMask); break; - case GL_STENCIL_BACK_FUNC: *params = mDepthStencil.stencilBackFunc; break; - case GL_STENCIL_BACK_REF: *params = mStencilBackRef; break; - case GL_STENCIL_BACK_VALUE_MASK: *params = clampToInt(mDepthStencil.stencilBackMask); break; - case GL_STENCIL_FAIL: *params = mDepthStencil.stencilFail; break; - case GL_STENCIL_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilPassDepthFail; break; - case GL_STENCIL_PASS_DEPTH_PASS: *params = mDepthStencil.stencilPassDepthPass; break; - case GL_STENCIL_BACK_FAIL: *params = mDepthStencil.stencilBackFail; break; - case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mDepthStencil.stencilBackPassDepthFail; break; - case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mDepthStencil.stencilBackPassDepthPass; break; - case GL_DEPTH_FUNC: *params = mDepthStencil.depthFunc; break; - case GL_BLEND_SRC_RGB: *params = mBlend.sourceBlendRGB; break; - case GL_BLEND_SRC_ALPHA: *params = mBlend.sourceBlendAlpha; break; - case GL_BLEND_DST_RGB: *params = mBlend.destBlendRGB; break; - case GL_BLEND_DST_ALPHA: *params = mBlend.destBlendAlpha; break; - case GL_BLEND_EQUATION_RGB: *params = mBlend.blendEquationRGB; break; - case GL_BLEND_EQUATION_ALPHA: *params = mBlend.blendEquationAlpha; break; - case GL_STENCIL_WRITEMASK: *params = clampToInt(mDepthStencil.stencilWritemask); break; - case GL_STENCIL_BACK_WRITEMASK: *params = clampToInt(mDepthStencil.stencilBackWritemask); break; - case GL_STENCIL_CLEAR_VALUE: *params = mStencilClearValue; break; - case GL_SAMPLE_BUFFERS: - case GL_SAMPLES: - { - gl::Framebuffer *framebuffer = mDrawFramebuffer; - if (framebuffer->completeness(data) == GL_FRAMEBUFFER_COMPLETE) - { - switch (pname) - { - case GL_SAMPLE_BUFFERS: - if (framebuffer->getSamples(data) != 0) - { - *params = 1; - } - else - { - *params = 0; - } - break; - case GL_SAMPLES: - *params = framebuffer->getSamples(data); - break; - } - } - else - { - *params = 0; - } - } - break; - case GL_VIEWPORT: - params[0] = mViewport.x; - params[1] = mViewport.y; - params[2] = mViewport.width; - params[3] = mViewport.height; - break; - case GL_SCISSOR_BOX: - params[0] = mScissor.x; - params[1] = mScissor.y; - params[2] = mScissor.width; - params[3] = mScissor.height; - break; - case GL_CULL_FACE_MODE: *params = mRasterizer.cullMode; break; - case GL_FRONT_FACE: *params = mRasterizer.frontFace; break; - case GL_RED_BITS: - case GL_GREEN_BITS: - case GL_BLUE_BITS: - case GL_ALPHA_BITS: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::FramebufferAttachment *colorbuffer = framebuffer->getFirstColorbuffer(); - - 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::FramebufferAttachment *depthbuffer = framebuffer->getDepthbuffer(); - - if (depthbuffer) - { - *params = depthbuffer->getDepthSize(); - } - else - { - *params = 0; - } - } - break; - case GL_STENCIL_BITS: - { - gl::Framebuffer *framebuffer = getDrawFramebuffer(); - gl::FramebufferAttachment *stencilbuffer = framebuffer->getStencilbuffer(); - - if (stencilbuffer) - { - *params = stencilbuffer->getStencilSize(); - } - else - { - *params = 0; - } - } - break; - case GL_TEXTURE_BINDING_2D: - ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); - *params = mSamplerTextures.at(GL_TEXTURE_2D)[mActiveSampler].id(); - break; - case GL_TEXTURE_BINDING_CUBE_MAP: - ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); - *params = mSamplerTextures.at(GL_TEXTURE_CUBE_MAP)[mActiveSampler].id(); - break; - case GL_TEXTURE_BINDING_3D: - ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); - *params = mSamplerTextures.at(GL_TEXTURE_3D)[mActiveSampler].id(); - break; - case GL_TEXTURE_BINDING_2D_ARRAY: - ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); - *params = mSamplerTextures.at(GL_TEXTURE_2D_ARRAY)[mActiveSampler].id(); - break; - case GL_UNIFORM_BUFFER_BINDING: - *params = mGenericUniformBuffer.id(); - break; - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - *params = mGenericTransformFeedbackBuffer.id(); - break; - case GL_COPY_READ_BUFFER_BINDING: - *params = mCopyReadBuffer.id(); - break; - case GL_COPY_WRITE_BUFFER_BINDING: - *params = mCopyWriteBuffer.id(); - break; - case GL_PIXEL_PACK_BUFFER_BINDING: - *params = mPack.pixelBuffer.id(); - break; - case GL_PIXEL_UNPACK_BUFFER_BINDING: - *params = mUnpack.pixelBuffer.id(); - break; - default: - UNREACHABLE(); - break; - } -} - -bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) -{ - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (static_cast(index) < mTransformFeedbackBuffers.size()) - { - *data = mTransformFeedbackBuffers[index].id(); - } - break; - case GL_UNIFORM_BUFFER_BINDING: - if (static_cast(index) < mUniformBuffers.size()) - { - *data = mUniformBuffers[index].id(); - } - break; - default: - return false; - } - - return true; -} - -bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) -{ - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER_START: - if (static_cast(index) < mTransformFeedbackBuffers.size()) - { - *data = mTransformFeedbackBuffers[index].getOffset(); - } - break; - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - if (static_cast(index) < mTransformFeedbackBuffers.size()) - { - *data = mTransformFeedbackBuffers[index].getSize(); - } - break; - case GL_UNIFORM_BUFFER_START: - if (static_cast(index) < mUniformBuffers.size()) - { - *data = mUniformBuffers[index].getOffset(); - } - break; - case GL_UNIFORM_BUFFER_SIZE: - if (static_cast(index) < mUniformBuffers.size()) - { - *data = mUniformBuffers[index].getSize(); - } - break; - default: - return false; - } - - return true; -} - -bool State::hasMappedBuffer(GLenum target) const -{ - if (target == GL_ARRAY_BUFFER) - { - for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); attribIndex++) - { - const gl::VertexAttribute &vertexAttrib = getVertexAttribState(static_cast(attribIndex)); - gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); - if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) - { - return true; - } - } - - return false; - } - else - { - Buffer *buffer = getTargetBuffer(target); - return (buffer && buffer->isMapped()); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/State.h b/src/3rdparty/angle/src/libGLESv2/State.h deleted file mode 100644 index c3e6106bd8..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/State.h +++ /dev/null @@ -1,325 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// State.h: Defines the State class, encapsulating raw GL state - -#ifndef LIBGLESV2_STATE_H_ -#define LIBGLESV2_STATE_H_ - -#include "common/angleutils.h" -#include "common/RefCountObject.h" -#include "libGLESv2/angletypes.h" -#include "libGLESv2/VertexAttribute.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/TransformFeedback.h" -#include "libGLESv2/Program.h" -#include "libGLESv2/Sampler.h" - -namespace gl -{ -class Query; -class VertexArray; -class Context; -struct Caps; -struct Data; - -typedef std::map< GLenum, BindingPointer > TextureMap; - -class State -{ - public: - State(); - ~State(); - - void initialize(const Caps& caps, GLuint clientVersion); - void reset(); - - // State chunk getters - const RasterizerState &getRasterizerState() const; - const BlendState &getBlendState() const; - const DepthStencilState &getDepthStencilState() const; - - // Clear behavior setters & state parameter block generation function - void setClearColor(float red, float green, float blue, float alpha); - void setClearDepth(float depth); - void setClearStencil(int stencil); - ClearParameters getClearParameters(GLbitfield mask) const; - - // Write mask manipulation - void setColorMask(bool red, bool green, bool blue, bool alpha); - void setDepthMask(bool mask); - - // Discard toggle & query - bool isRasterizerDiscardEnabled() const; - void setRasterizerDiscard(bool enabled); - - // Face culling state manipulation - bool isCullFaceEnabled() const; - void setCullFace(bool enabled); - void setCullMode(GLenum mode); - void setFrontFace(GLenum front); - - // Depth test state manipulation - bool isDepthTestEnabled() const; - void setDepthTest(bool enabled); - void setDepthFunc(GLenum depthFunc); - void setDepthRange(float zNear, float zFar); - void getDepthRange(float *zNear, float *zFar) const; - - // Blend state manipulation - bool isBlendEnabled() const; - void setBlend(bool enabled); - 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); - const ColorF &getBlendColor() const; - - // Stencil state maniupulation - bool isStencilTestEnabled() const; - void setStencilTest(bool enabled); - 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); - GLint getStencilRef() const; - GLint getStencilBackRef() const; - - // Depth bias/polygon offset state manipulation - bool isPolygonOffsetFillEnabled() const; - void setPolygonOffsetFill(bool enabled); - void setPolygonOffsetParams(GLfloat factor, GLfloat units); - - // Multisample coverage state manipulation - bool isSampleAlphaToCoverageEnabled() const; - void setSampleAlphaToCoverage(bool enabled); - bool isSampleCoverageEnabled() const; - void setSampleCoverage(bool enabled); - void setSampleCoverageParams(GLclampf value, bool invert); - void getSampleCoverageParams(GLclampf *value, bool *invert) const; - - // Scissor test state toggle & query - bool isScissorTestEnabled() const; - void setScissorTest(bool enabled); - void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height); - const Rectangle &getScissor() const; - - // Dither state toggle & query - bool isDitherEnabled() const; - void setDither(bool enabled); - - // Generic state toggle & query - void setEnableFeature(GLenum feature, bool enabled); - bool getEnableFeature(GLenum feature); - - // Line width state setter - void setLineWidth(GLfloat width); - - // Hint setters - void setGenerateMipmapHint(GLenum hint); - void setFragmentShaderDerivativeHint(GLenum hint); - - // Viewport state setter/getter - void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height); - const Rectangle &getViewport() const; - - // Texture binding & active texture unit manipulation - void setActiveSampler(unsigned int active); - unsigned int getActiveSampler() const; - void setSamplerTexture(GLenum type, Texture *texture); - Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; - GLuint getSamplerTextureId(unsigned int sampler, GLenum type) const; - void detachTexture(const TextureMap &zeroTextures, GLuint texture); - void initializeZeroTextures(const TextureMap &zeroTextures); - - // Sampler object binding manipulation - void setSamplerBinding(GLuint textureUnit, Sampler *sampler); - GLuint getSamplerId(GLuint textureUnit) const; - Sampler *getSampler(GLuint textureUnit) const; - void detachSampler(GLuint sampler); - - // Renderbuffer binding manipulation - void setRenderbufferBinding(Renderbuffer *renderbuffer); - GLuint getRenderbufferId() const; - Renderbuffer *getCurrentRenderbuffer(); - void detachRenderbuffer(GLuint renderbuffer); - - // Framebuffer binding manipulation - void setReadFramebufferBinding(Framebuffer *framebuffer); - void setDrawFramebufferBinding(Framebuffer *framebuffer); - Framebuffer *getTargetFramebuffer(GLenum target) const; - Framebuffer *getReadFramebuffer(); - Framebuffer *getDrawFramebuffer(); - const Framebuffer *getReadFramebuffer() const; - const Framebuffer *getDrawFramebuffer() const; - bool removeReadFramebufferBinding(GLuint framebuffer); - bool removeDrawFramebufferBinding(GLuint framebuffer); - - // Vertex array object binding manipulation - void setVertexArrayBinding(VertexArray *vertexArray); - GLuint getVertexArrayId() const; - VertexArray *getVertexArray() const; - bool removeVertexArrayBinding(GLuint vertexArray); - - // Program binding manipulation - void setCurrentProgram(GLuint programId, Program *newProgram); - void setCurrentProgramBinary(ProgramBinary *binary); - GLuint getCurrentProgramId() const; - ProgramBinary *getCurrentProgramBinary() const; - - // Transform feedback object (not buffer) binding manipulation - void setTransformFeedbackBinding(TransformFeedback *transformFeedback); - TransformFeedback *getCurrentTransformFeedback() const; - void detachTransformFeedback(GLuint transformFeedback); - - // Query binding manipulation - bool isQueryActive() const; - void setActiveQuery(GLenum target, Query *query); - GLuint getActiveQueryId(GLenum target) const; - Query *getActiveQuery(GLenum target) const; - - //// Typed buffer binding point manipulation //// - // GL_ARRAY_BUFFER - void setArrayBufferBinding(Buffer *buffer); - GLuint getArrayBufferId() const; - bool removeArrayBufferBinding(GLuint buffer); - - // GL_UNIFORM_BUFFER - Both indexed and generic targets - void setGenericUniformBufferBinding(Buffer *buffer); - void setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); - GLuint getIndexedUniformBufferId(GLuint index) const; - Buffer *getIndexedUniformBuffer(GLuint index) const; - - // GL_TRANSFORM_FEEDBACK_BUFFER - Both indexed and generic targets - void setGenericTransformFeedbackBufferBinding(Buffer *buffer); - void setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size); - GLuint getIndexedTransformFeedbackBufferId(GLuint index) const; - Buffer *getIndexedTransformFeedbackBuffer(GLuint index) const; - GLuint getIndexedTransformFeedbackBufferOffset(GLuint index) const; - size_t getTransformFeedbackBufferIndexRange() const; - - // GL_COPY_[READ/WRITE]_BUFFER - void setCopyReadBufferBinding(Buffer *buffer); - void setCopyWriteBufferBinding(Buffer *buffer); - - // GL_PIXEL[PACK/UNPACK]_BUFFER - void setPixelPackBufferBinding(Buffer *buffer); - void setPixelUnpackBufferBinding(Buffer *buffer); - - // Retrieve typed buffer by target (non-indexed) - Buffer *getTargetBuffer(GLenum target) const; - - // Vertex attrib manipulation - void setEnableVertexAttribArray(unsigned int attribNum, bool enabled); - void setVertexAttribf(GLuint index, const GLfloat values[4]); - void setVertexAttribu(GLuint index, const GLuint values[4]); - void setVertexAttribi(GLuint index, const GLint values[4]); - void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, - bool normalized, bool pureInteger, GLsizei stride, const void *pointer); - const VertexAttribute &getVertexAttribState(unsigned int attribNum) const; - const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const; - const void *getVertexAttribPointer(unsigned int attribNum) const; - - // Pixel pack state manipulation - void setPackAlignment(GLint alignment); - GLint getPackAlignment() const; - void setPackReverseRowOrder(bool reverseRowOrder); - bool getPackReverseRowOrder() const; - const PixelPackState &getPackState() const; - - // Pixel unpack state manipulation - void setUnpackAlignment(GLint alignment); - GLint getUnpackAlignment() const; - const PixelUnpackState &getUnpackState() const; - - // State query functions - void getBooleanv(GLenum pname, GLboolean *params); - void getFloatv(GLenum pname, GLfloat *params); - void getIntegerv(const gl::Data &data, GLenum pname, GLint *params); - bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); - bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); - - bool hasMappedBuffer(GLenum target) const; - - private: - DISALLOW_COPY_AND_ASSIGN(State); - - // Cached values from Context's caps - GLuint mMaxDrawBuffers; - GLuint mMaxCombinedTextureImageUnits; - - ColorF mColorClearValue; - GLclampf mDepthClearValue; - int mStencilClearValue; - - RasterizerState mRasterizer; - bool mScissorTest; - Rectangle mScissor; - - BlendState mBlend; - ColorF mBlendColor; - bool mSampleCoverage; - GLclampf mSampleCoverageValue; - bool mSampleCoverageInvert; - - DepthStencilState mDepthStencil; - GLint mStencilRef; - GLint mStencilBackRef; - - GLfloat mLineWidth; - - GLenum mGenerateMipmapHint; - GLenum mFragmentShaderDerivativeHint; - - Rectangle mViewport; - float mNearZ; - float mFarZ; - - BindingPointer mArrayBuffer; - Framebuffer *mReadFramebuffer; - Framebuffer *mDrawFramebuffer; - BindingPointer mRenderbuffer; - GLuint mCurrentProgramId; - BindingPointer mCurrentProgramBinary; - - typedef std::vector VertexAttribVector; - VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib - VertexArray *mVertexArray; - - // Texture and sampler bindings - size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 - - typedef std::vector< BindingPointer > TextureBindingVector; - typedef std::map TextureBindingMap; - TextureBindingMap mSamplerTextures; - - typedef std::vector< BindingPointer > SamplerBindingVector; - SamplerBindingVector mSamplers; - - typedef std::map< GLenum, BindingPointer > ActiveQueryMap; - ActiveQueryMap mActiveQueries; - - BindingPointer mGenericUniformBuffer; - typedef std::vector< OffsetBindingPointer > BufferVector; - BufferVector mUniformBuffers; - - BindingPointer mTransformFeedback; - BindingPointer mGenericTransformFeedbackBuffer; - BufferVector mTransformFeedbackBuffers; - - BindingPointer mCopyReadBuffer; - BindingPointer mCopyWriteBuffer; - - PixelUnpackState mUnpack; - PixelPackState mPack; -}; - -} - -#endif // LIBGLESV2_STATE_H_ - diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.cpp b/src/3rdparty/angle/src/libGLESv2/Texture.cpp deleted file mode 100644 index cd4fc4e32a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Texture.cpp +++ /dev/null @@ -1,1012 +0,0 @@ -// -// Copyright (c) 2002-2014 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 "libGLESv2/main.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/ImageIndex.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/renderer/Image.h" -#include "libGLESv2/renderer/d3d/TextureStorage.h" - -#include "libEGL/Surface.h" - -#include "common/mathutil.h" -#include "common/utilities.h" - -namespace gl -{ - -bool IsMipmapFiltered(const gl::SamplerState &samplerState) -{ - switch (samplerState.minFilter) - { - case GL_NEAREST: - case GL_LINEAR: - return false; - case GL_NEAREST_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - case GL_LINEAR_MIPMAP_LINEAR: - return true; - default: UNREACHABLE(); - return false; - } -} - -bool IsPointSampled(const gl::SamplerState &samplerState) -{ - return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); -} - -unsigned int Texture::mCurrentTextureSerial = 1; - -Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target) - : RefCountObject(id), - mTexture(impl), - mTextureSerial(issueTextureSerial()), - mUsage(GL_NONE), - mImmutableLevelCount(0), - mTarget(target) -{ -} - -Texture::~Texture() -{ - SafeDelete(mTexture); -} - -GLenum Texture::getTarget() const -{ - return mTarget; -} - -void Texture::setUsage(GLenum usage) -{ - mUsage = usage; - getImplementation()->setUsage(usage); -} - -GLenum Texture::getUsage() const -{ - return mUsage; -} - -GLint Texture::getBaseLevelWidth() const -{ - const rx::Image *baseImage = getBaseLevelImage(); - return (baseImage ? baseImage->getWidth() : 0); -} - -GLint Texture::getBaseLevelHeight() const -{ - const rx::Image *baseImage = getBaseLevelImage(); - return (baseImage ? baseImage->getHeight() : 0); -} - -GLint Texture::getBaseLevelDepth() const -{ - const rx::Image *baseImage = getBaseLevelImage(); - return (baseImage ? baseImage->getDepth() : 0); -} - -// Note: "base level image" is loosely defined to be any image from the base level, -// where in the base of 2D array textures and cube maps there are several. Don't use -// the base level image for anything except querying texture format and size. -GLenum Texture::getBaseLevelInternalFormat() const -{ - const rx::Image *baseImage = getBaseLevelImage(); - return (baseImage ? baseImage->getInternalFormat() : GL_NONE); -} - -GLsizei Texture::getWidth(const ImageIndex &index) const -{ - rx::Image *image = mTexture->getImage(index); - return image->getWidth(); -} - -GLsizei Texture::getHeight(const ImageIndex &index) const -{ - rx::Image *image = mTexture->getImage(index); - return image->getHeight(); -} - -GLenum Texture::getInternalFormat(const ImageIndex &index) const -{ - rx::Image *image = mTexture->getImage(index); - return image->getInternalFormat(); -} - -GLenum Texture::getActualFormat(const ImageIndex &index) const -{ - rx::Image *image = mTexture->getImage(index); - return image->getActualFormat(); -} - -Error Texture::generateMipmaps() -{ - return getImplementation()->generateMipmaps(); -} - -Error Texture::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) -{ - return mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); -} - -unsigned int Texture::getTextureSerial() const -{ - return mTextureSerial; -} - -unsigned int Texture::issueTextureSerial() -{ - return mCurrentTextureSerial++; -} - -bool Texture::isImmutable() const -{ - return (mImmutableLevelCount > 0); -} - -int Texture::immutableLevelCount() -{ - return mImmutableLevelCount; -} - -int Texture::mipLevels() const -{ - return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; -} - -const rx::Image *Texture::getBaseLevelImage() const -{ - return (getImplementation()->getLayerCount(0) > 0 ? getImplementation()->getImage(0, 0) : NULL); -} - -Texture2D::Texture2D(rx::TextureImpl *impl, GLuint id) - : Texture(impl, id, GL_TEXTURE_2D) -{ - mSurface = NULL; -} - -Texture2D::~Texture2D() -{ - if (mSurface) - { - mSurface->setBoundTexture(NULL); - mSurface = NULL; - } -} - -GLsizei Texture2D::getWidth(GLint level) const -{ - if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mTexture->getImage(level, 0)->getWidth(); - else - return 0; -} - -GLsizei Texture2D::getHeight(GLint level) const -{ - if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mTexture->getImage(level, 0)->getHeight(); - else - return 0; -} - -GLenum Texture2D::getInternalFormat(GLint level) const -{ - if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mTexture->getImage(level, 0)->getInternalFormat(); - else - return GL_NONE; -} - -GLenum Texture2D::getActualFormat(GLint level) const -{ - if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mTexture->getImage(level, 0)->getActualFormat(); - else - return GL_NONE; -} - -Error Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - releaseTexImage(); - - return mTexture->setImage(GL_TEXTURE_2D, level, width, height, 1, internalFormat, format, type, unpack, pixels); -} - -void Texture2D::bindTexImage(egl::Surface *surface) -{ - releaseTexImage(); - - mTexture->bindTexImage(surface); - - mSurface = surface; - mSurface->setBoundTexture(this); -} - -void Texture2D::releaseTexImage() -{ - if (mSurface) - { - mSurface->setBoundTexture(NULL); - mSurface = NULL; - - mTexture->releaseTexImage(); - } -} - -Error Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, - const PixelUnpackState &unpack, const void *pixels) -{ - releaseTexImage(); - - return mTexture->setCompressedImage(GL_TEXTURE_2D, level, format, width, height, 1, imageSize, unpack, pixels); -} - -Error Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->subImage(GL_TEXTURE_2D, level, xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels); -} - -Error Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->subImageCompressed(GL_TEXTURE_2D, level, xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels); -} - -Error Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, - Framebuffer *source) -{ - releaseTexImage(); - - return mTexture->copyImage(GL_TEXTURE_2D, level, format, x, y, width, height, source); -} - -Error Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) -{ - Error error = mTexture->storage(GL_TEXTURE_2D, levels, internalformat, width, height, 1); - if (error.isError()) - { - return error; - } - - mImmutableLevelCount = levels; - - return Error(GL_NO_ERROR); -} - -// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. -bool Texture2D::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const -{ - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - - if (width <= 0 || height <= 0) - { - return false; - } - - if (!textureCaps.get(getInternalFormat(0)).filterable && !IsPointSampled(samplerState)) - { - return false; - } - - bool npotSupport = extensions.textureNPOT; - - if (!npotSupport) - { - if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) || - (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height))) - { - return false; - } - } - - if (IsMipmapFiltered(samplerState)) - { - if (!npotSupport) - { - if (!gl::isPow2(width) || !gl::isPow2(height)) - { - return false; - } - } - - if (!isMipmapComplete()) - { - return false; - } - } - - // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: - // The internalformat specified for the texture arrays is a sized internal depth or - // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- - // MODE is NONE, and either the magnification filter is not NEAREST or the mini- - // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST. - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(0)); - if (formatInfo.depthBits > 0 && clientVersion > 2) - { - if (samplerState.compareMode == GL_NONE) - { - if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) || - samplerState.magFilter != GL_NEAREST) - { - return false; - } - } - } - - return true; -} - -bool Texture2D::isCompressed(GLint level) const -{ - return GetInternalFormatInfo(getInternalFormat(level)).compressed; -} - -bool Texture2D::isDepth(GLint level) const -{ - return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; -} - -Error Texture2D::generateMipmaps() -{ - releaseTexImage(); - - return mTexture->generateMipmaps(); -} - -// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool Texture2D::isMipmapComplete() const -{ - int levelCount = mipLevels(); - - for (int level = 0; level < levelCount; level++) - { - if (!isLevelComplete(level)) - { - return false; - } - } - - return true; -} - -bool Texture2D::isLevelComplete(int level) const -{ - if (isImmutable()) - { - return true; - } - - const rx::Image *baseImage = getBaseLevelImage(); - - GLsizei width = baseImage->getWidth(); - GLsizei height = baseImage->getHeight(); - - if (width <= 0 || height <= 0) - { - return false; - } - - // The base image level is complete if the width and height are positive - if (level == 0) - { - return true; - } - - ASSERT(level >= 1 && level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getImage(level, 0) != NULL); - rx::Image *image = mTexture->getImage(level, 0); - - if (image->getInternalFormat() != baseImage->getInternalFormat()) - { - return false; - } - - if (image->getWidth() != std::max(1, width >> level)) - { - return false; - } - - if (image->getHeight() != std::max(1, height >> level)) - { - return false; - } - - return true; -} - -TextureCubeMap::TextureCubeMap(rx::TextureImpl *impl, GLuint id) - : Texture(impl, id, GL_TEXTURE_CUBE_MAP) -{ -} - -TextureCubeMap::~TextureCubeMap() -{ -} - -GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const -{ - if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mTexture->getImage(level, targetToLayerIndex(target))->getWidth(); - else - return 0; -} - -GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const -{ - if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mTexture->getImage(level, targetToLayerIndex(target))->getHeight(); - else - return 0; -} - -GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const -{ - if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mTexture->getImage(level, targetToLayerIndex(target))->getInternalFormat(); - else - return GL_NONE; -} - -GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const -{ - if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mTexture->getImage(level, targetToLayerIndex(target))->getActualFormat(); - else - return GL_NONE; -} - -Error TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->setImage(target, level, width, height, 1, internalFormat, format, type, unpack, pixels); -} - -Error TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, - GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->setCompressedImage(target, level, format, width, height, 1, imageSize, unpack, pixels); -} - -Error TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->subImage(target, level, xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels); -} - -Error TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, - GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->subImageCompressed(target, level, xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels); -} - -// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool TextureCubeMap::isCubeComplete() const -{ - int baseWidth = getBaseLevelWidth(); - int baseHeight = getBaseLevelHeight(); - GLenum baseFormat = getBaseLevelInternalFormat(); - - if (baseWidth <= 0 || baseWidth != baseHeight) - { - return false; - } - - for (int faceIndex = 1; faceIndex < 6; faceIndex++) - { - const rx::Image *faceBaseImage = mTexture->getImage(0, faceIndex); - - if (faceBaseImage->getWidth() != baseWidth || - faceBaseImage->getHeight() != baseHeight || - faceBaseImage->getInternalFormat() != baseFormat ) - { - return false; - } - } - - return true; -} - -bool TextureCubeMap::isCompressed(GLenum target, GLint level) const -{ - return GetInternalFormatInfo(getInternalFormat(target, level)).compressed; -} - -bool TextureCubeMap::isDepth(GLenum target, GLint level) const -{ - return GetInternalFormatInfo(getInternalFormat(target, level)).depthBits > 0; -} - -Error TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, - GLsizei width, GLsizei height, Framebuffer *source) -{ - return mTexture->copyImage(target, level, format, x, y, width, height, source); -} - -Error TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) -{ - Error error = mTexture->storage(GL_TEXTURE_CUBE_MAP, levels, internalformat, size, size, 1); - if (error.isError()) - { - return error; - } - - mImmutableLevelCount = levels; - - return Error(GL_NO_ERROR); -} - -// Tests for texture sampling completeness -bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const -{ - int size = getBaseLevelWidth(); - - bool mipmapping = IsMipmapFiltered(samplerState); - - if (!textureCaps.get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filterable && !IsPointSampled(samplerState)) - { - return false; - } - - if (!gl::isPow2(size) && !extensions.textureNPOT) - { - if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping) - { - return false; - } - } - - if (!mipmapping) - { - if (!isCubeComplete()) - { - return false; - } - } - else - { - if (!isMipmapComplete()) // Also tests for isCubeComplete() - { - return false; - } - } - - return true; -} - -int TextureCubeMap::targetToLayerIndex(GLenum target) -{ - 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 target - GL_TEXTURE_CUBE_MAP_POSITIVE_X; -} - -GLenum TextureCubeMap::layerIndexToTarget(GLint layer) -{ - 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 GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; -} - -bool TextureCubeMap::isMipmapComplete() const -{ - if (isImmutable()) - { - return true; - } - - if (!isCubeComplete()) - { - return false; - } - - int levelCount = mipLevels(); - - for (int face = 0; face < 6; face++) - { - for (int level = 1; level < levelCount; level++) - { - if (!isFaceLevelComplete(face, level)) - { - return false; - } - } - } - - return true; -} - -bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const -{ - ASSERT(level >= 0 && faceIndex < 6 && level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getImage(level, faceIndex) != NULL); - - if (isImmutable()) - { - return true; - } - - int baseSize = getBaseLevelWidth(); - - if (baseSize <= 0) - { - return false; - } - - // "isCubeComplete" checks for base level completeness and we must call that - // to determine if any face at level 0 is complete. We omit that check here - // to avoid re-checking cube-completeness for every face at level 0. - if (level == 0) - { - return true; - } - - // Check that non-zero levels are consistent with the base level. - const rx::Image *faceLevelImage = mTexture->getImage(level, faceIndex); - - if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) - { - return false; - } - - if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) - { - return false; - } - - return true; -} - - -Texture3D::Texture3D(rx::TextureImpl *impl, GLuint id) - : Texture(impl, id, GL_TEXTURE_3D) -{ -} - -Texture3D::~Texture3D() -{ -} - -GLsizei Texture3D::getWidth(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getWidth() : 0; -} - -GLsizei Texture3D::getHeight(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getHeight() : 0; -} - -GLsizei Texture3D::getDepth(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getDepth() : 0; -} - -GLenum Texture3D::getInternalFormat(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getInternalFormat() : GL_NONE; -} - -GLenum Texture3D::getActualFormat(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getImage(level, 0)->getActualFormat() : GL_NONE; -} - -bool Texture3D::isCompressed(GLint level) const -{ - return GetInternalFormatInfo(getInternalFormat(level)).compressed; -} - -bool Texture3D::isDepth(GLint level) const -{ - return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; -} - -Error Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->setImage(GL_TEXTURE_3D, level, width, height, depth, internalFormat, format, type, unpack, pixels); -} - -Error Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, - GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->setCompressedImage(GL_TEXTURE_3D, level, format, width, height, depth, imageSize, unpack, pixels); -} - -Error Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->subImage(GL_TEXTURE_3D, level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); -} - -Error Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, - GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->subImageCompressed(GL_TEXTURE_3D, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, unpack, pixels); -} - -Error Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - Error error = mTexture->storage(GL_TEXTURE_3D, levels, internalformat, width, height, depth); - if (error.isError()) - { - return error; - } - - mImmutableLevelCount = levels; - - return Error(GL_NO_ERROR); -} - -bool Texture3D::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const -{ - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); - - if (width <= 0 || height <= 0 || depth <= 0) - { - return false; - } - - if (!textureCaps.get(getInternalFormat(0)).filterable && !IsPointSampled(samplerState)) - { - return false; - } - - if (IsMipmapFiltered(samplerState) && !isMipmapComplete()) - { - return false; - } - - return true; -} - -bool Texture3D::isMipmapComplete() const -{ - int levelCount = mipLevels(); - - for (int level = 0; level < levelCount; level++) - { - if (!isLevelComplete(level)) - { - return false; - } - } - - return true; -} - -bool Texture3D::isLevelComplete(int level) const -{ - ASSERT(level >= 0 && level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getImage(level, 0) != NULL); - - if (isImmutable()) - { - return true; - } - - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); - - if (width <= 0 || height <= 0 || depth <= 0) - { - return false; - } - - if (level == 0) - { - return true; - } - - rx::Image *levelImage = mTexture->getImage(level, 0); - - if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) - { - return false; - } - - if (levelImage->getWidth() != std::max(1, width >> level)) - { - return false; - } - - if (levelImage->getHeight() != std::max(1, height >> level)) - { - return false; - } - - if (levelImage->getDepth() != std::max(1, depth >> level)) - { - return false; - } - - return true; -} - -Texture2DArray::Texture2DArray(rx::TextureImpl *impl, GLuint id) - : Texture(impl, id, GL_TEXTURE_2D_ARRAY) -{ -} - -Texture2DArray::~Texture2DArray() -{ -} - -GLsizei Texture2DArray::getWidth(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getWidth() : 0; -} - -GLsizei Texture2DArray::getHeight(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getHeight() : 0; -} - -GLsizei Texture2DArray::getLayers(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mTexture->getLayerCount(level) : 0; -} - -GLenum Texture2DArray::getInternalFormat(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getInternalFormat() : GL_NONE; -} - -GLenum Texture2DArray::getActualFormat(GLint level) const -{ - return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mTexture->getLayerCount(level) > 0) ? mTexture->getImage(level, 0)->getActualFormat() : GL_NONE; -} - -bool Texture2DArray::isCompressed(GLint level) const -{ - return GetInternalFormatInfo(getInternalFormat(level)).compressed; -} - -bool Texture2DArray::isDepth(GLint level) const -{ - return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; -} - -Error Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->setImage(GL_TEXTURE_2D_ARRAY, level, width, height, depth, internalFormat, format, type, unpack, pixels); -} - -Error Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, - GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->setCompressedImage(GL_TEXTURE_2D_ARRAY, level, format, width, height, depth, imageSize, unpack, pixels); -} - -Error Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->subImage(GL_TEXTURE_2D_ARRAY, level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); -} - -Error Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, - GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) -{ - return mTexture->subImageCompressed(GL_TEXTURE_2D_ARRAY, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, unpack, pixels); -} - -Error Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - Error error = mTexture->storage(GL_TEXTURE_2D_ARRAY, levels, internalformat, width, height, depth); - if (error.isError()) - { - return error; - } - - mImmutableLevelCount = levels; - - return Error(GL_NO_ERROR); -} - -bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const -{ - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getLayers(0); - - if (width <= 0 || height <= 0 || depth <= 0) - { - return false; - } - - if (!textureCaps.get(getBaseLevelInternalFormat()).filterable && !IsPointSampled(samplerState)) - { - return false; - } - - if (IsMipmapFiltered(samplerState) && !isMipmapComplete()) - { - return false; - } - - return true; -} - -bool Texture2DArray::isMipmapComplete() const -{ - int levelCount = mipLevels(); - - for (int level = 1; level < levelCount; level++) - { - if (!isLevelComplete(level)) - { - return false; - } - } - - return true; -} - -bool Texture2DArray::isLevelComplete(int level) const -{ - ASSERT(level >= 0 && level < IMPLEMENTATION_MAX_TEXTURE_LEVELS); - - if (isImmutable()) - { - return true; - } - - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei layers = getLayers(0); - - if (width <= 0 || height <= 0 || layers <= 0) - { - return false; - } - - if (level == 0) - { - return true; - } - - if (getInternalFormat(level) != getInternalFormat(0)) - { - return false; - } - - if (getWidth(level) != std::max(1, width >> level)) - { - return false; - } - - if (getHeight(level) != std::max(1, height >> level)) - { - return false; - } - - if (getLayers(level) != layers) - { - return false; - } - - return true; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.h b/src/3rdparty/angle/src/libGLESv2/Texture.h deleted file mode 100644 index 66d4df8015..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Texture.h +++ /dev/null @@ -1,241 +0,0 @@ -// -// Copyright (c) 2002-2013 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 "common/debug.h" -#include "common/RefCountObject.h" -#include "libGLESv2/angletypes.h" -#include "libGLESv2/Constants.h" -#include "libGLESv2/renderer/TextureImpl.h" -#include "libGLESv2/Caps.h" - -#include "angle_gl.h" - -#include - -namespace egl -{ -class Surface; -} - -namespace rx -{ -class TextureStorageInterface; -class Image; -} - -namespace gl -{ -class Framebuffer; -class FramebufferAttachment; -struct ImageIndex; - -bool IsMipmapFiltered(const gl::SamplerState &samplerState); - -class Texture : public RefCountObject -{ - public: - Texture(rx::TextureImpl *impl, GLuint id, GLenum target); - - virtual ~Texture(); - - GLenum getTarget() const; - - const SamplerState &getSamplerState() const { return mSamplerState; } - SamplerState &getSamplerState() { return mSamplerState; } - - void setUsage(GLenum usage); - GLenum getUsage() const; - - GLint getBaseLevelWidth() const; - GLint getBaseLevelHeight() const; - GLint getBaseLevelDepth() const; - GLenum getBaseLevelInternalFormat() const; - - GLsizei getWidth(const ImageIndex &index) const; - GLsizei getHeight(const ImageIndex &index) const; - GLenum getInternalFormat(const ImageIndex &index) const; - GLenum getActualFormat(const ImageIndex &index) const; - - virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const = 0; - - virtual Error generateMipmaps(); - - virtual Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - - // Texture serials provide a unique way of identifying a Texture that isn't a raw pointer. - // "id" is not good enough, as Textures can be deleted, then re-allocated with the same id. - unsigned int getTextureSerial() const; - - bool isImmutable() const; - GLsizei immutableLevelCount(); - - rx::TextureImpl *getImplementation() { return mTexture; } - const rx::TextureImpl *getImplementation() const { return mTexture; } - - 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: - int mipLevels() const; - const rx::Image *getBaseLevelImage() const; - static unsigned int issueTextureSerial(); - - rx::TextureImpl *mTexture; - - SamplerState mSamplerState; - GLenum mUsage; - - GLsizei mImmutableLevelCount; - - GLenum mTarget; - - const unsigned int mTextureSerial; - static unsigned int mCurrentTextureSerial; - - private: - DISALLOW_COPY_AND_ASSIGN(Texture); -}; - -class Texture2D : public Texture -{ - public: - Texture2D(rx::TextureImpl *impl, GLuint id); - - virtual ~Texture2D(); - - GLsizei getWidth(GLint level) const; - GLsizei getHeight(GLint level) const; - GLenum getInternalFormat(GLint level) const; - GLenum getActualFormat(GLint level) const; - bool isCompressed(GLint level) const; - bool isDepth(GLint level) const; - - Error setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - Error setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); - Error subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - Error subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); - Error copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - Error storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); - - virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const; - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); - - virtual Error generateMipmaps(); - - private: - DISALLOW_COPY_AND_ASSIGN(Texture2D); - - bool isMipmapComplete() const; - bool isLevelComplete(int level) const; - - egl::Surface *mSurface; -}; - -class TextureCubeMap : public Texture -{ - public: - TextureCubeMap(rx::TextureImpl *impl, GLuint id); - - virtual ~TextureCubeMap(); - - GLsizei getWidth(GLenum target, GLint level) const; - GLsizei getHeight(GLenum target, GLint level) const; - GLenum getInternalFormat(GLenum target, GLint level) const; - GLenum getActualFormat(GLenum target, GLint level) const; - bool isCompressed(GLenum target, GLint level) const; - bool isDepth(GLenum target, GLint level) const; - - Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); - Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); - Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - Error storage(GLsizei levels, GLenum internalformat, GLsizei size); - - virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const; - - bool isCubeComplete() const; - - static int targetToLayerIndex(GLenum target); - static GLenum layerIndexToTarget(GLint layer); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); - - bool isMipmapComplete() const; - bool isFaceLevelComplete(int faceIndex, int level) const; -}; - -class Texture3D : public Texture -{ - public: - Texture3D(rx::TextureImpl *impl, GLuint id); - - virtual ~Texture3D(); - - GLsizei getWidth(GLint level) const; - GLsizei getHeight(GLint level) const; - GLsizei getDepth(GLint level) const; - GLenum getInternalFormat(GLint level) const; - GLenum getActualFormat(GLint level) const; - bool isCompressed(GLint level) const; - bool isDepth(GLint level) const; - - Error setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - Error setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); - Error subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - Error subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); - Error storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - - virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const; - - private: - DISALLOW_COPY_AND_ASSIGN(Texture3D); - - bool isMipmapComplete() const; - bool isLevelComplete(int level) const; -}; - -class Texture2DArray : public Texture -{ - public: - Texture2DArray(rx::TextureImpl *impl, GLuint id); - - virtual ~Texture2DArray(); - - GLsizei getWidth(GLint level) const; - GLsizei getHeight(GLint level) const; - GLsizei getLayers(GLint level) const; - GLenum getInternalFormat(GLint level) const; - GLenum getActualFormat(GLint level) const; - bool isCompressed(GLint level) const; - bool isDepth(GLint level) const; - - Error setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - Error setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); - Error subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - Error subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); - Error storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - - virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const; - - private: - DISALLOW_COPY_AND_ASSIGN(Texture2DArray); - - bool isMipmapComplete() const; - bool isLevelComplete(int level) const; -}; - -} - -#endif // LIBGLESV2_TEXTURE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/TransformFeedback.cpp b/src/3rdparty/angle/src/libGLESv2/TransformFeedback.cpp deleted file mode 100644 index bfa7072326..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/TransformFeedback.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright (c) 2014 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 "libGLESv2/TransformFeedback.h" -#include "libGLESv2/renderer/TransformFeedbackImpl.h" - -namespace gl -{ - -TransformFeedback::TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id) - : RefCountObject(id), - mTransformFeedback(impl), - mStarted(GL_FALSE), - mPrimitiveMode(GL_NONE), - mPaused(GL_FALSE) -{ - ASSERT(impl != NULL); -} - -TransformFeedback::~TransformFeedback() -{ - SafeDelete(mTransformFeedback); -} - -void TransformFeedback::start(GLenum primitiveMode) -{ - mStarted = GL_TRUE; - mPrimitiveMode = primitiveMode; - mPaused = GL_FALSE; - mTransformFeedback->begin(primitiveMode); -} - -void TransformFeedback::stop() -{ - mStarted = GL_FALSE; - mPrimitiveMode = GL_NONE; - mPaused = GL_FALSE; - mTransformFeedback->end(); -} - -GLboolean TransformFeedback::isStarted() const -{ - return mStarted; -} - -GLenum TransformFeedback::getDrawMode() const -{ - return mPrimitiveMode; -} - -void TransformFeedback::pause() -{ - mPaused = GL_TRUE; - mTransformFeedback->pause(); -} - -void TransformFeedback::resume() -{ - mPaused = GL_FALSE; - mTransformFeedback->resume(); -} - -GLboolean TransformFeedback::isPaused() const -{ - return mPaused; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/TransformFeedback.h b/src/3rdparty/angle/src/libGLESv2/TransformFeedback.h deleted file mode 100644 index 885a4fe172..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/TransformFeedback.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) 2014 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 LIBGLESV2_TRANSFORM_FEEDBACK_H_ -#define LIBGLESV2_TRANSFORM_FEEDBACK_H_ - -#include "common/angleutils.h" -#include "common/RefCountObject.h" - -#include "angle_gl.h" - -namespace rx -{ -class TransformFeedbackImpl; -} - -namespace gl -{ - -class TransformFeedback : public RefCountObject -{ - public: - TransformFeedback(rx::TransformFeedbackImpl* impl, GLuint id); - virtual ~TransformFeedback(); - - void start(GLenum primitiveMode); - void stop(); - GLboolean isStarted() const; - - GLenum getDrawMode() const; - - void pause(); - void resume(); - GLboolean isPaused() const; - - private: - DISALLOW_COPY_AND_ASSIGN(TransformFeedback); - - rx::TransformFeedbackImpl* mTransformFeedback; - - GLboolean mStarted; - GLenum mPrimitiveMode; - GLboolean mPaused; -}; - -} - -#endif // LIBGLESV2_TRANSFORM_FEEDBACK_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Uniform.cpp b/src/3rdparty/angle/src/libGLESv2/Uniform.cpp deleted file mode 100644 index bd0cd2eeec..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Uniform.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// -// Copyright (c) 2010-2013 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 "libGLESv2/Uniform.h" - -#include "common/utilities.h" - -namespace gl -{ - -LinkedUniform::LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, - const int blockIndex, const sh::BlockMemberInfo &blockInfo) - : type(type), - precision(precision), - name(name), - arraySize(arraySize), - blockIndex(blockIndex), - blockInfo(blockInfo), - data(NULL), - dirty(true), - psRegisterIndex(GL_INVALID_INDEX), - vsRegisterIndex(GL_INVALID_INDEX), - registerCount(0), - registerElement(0) -{ - // We use data storage for default block uniforms to cache values that are sent to D3D during rendering - // Uniform blocks/buffers are treated separately by the Renderer (ES3 path only) - if (isInDefaultBlock()) - { - size_t bytes = dataSize(); - data = new unsigned char[bytes]; - memset(data, 0, bytes); - registerCount = VariableRowCount(type) * elementCount(); - } -} - -LinkedUniform::~LinkedUniform() -{ - delete[] data; -} - -bool LinkedUniform::isArray() const -{ - return arraySize > 0; -} - -unsigned int LinkedUniform::elementCount() const -{ - return arraySize > 0 ? arraySize : 1; -} - -bool LinkedUniform::isReferencedByVertexShader() const -{ - return vsRegisterIndex != GL_INVALID_INDEX; -} - -bool LinkedUniform::isReferencedByFragmentShader() const -{ - return psRegisterIndex != GL_INVALID_INDEX; -} - -bool LinkedUniform::isInDefaultBlock() const -{ - return blockIndex == -1; -} - -size_t LinkedUniform::dataSize() const -{ - ASSERT(type != GL_STRUCT_ANGLEX); - return VariableInternalSize(type) * elementCount(); -} - -bool LinkedUniform::isSampler() const -{ - return IsSampler(type); -} - -UniformBlock::UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize) - : name(name), - elementIndex(elementIndex), - dataSize(dataSize), - psRegisterIndex(GL_INVALID_INDEX), - vsRegisterIndex(GL_INVALID_INDEX) -{ -} - -bool UniformBlock::isArrayElement() const -{ - return elementIndex != GL_INVALID_INDEX; -} - -bool UniformBlock::isReferencedByVertexShader() const -{ - return vsRegisterIndex != GL_INVALID_INDEX; -} - -bool UniformBlock::isReferencedByFragmentShader() const -{ - return psRegisterIndex != GL_INVALID_INDEX; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/Uniform.h b/src/3rdparty/angle/src/libGLESv2/Uniform.h deleted file mode 100644 index 633d70bb19..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/Uniform.h +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright (c) 2010-2013 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 LIBGLESV2_UNIFORM_H_ -#define LIBGLESV2_UNIFORM_H_ - -#include "common/debug.h" -#include "common/blocklayout.h" - -#include "libGLESv2/angletypes.h" - -#include "angle_gl.h" - -#include -#include - -namespace gl -{ - -// Helper struct representing a single shader uniform -struct LinkedUniform -{ - LinkedUniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, const int blockIndex, const sh::BlockMemberInfo &blockInfo); - - ~LinkedUniform(); - - bool isArray() const; - unsigned int elementCount() const; - bool isReferencedByVertexShader() const; - bool isReferencedByFragmentShader() const; - bool isInDefaultBlock() const; - size_t dataSize() const; - bool isSampler() const; - - const GLenum type; - const GLenum precision; - const std::string name; - const unsigned int arraySize; - const int blockIndex; - const sh::BlockMemberInfo blockInfo; - - unsigned char *data; - bool dirty; - - unsigned int psRegisterIndex; - unsigned int vsRegisterIndex; - unsigned int registerCount; - - // Register "elements" are used for uniform structs in ES3, to appropriately identify single uniforms - // inside aggregate types, which are packed according C-like structure rules. - unsigned int registerElement; -}; - -// Helper struct representing a single shader uniform block -struct UniformBlock -{ - // use GL_INVALID_INDEX for non-array elements - UniformBlock(const std::string &name, unsigned int elementIndex, unsigned int dataSize); - - bool isArrayElement() const; - bool isReferencedByVertexShader() const; - bool isReferencedByFragmentShader() const; - - const std::string name; - const unsigned int elementIndex; - const unsigned int dataSize; - - std::vector memberUniformIndexes; - - unsigned int psRegisterIndex; - unsigned int vsRegisterIndex; -}; - -} - -#endif // LIBGLESV2_UNIFORM_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/VertexArray.cpp b/src/3rdparty/angle/src/libGLESv2/VertexArray.cpp deleted file mode 100644 index f8ca661062..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/VertexArray.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// -// Copyright (c) 2013 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. -// -// Implementation of the state class for mananging GLES 3 Vertex Array Objects. -// - -#include "libGLESv2/VertexArray.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/renderer/VertexArrayImpl.h" - -namespace gl -{ - -VertexArray::VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs) - : mId(id), - mVertexArray(impl), - mVertexAttributes(maxAttribs) -{ - ASSERT(impl != NULL); -} - -VertexArray::~VertexArray() -{ - SafeDelete(mVertexArray); - - for (size_t i = 0; i < getMaxAttribs(); i++) - { - mVertexAttributes[i].buffer.set(NULL); - } - mElementArrayBuffer.set(NULL); -} - -GLuint VertexArray::id() const -{ - return mId; -} - -void VertexArray::detachBuffer(GLuint bufferName) -{ - for (size_t attribute = 0; attribute < getMaxAttribs(); attribute++) - { - if (mVertexAttributes[attribute].buffer.id() == bufferName) - { - mVertexAttributes[attribute].buffer.set(NULL); - } - } - - if (mElementArrayBuffer.id() == bufferName) - { - mElementArrayBuffer.set(NULL); - } -} - -const VertexAttribute& VertexArray::getVertexAttribute(size_t attributeIndex) const -{ - ASSERT(attributeIndex < getMaxAttribs()); - return mVertexAttributes[attributeIndex]; -} - -void VertexArray::setVertexAttribDivisor(GLuint index, GLuint divisor) -{ - ASSERT(index < getMaxAttribs()); - mVertexAttributes[index].divisor = divisor; - mVertexArray->setAttributeDivisor(index, divisor); -} - -void VertexArray::enableAttribute(unsigned int attributeIndex, bool enabledState) -{ - ASSERT(attributeIndex < getMaxAttribs()); - mVertexAttributes[attributeIndex].enabled = enabledState; - mVertexArray->enableAttribute(attributeIndex, enabledState); -} - -void VertexArray::setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, - bool normalized, bool pureInteger, GLsizei stride, const void *pointer) -{ - ASSERT(attributeIndex < getMaxAttribs()); - mVertexAttributes[attributeIndex].buffer.set(boundBuffer); - mVertexAttributes[attributeIndex].size = size; - mVertexAttributes[attributeIndex].type = type; - mVertexAttributes[attributeIndex].normalized = normalized; - mVertexAttributes[attributeIndex].pureInteger = pureInteger; - mVertexAttributes[attributeIndex].stride = stride; - mVertexAttributes[attributeIndex].pointer = pointer; - mVertexArray->setAttribute(attributeIndex, mVertexAttributes[attributeIndex]); -} - -void VertexArray::setElementArrayBuffer(Buffer *buffer) -{ - mElementArrayBuffer.set(buffer); - mVertexArray->setElementArrayBuffer(buffer); -} - -} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/VertexArray.h b/src/3rdparty/angle/src/libGLESv2/VertexArray.h deleted file mode 100644 index a724c0be1c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/VertexArray.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (c) 2013 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 class contains prototypes for representing GLES 3 Vertex Array Objects: -// -// The buffer objects that are to be used by the vertex stage of the GL are collected -// together to form a vertex array object. All state related to the definition of data used -// by the vertex processor is encapsulated in a vertex array object. -// - -#ifndef LIBGLESV2_VERTEXARRAY_H_ -#define LIBGLESV2_VERTEXARRAY_H_ - -#include "common/RefCountObject.h" -#include "libGLESv2/Constants.h" -#include "libGLESv2/VertexAttribute.h" - -#include - -namespace rx -{ -class VertexArrayImpl; -} - -namespace gl -{ -class Buffer; - -class VertexArray -{ - public: - VertexArray(rx::VertexArrayImpl *impl, GLuint id, size_t maxAttribs); - ~VertexArray(); - - GLuint id() const; - - const VertexAttribute& getVertexAttribute(size_t attributeIndex) const; - void detachBuffer(GLuint bufferName); - void setVertexAttribDivisor(GLuint index, GLuint divisor); - void enableAttribute(unsigned int attributeIndex, bool enabledState); - void setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, - bool normalized, bool pureInteger, GLsizei stride, const void *pointer); - - const VertexAttribute* getVertexAttributes() const { return &mVertexAttributes[0]; } - Buffer *getElementArrayBuffer() const { return mElementArrayBuffer.get(); } - void setElementArrayBuffer(Buffer *buffer); - GLuint getElementArrayBufferId() const { return mElementArrayBuffer.id(); } - size_t getMaxAttribs() const { return mVertexAttributes.size(); } - - private: - GLuint mId; - - rx::VertexArrayImpl *mVertexArray; - std::vector mVertexAttributes; - BindingPointer mElementArrayBuffer; -}; - -} - -#endif // LIBGLESV2_VERTEXARRAY_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/VertexAttribute.cpp b/src/3rdparty/angle/src/libGLESv2/VertexAttribute.cpp deleted file mode 100644 index 1096856b8a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/VertexAttribute.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright 2014 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. -// -// Implementation of the state class for mananging GLES 3 Vertex Array Objects. -// - -#include "libGLESv2/VertexAttribute.h" - -namespace gl -{ - -VertexAttribute::VertexAttribute() - : enabled(false), - type(GL_FLOAT), - size(4), - normalized(false), - pureInteger(false), - stride(0), - pointer(NULL), - divisor(0) -{ -} - -size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib) -{ - GLuint size = attrib.size; - switch (attrib.type) - { - case GL_BYTE: return size * sizeof(GLbyte); - case GL_UNSIGNED_BYTE: return size * sizeof(GLubyte); - case GL_SHORT: return size * sizeof(GLshort); - case GL_UNSIGNED_SHORT: return size * sizeof(GLushort); - case GL_INT: return size * sizeof(GLint); - case GL_UNSIGNED_INT: return size * sizeof(GLuint); - case GL_INT_2_10_10_10_REV: return 4; - case GL_UNSIGNED_INT_2_10_10_10_REV: return 4; - case GL_FIXED: return size * sizeof(GLfixed); - case GL_HALF_FLOAT: return size * sizeof(GLhalf); - case GL_FLOAT: return size * sizeof(GLfloat); - default: UNREACHABLE(); return size * sizeof(GLfloat); - } -} - -size_t ComputeVertexAttributeStride(const VertexAttribute& attrib) -{ - if (!attrib.enabled) - { - return 16; - } - return attrib.stride ? attrib.stride : ComputeVertexAttributeTypeSize(attrib); -} - -} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/VertexAttribute.h b/src/3rdparty/angle/src/libGLESv2/VertexAttribute.h deleted file mode 100644 index e9757b618b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/VertexAttribute.h +++ /dev/null @@ -1,119 +0,0 @@ -// -// Copyright (c) 2013 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. -// -// Helper structure describing a single vertex attribute -// - -#ifndef LIBGLESV2_VERTEXATTRIBUTE_H_ -#define LIBGLESV2_VERTEXATTRIBUTE_H_ - -#include "libGLESv2/Buffer.h" - -namespace gl -{ - -struct VertexAttribute -{ - bool enabled; // From glEnable/DisableVertexAttribArray - - GLenum type; - GLuint size; - bool normalized; - bool pureInteger; - GLuint stride; // 0 means natural stride - - union - { - const GLvoid *pointer; - GLintptr offset; - }; - BindingPointer buffer; // Captured when glVertexAttribPointer is called. - - GLuint divisor; - - VertexAttribute(); -}; - -template -T QuerySingleVertexAttributeParameter(const VertexAttribute& attrib, GLenum pname) -{ - switch (pname) - { - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: - return static_cast(attrib.enabled ? GL_TRUE : GL_FALSE); - case GL_VERTEX_ATTRIB_ARRAY_SIZE: - return static_cast(attrib.size); - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: - return static_cast(attrib.stride); - case GL_VERTEX_ATTRIB_ARRAY_TYPE: - return static_cast(attrib.type); - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: - return static_cast(attrib.normalized ? GL_TRUE : GL_FALSE); - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: - return static_cast(attrib.buffer.id()); - case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: - return static_cast(attrib.divisor); - case GL_VERTEX_ATTRIB_ARRAY_INTEGER: - return static_cast(attrib.pureInteger ? GL_TRUE : GL_FALSE); - default: - UNREACHABLE(); - return static_cast(0); - } -} - -size_t ComputeVertexAttributeTypeSize(const VertexAttribute& attrib); -size_t ComputeVertexAttributeStride(const VertexAttribute& attrib); - -struct VertexAttribCurrentValueData -{ - union - { - GLfloat FloatValues[4]; - GLint IntValues[4]; - GLuint UnsignedIntValues[4]; - }; - GLenum Type; - - void setFloatValues(const GLfloat floatValues[4]) - { - for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) - { - FloatValues[valueIndex] = floatValues[valueIndex]; - } - Type = GL_FLOAT; - } - - void setIntValues(const GLint intValues[4]) - { - for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) - { - IntValues[valueIndex] = intValues[valueIndex]; - } - Type = GL_INT; - } - - void setUnsignedIntValues(const GLuint unsignedIntValues[4]) - { - for (unsigned int valueIndex = 0; valueIndex < 4; valueIndex++) - { - UnsignedIntValues[valueIndex] = unsignedIntValues[valueIndex]; - } - Type = GL_UNSIGNED_INT; - } - - bool operator==(const VertexAttribCurrentValueData &other) - { - return (Type == other.Type && memcmp(FloatValues, other.FloatValues, sizeof(float) * 4) == 0); - } - - bool operator!=(const VertexAttribCurrentValueData &other) - { - return !(*this == other); - } -}; - -} - -#endif // LIBGLESV2_VERTEXATTRIBUTE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp deleted file mode 100644 index 5a0cfc5ad9..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp +++ /dev/null @@ -1,210 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2 - -#include "libGLESv2/angletypes.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/VertexAttribute.h" -#include "libGLESv2/State.h" -#include "libGLESv2/VertexArray.h" - -#include - -namespace gl -{ - -SamplerState::SamplerState() - : minFilter(GL_NEAREST_MIPMAP_LINEAR), - magFilter(GL_LINEAR), - wrapS(GL_REPEAT), - wrapT(GL_REPEAT), - wrapR(GL_REPEAT), - maxAnisotropy(1.0f), - baseLevel(0), - maxLevel(1000), - minLod(-FLT_MAX), - maxLod(FLT_MAX), - compareMode(GL_NONE), - compareFunc(GL_LEQUAL), - swizzleRed(GL_RED), - swizzleGreen(GL_GREEN), - swizzleBlue(GL_BLUE), - swizzleAlpha(GL_ALPHA) -{} - -bool SamplerState::swizzleRequired() const -{ - return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || - swizzleBlue != GL_BLUE || swizzleAlpha != GL_ALPHA; -} - -static void MinMax(int a, int b, int *minimum, int *maximum) -{ - if (a < b) - { - *minimum = a; - *maximum = b; - } - else - { - *minimum = b; - *maximum = a; - } -} - -bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection) -{ - int minSourceX, maxSourceX, minSourceY, maxSourceY; - MinMax(source.x, source.x + source.width, &minSourceX, &maxSourceX); - MinMax(source.y, source.y + source.height, &minSourceY, &maxSourceY); - - int minClipX, maxClipX, minClipY, maxClipY; - MinMax(clip.x, clip.x + clip.width, &minClipX, &maxClipX); - MinMax(clip.y, clip.y + clip.height, &minClipY, &maxClipY); - - if (minSourceX >= maxClipX || maxSourceX <= minClipX || minSourceY >= maxClipY || maxSourceY <= minClipY) - { - if (intersection) - { - intersection->x = minSourceX; - intersection->y = maxSourceY; - intersection->width = maxSourceX - minSourceX; - intersection->height = maxSourceY - minSourceY; - } - - return false; - } - else - { - if (intersection) - { - intersection->x = std::max(minSourceX, minClipX); - intersection->y = std::max(minSourceY, minClipY); - intersection->width = std::min(maxSourceX, maxClipX) - std::max(minSourceX, minClipX); - intersection->height = std::min(maxSourceY, maxClipY) - std::max(minSourceY, minClipY); - } - - return true; - } -} - -VertexFormat::VertexFormat() - : mType(GL_NONE), - mNormalized(GL_FALSE), - mComponents(0), - mPureInteger(false) -{} - -VertexFormat::VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger) - : mType(type), - mNormalized(normalized), - mComponents(components), - mPureInteger(pureInteger) -{ - // Float data can not be normalized, so ignore the user setting - if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) - { - mNormalized = GL_FALSE; - } -} - -VertexFormat::VertexFormat(const VertexAttribute &attrib) - : mType(attrib.type), - mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE), - mComponents(attrib.size), - mPureInteger(attrib.pureInteger) -{ - // Ensure we aren't initializing a vertex format which should be using - // the current-value type - ASSERT(attrib.enabled); - - // Float data can not be normalized, so ignore the user setting - if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) - { - mNormalized = GL_FALSE; - } -} - -VertexFormat::VertexFormat(const VertexAttribute &attrib, GLenum currentValueType) - : mType(attrib.type), - mNormalized(attrib.normalized ? GL_TRUE : GL_FALSE), - mComponents(attrib.size), - mPureInteger(attrib.pureInteger) -{ - if (!attrib.enabled) - { - mType = currentValueType; - mNormalized = GL_FALSE; - mComponents = 4; - mPureInteger = (currentValueType != GL_FLOAT); - } - - // Float data can not be normalized, so ignore the user setting - if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED) - { - mNormalized = GL_FALSE; - } -} - -void VertexFormat::GetInputLayout(VertexFormat *inputLayout, - ProgramBinary *programBinary, - const State &state) -{ - const VertexAttribute *vertexAttributes = state.getVertexArray()->getVertexAttributes(); - for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) - { - int semanticIndex = programBinary->getSemanticIndex(attributeIndex); - - if (semanticIndex != -1) - { - inputLayout[semanticIndex] = VertexFormat(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex).Type); - } - } -} - -bool VertexFormat::operator==(const VertexFormat &other) const -{ - return (mType == other.mType && - mComponents == other.mComponents && - mNormalized == other.mNormalized && - mPureInteger == other.mPureInteger ); -} - -bool VertexFormat::operator!=(const VertexFormat &other) const -{ - return !(*this == other); -} - -bool VertexFormat::operator<(const VertexFormat& other) const -{ - if (mType != other.mType) - { - return mType < other.mType; - } - if (mNormalized != other.mNormalized) - { - return mNormalized < other.mNormalized; - } - if (mComponents != other.mComponents) - { - return mComponents < other.mComponents; - } - return mPureInteger < other.mPureInteger; -} - -bool Box::operator==(const Box &other) const -{ - return (x == other.x && y == other.y && z == other.z && - width == other.width && height == other.height && depth == other.depth); -} - -bool Box::operator!=(const Box &other) const -{ - return !(*this == other); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.h b/src/3rdparty/angle/src/libGLESv2/angletypes.h deleted file mode 100644 index 78fe6b0e26..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/angletypes.h +++ /dev/null @@ -1,257 +0,0 @@ -// -// Copyright (c) 2012-2013 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. -// - -// angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2 - -#ifndef LIBGLESV2_ANGLETYPES_H_ -#define LIBGLESV2_ANGLETYPES_H_ - -#include "libGLESv2/Constants.h" -#include "common/RefCountObject.h" - -namespace gl -{ -class Buffer; -class State; -class ProgramBinary; -struct VertexAttribute; -struct VertexAttribCurrentValueData; - -enum SamplerType -{ - SAMPLER_PIXEL, - SAMPLER_VERTEX -}; - -template -struct Color -{ - T red; - T green; - T blue; - T alpha; - - Color() : red(0), green(0), blue(0), alpha(0) { } - Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a) { } -}; - -typedef Color ColorF; -typedef Color ColorI; -typedef Color ColorUI; - -struct Rectangle -{ - int x; - int y; - int width; - int height; - - Rectangle() : x(0), y(0), width(0), height(0) { } - Rectangle(int x_in, int y_in, int width_in, int height_in) : x(x_in), y(y_in), width(width_in), height(height_in) { } -}; - -bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection); - -struct Box -{ - int x; - int y; - int z; - int width; - int height; - int depth; - - Box() : x(0), y(0), z(0), width(0), height(0), depth(0) { } - Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in) : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in) { } - bool operator==(const Box &other) const; - bool operator!=(const Box &other) const; -}; - -struct Extents -{ - int width; - int height; - int depth; - - Extents() : width(0), height(0), depth(0) { } - Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { } -}; - -struct RasterizerState -{ - bool cullFace; - GLenum cullMode; - GLenum frontFace; - - bool polygonOffsetFill; - GLfloat polygonOffsetFactor; - GLfloat polygonOffsetUnits; - - bool pointDrawMode; - bool multiSample; - - bool rasterizerDiscard; -}; - -struct BlendState -{ - bool blend; - GLenum sourceBlendRGB; - GLenum destBlendRGB; - GLenum sourceBlendAlpha; - GLenum destBlendAlpha; - GLenum blendEquationRGB; - GLenum blendEquationAlpha; - - bool colorMaskRed; - bool colorMaskGreen; - bool colorMaskBlue; - bool colorMaskAlpha; - - bool sampleAlphaToCoverage; - - bool dither; -}; - -struct DepthStencilState -{ - bool depthTest; - GLenum depthFunc; - bool depthMask; - - bool stencilTest; - GLenum stencilFunc; - GLuint stencilMask; - GLenum stencilFail; - GLenum stencilPassDepthFail; - GLenum stencilPassDepthPass; - GLuint stencilWritemask; - GLenum stencilBackFunc; - GLuint stencilBackMask; - GLenum stencilBackFail; - GLenum stencilBackPassDepthFail; - GLenum stencilBackPassDepthPass; - GLuint stencilBackWritemask; -}; - -struct SamplerState -{ - SamplerState(); - - GLenum minFilter; - GLenum magFilter; - GLenum wrapS; - GLenum wrapT; - GLenum wrapR; - float maxAnisotropy; - - GLint baseLevel; - GLint maxLevel; - GLfloat minLod; - GLfloat maxLod; - - GLenum compareMode; - GLenum compareFunc; - - GLenum swizzleRed; - GLenum swizzleGreen; - GLenum swizzleBlue; - GLenum swizzleAlpha; - - bool swizzleRequired() const; -}; - -struct ClearParameters -{ - bool clearColor[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; - ColorF colorFClearValue; - ColorI colorIClearValue; - ColorUI colorUIClearValue; - GLenum colorClearType; - bool colorMaskRed; - bool colorMaskGreen; - bool colorMaskBlue; - bool colorMaskAlpha; - - bool clearDepth; - float depthClearValue; - - bool clearStencil; - GLint stencilClearValue; - GLuint stencilWriteMask; - - bool scissorEnabled; - Rectangle scissor; -}; - -struct PixelUnpackState -{ - BindingPointer pixelBuffer; - GLint alignment; - - PixelUnpackState() - : alignment(4) - {} - - explicit PixelUnpackState(GLint alignmentIn) - : alignment(alignmentIn) - {} -}; - -struct PixelPackState -{ - BindingPointer pixelBuffer; - GLint alignment; - bool reverseRowOrder; - - PixelPackState() - : alignment(4), - reverseRowOrder(false) - {} - - explicit PixelPackState(GLint alignmentIn, bool reverseRowOrderIn) - : alignment(alignmentIn), - reverseRowOrder(reverseRowOrderIn) - {} -}; - -struct VertexFormat -{ - GLenum mType; - GLboolean mNormalized; - GLuint mComponents; - bool mPureInteger; - - VertexFormat(); - VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger); - explicit VertexFormat(const VertexAttribute &attribute); - VertexFormat(const VertexAttribute &attribute, GLenum currentValueType); - - static void GetInputLayout(VertexFormat *inputLayout, - ProgramBinary *programBinary, - const State& currentValues); - - bool operator==(const VertexFormat &other) const; - bool operator!=(const VertexFormat &other) const; - bool operator<(const VertexFormat& other) const; -}; - -} - -namespace rx -{ - -enum VertexConversionType -{ - VERTEX_CONVERT_NONE = 0, - VERTEX_CONVERT_CPU = 1, - VERTEX_CONVERT_GPU = 2, - VERTEX_CONVERT_BOTH = 3 -}; - -} - -#endif // LIBGLESV2_ANGLETYPES_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/constants.h b/src/3rdparty/angle/src/libGLESv2/constants.h deleted file mode 100644 index 69c4823fb2..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/constants.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Contants.h: Defines some implementation specific and gl constants - -#ifndef LIBGLESV2_CONSTANTS_H_ -#define LIBGLESV2_CONSTANTS_H_ - -namespace gl -{ - -enum -{ - MAX_VERTEX_ATTRIBS = 16, - - // Implementation upper limits, real maximums depend on the hardware - IMPLEMENTATION_MAX_VARYING_VECTORS = 32, - IMPLEMENTATION_MAX_DRAW_BUFFERS = 8, - IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS = IMPLEMENTATION_MAX_DRAW_BUFFERS + 2, // 2 extra for depth and/or stencil buffers - - IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS = 16, - IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS = 16, - IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS = IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS + - IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS, - - IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4, - - // 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_2D_TEXTURE_SIZE = 16384, - IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384, - IMPLEMENTATION_MAX_3D_TEXTURE_SIZE = 2048, - IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS = 2048, - - IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE -}; - -} - -#endif // LIBGLESV2_CONSTANTS_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp new file mode 100644 index 0000000000..a6db1585e7 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl.cpp @@ -0,0 +1,1127 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_egl.cpp : Implements the EGL entry points. + +#include "libGLESv2/entry_points_egl.h" +#include "libGLESv2/entry_points_egl_ext.h" +#include "libGLESv2/entry_points_gles_2_0_ext.h" +#include "libGLESv2/entry_points_gles_3_0_ext.h" +#include "libGLESv2/global_state.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/Texture.h" +#include "libANGLE/Surface.h" +#include "libANGLE/validationEGL.h" + +#include "common/debug.h" +#include "common/version.h" + +#include + +namespace egl +{ + +// EGL 1.0 +EGLint EGLAPIENTRY GetError(void) +{ + EVENT("()"); + + EGLint error = GetGlobalError(); + SetGlobalError(Error(EGL_SUCCESS)); + return error; +} + +EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id) +{ + EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id); + + return Display::getDisplay(display_id, AttributeMap()); +} + +EGLBoolean EGLAPIENTRY Initialize(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); + + if (dpy == EGL_NO_DISPLAY) + { + SetGlobalError(Error(EGL_BAD_DISPLAY)); + return EGL_FALSE; + } + + Display *display = static_cast(dpy); + + Error error = display->initialize(); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (major) *major = 1; + if (minor) *minor = 4; + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY Terminate(EGLDisplay dpy) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy); + + if (dpy == EGL_NO_DISPLAY) + { + SetGlobalError(Error(EGL_BAD_DISPLAY)); + return EGL_FALSE; + } + + Display *display = static_cast(dpy); + gl::Context *context = GetGlobalContext(); + + if (display->isValidContext(context)) + { + SetGlobalContext(NULL); + SetGlobalDisplay(NULL); + } + + display->terminate(); + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +const char *EGLAPIENTRY QueryString(EGLDisplay dpy, EGLint name) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name); + + Display *display = static_cast(dpy); + if (!(display == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)) + { + Error error = ValidateDisplay(display); + if (error.isError()) + { + SetGlobalError(error); + return NULL; + } + } + + const char *result; + switch (name) + { + case EGL_CLIENT_APIS: + result = "OpenGL_ES"; + break; + case EGL_EXTENSIONS: + if (display == EGL_NO_DISPLAY) + { + result = Display::getClientExtensionString().c_str(); + } + else + { + result = display->getExtensionString().c_str(); + } + break; + case EGL_VENDOR: + result = display->getVendorString().c_str(); + break; + case EGL_VERSION: + result = "1.4 (ANGLE " ANGLE_VERSION_STRING ")"; + break; + default: + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return NULL; + } + + SetGlobalError(Error(EGL_SUCCESS)); + return result; +} + +EGLBoolean EGLAPIENTRY GetConfigs(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); + + Display *display = static_cast(dpy); + + Error error = ValidateDisplay(display); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (!num_config) + { + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; + } + + std::vector filteredConfigs = display->getConfigs(AttributeMap()); + if (configs) + { + filteredConfigs.resize(std::min(filteredConfigs.size(), config_size)); + for (size_t i = 0; i < filteredConfigs.size(); i++) + { + configs[i] = const_cast(filteredConfigs[i]); + } + } + *num_config = filteredConfigs.size(); + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY ChooseConfig(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); + + Display *display = static_cast(dpy); + + Error error = ValidateDisplay(display); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (!num_config) + { + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; + } + + std::vector filteredConfigs = display->getConfigs(AttributeMap(attrib_list)); + if (configs) + { + filteredConfigs.resize(std::min(filteredConfigs.size(), config_size)); + for (size_t i = 0; i < filteredConfigs.size(); i++) + { + configs[i] = const_cast(filteredConfigs[i]); + } + } + *num_config = filteredConfigs.size(); + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY GetConfigAttrib(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); + + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + + Error error = ValidateConfig(display, configuration); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (!display->getConfigAttrib(configuration, attribute, value)) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; + } + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLSurface EGLAPIENTRY CreateWindowSurface(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); + + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + AttributeMap attributes(attrib_list); + + Error error = ValidateCreateWindowSurface(display, configuration, win, attributes); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_SURFACE; + } + + egl::Surface *surface = nullptr; + error = display->createWindowSurface(configuration, win, attributes, &surface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_SURFACE; + } + + return static_cast(surface); +} + +EGLSurface EGLAPIENTRY CreatePbufferSurface(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); + + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + AttributeMap attributes(attrib_list); + + Error error = ValidateCreatePbufferSurface(display, configuration, attributes); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_SURFACE; + } + + egl::Surface *surface = nullptr; + error = display->createPbufferSurface(configuration, attributes, &surface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_SURFACE; + } + + return static_cast(surface); +} + +EGLSurface EGLAPIENTRY CreatePixmapSurface(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); + + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + + Error error = ValidateConfig(display, configuration); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_SURFACE; + } + + UNIMPLEMENTED(); // FIXME + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_NO_SURFACE; +} + +EGLBoolean EGLAPIENTRY DestroySurface(EGLDisplay dpy, EGLSurface surface) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + SetGlobalError(Error(EGL_BAD_SURFACE)); + return EGL_FALSE; + } + + display->destroySurface((Surface*)surface); + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY QuerySurface(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); + + Display *display = static_cast(dpy); + Surface *eglSurface = (Surface*)surface; + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + SetGlobalError(Error(EGL_BAD_SURFACE)); + return EGL_FALSE; + } + + switch (attribute) + { + case EGL_VG_ALPHA_FORMAT: + UNIMPLEMENTED(); // FIXME + break; + case EGL_VG_COLORSPACE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_CONFIG_ID: + *value = eglSurface->getConfig()->configID; + 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: + *value = eglSurface->getPixelAspectRatio(); + break; + case EGL_RENDER_BUFFER: + *value = eglSurface->getRenderBuffer(); + break; + case EGL_SWAP_BEHAVIOR: + *value = eglSurface->getSwapBehavior(); + break; + case EGL_TEXTURE_FORMAT: + *value = eglSurface->getTextureFormat(); + break; + case EGL_TEXTURE_TARGET: + *value = eglSurface->getTextureTarget(); + break; + case EGL_VERTICAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + break; + case EGL_WIDTH: + *value = eglSurface->getWidth(); + break; + case EGL_POST_SUB_BUFFER_SUPPORTED_NV: + if (!display->getExtensions().postSubBuffer) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; + } + *value = eglSurface->isPostSubBufferSupported(); + break; + case EGL_FIXED_SIZE_ANGLE: + if (!display->getExtensions().windowFixedSize) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; + } + *value = eglSurface->isFixedSize(); + break; + default: + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; + } + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLContext EGLAPIENTRY CreateContext(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); + + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + gl::Context* sharedGLContext = static_cast(share_context); + AttributeMap attributes(attrib_list); + + Error error = ValidateCreateContext(display, configuration, sharedGLContext, attributes); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_CONTEXT; + } + + gl::Context *context = nullptr; + error = display->createContext(configuration, sharedGLContext, attributes, &context); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_CONTEXT; + } + + SetGlobalError(Error(EGL_SUCCESS)); + return static_cast(context); +} + +EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx); + + Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); + + Error error = ValidateContext(display, context); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (ctx == EGL_NO_CONTEXT) + { + SetGlobalError(Error(EGL_BAD_CONTEXT)); + return EGL_FALSE; + } + + if (context == GetGlobalContext()) + { + SetGlobalDisplay(NULL); + SetGlobalContext(NULL); + } + + display->destroyContext(context); + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY MakeCurrent(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); + + Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); + + bool noContext = (ctx == EGL_NO_CONTEXT); + bool noSurface = (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE); + if (noContext != noSurface) + { + SetGlobalError(Error(EGL_BAD_MATCH)); + return EGL_FALSE; + } + + if (ctx != EGL_NO_CONTEXT) + { + Error error = ValidateContext(display, context); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + } + + if (dpy != EGL_NO_DISPLAY && display->isInitialized()) + { + if (display->testDeviceLost()) + { + display->notifyDeviceLost(); + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + SetGlobalError(Error(EGL_CONTEXT_LOST)); + return EGL_FALSE; + } + } + + Surface *drawSurface = static_cast(draw); + if (draw != EGL_NO_SURFACE) + { + Error error = ValidateSurface(display, drawSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + } + + Surface *readSurface = static_cast(read); + if (read != EGL_NO_SURFACE) + { + Error error = ValidateSurface(display, readSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + } + + if (draw != read) + { + UNIMPLEMENTED(); // FIXME + } + + SetGlobalDisplay(display); + SetGlobalDrawSurface(drawSurface); + SetGlobalReadSurface(readSurface); + SetGlobalContext(context); + + if (context != nullptr && display != nullptr && drawSurface != nullptr) + { + display->makeCurrent(drawSurface, readSurface, context); + } + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw) +{ + EVENT("(EGLint readdraw = %d)", readdraw); + + if (readdraw == EGL_READ) + { + SetGlobalError(Error(EGL_SUCCESS)); + return GetGlobalReadSurface(); + } + else if (readdraw == EGL_DRAW) + { + SetGlobalError(Error(EGL_SUCCESS)); + return GetGlobalDrawSurface(); + } + else + { + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_NO_SURFACE; + } +} + +EGLDisplay EGLAPIENTRY GetCurrentDisplay(void) +{ + EVENT("()"); + + EGLDisplay dpy = GetGlobalDisplay(); + + SetGlobalError(Error(EGL_SUCCESS)); + return dpy; +} + +EGLBoolean EGLAPIENTRY QueryContext(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); + + Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); + + Error error = ValidateContext(display, context); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + switch (attribute) + { + case EGL_CONFIG_ID: + *value = context->getConfigID(); + break; + case EGL_CONTEXT_CLIENT_TYPE: + *value = context->getClientType(); + break; + case EGL_CONTEXT_CLIENT_VERSION: + *value = context->getClientVersion(); + break; + case EGL_RENDER_BUFFER: + *value = context->getRenderBuffer(); + break; + default: + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; + } + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY WaitGL(void) +{ + EVENT("()"); + + UNIMPLEMENTED(); // FIXME + + SetGlobalError(Error(EGL_SUCCESS)); + return 0; +} + +EGLBoolean EGLAPIENTRY WaitNative(EGLint engine) +{ + EVENT("(EGLint engine = %d)", engine); + + UNIMPLEMENTED(); // FIXME + + SetGlobalError(Error(EGL_SUCCESS)); + return 0; +} + +EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface); + + Display *display = static_cast(dpy); + Surface *eglSurface = (Surface*)surface; + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + SetGlobalError(Error(EGL_CONTEXT_LOST)); + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + SetGlobalError(Error(EGL_BAD_SURFACE)); + return EGL_FALSE; + } + + error = eglSurface->swap(); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY CopyBuffers(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); + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + SetGlobalError(Error(EGL_CONTEXT_LOST)); + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + SetGlobalError(Error(EGL_SUCCESS)); + return 0; +} + +// EGL 1.1 +EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (buffer != EGL_BACK_BUFFER) + { + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE || eglSurface->getType() == EGL_WINDOW_BIT) + { + SetGlobalError(Error(EGL_BAD_SURFACE)); + return EGL_FALSE; + } + + if (eglSurface->getBoundTexture()) + { + SetGlobalError(Error(EGL_BAD_ACCESS)); + return EGL_FALSE; + } + + if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) + { + SetGlobalError(Error(EGL_BAD_MATCH)); + return EGL_FALSE; + } + + gl::Context *context = GetGlobalContext(); + if (context) + { + gl::Texture *textureObject = context->getTargetTexture(GL_TEXTURE_2D); + ASSERT(textureObject != NULL); + + if (textureObject->isImmutable()) + { + SetGlobalError(Error(EGL_BAD_MATCH)); + return EGL_FALSE; + } + + eglSurface->bindTexImage(textureObject, buffer); + } + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY SurfaceAttrib(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); + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer); + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (buffer != EGL_BACK_BUFFER) + { + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE || eglSurface->getType() == EGL_WINDOW_BIT) + { + SetGlobalError(Error(EGL_BAD_SURFACE)); + return EGL_FALSE; + } + + if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) + { + SetGlobalError(Error(EGL_BAD_MATCH)); + return EGL_FALSE; + } + + gl::Texture *texture = eglSurface->getBoundTexture(); + + if (texture) + { + eglSurface->releaseTexImage(buffer); + } + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY SwapInterval(EGLDisplay dpy, EGLint interval) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval); + + Display *display = static_cast(dpy); + + Error error = ValidateDisplay(display); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + Surface *draw_surface = static_cast(GetGlobalDrawSurface()); + + if (draw_surface == NULL) + { + SetGlobalError(Error(EGL_BAD_SURFACE)); + return EGL_FALSE; + } + + const egl::Config *surfaceConfig = draw_surface->getConfig(); + EGLint clampedInterval = std::min(std::max(interval, surfaceConfig->minSwapInterval), surfaceConfig->maxSwapInterval); + + draw_surface->setSwapInterval(clampedInterval); + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + + +// EGL 1.2 +EGLBoolean EGLAPIENTRY BindAPI(EGLenum api) +{ + EVENT("(EGLenum api = 0x%X)", api); + + switch (api) + { + case EGL_OPENGL_API: + case EGL_OPENVG_API: + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; // Not supported by this implementation + case EGL_OPENGL_ES_API: + break; + default: + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; + } + + SetGlobalAPI(api); + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLenum EGLAPIENTRY QueryAPI(void) +{ + EVENT("()"); + + EGLenum API = GetGlobalAPI(); + + SetGlobalError(Error(EGL_SUCCESS)); + return API; +} + +EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(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); + + Display *display = static_cast(dpy); + Config *configuration = static_cast(config); + AttributeMap attributes(attrib_list); + + Error error = ValidateCreatePbufferFromClientBuffer(display, buftype, buffer, configuration, attributes); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_SURFACE; + } + + egl::Surface *surface = nullptr; + error = display->createPbufferFromClientBuffer(configuration, buffer, attributes, &surface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_NO_SURFACE; + } + + return static_cast(surface); +} + +EGLBoolean EGLAPIENTRY ReleaseThread(void) +{ + EVENT("()"); + + MakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +EGLBoolean EGLAPIENTRY WaitClient(void) +{ + EVENT("()"); + + UNIMPLEMENTED(); // FIXME + + SetGlobalError(Error(EGL_SUCCESS)); + return 0; +} + +// EGL 1.4 +EGLContext EGLAPIENTRY GetCurrentContext(void) +{ + EVENT("()"); + + gl::Context *context = GetGlobalContext(); + + SetGlobalError(Error(EGL_SUCCESS)); + return static_cast(context); +} + +// EGL 1.5 +EGLSync EGLAPIENTRY CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum type = 0x%X, const EGLint* attrib_list = 0x%0.8p)", dpy, type, attrib_list); + + UNIMPLEMENTED(); + return EGL_NO_SYNC; +} + +EGLBoolean EGLAPIENTRY DestroySync(EGLDisplay dpy, EGLSync sync) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p)", dpy, sync); + + UNIMPLEMENTED(); + return EGL_FALSE; +} + +EGLint EGLAPIENTRY ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X, EGLTime timeout = %d)", dpy, sync, flags, timeout); + + UNIMPLEMENTED(); + return 0; +} + +EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint attribute = 0x%X, EGLAttrib *value = 0x%0.8p)", dpy, sync, attribute, value); + + UNIMPLEMENTED(); + return EGL_FALSE; +} + +EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLenum target = 0x%X, " + "EGLClientBuffer buffer = 0x%0.8p, const EGLAttrib *attrib_list = 0x%0.8p)", + dpy, ctx, target, buffer, attrib_list); + + UNIMPLEMENTED(); + return EGL_NO_IMAGE; +} + +EGLBoolean EGLAPIENTRY DestroyImage(EGLDisplay dpy, EGLImage image) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLImage image = 0x%0.8p)", dpy, image); + + UNIMPLEMENTED(); + return EGL_FALSE; +} + +EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list) +{ + EVENT("(EGLenum platform = %d, void* native_display = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", + platform, native_display, attrib_list); + + UNIMPLEMENTED(); + return EGL_NO_DISPLAY; +} + +EGLSurface EGLAPIENTRY CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_window = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", + dpy, config, native_window, attrib_list); + + UNIMPLEMENTED(); + return EGL_NO_SURFACE; +} + +EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_pixmap = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", + dpy, config, native_pixmap, attrib_list); + + UNIMPLEMENTED(); + return EGL_NO_SURFACE; +} + +EGLBoolean EGLAPIENTRY WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X)", dpy, sync, flags); + + UNIMPLEMENTED(); + return EGL_FALSE; +} + +__eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *procname) +{ + EVENT("(const char *procname = \"%s\")", procname); + + struct Extension + { + const char *name; + __eglMustCastToProperFunctionPointerType address; + }; + + static const Extension extensions[] = + { + { "eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)QuerySurfacePointerANGLE }, + { "eglPostSubBufferNV", (__eglMustCastToProperFunctionPointerType)PostSubBufferNV }, + { "eglGetPlatformDisplayEXT", (__eglMustCastToProperFunctionPointerType)GetPlatformDisplayEXT }, + { "glBlitFramebufferANGLE", (__eglMustCastToProperFunctionPointerType)gl::BlitFramebufferANGLE }, + { "glRenderbufferStorageMultisampleANGLE", (__eglMustCastToProperFunctionPointerType)gl::RenderbufferStorageMultisampleANGLE }, + { "glDeleteFencesNV", (__eglMustCastToProperFunctionPointerType)gl::DeleteFencesNV }, + { "glGenFencesNV", (__eglMustCastToProperFunctionPointerType)gl::GenFencesNV }, + { "glIsFenceNV", (__eglMustCastToProperFunctionPointerType)gl::IsFenceNV }, + { "glTestFenceNV", (__eglMustCastToProperFunctionPointerType)gl::TestFenceNV }, + { "glGetFenceivNV", (__eglMustCastToProperFunctionPointerType)gl::GetFenceivNV }, + { "glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)gl::FinishFenceNV }, + { "glSetFenceNV", (__eglMustCastToProperFunctionPointerType)gl::SetFenceNV }, + { "glGetTranslatedShaderSourceANGLE", (__eglMustCastToProperFunctionPointerType)gl::GetTranslatedShaderSourceANGLE }, + { "glTexStorage2DEXT", (__eglMustCastToProperFunctionPointerType)gl::TexStorage2DEXT }, + { "glGetGraphicsResetStatusEXT", (__eglMustCastToProperFunctionPointerType)gl::GetGraphicsResetStatusEXT }, + { "glReadnPixelsEXT", (__eglMustCastToProperFunctionPointerType)gl::ReadnPixelsEXT }, + { "glGetnUniformfvEXT", (__eglMustCastToProperFunctionPointerType)gl::GetnUniformfvEXT }, + { "glGetnUniformivEXT", (__eglMustCastToProperFunctionPointerType)gl::GetnUniformivEXT }, + { "glGenQueriesEXT", (__eglMustCastToProperFunctionPointerType)gl::GenQueriesEXT }, + { "glDeleteQueriesEXT", (__eglMustCastToProperFunctionPointerType)gl::DeleteQueriesEXT }, + { "glIsQueryEXT", (__eglMustCastToProperFunctionPointerType)gl::IsQueryEXT }, + { "glBeginQueryEXT", (__eglMustCastToProperFunctionPointerType)gl::BeginQueryEXT }, + { "glEndQueryEXT", (__eglMustCastToProperFunctionPointerType)gl::EndQueryEXT }, + { "glGetQueryivEXT", (__eglMustCastToProperFunctionPointerType)gl::GetQueryivEXT }, + { "glGetQueryObjectuivEXT", (__eglMustCastToProperFunctionPointerType)gl::GetQueryObjectuivEXT }, + { "glDrawBuffersEXT", (__eglMustCastToProperFunctionPointerType)gl::DrawBuffersEXT }, + { "glVertexAttribDivisorANGLE", (__eglMustCastToProperFunctionPointerType)gl::VertexAttribDivisorANGLE }, + { "glDrawArraysInstancedANGLE", (__eglMustCastToProperFunctionPointerType)gl::DrawArraysInstancedANGLE }, + { "glDrawElementsInstancedANGLE", (__eglMustCastToProperFunctionPointerType)gl::DrawElementsInstancedANGLE }, + { "glGetProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)gl::GetProgramBinaryOES }, + { "glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)gl::ProgramBinaryOES }, + { "glGetBufferPointervOES", (__eglMustCastToProperFunctionPointerType)gl::GetBufferPointervOES }, + { "glMapBufferOES", (__eglMustCastToProperFunctionPointerType)gl::MapBufferOES }, + { "glUnmapBufferOES", (__eglMustCastToProperFunctionPointerType)gl::UnmapBufferOES }, + { "glMapBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)gl::MapBufferRangeEXT }, + { "glFlushMappedBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)gl::FlushMappedBufferRangeEXT }, + { "", NULL }, + }; + + for (const Extension *extension = &extensions[0]; extension->address != nullptr; extension++) + { + if (strcmp(procname, extension->name) == 0) + { + return reinterpret_cast<__eglMustCastToProperFunctionPointerType>(extension->address); + } + } + + return NULL; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl.h b/src/3rdparty/angle/src/libGLESv2/entry_points_egl.h new file mode 100644 index 0000000000..259a209684 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl.h @@ -0,0 +1,74 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_egl.h : Defines the EGL entry points. + +#ifndef LIBGLESV2_ENTRYPOINTSEGL_H_ +#define LIBGLESV2_ENTRYPOINTSEGL_H_ + +#include +#include + +namespace egl +{ + +// EGL 1.0 +ANGLE_EXPORT EGLBoolean EGLAPIENTRY ChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target); +ANGLE_EXPORT EGLContext EGLAPIENTRY CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); +ANGLE_EXPORT EGLSurface EGLAPIENTRY CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list); +ANGLE_EXPORT EGLSurface EGLAPIENTRY CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list); +ANGLE_EXPORT EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroyContext(EGLDisplay dpy, EGLContext ctx); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroySurface(EGLDisplay dpy, EGLSurface surface); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY GetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); +ANGLE_EXPORT EGLDisplay EGLAPIENTRY GetCurrentDisplay(void); +ANGLE_EXPORT EGLSurface EGLAPIENTRY GetCurrentSurface(EGLint readdraw); +ANGLE_EXPORT EGLDisplay EGLAPIENTRY GetDisplay(EGLNativeDisplayType display_id); +ANGLE_EXPORT EGLint EGLAPIENTRY GetError(void); +ANGLE_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *procname); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY Initialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); +ANGLE_EXPORT const char *EGLAPIENTRY QueryString(EGLDisplay dpy, EGLint name); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY QuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY SwapBuffers(EGLDisplay dpy, EGLSurface surface); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY Terminate(EGLDisplay dpy); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY WaitGL(void); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY WaitNative(EGLint engine); + +// EGL 1.1 +ANGLE_EXPORT EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY SwapInterval(EGLDisplay dpy, EGLint interval); + +// EGL 1.2 +ANGLE_EXPORT EGLBoolean EGLAPIENTRY BindAPI(EGLenum api); +ANGLE_EXPORT EGLenum EGLAPIENTRY QueryAPI(void); +ANGLE_EXPORT EGLSurface EGLAPIENTRY CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseThread(void); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY WaitClient(void); + +// EGL 1.4 +ANGLE_EXPORT EGLContext EGLAPIENTRY GetCurrentContext(void); + +// EGL 1.5 +ANGLE_EXPORT EGLSync EGLAPIENTRY CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroySync(EGLDisplay dpy, EGLSync sync); +ANGLE_EXPORT EGLint EGLAPIENTRY ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value); +ANGLE_EXPORT EGLImage EGLAPIENTRY CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroyImage(EGLDisplay dpy, EGLImage image); +ANGLE_EXPORT EGLDisplay EGLAPIENTRY GetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list); +ANGLE_EXPORT EGLSurface EGLAPIENTRY CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list); +ANGLE_EXPORT EGLSurface EGLAPIENTRY CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list); +ANGLE_EXPORT EGLBoolean EGLAPIENTRY WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags); + +} + +#endif // LIBGLESV2_ENTRYPOINTSEGL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp new file mode 100644 index 0000000000..ded73dbb48 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp @@ -0,0 +1,271 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_ext.cpp : Implements the EGL extension entry points. + +#include "libGLESv2/entry_points_egl_ext.h" +#include "libGLESv2/global_state.h" + +#include "libANGLE/Display.h" +#include "libANGLE/Surface.h" +#include "libANGLE/validationEGL.h" + +#include "common/debug.h" + +namespace egl +{ + +// EGL_ANGLE_query_surface_pointer +EGLBoolean EGLAPIENTRY QuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value) +{ + EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)", + dpy, surface, attribute, value); + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (!display->getExtensions().querySurfacePointer) + { + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + SetGlobalError(Error(EGL_BAD_SURFACE)); + return EGL_FALSE; + } + + // validate the attribute parameter + switch (attribute) + { + case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: + if (!display->getExtensions().surfaceD3DTexture2DShareHandle) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; + } + break; + + default: + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; + } + + error = eglSurface->querySurfacePointerANGLE(attribute, value); + SetGlobalError(error); + return (error.isError() ? EGL_FALSE : EGL_TRUE); +} + + +// EGL_NV_post_sub_buffer +EGLBoolean EGLAPIENTRY PostSubBufferNV(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); + + if (x < 0 || y < 0 || width < 0 || height < 0) + { + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; + } + + Display *display = static_cast(dpy); + Surface *eglSurface = static_cast(surface); + + Error error = ValidateSurface(display, eglSurface); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + if (display->isDeviceLost()) + { + SetGlobalError(Error(EGL_CONTEXT_LOST)); + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + SetGlobalError(Error(EGL_BAD_SURFACE)); + return EGL_FALSE; + } + + if (!display->getExtensions().postSubBuffer) + { + // Spec is not clear about how this should be handled. + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; + } + + error = eglSurface->postSubBuffer(x, y, width, height); + if (error.isError()) + { + SetGlobalError(error); + return EGL_FALSE; + } + + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; +} + +// EGL_EXT_platform_base +EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) +{ + EVENT("(EGLenum platform = %d, void* native_display = 0x%0.8p, const EGLint* attrib_list = 0x%0.8p)", + platform, native_display, attrib_list); + + const ClientExtensions &clientExtensions = Display::getClientExtensions(); + + switch (platform) + { + case EGL_PLATFORM_ANGLE_ANGLE: + if (!clientExtensions.platformANGLE) + { + SetGlobalError(Error(EGL_BAD_PARAMETER)); + return EGL_NO_DISPLAY; + } + break; + + default: + SetGlobalError(Error(EGL_BAD_CONFIG)); + return EGL_NO_DISPLAY; + } + + EGLint platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; + EGLint deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE; + bool majorVersionSpecified = false; + bool minorVersionSpecified = false; + bool enableAutoTrimSpecified = false; + + if (attrib_list) + { + for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2) + { + switch (curAttrib[0]) + { + case EGL_PLATFORM_ANGLE_TYPE_ANGLE: + switch (curAttrib[1]) + { + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: + break; + + case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: + if (!clientExtensions.platformANGLED3D) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: + if (!clientExtensions.platformANGLEOpenGL) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; + } + break; + + default: + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; + } + platformType = curAttrib[1]; + break; + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE: + if (curAttrib[1] != EGL_DONT_CARE) + { + majorVersionSpecified = true; + } + break; + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE: + if (curAttrib[1] != EGL_DONT_CARE) + { + minorVersionSpecified = true; + } + break; + + case EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE: + switch (curAttrib[1]) + { + case EGL_TRUE: + case EGL_FALSE: + break; + default: + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; + } + enableAutoTrimSpecified = true; + break; + + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE: + if (!clientExtensions.platformANGLED3D) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; + } + + switch (curAttrib[1]) + { + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE: + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE: + case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: + break; + + default: + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; + } + deviceType = curAttrib[1]; + break; + + default: + break; + } + } + } + + if (!majorVersionSpecified && minorVersionSpecified) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; + } + + if (deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE && + platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE, "EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE requires a device type of " + "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.")); + return EGL_NO_DISPLAY; + } + + if (enableAutoTrimSpecified && + platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) + { + SetGlobalError(Error(EGL_BAD_ATTRIBUTE, "EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE requires a device type of " + "EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE.")); + return EGL_NO_DISPLAY; + } + + SetGlobalError(Error(EGL_SUCCESS)); + + EGLNativeDisplayType displayId = static_cast(native_display); + return Display::getDisplay(displayId, AttributeMap(attrib_list)); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h new file mode 100644 index 0000000000..9de1027082 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.h @@ -0,0 +1,30 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_egl_ext.h : Defines the EGL extension entry points. + +#ifndef LIBGLESV2_ENTRYPOINTSEGLEXT_H_ +#define LIBGLESV2_ENTRYPOINTSEGLEXT_H_ + +#include +#include +#include + +namespace egl +{ + +// EGL_ANGLE_query_surface_pointer +ANGLE_EXPORT EGLBoolean EGLAPIENTRY QuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); + +// EGL_NV_post_sub_buffer +ANGLE_EXPORT EGLBoolean EGLAPIENTRY PostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height); + +// EGL_EXT_platform_base +ANGLE_EXPORT EGLDisplay EGLAPIENTRY GetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list); + +} + +#endif // LIBGLESV2_ENTRYPOINTSEGLEXT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp new file mode 100644 index 0000000000..6d3089ba4f --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.cpp @@ -0,0 +1,4318 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_gles_2_0.cpp : Implements the GLES 2.0 entry points. + +#include "libGLESv2/entry_points_gles_2_0.h" +#include "libGLESv2/global_state.h" + +#include "libANGLE/formatutils.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Compiler.h" +#include "libANGLE/Context.h" +#include "libANGLE/Error.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Renderbuffer.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Program.h" +#include "libANGLE/Texture.h" +#include "libANGLE/VertexArray.h" +#include "libANGLE/VertexAttribute.h" +#include "libANGLE/FramebufferAttachment.h" + +#include "libANGLE/validationES.h" +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES3.h" +#include "libANGLE/queryconversions.h" + +#include "common/debug.h" +#include "common/utilities.h" +#include "common/version.h" + +namespace gl +{ + +void GL_APIENTRY ActiveTexture(GLenum texture) +{ + EVENT("(GLenum texture = 0x%X)", texture); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getCaps().maxCombinedTextureImageUnits - 1) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + context->getState().setActiveSampler(texture - GL_TEXTURE0); + } +} + +void GL_APIENTRY AttachShader(GLuint program, GLuint shader) +{ + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + Program *programObject = context->getProgram(program); + Shader *shaderObject = context->getShader(shader); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (!programObject->attachShader(shaderObject)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } +} + +void GL_APIENTRY BindAttribLocation(GLuint program, GLuint index, const GLchar* name) +{ + EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (strncmp(name, "gl_", 3) == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + programObject->bindAttributeLocation(index, name); + } +} + +void GL_APIENTRY BindBuffer(GLenum target, GLuint buffer) +{ + EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (target) + { + case GL_ARRAY_BUFFER: + context->bindArrayBuffer(buffer); + return; + case GL_ELEMENT_ARRAY_BUFFER: + context->bindElementArrayBuffer(buffer); + return; + case GL_COPY_READ_BUFFER: + context->bindCopyReadBuffer(buffer); + return; + case GL_COPY_WRITE_BUFFER: + context->bindCopyWriteBuffer(buffer); + return; + case GL_PIXEL_PACK_BUFFER: + context->bindPixelPackBuffer(buffer); + return; + case GL_PIXEL_UNPACK_BUFFER: + context->bindPixelUnpackBuffer(buffer); + return; + case GL_UNIFORM_BUFFER: + context->bindGenericUniformBuffer(buffer); + return; + case GL_TRANSFORM_FEEDBACK_BUFFER: + context->bindGenericTransformFeedbackBuffer(buffer); + return; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY BindFramebuffer(GLenum target, GLuint framebuffer) +{ + EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidFramebufferTarget(target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) + { + context->bindReadFramebuffer(framebuffer); + } + + if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) + { + context->bindDrawFramebuffer(framebuffer); + } + } +} + +void GL_APIENTRY BindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (target != GL_RENDERBUFFER) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + context->bindRenderbuffer(renderbuffer); + } +} + +void GL_APIENTRY BindTexture(GLenum target, GLuint texture) +{ + EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); + + Context *context = GetValidGlobalContext(); + if (context) + { + Texture *textureObject = context->getTexture(texture); + + if (textureObject && textureObject->getTarget() != target && texture != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + switch (target) + { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + break; + + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + context->bindTexture(target, texture); + } +} + +void GL_APIENTRY BlendColor(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->getState().setBlendColor(clamp01(red), clamp01(green), clamp01(blue), clamp01(alpha)); + } +} + +void GL_APIENTRY BlendEquation(GLenum mode) +{ + BlendEquationSeparate(mode, mode); +} + +void GL_APIENTRY BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (modeRGB) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + case GL_MIN: + case GL_MAX: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (modeAlpha) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + case GL_MIN: + case GL_MAX: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + context->getState().setBlendEquation(modeRGB, modeAlpha); + } +} + +void GL_APIENTRY BlendFunc(GLenum sfactor, GLenum dfactor) +{ + BlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); +} + +void GL_APIENTRY BlendFuncSeparate(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + 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: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + 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; + + case GL_SRC_ALPHA_SATURATE: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + 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: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + 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; + + case GL_SRC_ALPHA_SATURATE: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + 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"); + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->getState().setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); + } +} + +void GL_APIENTRY BufferData(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (size < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + switch (usage) + { + case GL_STREAM_DRAW: + case GL_STATIC_DRAW: + case GL_DYNAMIC_DRAW: + break; + + case GL_STREAM_READ: + case GL_STREAM_COPY: + case GL_STATIC_READ: + case GL_STATIC_COPY: + case GL_DYNAMIC_READ: + case GL_DYNAMIC_COPY: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (!buffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + Error error = buffer->bufferData(data, size, usage); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY BufferSubData(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (size < 0 || offset < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (data == NULL) + { + return; + } + + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (!buffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (buffer->isMapped()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // Check for possible overflow of size + offset + if (!rx::IsUnsignedAdditionSafe(size, offset)) + { + context->recordError(Error(GL_OUT_OF_MEMORY)); + return; + } + + if (size + offset > buffer->getSize()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Error error = buffer->bufferSubData(data, size, offset); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +GLenum GL_APIENTRY CheckFramebufferStatus(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidFramebufferTarget(target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return 0; + } + + Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + return framebuffer->checkStatus(context->getData()); + } + + return 0; +} + +void GL_APIENTRY Clear(GLbitfield mask) +{ + EVENT("(GLbitfield mask = 0x%X)", mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); + ASSERT(framebufferObject); + + if (framebufferObject->checkStatus(context->getData()) != GL_FRAMEBUFFER_COMPLETE) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return; + } + + if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Error error = framebufferObject->clear(context->getData(), mask); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY ClearColor(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->getState().setColorClearValue(red, green, blue, alpha); + } +} + +void GL_APIENTRY ClearDepthf(GLclampf depth) +{ + EVENT("(GLclampf depth = %f)", depth); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->getState().setDepthClearValue(depth); + } +} + +void GL_APIENTRY ClearStencil(GLint s) +{ + EVENT("(GLint s = %d)", s); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->getState().setStencilClearValue(s); + } +} + +void GL_APIENTRY ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + EVENT("(GLboolean red = %d, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)", + red, green, blue, alpha); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->getState().setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE); + } +} + +void GL_APIENTRY CompileShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + shaderObject->compile(context->getCompiler()); + } +} + +void GL_APIENTRY CompressedTexImage2D(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2TexImageParameters(context, target, level, internalformat, true, false, + 0, 0, width, height, border, GL_NONE, GL_NONE, data)) + { + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3TexImageParameters(context, target, level, internalformat, true, false, + 0, 0, 0, width, height, 1, border, GL_NONE, GL_NONE, data)) + { + return; + } + + const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); + if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Extents size(width, height, 1); + Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + Error error = texture->setCompressedImage(target, level, internalformat, size, context->getState().getUnpackState(), + reinterpret_cast(data)); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY CompressedTexSubImage2D(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2TexImageParameters(context, target, level, GL_NONE, true, true, + xoffset, yoffset, width, height, 0, GL_NONE, GL_NONE, data)) + { + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true, + xoffset, yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE, data)) + { + return; + } + + const InternalFormat &formatInfo = GetInternalFormatInfo(format); + if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + + Box area(xoffset, yoffset, 0, width, height, 1); + Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + Error error = texture->setCompressedSubImage(target, level, area, format, context->getState().getUnpackState(), + reinterpret_cast(data)); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY CopyTexImage2D(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, + 0, 0, x, y, width, height, border)) + { + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3CopyTexImageParameters(context, target, level, internalformat, false, + 0, 0, 0, x, y, width, height, border)) + { + return; + } + + Rectangle sourceArea(x, y, width, height); + + const Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + Error error = texture->copyImage(target, level, sourceArea, internalformat, framebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY CopyTexSubImage2D(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, + xoffset, yoffset, x, y, width, height, 0)) + { + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, + xoffset, yoffset, 0, x, y, width, height, 0)) + { + return; + } + + Offset destOffset(xoffset, yoffset, 0); + Rectangle sourceArea(x, y, width, height); + + const Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +GLuint GL_APIENTRY CreateProgram(void) +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + return context->createProgram(); + } + + return 0; +} + +GLuint GL_APIENTRY CreateShader(GLenum type) +{ + EVENT("(GLenum type = 0x%X)", type); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (type) + { + case GL_FRAGMENT_SHADER: + case GL_VERTEX_SHADER: + return context->createShader(type); + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return 0; + } + } + + return 0; +} + +void GL_APIENTRY CullFace(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (mode) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + context->getState().setCullMode(mode); + } +} + +void GL_APIENTRY DeleteBuffers(GLsizei n, const GLuint* buffers) +{ + EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + context->deleteBuffer(buffers[i]); + } + } +} + +void GL_APIENTRY DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +{ + EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + if (framebuffers[i] != 0) + { + context->deleteFramebuffer(framebuffers[i]); + } + } + } +} + +void GL_APIENTRY DeleteProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (program == 0) + { + return; + } + + if (!context->getProgram(program)) + { + if(context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + context->deleteProgram(program); + } +} + +void GL_APIENTRY DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +{ + EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + context->deleteRenderbuffer(renderbuffers[i]); + } + } +} + +void GL_APIENTRY DeleteShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (shader == 0) + { + return; + } + + if (!context->getShader(shader)) + { + if(context->getProgram(shader)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + context->deleteShader(shader); + } +} + +void GL_APIENTRY DeleteTextures(GLsizei n, const GLuint* textures) +{ + EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + if (textures[i] != 0) + { + context->deleteTexture(textures[i]); + } + } + } +} + +void GL_APIENTRY DepthFunc(GLenum func) +{ + EVENT("(GLenum func = 0x%X)", func); + + Context *context = GetValidGlobalContext(); + if (context) + { + 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: + context->getState().setDepthFunc(func); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY DepthMask(GLboolean flag) +{ + EVENT("(GLboolean flag = %u)", flag); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->getState().setDepthMask(flag != GL_FALSE); + } +} + +void GL_APIENTRY DepthRangef(GLclampf zNear, GLclampf zFar) +{ + EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->getState().setDepthRange(zNear, zFar); + } +} + +void GL_APIENTRY DetachShader(GLuint program, GLuint shader) +{ + EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); + + Context *context = GetValidGlobalContext(); + if (context) + { + Program *programObject = context->getProgram(program); + Shader *shaderObject = context->getShader(shader); + + if (!programObject) + { + Shader *shaderByProgramHandle; + shaderByProgramHandle = context->getShader(program); + if (!shaderByProgramHandle) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + else + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } + + if (!shaderObject) + { + Program *programByShaderHandle = context->getProgram(shader); + if (!programByShaderHandle) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + else + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } + + if (!programObject->detachShader(shaderObject)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } +} + +void GL_APIENTRY Disable(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidCap(context, cap)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + context->getState().setEnableFeature(cap, false); + } +} + +void GL_APIENTRY DisableVertexAttribArray(GLuint index) +{ + EVENT("(GLuint index = %d)", index); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->getState().setEnableVertexAttribArray(index, false); + } +} + +void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateDrawArrays(context, mode, first, count, 0)) + { + return; + } + + Error error = context->drawArrays(mode, first, count, 0); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY DrawElements(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + rx::RangeUI indexRange; + if (!ValidateDrawElements(context, mode, count, type, indices, 0, &indexRange)) + { + return; + } + + Error error = context->drawElements(mode, count, type, indices, 0, indexRange); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY Enable(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidCap(context, cap)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + context->getState().setEnableFeature(cap, true); + } +} + +void GL_APIENTRY EnableVertexAttribArray(GLuint index) +{ + EVENT("(GLuint index = %d)", index); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->getState().setEnableVertexAttribArray(index, true); + } +} + +void GL_APIENTRY Finish(void) +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + Error error = context->finish(); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY Flush(void) +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + if (context) + { + Error error = context->flush(); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY FramebufferRenderbuffer(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidFramebufferTarget(target) || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (!ValidateFramebufferRenderbufferParameters(context, target, attachment, renderbuffertarget, renderbuffer)) + { + return; + } + + Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (renderbuffer != 0) + { + Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); + framebuffer->setRenderbufferAttachment(attachment, renderbufferObject); + } + else + { + framebuffer->setNULLAttachment(attachment); + } + } +} + +void GL_APIENTRY FramebufferTexture2D(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level)) + { + return; + } + + Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (texture != 0) + { + Texture *textureObj = context->getTexture(texture); + + ImageIndex index = ImageIndex::MakeInvalid(); + + if (textarget == GL_TEXTURE_2D) + { + index = ImageIndex::Make2D(level); + } + else + { + ASSERT(IsCubeMapTextureTarget(textarget)); + index = ImageIndex::MakeCube(textarget, level); + } + + framebuffer->setTextureAttachment(attachment, textureObj, index); + } + else + { + framebuffer->setNULLAttachment(attachment); + } + } +} + +void GL_APIENTRY FrontFace(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (mode) + { + case GL_CW: + case GL_CCW: + context->getState().setFrontFace(mode); + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GenBuffers(GLsizei n, GLuint* buffers) +{ + EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + buffers[i] = context->createBuffer(); + } + } +} + +void GL_APIENTRY GenerateMipmap(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidTextureTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Texture *texture = context->getTargetTexture(target); + + if (texture == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + GLenum baseTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target; + GLenum internalFormat = texture->getInternalFormat(baseTarget, 0); + const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat); + const InternalFormat &formatInfo = GetInternalFormatInfo(internalFormat); + + // GenerateMipmap should not generate an INVALID_OPERATION for textures created with + // unsized formats or that are color renderable and filterable. Since we do not track if + // the texture was created with sized or unsized format (only sized formats are stored), + // it is not possible to make sure the the LUMA formats can generate mipmaps (they should + // be able to) because they aren't color renderable. Simply do a special case for LUMA + // textures since they're the only texture format that can be created with unsized formats + // that is not color renderable. New unsized formats are unlikely to be added, since ES2 + // was the last version to use add them. + bool isLUMA = internalFormat == GL_LUMINANCE8_EXT || + internalFormat == GL_LUMINANCE8_ALPHA8_EXT || + internalFormat == GL_ALPHA8_EXT; + + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable || + (!formatCaps.renderable && !isLUMA) || formatInfo.compressed) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // GL_EXT_sRGB does not support mipmap generation on sRGB textures + if (context->getClientVersion() == 2 && formatInfo.colorEncoding == GL_SRGB) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // Non-power of 2 ES2 check + if (!context->getExtensions().textureNPOT && (!isPow2(texture->getWidth(baseTarget, 0)) || !isPow2(texture->getHeight(baseTarget, 0)))) + { + ASSERT(context->getClientVersion() <= 2 && (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP)); + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // Cube completeness check + if (target == GL_TEXTURE_CUBE_MAP && !texture->isCubeComplete()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + Error error = texture->generateMipmaps(); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY GenFramebuffers(GLsizei n, GLuint* framebuffers) +{ + EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + framebuffers[i] = context->createFramebuffer(); + } + } +} + +void GL_APIENTRY GenRenderbuffers(GLsizei n, GLuint* renderbuffers) +{ + EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + renderbuffers[i] = context->createRenderbuffer(); + } + } +} + +void GL_APIENTRY GenTextures(GLsizei n, GLuint* textures) +{ + EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + textures[i] = context->createTexture(); + } + } +} + +void GL_APIENTRY GetActiveAttrib(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (bufsize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (index >= (GLuint)programObject->getActiveAttributeCount()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + programObject->getActiveAttribute(index, bufsize, length, size, type, name); + } +} + +void GL_APIENTRY GetActiveUniform(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); + + + Context *context = GetValidGlobalContext(); + if (context) + { + if (bufsize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (index >= (GLuint)programObject->getActiveUniformCount()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + programObject->getActiveUniform(index, bufsize, length, size, type, name); + } +} + +void GL_APIENTRY GetAttachedShaders(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (maxcount < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + return programObject->getAttachedShaders(maxcount, count, shaders); + } +} + +GLint GL_APIENTRY GetAttribLocation(GLuint program, const GLchar* name) +{ + EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return -1; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return -1; + } + } + + if (!programObject->isLinked()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return -1; + } + + return programObject->getAttributeLocation(name); + } + + return -1; +} + +void GL_APIENTRY GetBooleanv(GLenum pname, GLboolean* params) +{ + EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) + { + return; + } + + if (nativeType == GL_BOOL) + { + context->getBooleanv(pname, params); + } + else + { + CastStateValues(context, nativeType, pname, numParams, params); + } + } +} + +void GL_APIENTRY GetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (!ValidBufferParameter(context, pname)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (!buffer) + { + // A null buffer means that "0" is bound to the requested buffer target + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + switch (pname) + { + case GL_BUFFER_USAGE: + *params = static_cast(buffer->getUsage()); + break; + case GL_BUFFER_SIZE: + *params = clampCast(buffer->getSize()); + break; + case GL_BUFFER_ACCESS_FLAGS: + *params = buffer->getAccessFlags(); + break; + case GL_BUFFER_MAPPED: + *params = static_cast(buffer->isMapped()); + break; + case GL_BUFFER_MAP_OFFSET: + *params = clampCast(buffer->getMapOffset()); + break; + case GL_BUFFER_MAP_LENGTH: + *params = clampCast(buffer->getMapLength()); + break; + default: UNREACHABLE(); break; + } + } +} + +GLenum GL_APIENTRY GetError(void) +{ + EVENT("()"); + + Context *context = GetGlobalContext(); + + if (context) + { + return context->getError(); + } + + return GL_NO_ERROR; +} + +void GL_APIENTRY GetFloatv(GLenum pname, GLfloat* params) +{ + EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) + { + return; + } + + if (nativeType == GL_FLOAT) + { + context->getFloatv(pname, params); + } + else + { + CastStateValues(context, nativeType, pname, numParams, params); + } + } +} + +void GL_APIENTRY GetFramebufferAttachmentParameteriv(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidFramebufferTarget(target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + int clientVersion = context->getClientVersion(); + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + if (clientVersion < 3 && !context->getExtensions().sRGB) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + if (clientVersion < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + // Determine if the attachment is a valid enum + switch (attachment) + { + case GL_BACK: + case GL_FRONT: + case GL_DEPTH: + case GL_STENCIL: + case GL_DEPTH_STENCIL_ATTACHMENT: + if (clientVersion < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + default: + if (attachment < GL_COLOR_ATTACHMENT0_EXT || + (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + } + + Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (framebuffer->id() == 0) + { + if (clientVersion < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + switch (attachment) + { + case GL_BACK: + case GL_DEPTH: + case GL_STENCIL: + break; + + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } + else + { + if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + { + // Valid attachment query + } + else + { + switch (attachment) + { + case GL_DEPTH_ATTACHMENT: + case GL_STENCIL_ATTACHMENT: + break; + + case GL_DEPTH_STENCIL_ATTACHMENT: + if (framebuffer->hasValidDepthStencil()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } + } + + const FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment); + if (attachmentObject) + { + ASSERT(attachmentObject->type() == GL_RENDERBUFFER || + attachmentObject->type() == GL_TEXTURE || + attachmentObject->type() == GL_FRAMEBUFFER_DEFAULT); + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = attachmentObject->type(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (attachmentObject->type() != GL_RENDERBUFFER && attachmentObject->type() != GL_TEXTURE) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = attachmentObject->id(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: + if (attachmentObject->type() != GL_TEXTURE) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = attachmentObject->mipLevel(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: + if (attachmentObject->type() != GL_TEXTURE) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = attachmentObject->cubeMapFace(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: + *params = attachmentObject->getRedSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: + *params = attachmentObject->getGreenSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: + *params = attachmentObject->getBlueSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: + *params = attachmentObject->getAlphaSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: + *params = attachmentObject->getDepthSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: + *params = attachmentObject->getStencilSize(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + *params = attachmentObject->getComponentType(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + *params = attachmentObject->getColorEncoding(); + break; + + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: + if (attachmentObject->type() != GL_TEXTURE) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = attachmentObject->layer(); + break; + + default: + UNREACHABLE(); + break; + } + } + else + { + // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE + // is NONE, then querying any other pname will generate INVALID_ENUM. + + // ES 3.0.2 spec pg 235 states that if the attachment type is none, + // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an + // INVALID_OPERATION for all other pnames + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + *params = GL_NONE; + break; + + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: + if (clientVersion < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = 0; + break; + + default: + if (clientVersion < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + else + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } + } + } +} + +void GL_APIENTRY GetIntegerv(GLenum pname, GLint* params) +{ + EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + GLenum nativeType; + unsigned int numParams = 0; + + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) + { + return; + } + + if (nativeType == GL_INT) + { + context->getIntegerv(pname, params); + } + else + { + CastStateValues(context, nativeType, pname, numParams, params); + } + } +} + +void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint* params) +{ + EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + Program *programObject = context->getProgram(program); + + if (!programObject) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (context->getClientVersion() < 3) + { + switch (pname) + { + case GL_ACTIVE_UNIFORM_BLOCKS: + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + case GL_TRANSFORM_FEEDBACK_VARYINGS: + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } + + 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->getBinaryLength(); + return; + case GL_ACTIVE_UNIFORM_BLOCKS: + *params = programObject->getActiveUniformBlockCount(); + return; + case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: + *params = programObject->getActiveUniformBlockMaxLength(); + break; + case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: + *params = programObject->getTransformFeedbackBufferMode(); + break; + case GL_TRANSFORM_FEEDBACK_VARYINGS: + *params = programObject->getTransformFeedbackVaryingCount(); + break; + case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: + *params = programObject->getTransformFeedbackVaryingMaxLength(); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetProgramInfoLog(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (bufsize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + programObject->getInfoLog(bufsize, length, infolog); + } +} + +void GL_APIENTRY GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (target != GL_RENDERBUFFER) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (context->getState().getRenderbufferId() == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + Renderbuffer *renderbuffer = context->getRenderbuffer(context->getState().getRenderbufferId()); + + 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->getExtensions().framebufferMultisample) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = renderbuffer->getSamples(); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + 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: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetShaderInfoLog(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (bufsize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + shaderObject->getInfoLog(bufsize, length, infolog); + } +} + +void GL_APIENTRY GetShaderPrecisionFormat(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (shadertype) + { + case GL_VERTEX_SHADER: + switch (precisiontype) + { + case GL_LOW_FLOAT: + context->getCaps().vertexLowpFloat.get(range, precision); + break; + case GL_MEDIUM_FLOAT: + context->getCaps().vertexMediumpFloat.get(range, precision); + break; + case GL_HIGH_FLOAT: + context->getCaps().vertexHighpFloat.get(range, precision); + break; + + case GL_LOW_INT: + context->getCaps().vertexLowpInt.get(range, precision); + break; + case GL_MEDIUM_INT: + context->getCaps().vertexMediumpInt.get(range, precision); + break; + case GL_HIGH_INT: + context->getCaps().vertexHighpInt.get(range, precision); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + case GL_FRAGMENT_SHADER: + switch (precisiontype) + { + case GL_LOW_FLOAT: + context->getCaps().fragmentLowpFloat.get(range, precision); + break; + case GL_MEDIUM_FLOAT: + context->getCaps().fragmentMediumpFloat.get(range, precision); + break; + case GL_HIGH_FLOAT: + context->getCaps().fragmentHighpFloat.get(range, precision); + break; + + case GL_LOW_INT: + context->getCaps().fragmentLowpInt.get(range, precision); + break; + case GL_MEDIUM_INT: + context->getCaps().fragmentMediumpInt.get(range, precision); + break; + case GL_HIGH_INT: + context->getCaps().fragmentHighpInt.get(range, precision); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + } +} + +void GL_APIENTRY GetShaderSource(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (bufsize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + shaderObject->getSource(bufsize, length, source); + } +} + +const GLubyte *GL_APIENTRY GetString(GLenum name) +{ + EVENT("(GLenum name = 0x%X)", name); + + Context *context = GetValidGlobalContext(); + + switch (name) + { + case GL_VENDOR: + return (GLubyte*)"Google Inc."; + + case GL_RENDERER: + return (GLubyte*)((context != NULL) ? context->getRendererString().c_str() : "ANGLE"); + + case GL_VERSION: + if (context->getClientVersion() == 2) + { + return (GLubyte*)"OpenGL ES 2.0 (ANGLE " ANGLE_VERSION_STRING ")"; + } + else + { + return (GLubyte*)"OpenGL ES 3.0 (ANGLE " ANGLE_VERSION_STRING ")"; + } + + case GL_SHADING_LANGUAGE_VERSION: + if (context->getClientVersion() == 2) + { + return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " ANGLE_VERSION_STRING ")"; + } + else + { + return (GLubyte*)"OpenGL ES GLSL ES 3.00 (ANGLE " ANGLE_VERSION_STRING ")"; + } + + case GL_EXTENSIONS: + return (GLubyte*)((context != NULL) ? context->getExtensionString().c_str() : ""); + + default: + if (context) + { + context->recordError(Error(GL_INVALID_ENUM)); + } + return NULL; + } +} + +void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + Texture *texture = context->getTargetTexture(target); + + if (!texture) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = (GLfloat)texture->getSamplerState().magFilter; + break; + case GL_TEXTURE_MIN_FILTER: + *params = (GLfloat)texture->getSamplerState().minFilter; + break; + case GL_TEXTURE_WRAP_S: + *params = (GLfloat)texture->getSamplerState().wrapS; + break; + case GL_TEXTURE_WRAP_T: + *params = (GLfloat)texture->getSamplerState().wrapT; + break; + case GL_TEXTURE_WRAP_R: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->getSamplerState().wrapR; + break; + case GL_TEXTURE_IMMUTABLE_FORMAT: + // Exposed to ES2.0 through EXT_texture_storage, no client version validation. + *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE); + break; + case GL_TEXTURE_IMMUTABLE_LEVELS: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->immutableLevelCount(); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = (GLfloat)texture->getUsage(); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->getSamplerState().maxAnisotropy; + break; + case GL_TEXTURE_SWIZZLE_R: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->getSamplerState().swizzleRed; + break; + case GL_TEXTURE_SWIZZLE_G: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->getSamplerState().swizzleGreen; + break; + case GL_TEXTURE_SWIZZLE_B: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->getSamplerState().swizzleBlue; + break; + case GL_TEXTURE_SWIZZLE_A: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->getSamplerState().swizzleAlpha; + break; + case GL_TEXTURE_BASE_LEVEL: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->getSamplerState().baseLevel; + break; + case GL_TEXTURE_MAX_LEVEL: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLfloat)texture->getSamplerState().maxLevel; + break; + case GL_TEXTURE_MIN_LOD: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().minLod; + break; + case GL_TEXTURE_MAX_LOD: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().maxLod; + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + Texture *texture = context->getTargetTexture(target); + + if (!texture) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (pname) + { + case GL_TEXTURE_MAG_FILTER: + *params = texture->getSamplerState().magFilter; + break; + case GL_TEXTURE_MIN_FILTER: + *params = texture->getSamplerState().minFilter; + break; + case GL_TEXTURE_WRAP_S: + *params = texture->getSamplerState().wrapS; + break; + case GL_TEXTURE_WRAP_T: + *params = texture->getSamplerState().wrapT; + break; + case GL_TEXTURE_WRAP_R: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().wrapR; + break; + case GL_TEXTURE_IMMUTABLE_FORMAT: + // Exposed to ES2.0 through EXT_texture_storage, no client version validation. + *params = texture->isImmutable() ? GL_TRUE : GL_FALSE; + break; + case GL_TEXTURE_IMMUTABLE_LEVELS: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = static_cast(texture->immutableLevelCount()); + break; + case GL_TEXTURE_USAGE_ANGLE: + *params = texture->getUsage(); + break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + if (!context->getExtensions().textureFilterAnisotropic) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLint)texture->getSamplerState().maxAnisotropy; + break; + case GL_TEXTURE_SWIZZLE_R: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().swizzleRed; + break; + case GL_TEXTURE_SWIZZLE_G: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().swizzleGreen; + break; + case GL_TEXTURE_SWIZZLE_B: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().swizzleBlue; + break; + case GL_TEXTURE_SWIZZLE_A: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().swizzleAlpha; + break; + case GL_TEXTURE_BASE_LEVEL: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().baseLevel; + break; + case GL_TEXTURE_MAX_LEVEL: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = texture->getSamplerState().maxLevel; + break; + case GL_TEXTURE_MIN_LOD: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLint)texture->getSamplerState().minLod; + break; + case GL_TEXTURE_MAX_LOD: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + *params = (GLint)texture->getSamplerState().maxLod; + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetUniformfv(GLuint program, GLint location, GLfloat* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateGetUniformfv(context, program, location, params)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->getUniformfv(location, params); + } +} + +void GL_APIENTRY GetUniformiv(GLuint program, GLint location, GLint* params) +{ + EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateGetUniformiv(context, program, location, params)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->getUniformiv(location, params); + } +} + +GLint GL_APIENTRY GetUniformLocation(GLuint program, const GLchar* name) +{ + EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (strstr(name, "gl_") == name) + { + return -1; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return -1; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return -1; + } + } + + if (!programObject->isLinked()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return -1; + } + + return programObject->getUniformLocation(name); + } + + return -1; +} + +void GL_APIENTRY GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!ValidateGetVertexAttribParameters(context, pname)) + { + return; + } + + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + const VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); + for (int i = 0; i < 4; ++i) + { + params[i] = currentValueData.FloatValues[i]; + } + } + else + { + const VertexAttribute &attribState = context->getState().getVertexArray()->getVertexAttribute(index); + *params = QuerySingleVertexAttributeParameter(attribState, pname); + } + } +} + +void GL_APIENTRY GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!ValidateGetVertexAttribParameters(context, pname)) + { + return; + } + + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + const VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); + for (int i = 0; i < 4; ++i) + { + float currentValue = currentValueData.FloatValues[i]; + params[i] = iround(currentValue); + } + } + else + { + const VertexAttribute &attribState = context->getState().getVertexArray()->getVertexAttribute(index); + *params = QuerySingleVertexAttributeParameter(attribState, pname); + } + } +} + +void GL_APIENTRY GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) +{ + EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + *pointer = const_cast(context->getState().getVertexAttribPointer(index)); + } +} + +void GL_APIENTRY Hint(GLenum target, GLenum mode) +{ + EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (mode) + { + case GL_FASTEST: + case GL_NICEST: + case GL_DONT_CARE: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (target) + { + case GL_GENERATE_MIPMAP_HINT: + context->getState().setGenerateMipmapHint(mode); + break; + + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + context->getState().setFragmentShaderDerivativeHint(mode); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +GLboolean GL_APIENTRY IsBuffer(GLuint buffer) +{ + EVENT("(GLuint buffer = %d)", buffer); + + Context *context = GetValidGlobalContext(); + if (context && buffer) + { + Buffer *bufferObject = context->getBuffer(buffer); + + if (bufferObject) + { + return GL_TRUE; + } + } + + return GL_FALSE; +} + +GLboolean GL_APIENTRY IsEnabled(GLenum cap) +{ + EVENT("(GLenum cap = 0x%X)", cap); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidCap(context, cap)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return GL_FALSE; + } + + return context->getState().getEnableFeature(cap); + } + + return false; +} + +GLboolean GL_APIENTRY IsFramebuffer(GLuint framebuffer) +{ + EVENT("(GLuint framebuffer = %d)", framebuffer); + + Context *context = GetValidGlobalContext(); + if (context && framebuffer) + { + Framebuffer *framebufferObject = context->getFramebuffer(framebuffer); + + if (framebufferObject) + { + return GL_TRUE; + } + } + + return GL_FALSE; +} + +GLboolean GL_APIENTRY IsProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + Context *context = GetValidGlobalContext(); + if (context && program) + { + Program *programObject = context->getProgram(program); + + if (programObject) + { + return GL_TRUE; + } + } + + return GL_FALSE; +} + +GLboolean GL_APIENTRY IsRenderbuffer(GLuint renderbuffer) +{ + EVENT("(GLuint renderbuffer = %d)", renderbuffer); + + Context *context = GetValidGlobalContext(); + if (context && renderbuffer) + { + Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); + + if (renderbufferObject) + { + return GL_TRUE; + } + } + + return GL_FALSE; +} + +GLboolean GL_APIENTRY IsShader(GLuint shader) +{ + EVENT("(GLuint shader = %d)", shader); + + Context *context = GetValidGlobalContext(); + if (context && shader) + { + Shader *shaderObject = context->getShader(shader); + + if (shaderObject) + { + return GL_TRUE; + } + } + + return GL_FALSE; +} + +GLboolean GL_APIENTRY IsTexture(GLuint texture) +{ + EVENT("(GLuint texture = %d)", texture); + + Context *context = GetValidGlobalContext(); + if (context && texture) + { + Texture *textureObject = context->getTexture(texture); + + if (textureObject) + { + return GL_TRUE; + } + } + + return GL_FALSE; +} + +void GL_APIENTRY LineWidth(GLfloat width) +{ + EVENT("(GLfloat width = %f)", width); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (width <= 0.0f) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->getState().setLineWidth(width); + } +} + +void GL_APIENTRY LinkProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + Error error = programObject->link(context->getData()); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY PixelStorei(GLenum pname, GLint param) +{ + EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + switch (pname) + { + case GL_UNPACK_IMAGE_HEIGHT: + case GL_UNPACK_SKIP_IMAGES: + case GL_UNPACK_ROW_LENGTH: + case GL_UNPACK_SKIP_ROWS: + case GL_UNPACK_SKIP_PIXELS: + case GL_PACK_ROW_LENGTH: + case GL_PACK_SKIP_ROWS: + case GL_PACK_SKIP_PIXELS: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } + + if (param < 0) + { + context->recordError(Error(GL_INVALID_VALUE, "Cannot use negative values in PixelStorei")); + return; + } + + State &state = context->getState(); + + switch (pname) + { + case GL_UNPACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + state.setUnpackAlignment(param); + break; + + case GL_PACK_ALIGNMENT: + if (param != 1 && param != 2 && param != 4 && param != 8) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + state.setPackAlignment(param); + break; + + case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + state.setPackReverseRowOrder(param != 0); + break; + + case GL_UNPACK_ROW_LENGTH: + ASSERT(context->getClientVersion() >= 3); + state.setUnpackRowLength(param); + break; + + case GL_UNPACK_IMAGE_HEIGHT: + ASSERT(context->getClientVersion() >= 3); + state.getUnpackState().imageHeight = param; + break; + + case GL_UNPACK_SKIP_IMAGES: + ASSERT(context->getClientVersion() >= 3); + state.getUnpackState().skipImages = param; + break; + + case GL_UNPACK_SKIP_ROWS: + ASSERT(context->getClientVersion() >= 3); + state.getUnpackState().skipRows = param; + break; + + case GL_UNPACK_SKIP_PIXELS: + ASSERT(context->getClientVersion() >= 3); + state.getUnpackState().skipPixels = param; + break; + + case GL_PACK_ROW_LENGTH: + ASSERT(context->getClientVersion() >= 3); + state.getPackState().rowLength = param; + break; + + case GL_PACK_SKIP_ROWS: + ASSERT(context->getClientVersion() >= 3); + state.getPackState().skipRows = param; + break; + + case GL_PACK_SKIP_PIXELS: + ASSERT(context->getClientVersion() >= 3); + state.getPackState().skipPixels = param; + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY PolygonOffset(GLfloat factor, GLfloat units) +{ + EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); + + Context *context = GetValidGlobalContext(); + if (context) + { + context->getState().setPolygonOffsetParams(factor, units); + } +} + +void GL_APIENTRY ReadPixels(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (width < 0 || height < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!ValidateReadPixelsParameters(context, x, y, width, height, + format, type, NULL, pixels)) + { + return; + } + + Framebuffer *framebufferObject = context->getState().getReadFramebuffer(); + ASSERT(framebufferObject); + + Rectangle area(x, y, width, height); + Error error = framebufferObject->readPixels(context->getState(), area, format, type, pixels); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY ReleaseShaderCompiler(void) +{ + EVENT("()"); + + Context *context = GetValidGlobalContext(); + + if (context) + { + Compiler *compiler = context->getCompiler(); + Error error = compiler->release(); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", + target, internalformat, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateRenderbufferStorageParametersANGLE(context, target, 0, internalformat, + width, height)) + { + return; + } + + Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); + Error error = renderbuffer->setStorage(internalformat, width, height); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY SampleCoverage(GLclampf value, GLboolean invert) +{ + EVENT("(GLclampf value = %f, GLboolean invert = %u)", value, invert); + + Context* context = GetValidGlobalContext(); + + if (context) + { + context->getState().setSampleCoverageParams(clamp01(value), invert == GL_TRUE); + } +} + +void GL_APIENTRY Scissor(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); + + Context* context = GetValidGlobalContext(); + if (context) + { + if (width < 0 || height < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->getState().setScissorParams(x, y, width, height); + } +} + +void GL_APIENTRY ShaderBinary(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); + + Context* context = GetValidGlobalContext(); + if (context) + { + const std::vector &shaderBinaryFormats = context->getCaps().shaderBinaryFormats; + if (std::find(shaderBinaryFormats.begin(), shaderBinaryFormats.end(), binaryformat) == shaderBinaryFormats.end()) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + // No binary shader formats are supported. + UNIMPLEMENTED(); + } +} + +void GL_APIENTRY ShaderSource(GLuint shader, GLsizei count, const GLchar* const* 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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (count < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + if (context->getProgram(shader)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + shaderObject->setSource(count, string, length); + } +} + +void GL_APIENTRY StencilFunc(GLenum func, GLint ref, GLuint mask) +{ + StencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); +} + +void GL_APIENTRY StencilFuncSeparate(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + 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: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilParams(func, ref, mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilBackParams(func, ref, mask); + } + } +} + +void GL_APIENTRY StencilMask(GLuint mask) +{ + StencilMaskSeparate(GL_FRONT_AND_BACK, mask); +} + +void GL_APIENTRY StencilMaskSeparate(GLenum face, GLuint mask) +{ + EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilWritemask(mask); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilBackWritemask(mask); + } + } +} + +void GL_APIENTRY StencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + StencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); +} + +void GL_APIENTRY StencilOpSeparate(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + 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: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + 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: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + 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: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilOperations(fail, zfail, zpass); + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->getState().setStencilBackOperations(fail, zfail, zpass); + } + } +} + +void GL_APIENTRY TexImage2D(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, width, height, border, format, type, pixels)) + { + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, 0, width, height, 1, border, format, type, pixels)) + { + return; + } + + Extents size(width, height, 1); + Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + Error error = texture->setImage(target, level, internalformat, size, format, type, context->getState().getUnpackState(), + reinterpret_cast(pixels)); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateTexParamParameters(context, pname, static_cast(param))) + { + return; + } + + Texture *texture = context->getTargetTexture(target); + + if (!texture) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: texture->getSamplerState().wrapS = uiround(param); break; + case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = uiround(param); break; + case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = uiround(param); break; + case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = uiround(param); break; + case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = uiround(param); break; + case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(uiround(param)); break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->getSamplerState().maxAnisotropy = std::min(param, context->getExtensions().maxTextureAnisotropy); break; + case GL_TEXTURE_COMPARE_MODE: texture->getSamplerState().compareMode = uiround(param); break; + case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = uiround(param); break; + case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = uiround(param); break; + case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = uiround(param); break; + case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = uiround(param); break; + case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = uiround(param); break; + case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = iround(param); break; + case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = iround(param); break; + case GL_TEXTURE_MIN_LOD: texture->getSamplerState().minLod = param; break; + case GL_TEXTURE_MAX_LOD: texture->getSamplerState().maxLod = param; break; + default: UNREACHABLE(); break; + } + } +} + +void GL_APIENTRY TexParameterfv(GLenum target, GLenum pname, const GLfloat* params) +{ + TexParameterf(target, pname, (GLfloat)*params); +} + +void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateTexParamParameters(context, pname, param)) + { + return; + } + + Texture *texture = context->getTargetTexture(target); + + if (!texture) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: texture->getSamplerState().wrapS = (GLenum)param; break; + case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = (GLenum)param; break; + case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = (GLenum)param; break; + case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = (GLenum)param; break; + case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = (GLenum)param; break; + case GL_TEXTURE_USAGE_ANGLE: texture->setUsage((GLenum)param); break; + case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->getSamplerState().maxAnisotropy = std::min((float)param, context->getExtensions().maxTextureAnisotropy); break; + case GL_TEXTURE_COMPARE_MODE: texture->getSamplerState().compareMode = (GLenum)param; break; + case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = (GLenum)param; break; + case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = (GLenum)param; break; + case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = (GLenum)param; break; + case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = (GLenum)param; break; + case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = (GLenum)param; break; + case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = param; break; + case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = param; break; + case GL_TEXTURE_MIN_LOD: texture->getSamplerState().minLod = (GLfloat)param; break; + case GL_TEXTURE_MAX_LOD: texture->getSamplerState().maxLod = (GLfloat)param; break; + default: UNREACHABLE(); break; + } + } +} + +void GL_APIENTRY TexParameteriv(GLenum target, GLenum pname, const GLint* params) +{ + TexParameteri(target, pname, *params); +} + +void GL_APIENTRY TexSubImage2D(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3 && + !ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, + xoffset, yoffset, width, height, 0, format, type, pixels)) + { + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true, + xoffset, yoffset, 0, width, height, 1, 0, format, type, pixels)) + { + return; + } + + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + Box area(xoffset, yoffset, 0, width, height, 1); + Texture *texture = context->getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target); + Error error = texture->setSubImage(target, level, area, format, type, context->getState().getUnpackState(), + reinterpret_cast(pixels)); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY Uniform1f(GLint location, GLfloat x) +{ + Uniform1fv(location, 1, &x); +} + +void GL_APIENTRY Uniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_FLOAT, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform1fv(location, count, v); + } +} + +void GL_APIENTRY Uniform1i(GLint location, GLint x) +{ + Uniform1iv(location, 1, &x); +} + +void GL_APIENTRY Uniform1iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_INT, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform1iv(location, count, v); + } +} + +void GL_APIENTRY Uniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLfloat xy[2] = {x, y}; + + Uniform2fv(location, 1, xy); +} + +void GL_APIENTRY Uniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_FLOAT_VEC2, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform2fv(location, count, v); + } +} + +void GL_APIENTRY Uniform2i(GLint location, GLint x, GLint y) +{ + GLint xy[2] = {x, y}; + + Uniform2iv(location, 1, xy); +} + +void GL_APIENTRY Uniform2iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_INT_VEC2, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform2iv(location, count, v); + } +} + +void GL_APIENTRY Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat xyz[3] = {x, y, z}; + + Uniform3fv(location, 1, xyz); +} + +void GL_APIENTRY Uniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_FLOAT_VEC3, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform3fv(location, count, v); + } +} + +void GL_APIENTRY Uniform3i(GLint location, GLint x, GLint y, GLint z) +{ + GLint xyz[3] = {x, y, z}; + + Uniform3iv(location, 1, xyz); +} + +void GL_APIENTRY Uniform3iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_INT_VEC3, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform3iv(location, count, v); + } +} + +void GL_APIENTRY Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLfloat xyzw[4] = {x, y, z, w}; + + Uniform4fv(location, 1, xyzw); +} + +void GL_APIENTRY Uniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_FLOAT_VEC4, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform4fv(location, count, v); + } +} + +void GL_APIENTRY Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + GLint xyzw[4] = {x, y, z, w}; + + Uniform4iv(location, 1, xyzw); +} + +void GL_APIENTRY Uniform4iv(GLint location, GLsizei count, const GLint* v) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_INT_VEC4, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform4iv(location, count, v); + } +} + +void GL_APIENTRY UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix2fv(location, count, transpose, value); + } +} + +void GL_APIENTRY UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix3fv(location, count, transpose, value); + } +} + +void GL_APIENTRY UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix4fv(location, count, transpose, value); + } +} + +void GL_APIENTRY UseProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + Program *programObject = context->getProgram(program); + + if (!programObject && program != 0) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (program != 0 && !programObject->isLinked()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->useProgram(program); + } +} + +void GL_APIENTRY ValidateProgram(GLuint program) +{ + EVENT("(GLuint program = %d)", program); + + Context *context = GetValidGlobalContext(); + if (context) + { + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + programObject->validate(context->getCaps()); + } +} + +void GL_APIENTRY VertexAttrib1f(GLuint index, GLfloat x) +{ + EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLfloat vals[4] = { x, 0, 0, 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void GL_APIENTRY VertexAttrib1fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLfloat vals[4] = { values[0], 0, 0, 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void GL_APIENTRY VertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +{ + EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLfloat vals[4] = { x, y, 0, 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void GL_APIENTRY VertexAttrib2fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLfloat vals[4] = { values[0], values[1], 0, 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void GL_APIENTRY VertexAttrib3f(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLfloat vals[4] = { x, y, z, 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void GL_APIENTRY VertexAttrib3fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLfloat vals[4] = { values[0], values[1], values[2], 1 }; + context->getState().setVertexAttribf(index, vals); + } +} + +void GL_APIENTRY VertexAttrib4f(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLfloat vals[4] = { x, y, z, w }; + context->getState().setVertexAttribf(index, vals); + } +} + +void GL_APIENTRY VertexAttrib4fv(GLuint index, const GLfloat* values) +{ + EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->getState().setVertexAttribf(index, values); + } +} + +void GL_APIENTRY VertexAttribPointer(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 = %u, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)", + index, size, type, normalized, stride, ptr); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (size < 1 || size > 4) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + switch (type) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_FIXED: + case GL_FLOAT: + break; + + case GL_HALF_FLOAT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_2_10_10_10_REV: + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (stride < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // [OpenGL ES 3.0.2] Section 2.8 page 24: + // An INVALID_OPERATION error is generated when a non-zero vertex array object + // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, + // and the pointer argument is not NULL. + if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && ptr != NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, + normalized == GL_TRUE, false, stride, ptr); + } +} + +void GL_APIENTRY Viewport(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (width < 0 || height < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->getState().setViewportParams(x, y, width, height); + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.h new file mode 100644 index 0000000000..eee5fb5468 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0.h @@ -0,0 +1,163 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_gles_2_0.h : Defines the GLES 2.0 entry points. + +#ifndef LIBGLESV2_ENTRYPOINTGLES20_H_ +#define LIBGLESV2_ENTRYPOINTGLES20_H_ + +#include +#include + +namespace gl +{ + +ANGLE_EXPORT void GL_APIENTRY ActiveTexture(GLenum texture); +ANGLE_EXPORT void GL_APIENTRY AttachShader(GLuint program, GLuint shader); +ANGLE_EXPORT void GL_APIENTRY BindAttribLocation(GLuint program, GLuint index, const GLchar* name); +ANGLE_EXPORT void GL_APIENTRY BindBuffer(GLenum target, GLuint buffer); +ANGLE_EXPORT void GL_APIENTRY BindFramebuffer(GLenum target, GLuint framebuffer); +ANGLE_EXPORT void GL_APIENTRY BindRenderbuffer(GLenum target, GLuint renderbuffer); +ANGLE_EXPORT void GL_APIENTRY BindTexture(GLenum target, GLuint texture); +ANGLE_EXPORT void GL_APIENTRY BlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +ANGLE_EXPORT void GL_APIENTRY BlendEquation(GLenum mode); +ANGLE_EXPORT void GL_APIENTRY BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); +ANGLE_EXPORT void GL_APIENTRY BlendFunc(GLenum sfactor, GLenum dfactor); +ANGLE_EXPORT void GL_APIENTRY BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +ANGLE_EXPORT void GL_APIENTRY BufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); +ANGLE_EXPORT void GL_APIENTRY BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); +ANGLE_EXPORT GLenum GL_APIENTRY CheckFramebufferStatus(GLenum target); +ANGLE_EXPORT void GL_APIENTRY Clear(GLbitfield mask); +ANGLE_EXPORT void GL_APIENTRY ClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +ANGLE_EXPORT void GL_APIENTRY ClearDepthf(GLfloat depth); +ANGLE_EXPORT void GL_APIENTRY ClearStencil(GLint s); +ANGLE_EXPORT void GL_APIENTRY ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +ANGLE_EXPORT void GL_APIENTRY CompileShader(GLuint shader); +ANGLE_EXPORT void GL_APIENTRY CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data); +ANGLE_EXPORT void GL_APIENTRY CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data); +ANGLE_EXPORT void GL_APIENTRY CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +ANGLE_EXPORT void GL_APIENTRY CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +ANGLE_EXPORT GLuint GL_APIENTRY CreateProgram(void); +ANGLE_EXPORT GLuint GL_APIENTRY CreateShader(GLenum type); +ANGLE_EXPORT void GL_APIENTRY CullFace(GLenum mode); +ANGLE_EXPORT void GL_APIENTRY DeleteBuffers(GLsizei n, const GLuint* buffers); +ANGLE_EXPORT void GL_APIENTRY DeleteFramebuffers(GLsizei n, const GLuint* framebuffers); +ANGLE_EXPORT void GL_APIENTRY DeleteProgram(GLuint program); +ANGLE_EXPORT void GL_APIENTRY DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); +ANGLE_EXPORT void GL_APIENTRY DeleteShader(GLuint shader); +ANGLE_EXPORT void GL_APIENTRY DeleteTextures(GLsizei n, const GLuint* textures); +ANGLE_EXPORT void GL_APIENTRY DepthFunc(GLenum func); +ANGLE_EXPORT void GL_APIENTRY DepthMask(GLboolean flag); +ANGLE_EXPORT void GL_APIENTRY DepthRangef(GLfloat n, GLfloat f); +ANGLE_EXPORT void GL_APIENTRY DetachShader(GLuint program, GLuint shader); +ANGLE_EXPORT void GL_APIENTRY Disable(GLenum cap); +ANGLE_EXPORT void GL_APIENTRY DisableVertexAttribArray(GLuint index); +ANGLE_EXPORT void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count); +ANGLE_EXPORT void GL_APIENTRY DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); +ANGLE_EXPORT void GL_APIENTRY Enable(GLenum cap); +ANGLE_EXPORT void GL_APIENTRY EnableVertexAttribArray(GLuint index); +ANGLE_EXPORT void GL_APIENTRY Finish(void); +ANGLE_EXPORT void GL_APIENTRY Flush(void); +ANGLE_EXPORT void GL_APIENTRY FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +ANGLE_EXPORT void GL_APIENTRY FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +ANGLE_EXPORT void GL_APIENTRY FrontFace(GLenum mode); +ANGLE_EXPORT void GL_APIENTRY GenBuffers(GLsizei n, GLuint* buffers); +ANGLE_EXPORT void GL_APIENTRY GenerateMipmap(GLenum target); +ANGLE_EXPORT void GL_APIENTRY GenFramebuffers(GLsizei n, GLuint* framebuffers); +ANGLE_EXPORT void GL_APIENTRY GenRenderbuffers(GLsizei n, GLuint* renderbuffers); +ANGLE_EXPORT void GL_APIENTRY GenTextures(GLsizei n, GLuint* textures); +ANGLE_EXPORT void GL_APIENTRY GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name); +ANGLE_EXPORT void GL_APIENTRY GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); +ANGLE_EXPORT GLint GL_APIENTRY GetAttribLocation(GLuint program, const GLchar* name); +ANGLE_EXPORT void GL_APIENTRY GetBooleanv(GLenum pname, GLboolean* params); +ANGLE_EXPORT void GL_APIENTRY GetBufferParameteriv(GLenum target, GLenum pname, GLint* params); +ANGLE_EXPORT GLenum GL_APIENTRY GetError(void); +ANGLE_EXPORT void GL_APIENTRY GetFloatv(GLenum pname, GLfloat* params); +ANGLE_EXPORT void GL_APIENTRY GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetIntegerv(GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog); +ANGLE_EXPORT void GL_APIENTRY GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog); +ANGLE_EXPORT void GL_APIENTRY GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); +ANGLE_EXPORT void GL_APIENTRY GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); +ANGLE_EXPORT const GLubyte *GL_APIENTRY GetString(GLenum name); +ANGLE_EXPORT void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params); +ANGLE_EXPORT void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetUniformfv(GLuint program, GLint location, GLfloat* params); +ANGLE_EXPORT void GL_APIENTRY GetUniformiv(GLuint program, GLint location, GLint* params); +ANGLE_EXPORT GLint GL_APIENTRY GetUniformLocation(GLuint program, const GLchar* name); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribiv(GLuint index, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer); +ANGLE_EXPORT void GL_APIENTRY Hint(GLenum target, GLenum mode); +ANGLE_EXPORT GLboolean GL_APIENTRY IsBuffer(GLuint buffer); +ANGLE_EXPORT GLboolean GL_APIENTRY IsEnabled(GLenum cap); +ANGLE_EXPORT GLboolean GL_APIENTRY IsFramebuffer(GLuint framebuffer); +ANGLE_EXPORT GLboolean GL_APIENTRY IsProgram(GLuint program); +ANGLE_EXPORT GLboolean GL_APIENTRY IsRenderbuffer(GLuint renderbuffer); +ANGLE_EXPORT GLboolean GL_APIENTRY IsShader(GLuint shader); +ANGLE_EXPORT GLboolean GL_APIENTRY IsTexture(GLuint texture); +ANGLE_EXPORT void GL_APIENTRY LineWidth(GLfloat width); +ANGLE_EXPORT void GL_APIENTRY LinkProgram(GLuint program); +ANGLE_EXPORT void GL_APIENTRY PixelStorei(GLenum pname, GLint param); +ANGLE_EXPORT void GL_APIENTRY PolygonOffset(GLfloat factor, GLfloat units); +ANGLE_EXPORT void GL_APIENTRY ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); +ANGLE_EXPORT void GL_APIENTRY ReleaseShaderCompiler(void); +ANGLE_EXPORT void GL_APIENTRY RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY SampleCoverage(GLfloat value, GLboolean invert); +ANGLE_EXPORT void GL_APIENTRY Scissor(GLint x, GLint y, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length); +ANGLE_EXPORT void GL_APIENTRY ShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); +ANGLE_EXPORT void GL_APIENTRY StencilFunc(GLenum func, GLint ref, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilMask(GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilMaskSeparate(GLenum face, GLuint mask); +ANGLE_EXPORT void GL_APIENTRY StencilOp(GLenum fail, GLenum zfail, GLenum zpass); +ANGLE_EXPORT void GL_APIENTRY StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); +ANGLE_EXPORT void GL_APIENTRY TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); +ANGLE_EXPORT void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param); +ANGLE_EXPORT void GL_APIENTRY TexParameterfv(GLenum target, GLenum pname, const GLfloat* params); +ANGLE_EXPORT void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param); +ANGLE_EXPORT void GL_APIENTRY TexParameteriv(GLenum target, GLenum pname, const GLint* params); +ANGLE_EXPORT void GL_APIENTRY TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); +ANGLE_EXPORT void GL_APIENTRY Uniform1f(GLint location, GLfloat x); +ANGLE_EXPORT void GL_APIENTRY Uniform1fv(GLint location, GLsizei count, const GLfloat* v); +ANGLE_EXPORT void GL_APIENTRY Uniform1i(GLint location, GLint x); +ANGLE_EXPORT void GL_APIENTRY Uniform1iv(GLint location, GLsizei count, const GLint* v); +ANGLE_EXPORT void GL_APIENTRY Uniform2f(GLint location, GLfloat x, GLfloat y); +ANGLE_EXPORT void GL_APIENTRY Uniform2fv(GLint location, GLsizei count, const GLfloat* v); +ANGLE_EXPORT void GL_APIENTRY Uniform2i(GLint location, GLint x, GLint y); +ANGLE_EXPORT void GL_APIENTRY Uniform2iv(GLint location, GLsizei count, const GLint* v); +ANGLE_EXPORT void GL_APIENTRY Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z); +ANGLE_EXPORT void GL_APIENTRY Uniform3fv(GLint location, GLsizei count, const GLfloat* v); +ANGLE_EXPORT void GL_APIENTRY Uniform3i(GLint location, GLint x, GLint y, GLint z); +ANGLE_EXPORT void GL_APIENTRY Uniform3iv(GLint location, GLsizei count, const GLint* v); +ANGLE_EXPORT void GL_APIENTRY Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +ANGLE_EXPORT void GL_APIENTRY Uniform4fv(GLint location, GLsizei count, const GLfloat* v); +ANGLE_EXPORT void GL_APIENTRY Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w); +ANGLE_EXPORT void GL_APIENTRY Uniform4iv(GLint location, GLsizei count, const GLint* v); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY UseProgram(GLuint program); +ANGLE_EXPORT void GL_APIENTRY ValidateProgram(GLuint program); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib1f(GLuint indx, GLfloat x); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib1fv(GLuint indx, const GLfloat* values); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib2fv(GLuint indx, const GLfloat* values); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib3fv(GLuint indx, const GLfloat* values); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +ANGLE_EXPORT void GL_APIENTRY VertexAttrib4fv(GLuint indx, const GLfloat* values); +ANGLE_EXPORT void GL_APIENTRY VertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr); +ANGLE_EXPORT void GL_APIENTRY Viewport(GLint x, GLint y, GLsizei width, GLsizei height); + +} + +#endif // LIBGLESV2_ENTRYPOINTGLES20_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp new file mode 100644 index 0000000000..8be6ae7d2f --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.cpp @@ -0,0 +1,1058 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_gles_2_0_ext.cpp : Implements the GLES 2.0 extension entry points. + +#include "libGLESv2/entry_points_gles_2_0_ext.h" +#include "libGLESv2/global_state.h" + +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" +#include "libANGLE/Error.h" +#include "libANGLE/Fence.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Shader.h" +#include "libANGLE/Query.h" + +#include "libANGLE/validationES.h" +#include "libANGLE/validationES2.h" +#include "libANGLE/validationES3.h" + +#include "common/debug.h" +#include "common/utilities.h" + +namespace gl +{ + +void GL_APIENTRY BeginQueryEXT(GLenum target, GLuint id) +{ + EVENT("(GLenum target = 0x%X, GLuint %d)", target, id); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateBeginQuery(context, target, id)) + { + return; + } + + Error error = context->beginQuery(target, id); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY DeleteFencesNV(GLsizei n, const GLuint* fences) +{ + EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + context->deleteFenceNV(fences[i]); + } + } +} + +void GL_APIENTRY DeleteQueriesEXT(GLsizei n, const GLuint *ids) +{ + EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + context->deleteQuery(ids[i]); + } + } +} + +void GL_APIENTRY DrawArraysInstancedANGLE(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateDrawArraysInstancedANGLE(context, mode, first, count, primcount)) + { + return; + } + + Error error = context->drawArrays(mode, first, count, primcount); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY DrawElementsInstancedANGLE(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + rx::RangeUI indexRange; + if (!ValidateDrawElementsInstancedANGLE(context, mode, count, type, indices, primcount, &indexRange)) + { + return; + } + + Error error = context->drawElements(mode, count, type, indices, primcount, indexRange); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY EndQueryEXT(GLenum target) +{ + EVENT("GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateEndQuery(context, target)) + { + return; + } + + Error error = context->endQuery(target); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY FinishFenceNV(GLuint fence) +{ + EVENT("(GLuint fence = %d)", fence); + + Context *context = GetValidGlobalContext(); + if (context) + { + FenceNV *fenceObject = context->getFenceNV(fence); + + if (fenceObject == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (fenceObject->isFence() != GL_TRUE) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + fenceObject->finishFence(); + } +} + +void GL_APIENTRY GenFencesNV(GLsizei n, GLuint* fences) +{ + EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < n; i++) + { + fences[i] = context->createFenceNV(); + } + } +} + +void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint* ids) +{ + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (GLsizei i = 0; i < n; i++) + { + ids[i] = context->createQuery(); + } + } +} + +void GL_APIENTRY GetFenceivNV(GLuint fence, GLenum pname, GLint *params) +{ + EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + FenceNV *fenceObject = context->getFenceNV(fence); + + if (fenceObject == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (fenceObject->isFence() != GL_TRUE) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + 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. + GLboolean status = GL_TRUE; + if (fenceObject->getStatus() != GL_TRUE) + { + Error error = fenceObject->testFence(&status); + if (error.isError()) + { + context->recordError(error); + return; + } + } + *params = status; + break; + } + + case GL_FENCE_CONDITION_NV: + { + *params = static_cast(fenceObject->getCondition()); + break; + } + + default: + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } + } +} + +GLenum GL_APIENTRY GetGraphicsResetStatusEXT(void) +{ + EVENT("()"); + + Context *context = GetGlobalContext(); + + if (context) + { + return context->getResetStatus(); + } + + return GL_NO_ERROR; +} + +void GL_APIENTRY GetQueryivEXT(GLenum target, GLenum pname, GLint *params) +{ + EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidQueryType(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (pname) + { + case GL_CURRENT_QUERY_EXT: + params[0] = context->getState().getActiveQueryId(target); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) +{ + EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (!queryObject) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (context->getState().getActiveQueryId(queryObject->getType()) == id) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + switch(pname) + { + case GL_QUERY_RESULT_EXT: + { + Error error = queryObject->getResult(params); + if (error.isError()) + { + context->recordError(error); + return; + } + } + break; + + case GL_QUERY_RESULT_AVAILABLE_EXT: + { + Error error = queryObject->isResultAvailable(params); + if (error.isError()) + { + context->recordError(error); + return; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetTranslatedShaderSourceANGLE(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (bufsize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // Only returns extra info if ANGLE_GENERATE_SHADER_DEBUG_INFO is defined + shaderObject->getTranslatedSourceWithDebugInfo(bufsize, length, source); + } +} + +void GL_APIENTRY GetnUniformfvEXT(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateGetnUniformfvEXT(context, program, location, bufSize, params)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->getUniformfv(location, params); + } +} + +void GL_APIENTRY GetnUniformivEXT(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateGetnUniformivEXT(context, program, location, bufSize, params)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->getUniformiv(location, params); + } +} + +GLboolean GL_APIENTRY IsFenceNV(GLuint fence) +{ + EVENT("(GLuint fence = %d)", fence); + + Context *context = GetValidGlobalContext(); + if (context) + { + FenceNV *fenceObject = context->getFenceNV(fence); + + if (fenceObject == NULL) + { + return GL_FALSE; + } + + return fenceObject->isFence(); + } + + return GL_FALSE; +} + +GLboolean GL_APIENTRY IsQueryEXT(GLuint id) +{ + EVENT("(GLuint id = %d)", id); + + Context *context = GetValidGlobalContext(); + if (context) + { + return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE; + } + + return GL_FALSE; +} + +void GL_APIENTRY ReadnPixelsEXT(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (width < 0 || height < 0 || bufSize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!ValidateReadPixelsParameters(context, x, y, width, height, + format, type, &bufSize, data)) + { + return; + } + + Framebuffer *framebufferObject = context->getState().getReadFramebuffer(); + ASSERT(framebufferObject); + + Rectangle area(x, y, width, height); + Error error = framebufferObject->readPixels(context->getState(), area, format, type, data); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY RenderbufferStorageMultisampleANGLE(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateRenderbufferStorageParametersANGLE(context, target, samples, internalformat, + width, height)) + { + return; + } + + Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); + Error error = renderbuffer->setStorageMultisample(samples, internalformat, width, height); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY SetFenceNV(GLuint fence, GLenum condition) +{ + EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (condition != GL_ALL_COMPLETED_NV) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + FenceNV *fenceObject = context->getFenceNV(fence); + + if (fenceObject == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + Error error = fenceObject->setFence(condition); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +GLboolean GL_APIENTRY TestFenceNV(GLuint fence) +{ + EVENT("(GLuint fence = %d)", fence); + + Context *context = GetValidGlobalContext(); + if (context) + { + FenceNV *fenceObject = context->getFenceNV(fence); + + if (fenceObject == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_TRUE; + } + + if (fenceObject->isFence() != GL_TRUE) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_TRUE; + } + + GLboolean result; + Error error = fenceObject->testFence(&result); + if (error.isError()) + { + context->recordError(error); + return GL_TRUE; + } + + return result; + } + + return GL_TRUE; +} + +void GL_APIENTRY TexStorage2DEXT(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!context->getExtensions().textureStorage) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (context->getClientVersion() < 3 && + !ValidateES2TexStorageParameters(context, target, levels, internalformat, width, height)) + { + return; + } + + if (context->getClientVersion() >= 3 && + !ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1)) + { + return; + } + + Extents size(width, height, 1); + Texture *texture = context->getTargetTexture(target); + Error error = texture->setStorage(target, levels, internalformat, size); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY VertexAttribDivisorANGLE(GLuint index, GLuint divisor) +{ + EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->setVertexAttribDivisor(index, divisor); + } +} + +void GL_APIENTRY BlitFramebufferANGLE(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, filter, + true)) + { + return; + } + + Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); + ASSERT(readFramebuffer); + + Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); + ASSERT(drawFramebuffer); + + Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); + Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); + + Error error = drawFramebuffer->blit(context->getState(), srcArea, dstArea, mask, filter, readFramebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY TexImage3DOES(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); + + UNIMPLEMENTED(); // FIXME +} + +void GL_APIENTRY GetProgramBinaryOES(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + Error error = programObject->saveBinary(binaryFormat, binary, bufSize, length); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY ProgramBinaryOES(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + const std::vector &programBinaryFormats = context->getCaps().programBinaryFormats; + if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) == programBinaryFormats.end()) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Program *programObject = context->getProgram(program); + if (!programObject) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + Error error = programObject->loadBinary(binaryFormat, binary, length); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs) +{ + EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (n < 0 || static_cast(n) > context->getCaps().maxDrawBuffers) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + ASSERT(context->getState().getDrawFramebuffer()); + + if (context->getState().getDrawFramebuffer()->id() == 0) + { + if (n != 1) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (bufs[0] != GL_NONE && bufs[0] != GL_BACK) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } + else + { + for (int colorAttachment = 0; colorAttachment < n; colorAttachment++) + { + const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment; + if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + } + } + + Framebuffer *framebuffer = context->getState().getDrawFramebuffer(); + ASSERT(framebuffer); + + framebuffer->setDrawBuffers(n, bufs); + } +} + +void GL_APIENTRY GetBufferPointervOES(GLenum target, GLenum pname, void** params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (pname != GL_BUFFER_MAP_POINTER) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (!buffer || !buffer->isMapped()) + { + *params = NULL; + } + else + { + *params = buffer->getMapPointer(); + } + } +} + +void *GL_APIENTRY MapBufferOES(GLenum target, GLenum access) +{ + EVENT("(GLenum target = 0x%X, GLbitfield access = 0x%X)", target, access); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return NULL; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (buffer == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + if (access != GL_WRITE_ONLY_OES) + { + context->recordError(Error(GL_INVALID_ENUM)); + return NULL; + } + + if (buffer->isMapped()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + Error error = buffer->mapRange(0, buffer->getSize(), GL_MAP_WRITE_BIT); + if (error.isError()) + { + context->recordError(error); + return NULL; + } + + return buffer->getMapPointer(); + } + + return NULL; +} + +GLboolean GL_APIENTRY UnmapBufferOES(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return GL_FALSE; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (buffer == NULL || !buffer->isMapped()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_FALSE; + } + + // TODO: detect if we had corruption. if so, throw an error and return false. + + Error error = buffer->unmap(); + if (error.isError()) + { + context->recordError(error); + return GL_FALSE; + } + + return GL_TRUE; + } + + return GL_FALSE; +} + +void *GL_APIENTRY MapBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", + target, offset, length, access); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return NULL; + } + + if (offset < 0 || length < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return NULL; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (buffer == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + // Check for buffer overflow + size_t offsetSize = static_cast(offset); + size_t lengthSize = static_cast(length); + + if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) || + offsetSize + lengthSize > static_cast(buffer->getSize())) + { + context->recordError(Error(GL_INVALID_VALUE)); + return NULL; + } + + // Check for invalid bits in the mask + GLbitfield allAccessBits = GL_MAP_READ_BIT | + GL_MAP_WRITE_BIT | + GL_MAP_INVALIDATE_RANGE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT | + GL_MAP_FLUSH_EXPLICIT_BIT | + GL_MAP_UNSYNCHRONIZED_BIT; + + if (access & ~(allAccessBits)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return NULL; + } + + if (length == 0 || buffer->isMapped()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + // Check for invalid bit combinations + if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + GLbitfield writeOnlyBits = GL_MAP_INVALIDATE_RANGE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT | + GL_MAP_UNSYNCHRONIZED_BIT; + + if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + Error error = buffer->mapRange(offset, length, access); + if (error.isError()) + { + context->recordError(error); + return NULL; + } + + return buffer->getMapPointer(); + } + + return NULL; +} + +void GL_APIENTRY FlushMappedBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (offset < 0 || length < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (buffer == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // Check for buffer overflow + size_t offsetSize = static_cast(offset); + size_t lengthSize = static_cast(length); + + if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) || + offsetSize + lengthSize > static_cast(buffer->getMapLength())) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + // We do not currently support a non-trivial implementation of FlushMappedBufferRange + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h new file mode 100644 index 0000000000..816519fe1f --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_2_0_ext.h @@ -0,0 +1,78 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_gles_2_0_ext.h : Defines the GLES 2.0 extension entry points. + +#ifndef LIBGLESV2_ENTRYPOINTGLES20EXT_H_ +#define LIBGLESV2_ENTRYPOINTGLES20EXT_H_ + +#include +#include +#include + +namespace gl +{ + +// GL_ANGLE_framebuffer_blit +ANGLE_EXPORT void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); + +// GL_ANGLE_framebuffer_multisample +ANGLE_EXPORT void GL_APIENTRY RenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); + +// GL_NV_fence +ANGLE_EXPORT void GL_APIENTRY DeleteFencesNV(GLsizei n, const GLuint* fences); +ANGLE_EXPORT void GL_APIENTRY GenFencesNV(GLsizei n, GLuint* fences); +ANGLE_EXPORT GLboolean GL_APIENTRY IsFenceNV(GLuint fence); +ANGLE_EXPORT GLboolean GL_APIENTRY TestFenceNV(GLuint fence); +ANGLE_EXPORT void GL_APIENTRY GetFenceivNV(GLuint fence, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY FinishFenceNV(GLuint fence); +ANGLE_EXPORT void GL_APIENTRY SetFenceNV(GLuint fence, GLenum condition); + +// GL_ANGLE_translated_shader_source +ANGLE_EXPORT void GL_APIENTRY GetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source); + +// GL_EXT_texture_storage +ANGLE_EXPORT void GL_APIENTRY TexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); + +// GL_EXT_robustness +ANGLE_EXPORT GLenum GL_APIENTRY GetGraphicsResetStatusEXT(void); +ANGLE_EXPORT void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +ANGLE_EXPORT void GL_APIENTRY GetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, float *params); +ANGLE_EXPORT void GL_APIENTRY GetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint *params); + +// GL_EXT_occlusion_query_boolean +ANGLE_EXPORT void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint *ids); +ANGLE_EXPORT void GL_APIENTRY DeleteQueriesEXT(GLsizei n, const GLuint *ids); +ANGLE_EXPORT GLboolean GL_APIENTRY IsQueryEXT(GLuint id); +ANGLE_EXPORT void GL_APIENTRY BeginQueryEXT(GLenum target, GLuint id); +ANGLE_EXPORT void GL_APIENTRY EndQueryEXT(GLenum target); +ANGLE_EXPORT void GL_APIENTRY GetQueryivEXT(GLenum target, GLenum pname, GLint *params); +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params); + +// GL_EXT_draw_buffers +ANGLE_EXPORT void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs); + +// GL_ANGLE_instanced_arrays +ANGLE_EXPORT void GL_APIENTRY DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount); +ANGLE_EXPORT void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); +ANGLE_EXPORT void GL_APIENTRY VertexAttribDivisorANGLE(GLuint index, GLuint divisor); + +// GL_OES_get_program_binary +ANGLE_EXPORT void GL_APIENTRY GetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +ANGLE_EXPORT void GL_APIENTRY ProgramBinaryOES(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length); + +// GL_OES_mapbuffer +ANGLE_EXPORT void *GL_APIENTRY MapBufferOES(GLenum target, GLenum access); +ANGLE_EXPORT GLboolean GL_APIENTRY UnmapBufferOES(GLenum target); +ANGLE_EXPORT void GL_APIENTRY GetBufferPointervOES(GLenum target, GLenum pname, GLvoid **params); + +// GL_EXT_map_buffer_range +ANGLE_EXPORT void *GL_APIENTRY MapBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +ANGLE_EXPORT void GL_APIENTRY FlushMappedBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length); + +} + +#endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp new file mode 100644 index 0000000000..d8bdcd2e50 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.cpp @@ -0,0 +1,3394 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_gles_3_0.cpp : Implements the GLES 3.0 entry points. + +#include "libGLESv2/entry_points_gles_3_0.h" +#include "libGLESv2/entry_points_gles_2_0_ext.h" +#include "libGLESv2/global_state.h" + +#include "libANGLE/formatutils.h" +#include "libANGLE/Buffer.h" +#include "libANGLE/Context.h" +#include "libANGLE/Error.h" +#include "libANGLE/Fence.h" +#include "libANGLE/Framebuffer.h" +#include "libANGLE/Query.h" +#include "libANGLE/VertexArray.h" + +#include "libANGLE/validationES.h" +#include "libANGLE/validationES3.h" +#include "libANGLE/queryconversions.h" + +#include "common/debug.h" + +namespace gl +{ + +void GL_APIENTRY ReadBuffer(GLenum mode) +{ + EVENT("(GLenum mode = 0x%X)", mode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateReadBuffer(context, mode)) + { + return; + } + + Framebuffer *readFBO = context->getState().getReadFramebuffer(); + readFBO->setReadBuffer(mode); + } +} + +void GL_APIENTRY DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) +{ + EVENT("(GLenum mode = 0x%X, GLuint start = %u, GLuint end = %u, GLsizei count = %d, GLenum type = 0x%X, " + "const GLvoid* indices = 0x%0.8p)", mode, start, end, count, type, indices); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + rx::RangeUI indexRange; + if (!ValidateDrawElements(context, mode, count, type, indices, 0, &indexRange)) + { + return; + } + if (indexRange.end > end || indexRange.start < start) + { + // GL spec says that behavior in this case is undefined - generating an error is fine. + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // As long as index validation is done, it doesn't matter whether the context receives a drawElements or + // a drawRangeElements call - the GL back-end is free to choose to call drawRangeElements based on the + // validated index range. If index validation is removed, adding drawRangeElements to the context interface + // should be reconsidered. + Error error = context->drawElements(mode, count, type, indices, 0, indexRange); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, 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, 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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // validateES3TexImageFormat sets the error code if there is an error + if (!ValidateES3TexImageParameters(context, target, level, internalformat, false, false, + 0, 0, 0, width, height, depth, border, format, type, pixels)) + { + return; + } + + Extents size(width, height, depth); + Texture *texture = context->getTargetTexture(target); + Error error = texture->setImage(target, level, internalformat, size, format, type, context->getState().getUnpackState(), + reinterpret_cast(pixels)); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " + "GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", + target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // validateES3TexImageFormat sets the error code if there is an error + if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true, + xoffset, yoffset, zoffset, width, height, depth, 0, + format, type, pixels)) + { + return; + } + + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0 || depth == 0) + { + return; + } + + Box area(xoffset, yoffset, zoffset, width, height, depth); + Texture *texture = context->getTargetTexture(target); + Error error = texture->setSubImage(target, level, area, format, type, context->getState().getUnpackState(), + reinterpret_cast(pixels)); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", + target, level, xoffset, yoffset, zoffset, x, y, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, yoffset, zoffset, + x, y, width, height, 0)) + { + return; + } + + Offset destOffset(xoffset, yoffset, zoffset); + Rectangle sourceArea(x, y, width, height); + + const Framebuffer *framebuffer = context->getState().getReadFramebuffer(); + Texture *texture = context->getTargetTexture(target); + Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, 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, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, " + "const GLvoid* data = 0x%0.8p)", + target, level, internalformat, width, height, depth, border, imageSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); + if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + // validateES3TexImageFormat sets the error code if there is an error + if (!ValidateES3TexImageParameters(context, target, level, internalformat, true, false, + 0, 0, 0, width, height, depth, border, GL_NONE, GL_NONE, data)) + { + return; + } + + Extents size(width, height, depth); + Texture *texture = context->getTargetTexture(target); + Error error = texture->setCompressedImage(target, level, internalformat, size, context->getState().getUnpackState(), + reinterpret_cast(data)); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) +{ + EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " + "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " + "GLenum format = 0x%X, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", + target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + const InternalFormat &formatInfo = GetInternalFormatInfo(format); + if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!data) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + // validateES3TexImageFormat sets the error code if there is an error + if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true, + 0, 0, 0, width, height, depth, 0, GL_NONE, GL_NONE, data)) + { + return; + } + + // Zero sized uploads are valid but no-ops + if (width == 0 || height == 0) + { + return; + } + + Box area(xoffset, yoffset, zoffset, width, height, depth); + Texture *texture = context->getTargetTexture(target); + Error error = texture->setCompressedSubImage(target, level, area, format, context->getState().getUnpackState(), + reinterpret_cast(data)); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY GenQueries(GLsizei n, GLuint* ids) +{ + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (GLsizei i = 0; i < n; i++) + { + ids[i] = context->createQuery(); + } + } +} + +void GL_APIENTRY DeleteQueries(GLsizei n, const GLuint* ids) +{ + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (GLsizei i = 0; i < n; i++) + { + context->deleteQuery(ids[i]); + } + } +} + +GLboolean GL_APIENTRY IsQuery(GLuint id) +{ + EVENT("(GLuint id = %u)", id); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_FALSE; + } + + return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE; + } + + return GL_FALSE; +} + +void GL_APIENTRY BeginQuery(GLenum target, GLuint id) +{ + EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateBeginQuery(context, target, id)) + { + return; + } + + Error error = context->beginQuery(target, id); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY EndQuery(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateEndQuery(context, target)) + { + return; + } + + Error error = context->endQuery(target); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY GetQueryiv(GLenum target, GLenum pname, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidQueryType(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (pname) + { + case GL_CURRENT_QUERY: + params[0] = static_cast(context->getState().getActiveQueryId(target)); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) +{ + EVENT("(GLuint id = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", id, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + Query *queryObject = context->getQuery(id, false, GL_NONE); + + if (!queryObject) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (context->getState().getActiveQueryId(queryObject->getType()) == id) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + switch(pname) + { + case GL_QUERY_RESULT_EXT: + { + Error error = queryObject->getResult(params); + if (error.isError()) + { + context->recordError(error); + return; + } + } + break; + + case GL_QUERY_RESULT_AVAILABLE_EXT: + { + Error error = queryObject->isResultAvailable(params); + if (error.isError()) + { + context->recordError(error); + return; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +GLboolean GL_APIENTRY UnmapBuffer(GLenum target) +{ + EVENT("(GLenum target = 0x%X)", target); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_FALSE; + } + + return UnmapBufferOES(target); + } + + return GL_FALSE; +} + +void GL_APIENTRY GetBufferPointerv(GLenum target, GLenum pname, GLvoid** params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + GetBufferPointervOES(target, pname, params); + } +} + +void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum* bufs) +{ + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + DrawBuffersEXT(n, bufs); + } +} + +void GL_APIENTRY UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x3, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix2x3fv(location, count, transpose, value); + } +} + +void GL_APIENTRY UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x2, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix3x2fv(location, count, transpose, value); + } +} + +void GL_APIENTRY UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x4, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix2x4fv(location, count, transpose, value); + } +} + +void GL_APIENTRY UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x2, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix4x2fv(location, count, transpose, value); + } +} + +void GL_APIENTRY UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x4, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix3x4fv(location, count, transpose, value); + } +} + +void GL_APIENTRY UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", + location, count, transpose, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x3, location, count, transpose)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniformMatrix4x3fv(location, count, transpose, value); + } +} + +void GL_APIENTRY BlitFramebuffer(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, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, filter, + false)) + { + return; + } + + Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); + ASSERT(readFramebuffer); + + Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); + ASSERT(drawFramebuffer); + + Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); + Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); + + Error error = drawFramebuffer->blit(context->getState(), srcArea, dstArea, mask, filter, readFramebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY RenderbufferStorageMultisample(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateES3RenderbufferStorageParameters(context, target, samples, internalformat, width, height)) + { + return; + } + + Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); + renderbuffer->setStorageMultisample(samples, internalformat, width, height); + } +} + +void GL_APIENTRY FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) +{ + EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, GLint layer = %d)", + target, attachment, texture, level, layer); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateFramebufferTextureLayer(context, target, attachment, texture, + level, layer)) + { + return; + } + + Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (texture != 0) + { + Texture *textureObject = context->getTexture(texture); + + ImageIndex index = ImageIndex::MakeInvalid(); + + if (textureObject->getTarget() == GL_TEXTURE_3D) + { + index = ImageIndex::Make3D(level, layer); + } + else + { + ASSERT(textureObject->getTarget() == GL_TEXTURE_2D_ARRAY); + index = ImageIndex::Make2DArray(level, layer); + } + + framebuffer->setTextureAttachment(attachment, textureObject, index); + } + else + { + framebuffer->setNULLAttachment(attachment); + } + } +} + +GLvoid *GL_APIENTRY MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", + target, offset, length, access); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + return MapBufferRangeEXT(target, offset, length, access); + } + + return NULL; +} + +void GL_APIENTRY FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) +{ + EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + FlushMappedBufferRangeEXT(target, offset, length); + } +} + +void GL_APIENTRY BindVertexArray(GLuint array) +{ + EVENT("(GLuint array = %u)", array); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + VertexArray *vao = context->getVertexArray(array); + + if (!vao) + { + // The default VAO should always exist + ASSERT(array != 0); + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->bindVertexArray(array); + } +} + +void GL_APIENTRY DeleteVertexArrays(GLsizei n, const GLuint* arrays) +{ + EVENT("(GLsizei n = %d, const GLuint* arrays = 0x%0.8p)", n, arrays); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) + { + if (arrays[arrayIndex] != 0) + { + context->deleteVertexArray(arrays[arrayIndex]); + } + } + } +} + +void GL_APIENTRY GenVertexArrays(GLsizei n, GLuint* arrays) +{ + EVENT("(GLsizei n = %d, GLuint* arrays = 0x%0.8p)", n, arrays); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (n < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) + { + arrays[arrayIndex] = context->createVertexArray(); + } + } +} + +GLboolean GL_APIENTRY IsVertexArray(GLuint array) +{ + EVENT("(GLuint array = %u)", array); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_FALSE; + } + + if (array == 0) + { + return GL_FALSE; + } + + VertexArray *vao = context->getVertexArray(array); + + return (vao != NULL ? GL_TRUE : GL_FALSE); + } + + return GL_FALSE; +} + +void GL_APIENTRY GetIntegeri_v(GLenum target, GLuint index, GLint* data) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint* data = 0x%0.8p)", + target, index, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + const Caps &caps = context->getCaps(); + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= caps.maxTransformFeedbackSeparateAttributes) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_BINDING: + if (index >= caps.maxCombinedUniformBlocks) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (!(context->getIndexedIntegerv(target, index, data))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (numParams == 0) + { + return; // it is known that pname is valid, but there are no parameters to return + } + + if (nativeType == GL_INT_64_ANGLEX) + { + GLint64 minIntValue = static_cast(std::numeric_limits::min()); + GLint64 maxIntValue = static_cast(std::numeric_limits::max()); + GLint64 *int64Params = new GLint64[numParams]; + + context->getIndexedInteger64v(target, index, int64Params); + + for (unsigned int i = 0; i < numParams; ++i) + { + GLint64 clampedValue = std::max(std::min(int64Params[i], maxIntValue), minIntValue); + data[i] = static_cast(clampedValue); + } + + delete [] int64Params; + } + else + { + UNREACHABLE(); + } + } + } +} + +void GL_APIENTRY BeginTransformFeedback(GLenum primitiveMode) +{ + EVENT("(GLenum primitiveMode = 0x%X)", primitiveMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + switch (primitiveMode) + { + case GL_TRIANGLES: + case GL_LINES: + case GL_POINTS: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != NULL); + + if (transformFeedback->isStarted()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (transformFeedback->isPaused()) + { + transformFeedback->resume(); + } + else + { + transformFeedback->start(primitiveMode); + } + } +} + +void GL_APIENTRY EndTransformFeedback(void) +{ + EVENT("(void)"); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != NULL); + + if (!transformFeedback->isStarted()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + transformFeedback->stop(); + } +} + +void GL_APIENTRY BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u, GLintptr offset = %d, GLsizeiptr size = %d)", + target, index, buffer, offset, size); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + const Caps &caps = context->getCaps(); + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER: + if (index >= caps.maxTransformFeedbackSeparateAttributes) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + case GL_UNIFORM_BUFFER: + if (index >= caps.maxUniformBufferBindings) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (buffer != 0 && size <= 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER: + { + // size and offset must be a multiple of 4 + if (buffer != 0 && ((offset % 4) != 0 || (size % 4) != 0)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + // Cannot bind a transform feedback buffer if the current transform feedback is active (3.0.4 pg 91 section 2.15.2) + TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size); + context->bindGenericTransformFeedbackBuffer(buffer); + break; + } + + case GL_UNIFORM_BUFFER: + + // it is an error to bind an offset not a multiple of the alignment + if (buffer != 0 && (offset % caps.uniformBufferOffsetAlignment) != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->bindIndexedUniformBuffer(buffer, index, offset, size); + context->bindGenericUniformBuffer(buffer); + break; + + default: + UNREACHABLE(); + } + } +} + +void GL_APIENTRY BindBufferBase(GLenum target, GLuint index, GLuint buffer) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u)", + target, index, buffer); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + const Caps &caps = context->getCaps(); + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER: + if (index >= caps.maxTransformFeedbackSeparateAttributes) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + case GL_UNIFORM_BUFFER: + if (index >= caps.maxUniformBufferBindings) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER: + { + // Cannot bind a transform feedback buffer if the current transform feedback is active (3.0.4 pg 91 section 2.15.2) + TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0); + context->bindGenericTransformFeedbackBuffer(buffer); + break; + } + case GL_UNIFORM_BUFFER: + context->bindIndexedUniformBuffer(buffer, index, 0, 0); + context->bindGenericUniformBuffer(buffer); + break; + + default: + UNREACHABLE(); + } + } +} + +void GL_APIENTRY TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) +{ + EVENT("(GLuint program = %u, GLsizei count = %d, const GLchar* const* varyings = 0x%0.8p, GLenum bufferMode = 0x%X)", + program, count, varyings, bufferMode); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (count < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + const Caps &caps = context->getCaps(); + switch (bufferMode) + { + case GL_INTERLEAVED_ATTRIBS: + break; + case GL_SEPARATE_ATTRIBS: + if (static_cast(count) > caps.maxTransformFeedbackSeparateAttributes) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (!ValidProgram(context, program)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->setTransformFeedbackVaryings(count, varyings, bufferMode); + } +} + +void GL_APIENTRY GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) +{ + EVENT("(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, " + "GLsizei* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", + program, index, bufSize, length, size, type, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (bufSize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!ValidProgram(context, program)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + if (index >= static_cast(programObject->getTransformFeedbackVaryingCount())) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name); + } +} + +void GL_APIENTRY VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) +{ + EVENT("(GLuint index = %u, GLint size = %d, GLenum type = 0x%X, GLsizei stride = %d, const GLvoid* pointer = 0x%0.8p)", + index, size, type, stride, pointer); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (size < 1 || size > 4) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + switch (type) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_2_10_10_10_REV: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (stride < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // [OpenGL ES 3.0.2] Section 2.8 page 24: + // An INVALID_OPERATION error is generated when a non-zero vertex array object + // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, + // and the pointer argument is not NULL. + if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && pointer != NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, false, true, + stride, pointer); + } +} + +void GL_APIENTRY GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) +{ + EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", + index, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!ValidateGetVertexAttribParameters(context, pname)) + { + return; + } + + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + const VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); + for (int i = 0; i < 4; ++i) + { + params[i] = currentValueData.IntValues[i]; + } + } + else + { + const VertexAttribute &attribState = context->getState().getVertexArray()->getVertexAttribute(index); + *params = QuerySingleVertexAttributeParameter(attribState, pname); + } + } +} + +void GL_APIENTRY GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) +{ + EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLuint* params = 0x%0.8p)", + index, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (!ValidateGetVertexAttribParameters(context, pname)) + { + return; + } + + if (pname == GL_CURRENT_VERTEX_ATTRIB) + { + const VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); + for (int i = 0; i < 4; ++i) + { + params[i] = currentValueData.UnsignedIntValues[i]; + } + } + else + { + const VertexAttribute &attribState = context->getState().getVertexArray()->getVertexAttribute(index); + *params = QuerySingleVertexAttributeParameter(attribState, pname); + } + } +} + +void GL_APIENTRY VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) +{ + EVENT("(GLuint index = %u, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)", + index, x, y, z, w); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLint vals[4] = { x, y, z, w }; + context->getState().setVertexAttribi(index, vals); + } +} + +void GL_APIENTRY VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) +{ + EVENT("(GLuint index = %u, GLuint x = %u, GLuint y = %u, GLuint z = %u, GLuint w = %u)", + index, x, y, z, w); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + GLuint vals[4] = { x, y, z, w }; + context->getState().setVertexAttribu(index, vals); + } +} + +void GL_APIENTRY VertexAttribI4iv(GLuint index, const GLint* v) +{ + EVENT("(GLuint index = %u, const GLint* v = 0x%0.8p)", index, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->getState().setVertexAttribi(index, v); + } +} + +void GL_APIENTRY VertexAttribI4uiv(GLuint index, const GLuint* v) +{ + EVENT("(GLuint index = %u, const GLuint* v = 0x%0.8p)", index, v); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->getState().setVertexAttribu(index, v); + } +} + +void GL_APIENTRY GetUniformuiv(GLuint program, GLint location, GLuint* params) +{ + EVENT("(GLuint program = %u, GLint location = %d, GLuint* params = 0x%0.8p)", + program, location, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateGetUniformuiv(context, program, location, params)) + { + return; + } + + Program *programObject = context->getProgram(program); + ASSERT(programObject); + + programObject->getUniformuiv(location, params); + } +} + +GLint GL_APIENTRY GetFragDataLocation(GLuint program, const GLchar *name) +{ + EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)", + program, name); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return -1; + } + + if (program == 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return -1; + } + + Program *programObject = context->getProgram(program); + + if (!programObject || !programObject->isLinked()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return -1; + } + + return programObject->getFragDataLocation(name); + } + + return 0; +} + +void GL_APIENTRY Uniform1ui(GLint location, GLuint v0) +{ + Uniform1uiv(location, 1, &v0); +} + +void GL_APIENTRY Uniform2ui(GLint location, GLuint v0, GLuint v1) +{ + const GLuint xy[] = { v0, v1 }; + Uniform2uiv(location, 1, xy); +} + +void GL_APIENTRY Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) +{ + const GLuint xyz[] = { v0, v1, v2 }; + Uniform3uiv(location, 1, xyz); +} + +void GL_APIENTRY Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +{ + const GLuint xyzw[] = { v0, v1, v2, v3 }; + Uniform4uiv(location, 1, xyzw); +} + +void GL_APIENTRY Uniform1uiv(GLint location, GLsizei count, const GLuint* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", + location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_UNSIGNED_INT, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform1uiv(location, count, value); + } +} + +void GL_APIENTRY Uniform2uiv(GLint location, GLsizei count, const GLuint* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", + location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC2, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform2uiv(location, count, value); + } +} + +void GL_APIENTRY Uniform3uiv(GLint location, GLsizei count, const GLuint* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value)", + location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC3, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform3uiv(location, count, value); + } +} + +void GL_APIENTRY Uniform4uiv(GLint location, GLsizei count, const GLuint* value) +{ + EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", + location, count, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC4, location, count)) + { + return; + } + + Program *program = context->getState().getProgram(); + program->setUniform4uiv(location, count, value); + } +} + +void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint* value = 0x%0.8p)", + buffer, drawbuffer, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateClearBuffer(context)) + { + return; + } + + switch (buffer) + { + case GL_COLOR: + if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + case GL_STENCIL: + if (drawbuffer != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); + ASSERT(framebufferObject); + + Error error = framebufferObject->clearBufferiv(context->getState(), buffer, drawbuffer, value); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint* value = 0x%0.8p)", + buffer, drawbuffer, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateClearBuffer(context)) + { + return; + } + + switch (buffer) + { + case GL_COLOR: + if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); + ASSERT(framebufferObject); + + Error error = framebufferObject->clearBufferuiv(context->getState(), buffer, drawbuffer, value); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat* value = 0x%0.8p)", + buffer, drawbuffer, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateClearBuffer(context)) + { + return; + } + + switch (buffer) + { + case GL_COLOR: + if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + case GL_DEPTH: + if (drawbuffer != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); + ASSERT(framebufferObject); + + Error error = framebufferObject->clearBufferfv(context->getState(), buffer, drawbuffer, value); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +{ + EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth, GLint stencil = %d)", + buffer, drawbuffer, depth, stencil); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (!ValidateClearBuffer(context)) + { + return; + } + + switch (buffer) + { + case GL_DEPTH_STENCIL: + if (drawbuffer != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); + ASSERT(framebufferObject); + + Error error = framebufferObject->clearBufferfi(context->getState(), buffer, drawbuffer, depth, stencil); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +const GLubyte *GL_APIENTRY GetStringi(GLenum name, GLuint index) +{ + EVENT("(GLenum name = 0x%X, GLuint index = %u)", name, index); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return NULL; + } + + if (name != GL_EXTENSIONS) + { + context->recordError(Error(GL_INVALID_ENUM)); + return NULL; + } + + if (index >= context->getExtensionStringCount()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return NULL; + } + + return reinterpret_cast(context->getExtensionString(index).c_str()); + } + + return NULL; +} + +void GL_APIENTRY CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) +{ + EVENT("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)", + readTarget, writeTarget, readOffset, writeOffset, size); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidBufferTarget(context, readTarget) || !ValidBufferTarget(context, writeTarget)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Buffer *readBuffer = context->getState().getTargetBuffer(readTarget); + Buffer *writeBuffer = context->getState().getTargetBuffer(writeTarget); + + if (!readBuffer || !writeBuffer) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // Verify that readBuffer and writeBuffer are not currently mapped + if (readBuffer->isMapped() || writeBuffer->isMapped()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (readOffset < 0 || writeOffset < 0 || size < 0 || + static_cast(readOffset + size) > readBuffer->getSize() || + static_cast(writeOffset + size) > writeBuffer->getSize()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (readBuffer == writeBuffer && std::abs(readOffset - writeOffset) < size) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + // if size is zero, the copy is a successful no-op + if (size > 0) + { + Error error = writeBuffer->copyBufferSubData(readBuffer, readOffset, writeOffset, size); + if (error.isError()) + { + context->recordError(error); + return; + } + } + } +} + +void GL_APIENTRY GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) +{ + EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLchar* const* uniformNames = 0x%0.8p, GLuint* uniformIndices = 0x%0.8p)", + program, uniformCount, uniformNames, uniformIndices); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (uniformCount < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (!programObject->isLinked()) + { + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + uniformIndices[uniformId] = GL_INVALID_INDEX; + } + } + else + { + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]); + } + } + } +} + +void GL_APIENTRY GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) +{ + EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLuint* uniformIndices = 0x%0.8p, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", + program, uniformCount, uniformIndices, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (uniformCount < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + switch (pname) + { + case GL_UNIFORM_TYPE: + case GL_UNIFORM_SIZE: + case GL_UNIFORM_NAME_LENGTH: + case GL_UNIFORM_BLOCK_INDEX: + case GL_UNIFORM_OFFSET: + case GL_UNIFORM_ARRAY_STRIDE: + case GL_UNIFORM_MATRIX_STRIDE: + case GL_UNIFORM_IS_ROW_MAJOR: + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (uniformCount > programObject->getActiveUniformCount()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + const GLuint index = uniformIndices[uniformId]; + + if (index >= static_cast(programObject->getActiveUniformCount())) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + for (int uniformId = 0; uniformId < uniformCount; uniformId++) + { + const GLuint index = uniformIndices[uniformId]; + params[uniformId] = programObject->getActiveUniformi(index, pname); + } + } +} + +GLuint GL_APIENTRY GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) +{ + EVENT("(GLuint program = %u, const GLchar* uniformBlockName = 0x%0.8p)", program, uniformBlockName); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_INVALID_INDEX; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_INVALID_INDEX; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return GL_INVALID_INDEX; + } + } + + return programObject->getUniformBlockIndex(uniformBlockName); + } + + return 0; +} + +void GL_APIENTRY GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) +{ + EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", + program, uniformBlockIndex, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + switch (pname) + { + case GL_UNIFORM_BLOCK_BINDING: + *params = static_cast(programObject->getUniformBlockBinding(uniformBlockIndex)); + break; + + case GL_UNIFORM_BLOCK_DATA_SIZE: + case GL_UNIFORM_BLOCK_NAME_LENGTH: + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params); + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) +{ + EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLchar* uniformBlockName = 0x%0.8p)", + program, uniformBlockIndex, bufSize, length, uniformBlockName); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName); + } +} + +void GL_APIENTRY UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) +{ + EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLuint uniformBlockBinding = %u)", + program, uniformBlockIndex, uniformBlockBinding); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (uniformBlockBinding >= context->getCaps().maxUniformBufferBindings) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Program *programObject = context->getProgram(program); + + if (!programObject) + { + if (context->getShader(program)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + else + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + } + + // if never linked, there won't be any uniform blocks + if (uniformBlockIndex >= programObject->getActiveUniformBlockCount()) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding); + } +} + +void GL_APIENTRY DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) +{ + EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)", + mode, first, count, instanceCount); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateDrawArraysInstanced(context, mode, first, count, instanceCount)) + { + return; + } + + Error error = context->drawArrays(mode, first, count, instanceCount); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) +{ + EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei instanceCount = %d)", + mode, count, type, indices, instanceCount); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + rx::RangeUI indexRange; + if (!ValidateDrawElementsInstanced(context, mode, count, type, indices, instanceCount, &indexRange)) + { + return; + } + + Error error = context->drawElements(mode, count, type, indices, instanceCount, indexRange); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +GLsync GL_APIENTRY FenceSync_(GLenum condition, GLbitfield flags) +{ + EVENT("(GLenum condition = 0x%X, GLbitfield flags = 0x%X)", condition, flags); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return 0; + } + + if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) + { + context->recordError(Error(GL_INVALID_ENUM)); + return 0; + } + + if (flags != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return 0; + } + + GLsync fenceSync = context->createFenceSync(); + + FenceSync *fenceSyncObject = context->getFenceSync(fenceSync); + Error error = fenceSyncObject->set(condition); + if (error.isError()) + { + context->deleteFenceSync(fenceSync); + context->recordError(error); + return NULL; + } + + return fenceSync; + } + + return NULL; +} + +GLboolean GL_APIENTRY IsSync(GLsync sync) +{ + EVENT("(GLsync sync = 0x%0.8p)", sync); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_FALSE; + } + + return (context->getFenceSync(sync) != NULL); + } + + return GL_FALSE; +} + +void GL_APIENTRY DeleteSync(GLsync sync) +{ + EVENT("(GLsync sync = 0x%0.8p)", sync); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (sync != static_cast(0) && !context->getFenceSync(sync)) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->deleteFenceSync(sync); + } +} + +GLenum GL_APIENTRY ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", + sync, flags, timeout); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_WAIT_FAILED; + } + + if ((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return GL_WAIT_FAILED; + } + + FenceSync *fenceSync = context->getFenceSync(sync); + + if (!fenceSync) + { + context->recordError(Error(GL_INVALID_VALUE)); + return GL_WAIT_FAILED; + } + + GLenum result = GL_WAIT_FAILED; + Error error = fenceSync->clientWait(flags, timeout, &result); + if (error.isError()) + { + context->recordError(error); + return GL_WAIT_FAILED; + } + + return result; + } + + return GL_FALSE; +} + +void GL_APIENTRY WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +{ + EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", + sync, flags, timeout); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (flags != 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + if (timeout != GL_TIMEOUT_IGNORED) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + FenceSync *fenceSync = context->getFenceSync(sync); + + if (!fenceSync) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + Error error = fenceSync->serverWait(flags, timeout); + if (error.isError()) + { + context->recordError(error); + } + } +} + +void GL_APIENTRY GetInteger64v(GLenum pname, GLint64* params) +{ + EVENT("(GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", + pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + GLenum nativeType; + unsigned int numParams = 0; + if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) + { + return; + } + + if (nativeType == GL_INT_64_ANGLEX) + { + context->getInteger64v(pname, params); + } + else + { + CastStateValues(context, nativeType, pname, numParams, params); + } + } +} + +void GL_APIENTRY GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) +{ + EVENT("(GLsync sync = 0x%0.8p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLint* values = 0x%0.8p)", + sync, pname, bufSize, length, values); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (bufSize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + FenceSync *fenceSync = context->getFenceSync(sync); + + if (!fenceSync) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + switch (pname) + { + case GL_OBJECT_TYPE: values[0] = static_cast(GL_SYNC_FENCE); break; + case GL_SYNC_CONDITION: values[0] = static_cast(fenceSync->getCondition()); break; + case GL_SYNC_FLAGS: values[0] = 0; break; + + case GL_SYNC_STATUS: + { + Error error = fenceSync->getStatus(values); + if (error.isError()) + { + context->recordError(error); + return; + } + break; + } + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY GetInteger64i_v(GLenum target, GLuint index, GLint64* data) +{ + EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint64* data = 0x%0.8p)", + target, index, data); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + const Caps &caps = context->getCaps(); + switch (target) + { + case GL_TRANSFORM_FEEDBACK_BUFFER_START: + case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= caps.maxTransformFeedbackSeparateAttributes) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + case GL_UNIFORM_BUFFER_START: + case GL_UNIFORM_BUFFER_SIZE: + case GL_UNIFORM_BUFFER_BINDING: + if (index >= caps.maxUniformBufferBindings) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (!(context->getIndexedInteger64v(target, index, data))) + { + GLenum nativeType; + unsigned int numParams = 0; + if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (numParams == 0) + return; // it is known that pname is valid, but there are no parameters to return + + if (nativeType == GL_INT) + { + GLint *intParams = new GLint[numParams]; + + context->getIndexedIntegerv(target, index, intParams); + + for (unsigned int i = 0; i < numParams; ++i) + { + data[i] = static_cast(intParams[i]); + } + + delete [] intParams; + } + else + { + UNREACHABLE(); + } + } + } +} + +void GL_APIENTRY GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) +{ + EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", + target, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidBufferTarget(context, target)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (!ValidBufferParameter(context, pname)) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + Buffer *buffer = context->getState().getTargetBuffer(target); + + if (!buffer) + { + // A null buffer means that "0" is bound to the requested buffer target + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + switch (pname) + { + case GL_BUFFER_USAGE: + *params = static_cast(buffer->getUsage()); + break; + case GL_BUFFER_SIZE: + *params = buffer->getSize(); + break; + case GL_BUFFER_ACCESS_FLAGS: + *params = static_cast(buffer->getAccessFlags()); + break; + case GL_BUFFER_MAPPED: + *params = static_cast(buffer->isMapped()); + break; + case GL_BUFFER_MAP_OFFSET: + *params = buffer->getMapOffset(); + break; + case GL_BUFFER_MAP_LENGTH: + *params = buffer->getMapLength(); + break; + default: UNREACHABLE(); break; + } + } +} + +void GL_APIENTRY GenSamplers(GLsizei count, GLuint* samplers) +{ + EVENT("(GLsizei count = %d, GLuint* samplers = 0x%0.8p)", count, samplers); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (count < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < count; i++) + { + samplers[i] = context->createSampler(); + } + } +} + +void GL_APIENTRY DeleteSamplers(GLsizei count, const GLuint* samplers) +{ + EVENT("(GLsizei count = %d, const GLuint* samplers = 0x%0.8p)", count, samplers); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (count < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + for (int i = 0; i < count; i++) + { + context->deleteSampler(samplers[i]); + } + } +} + +GLboolean GL_APIENTRY IsSampler(GLuint sampler) +{ + EVENT("(GLuint sampler = %u)", sampler); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_FALSE; + } + + return context->isSampler(sampler); + } + + return GL_FALSE; +} + +void GL_APIENTRY BindSampler(GLuint unit, GLuint sampler) +{ + EVENT("(GLuint unit = %u, GLuint sampler = %u)", unit, sampler); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (sampler != 0 && !context->isSampler(sampler)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (unit >= context->getCaps().maxCombinedTextureImageUnits) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->bindSampler(unit, sampler); + } +} + +void GL_APIENTRY SamplerParameteri(GLuint sampler, GLenum pname, GLint param) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint param = %d)", sampler, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateSamplerObjectParameter(context, pname)) + { + return; + } + + if (!ValidateTexParamParameters(context, pname, param)) + { + return; + } + + if (!context->isSampler(sampler)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->samplerParameteri(sampler, pname, param); + } +} + +void GL_APIENTRY SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) +{ + SamplerParameteri(sampler, pname, *param); +} + +void GL_APIENTRY SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLfloat param = %g)", sampler, pname, param); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateSamplerObjectParameter(context, pname)) + { + return; + } + + if (!ValidateTexParamParameters(context, pname, static_cast(param))) + { + return; + } + + if (!context->isSampler(sampler)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->samplerParameterf(sampler, pname, param); + } +} + +void GL_APIENTRY SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) +{ + SamplerParameterf(sampler, pname, *param); +} + +void GL_APIENTRY GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) +{ + EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", sampler, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateSamplerObjectParameter(context, pname)) + { + return; + } + + if (!context->isSampler(sampler)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + *params = context->getSamplerParameteri(sampler, pname); + } +} + +void GL_APIENTRY GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) +{ + EVENT("(GLuint sample = %ur, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", sampler, pname, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateSamplerObjectParameter(context, pname)) + { + return; + } + + if (!context->isSampler(sampler)) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + *params = context->getSamplerParameterf(sampler, pname); + } +} + +void GL_APIENTRY VertexAttribDivisor(GLuint index, GLuint divisor) +{ + EVENT("(GLuint index = %u, GLuint divisor = %u)", index, divisor); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (index >= MAX_VERTEX_ATTRIBS) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + context->setVertexAttribDivisor(index, divisor); + } +} + +void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id) +{ + EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + switch (target) + { + case GL_TRANSFORM_FEEDBACK: + { + // Cannot bind a transform feedback object if the current one is started and not paused (3.0.2 pg 85 section 2.14.1) + TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // Cannot bind a transform feedback object that does not exist (3.0.2 pg 85 section 2.14.1) + if (context->getTransformFeedback(id) == NULL) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + context->bindTransformFeedback(id); + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +void GL_APIENTRY DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) +{ + EVENT("(GLsizei n = %d, const GLuint* ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + for (int i = 0; i < n; i++) + { + context->deleteTransformFeedback(ids[i]); + } + } +} + +void GL_APIENTRY GenTransformFeedbacks(GLsizei n, GLuint* ids) +{ + EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + for (int i = 0; i < n; i++) + { + ids[i] = context->createTransformFeedback(); + } + } +} + +GLboolean GL_APIENTRY IsTransformFeedback(GLuint id) +{ + EVENT("(GLuint id = %u)", id); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return GL_FALSE; + } + + return ((context->getTransformFeedback(id) != NULL) ? GL_TRUE : GL_FALSE); + } + + return GL_FALSE; +} + +void GL_APIENTRY PauseTransformFeedback(void) +{ + EVENT("(void)"); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != NULL); + + // Current transform feedback must be started and not paused in order to pause (3.0.2 pg 86) + if (!transformFeedback->isStarted() || transformFeedback->isPaused()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + transformFeedback->pause(); + } +} + +void GL_APIENTRY ResumeTransformFeedback(void) +{ + EVENT("(void)"); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); + ASSERT(transformFeedback != NULL); + + // Current transform feedback must be started and paused in order to resume (3.0.2 pg 86) + if (!transformFeedback->isStarted() || !transformFeedback->isPaused()) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + transformFeedback->resume(); + } +} + +void GL_APIENTRY GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary) +{ + EVENT("(GLuint program = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLenum* binaryFormat = 0x%0.8p, GLvoid* binary = 0x%0.8p)", + program, bufSize, length, binaryFormat, binary); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // TODO: Pipe through to the OES extension for now, needs proper validation + return GetProgramBinaryOES(program, bufSize, length, binaryFormat, binary); + } +} + +void GL_APIENTRY ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length) +{ + EVENT("(GLuint program = %u, GLenum binaryFormat = 0x%X, const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", + program, binaryFormat, binary, length); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // TODO: Pipe through to the OES extension for now, needs proper validation + return ProgramBinaryOES(program, binaryFormat, binary, length); + } +} + +void GL_APIENTRY ProgramParameteri(GLuint program, GLenum pname, GLint value) +{ + EVENT("(GLuint program = %u, GLenum pname = 0x%X, GLint value = %d)", + program, pname, value); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + // glProgramParameteri + UNIMPLEMENTED(); + } +} + +void GL_APIENTRY InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) +{ + EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p)", + target, numAttachments, attachments); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments)) + { + return; + } + + Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (framebuffer->checkStatus(context->getData()) == GL_FRAMEBUFFER_COMPLETE) + { + Error error = framebuffer->invalidate(numAttachments, attachments); + if (error.isError()) + { + context->recordError(error); + return; + } + } + } +} + +void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) +{ + EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p, GLint x = %d, " + "GLint y = %d, GLsizei width = %d, GLsizei height = %d)", + target, numAttachments, attachments, x, y, width, height); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments)) + { + return; + } + + Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); + + if (framebuffer->checkStatus(context->getData()) == GL_FRAMEBUFFER_COMPLETE) + { + Rectangle area(x, y, width, height); + Error error = framebuffer->invalidateSub(numAttachments, attachments, area); + if (error.isError()) + { + context->recordError(error); + return; + } + } + } +} + +void GL_APIENTRY TexStorage2D(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); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1)) + { + return; + } + + Extents size(width, height, 1); + Texture *texture = context->getTargetTexture(target); + Error error = texture->setStorage(target, levels, internalformat, size); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +{ + EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " + "GLsizei height = %d, GLsizei depth = %d)", + target, levels, internalformat, width, height, depth); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, depth)) + { + return; + } + + Extents size(width, height, depth); + Texture *texture = context->getTargetTexture(target); + Error error = texture->setStorage(target, levels, internalformat, size); + if (error.isError()) + { + context->recordError(error); + return; + } + } +} + +void GL_APIENTRY GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) +{ + EVENT("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, " + "GLint* params = 0x%0.8p)", + target, internalformat, pname, bufSize, params); + + Context *context = GetValidGlobalContext(); + if (context) + { + if (context->getClientVersion() < 3) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return; + } + + const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); + if (!formatCaps.renderable) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (target != GL_RENDERBUFFER) + { + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + + if (bufSize < 0) + { + context->recordError(Error(GL_INVALID_VALUE)); + return; + } + + switch (pname) + { + case GL_NUM_SAMPLE_COUNTS: + if (bufSize != 0) + { + *params = formatCaps.sampleCounts.size(); + } + break; + + case GL_SAMPLES: + { + size_t returnCount = std::min(bufSize, formatCaps.sampleCounts.size()); + auto sampleReverseIt = formatCaps.sampleCounts.rbegin(); + for (size_t sampleIndex = 0; sampleIndex < returnCount; ++sampleIndex) + { + params[sampleIndex] = *sampleReverseIt++;; + } + } + break; + + default: + context->recordError(Error(GL_INVALID_ENUM)); + return; + } + } +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.h new file mode 100644 index 0000000000..09ca0e4641 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0.h @@ -0,0 +1,125 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_gles_3_0.h : Defines the GLES 3.0 entry points. + +#ifndef LIBGLESV2_ENTRYPOINTGLES30_H_ +#define LIBGLESV2_ENTRYPOINTGLES30_H_ + +#include +#include + +namespace gl +{ + +ANGLE_EXPORT void GL_APIENTRY ReadBuffer(GLenum mode); +ANGLE_EXPORT void GL_APIENTRY DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices); +ANGLE_EXPORT void GL_APIENTRY TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); +ANGLE_EXPORT void GL_APIENTRY TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels); +ANGLE_EXPORT void GL_APIENTRY CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data); +ANGLE_EXPORT void GL_APIENTRY CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data); +ANGLE_EXPORT void GL_APIENTRY GenQueries(GLsizei n, GLuint* ids); +ANGLE_EXPORT void GL_APIENTRY DeleteQueries(GLsizei n, const GLuint* ids); +ANGLE_EXPORT GLboolean GL_APIENTRY IsQuery(GLuint id); +ANGLE_EXPORT void GL_APIENTRY BeginQuery(GLenum target, GLuint id); +ANGLE_EXPORT void GL_APIENTRY EndQuery(GLenum target); +ANGLE_EXPORT void GL_APIENTRY GetQueryiv(GLenum target, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params); +ANGLE_EXPORT GLboolean GL_APIENTRY UnmapBuffer(GLenum target); +ANGLE_EXPORT void GL_APIENTRY GetBufferPointerv(GLenum target, GLenum pname, GLvoid** params); +ANGLE_EXPORT void GL_APIENTRY DrawBuffers(GLsizei n, const GLenum* bufs); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +ANGLE_EXPORT void GL_APIENTRY RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +ANGLE_EXPORT GLvoid* GL_APIENTRY MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +ANGLE_EXPORT void GL_APIENTRY FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length); +ANGLE_EXPORT void GL_APIENTRY BindVertexArray(GLuint array); +ANGLE_EXPORT void GL_APIENTRY DeleteVertexArrays(GLsizei n, const GLuint* arrays); +ANGLE_EXPORT void GL_APIENTRY GenVertexArrays(GLsizei n, GLuint* arrays); +ANGLE_EXPORT GLboolean GL_APIENTRY IsVertexArray(GLuint array); +ANGLE_EXPORT void GL_APIENTRY GetIntegeri_v(GLenum target, GLuint index, GLint* data); +ANGLE_EXPORT void GL_APIENTRY BeginTransformFeedback(GLenum primitiveMode); +ANGLE_EXPORT void GL_APIENTRY EndTransformFeedback(void); +ANGLE_EXPORT void GL_APIENTRY BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +ANGLE_EXPORT void GL_APIENTRY BindBufferBase(GLenum target, GLuint index, GLuint buffer); +ANGLE_EXPORT void GL_APIENTRY TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode); +ANGLE_EXPORT void GL_APIENTRY GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name); +ANGLE_EXPORT void GL_APIENTRY VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params); +ANGLE_EXPORT void GL_APIENTRY VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w); +ANGLE_EXPORT void GL_APIENTRY VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +ANGLE_EXPORT void GL_APIENTRY VertexAttribI4iv(GLuint index, const GLint* v); +ANGLE_EXPORT void GL_APIENTRY VertexAttribI4uiv(GLuint index, const GLuint* v); +ANGLE_EXPORT void GL_APIENTRY GetUniformuiv(GLuint program, GLint location, GLuint* params); +ANGLE_EXPORT GLint GL_APIENTRY GetFragDataLocation(GLuint program, const GLchar *name); +ANGLE_EXPORT void GL_APIENTRY Uniform1ui(GLint location, GLuint v0); +ANGLE_EXPORT void GL_APIENTRY Uniform2ui(GLint location, GLuint v0, GLuint v1); +ANGLE_EXPORT void GL_APIENTRY Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2); +ANGLE_EXPORT void GL_APIENTRY Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +ANGLE_EXPORT void GL_APIENTRY Uniform1uiv(GLint location, GLsizei count, const GLuint* value); +ANGLE_EXPORT void GL_APIENTRY Uniform2uiv(GLint location, GLsizei count, const GLuint* value); +ANGLE_EXPORT void GL_APIENTRY Uniform3uiv(GLint location, GLsizei count, const GLuint* value); +ANGLE_EXPORT void GL_APIENTRY Uniform4uiv(GLint location, GLsizei count, const GLuint* value); +ANGLE_EXPORT void GL_APIENTRY ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); +ANGLE_EXPORT void GL_APIENTRY ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value); +ANGLE_EXPORT void GL_APIENTRY ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value); +ANGLE_EXPORT void GL_APIENTRY ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +ANGLE_EXPORT const GLubyte *GL_APIENTRY GetStringi(GLenum name, GLuint index); +ANGLE_EXPORT void GL_APIENTRY CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +ANGLE_EXPORT void GL_APIENTRY GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params); +ANGLE_EXPORT GLuint GL_APIENTRY GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName); +ANGLE_EXPORT void GL_APIENTRY UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +ANGLE_EXPORT void GL_APIENTRY DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount); +ANGLE_EXPORT void GL_APIENTRY DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount); +ANGLE_EXPORT GLsync GL_APIENTRY FenceSync_(GLenum condition, GLbitfield flags); +ANGLE_EXPORT GLboolean GL_APIENTRY IsSync(GLsync sync); +ANGLE_EXPORT void GL_APIENTRY DeleteSync(GLsync sync); +ANGLE_EXPORT GLenum GL_APIENTRY ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); +ANGLE_EXPORT void GL_APIENTRY WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); +ANGLE_EXPORT void GL_APIENTRY GetInteger64v(GLenum pname, GLint64* params); +ANGLE_EXPORT void GL_APIENTRY GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values); +ANGLE_EXPORT void GL_APIENTRY GetInteger64i_v(GLenum target, GLuint index, GLint64* data); +ANGLE_EXPORT void GL_APIENTRY GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params); +ANGLE_EXPORT void GL_APIENTRY GenSamplers(GLsizei count, GLuint* samplers); +ANGLE_EXPORT void GL_APIENTRY DeleteSamplers(GLsizei count, const GLuint* samplers); +ANGLE_EXPORT GLboolean GL_APIENTRY IsSampler(GLuint sampler); +ANGLE_EXPORT void GL_APIENTRY BindSampler(GLuint unit, GLuint sampler); +ANGLE_EXPORT void GL_APIENTRY SamplerParameteri(GLuint sampler, GLenum pname, GLint param); +ANGLE_EXPORT void GL_APIENTRY SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param); +ANGLE_EXPORT void GL_APIENTRY SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param); +ANGLE_EXPORT void GL_APIENTRY SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param); +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params); +ANGLE_EXPORT void GL_APIENTRY GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params); +ANGLE_EXPORT void GL_APIENTRY VertexAttribDivisor(GLuint index, GLuint divisor); +ANGLE_EXPORT void GL_APIENTRY BindTransformFeedback(GLenum target, GLuint id); +ANGLE_EXPORT void GL_APIENTRY DeleteTransformFeedbacks(GLsizei n, const GLuint* ids); +ANGLE_EXPORT void GL_APIENTRY GenTransformFeedbacks(GLsizei n, GLuint* ids); +ANGLE_EXPORT GLboolean GL_APIENTRY IsTransformFeedback(GLuint id); +ANGLE_EXPORT void GL_APIENTRY PauseTransformFeedback(void); +ANGLE_EXPORT void GL_APIENTRY ResumeTransformFeedback(void); +ANGLE_EXPORT void GL_APIENTRY GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary); +ANGLE_EXPORT void GL_APIENTRY ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length); +ANGLE_EXPORT void GL_APIENTRY ProgramParameteri(GLuint program, GLenum pname, GLint value); +ANGLE_EXPORT void GL_APIENTRY InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments); +ANGLE_EXPORT void GL_APIENTRY InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +ANGLE_EXPORT void GL_APIENTRY TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +ANGLE_EXPORT void GL_APIENTRY GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params); + +} + +#endif // LIBGLESV2_ENTRYPOINTGLES30_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.cpp new file mode 100644 index 0000000000..6f6983fd91 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.cpp @@ -0,0 +1,14 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_gles_3_0_ext.cpp : Implements the GLES 3.0 extension entry points. + +#include "libGLESv2/entry_points_gles_3_0_ext.h" +#include "libGLESv2/global_state.h" + +namespace gl +{ +} diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.h b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.h new file mode 100644 index 0000000000..fec4c1298a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_gles_3_0_ext.h @@ -0,0 +1,23 @@ +// +// Copyright(c) 2014 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. +// + +// entry_points_gles_3_0_ext.h : Defines the GLES 3.0 extension entry points. + +#ifndef LIBGLESV2_ENTRYPOINTGLES30EXT_H_ +#define LIBGLESV2_ENTRYPOINTGLES30EXT_H_ + +#include +#include +#include + +namespace gl +{ + +// No GLES 3.0 extensions yet + +} + +#endif // LIBGLESV2_ENTRYPOINTGLES30EXT_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/formatutils.cpp b/src/3rdparty/angle/src/libGLESv2/formatutils.cpp deleted file mode 100644 index 8674d5337f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/formatutils.cpp +++ /dev/null @@ -1,629 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// formatutils.cpp: Queries for GL image formats. - -#include "common/mathutil.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/imageformats.h" -#include "libGLESv2/renderer/copyimage.h" - -namespace gl -{ - -// ES2 requires that format is equal to internal format at all glTex*Image2D entry points and the implementation -// can decide the true, sized, internal format. The ES2FormatMap determines the internal format for all valid -// format and type combinations. - -FormatType::FormatType() - : internalFormat(GL_NONE), - colorWriteFunction(NULL) -{ -} - -typedef std::pair FormatTypePair; -typedef std::pair FormatPair; -typedef std::map FormatMap; - -// A helper function to insert data into the format map with fewer characters. -static inline void InsertFormatMapping(FormatMap *map, GLenum format, GLenum type, GLenum internalFormat, ColorWriteFunction writeFunc) -{ - FormatType info; - info.internalFormat = internalFormat; - info.colorWriteFunction = writeFunc; - map->insert(FormatPair(FormatTypePair(format, type), info)); -} - -FormatMap BuildFormatMap() -{ - FormatMap map; - - using namespace rx; - - // | Format | Type | Internal format | Color write function | - InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_BYTE, GL_RGBA8, WriteColor ); - InsertFormatMapping(&map, GL_RGBA, GL_BYTE, GL_RGBA8_SNORM, WriteColor ); - InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_RGBA4, WriteColor ); - InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_RGB5_A1, WriteColor ); - InsertFormatMapping(&map, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2, WriteColor ); - InsertFormatMapping(&map, GL_RGBA, GL_FLOAT, GL_RGBA32F, WriteColor); - InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F, WriteColor); - InsertFormatMapping(&map, GL_RGBA, GL_HALF_FLOAT_OES, GL_RGBA16F, WriteColor); - - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_RGBA8UI, WriteColor ); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_BYTE, GL_RGBA8I, WriteColor ); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_RGBA16UI, WriteColor ); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_SHORT, GL_RGBA16I, WriteColor ); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI, WriteColor ); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_INT, GL_RGBA32I, WriteColor ); - InsertFormatMapping(&map, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_RGB10_A2UI, WriteColor ); - - InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8, WriteColor ); - InsertFormatMapping(&map, GL_RGB, GL_BYTE, GL_RGB8_SNORM, WriteColor ); - InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB565, WriteColor ); - InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_R11F_G11F_B10F, WriteColor ); - InsertFormatMapping(&map, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_RGB9_E5, WriteColor ); - InsertFormatMapping(&map, GL_RGB, GL_FLOAT, GL_RGB32F, WriteColor ); - InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT, GL_RGB16F, WriteColor ); - InsertFormatMapping(&map, GL_RGB, GL_HALF_FLOAT_OES, GL_RGB16F, WriteColor ); - - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_RGB8UI, WriteColor ); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_BYTE, GL_RGB8I, WriteColor ); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_RGB16UI, WriteColor ); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_SHORT, GL_RGB16I, WriteColor ); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_RGB32UI, WriteColor ); - InsertFormatMapping(&map, GL_RGB_INTEGER, GL_INT, GL_RGB32I, WriteColor ); - - InsertFormatMapping(&map, GL_RG, GL_UNSIGNED_BYTE, GL_RG8, WriteColor ); - InsertFormatMapping(&map, GL_RG, GL_BYTE, GL_RG8_SNORM, WriteColor ); - InsertFormatMapping(&map, GL_RG, GL_FLOAT, GL_RG32F, WriteColor ); - InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT, GL_RG16F, WriteColor ); - InsertFormatMapping(&map, GL_RG, GL_HALF_FLOAT_OES, GL_RG16F, WriteColor ); - - InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_RG8UI, WriteColor ); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_BYTE, GL_RG8I, WriteColor ); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_RG16UI, WriteColor ); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_SHORT, GL_RG16I, WriteColor ); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_RG32UI, WriteColor ); - InsertFormatMapping(&map, GL_RG_INTEGER, GL_INT, GL_RG32I, WriteColor ); - - InsertFormatMapping(&map, GL_RED, GL_UNSIGNED_BYTE, GL_R8, WriteColor ); - InsertFormatMapping(&map, GL_RED, GL_BYTE, GL_R8_SNORM, WriteColor ); - InsertFormatMapping(&map, GL_RED, GL_FLOAT, GL_R32F, WriteColor ); - InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT, GL_R16F, WriteColor ); - InsertFormatMapping(&map, GL_RED, GL_HALF_FLOAT_OES, GL_R16F, WriteColor ); - - InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_R8UI, WriteColor ); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_BYTE, GL_R8I, WriteColor ); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_R16UI, WriteColor ); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_SHORT, GL_R16I, WriteColor ); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_R32UI, WriteColor ); - InsertFormatMapping(&map, GL_RED_INTEGER, GL_INT, GL_R32I, WriteColor ); - - InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE8_ALPHA8_EXT, WriteColor ); - InsertFormatMapping(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE8_EXT, WriteColor ); - InsertFormatMapping(&map, GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA8_EXT, WriteColor ); - InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA32F_EXT, WriteColor ); - InsertFormatMapping(&map, GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE32F_EXT, WriteColor ); - InsertFormatMapping(&map, GL_ALPHA, GL_FLOAT, GL_ALPHA32F_EXT, WriteColor ); - InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA16F_EXT, WriteColor ); - InsertFormatMapping(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, GL_LUMINANCE_ALPHA16F_EXT, WriteColor ); - InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE16F_EXT, WriteColor ); - InsertFormatMapping(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, GL_LUMINANCE16F_EXT, WriteColor ); - InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT, GL_ALPHA16F_EXT, WriteColor ); - InsertFormatMapping(&map, GL_ALPHA, GL_HALF_FLOAT_OES, GL_ALPHA16F_EXT, WriteColor ); - - InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_BGRA8_EXT, WriteColor ); - InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_BGRA4_ANGLEX, WriteColor ); - InsertFormatMapping(&map, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_BGR5_A1_ANGLEX, WriteColor ); - - InsertFormatMapping(&map, GL_SRGB_EXT, GL_UNSIGNED_BYTE, GL_SRGB8, WriteColor ); - InsertFormatMapping(&map, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE, GL_SRGB8_ALPHA8, WriteColor ); - - InsertFormatMapping(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, NULL ); - InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL ); - InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL ); - InsertFormatMapping(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL ); - - InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16, NULL ); - InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_DEPTH_COMPONENT32_OES, NULL ); - InsertFormatMapping(&map, GL_DEPTH_COMPONENT, GL_FLOAT, GL_DEPTH_COMPONENT32F, NULL ); - - InsertFormatMapping(&map, GL_STENCIL, GL_UNSIGNED_BYTE, GL_STENCIL_INDEX8, NULL ); - - InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_DEPTH24_STENCIL8, NULL ); - InsertFormatMapping(&map, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_DEPTH32F_STENCIL8, NULL ); - - return map; -} - -Type::Type() - : bytes(0), - specialInterpretation(false) -{ -} - -// Map of sizes of input types -typedef std::pair TypeInfoPair; -typedef std::map TypeInfoMap; - -static inline void InsertTypeInfo(TypeInfoMap *map, GLenum type, GLuint bytes, bool specialInterpretation) -{ - Type info; - info.bytes = bytes; - info.specialInterpretation = specialInterpretation; - - map->insert(std::make_pair(type, info)); -} - -bool operator<(const Type& a, const Type& b) -{ - return memcmp(&a, &b, sizeof(Type)) < 0; -} - -static TypeInfoMap BuildTypeInfoMap() -{ - TypeInfoMap map; - - InsertTypeInfo(&map, GL_UNSIGNED_BYTE, 1, false); - InsertTypeInfo(&map, GL_BYTE, 1, false); - InsertTypeInfo(&map, GL_UNSIGNED_SHORT, 2, false); - InsertTypeInfo(&map, GL_SHORT, 2, false); - InsertTypeInfo(&map, GL_UNSIGNED_INT, 4, false); - InsertTypeInfo(&map, GL_INT, 4, false); - InsertTypeInfo(&map, GL_HALF_FLOAT, 2, false); - InsertTypeInfo(&map, GL_HALF_FLOAT_OES, 2, false); - InsertTypeInfo(&map, GL_FLOAT, 4, false); - InsertTypeInfo(&map, GL_UNSIGNED_SHORT_5_6_5, 2, true ); - InsertTypeInfo(&map, GL_UNSIGNED_SHORT_4_4_4_4, 2, true ); - InsertTypeInfo(&map, GL_UNSIGNED_SHORT_5_5_5_1, 2, true ); - InsertTypeInfo(&map, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, 2, true ); - InsertTypeInfo(&map, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, 2, true ); - InsertTypeInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, 4, true ); - InsertTypeInfo(&map, GL_UNSIGNED_INT_24_8, 4, true ); - InsertTypeInfo(&map, GL_UNSIGNED_INT_10F_11F_11F_REV, 4, true ); - InsertTypeInfo(&map, GL_UNSIGNED_INT_5_9_9_9_REV, 4, true ); - InsertTypeInfo(&map, GL_UNSIGNED_INT_24_8_OES, 4, true ); - InsertTypeInfo(&map, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, 8, true ); - - return map; -} - -// Information about internal formats -static bool AlwaysSupported(GLuint, const Extensions &) -{ - return true; -} - -static bool UnimplementedSupport(GLuint, const Extensions &) -{ - return false; -} - -static bool NeverSupported(GLuint, const Extensions &) -{ - return false; -} - -template -static bool RequireES(GLuint clientVersion, const Extensions &) -{ - return clientVersion >= minCoreGLVersion; -} - -// Pointer to a boolean memeber of the Extensions struct -typedef bool(Extensions::*ExtensionBool); - -// Check support for a single extension -template -static bool RequireExt(GLuint, const Extensions & extensions) -{ - return extensions.*bool1; -} - -// Check for a minimum client version or a single extension -template -static bool RequireESOrExt(GLuint clientVersion, const Extensions &extensions) -{ - return clientVersion >= minCoreGLVersion || extensions.*bool1; -} - -// Check for a minimum client version or two extensions -template -static bool RequireESOrExtAndExt(GLuint clientVersion, const Extensions &extensions) -{ - return clientVersion >= minCoreGLVersion || (extensions.*bool1 && extensions.*bool2); -} - -// Check for a minimum client version or at least one of two extensions -template -static bool RequireESOrExtOrExt(GLuint clientVersion, const Extensions &extensions) -{ - return clientVersion >= minCoreGLVersion || extensions.*bool1 || extensions.*bool2; -} - -// Check support for two extensions -template -static bool RequireExtAndExt(GLuint, const Extensions &extensions) -{ - return extensions.*bool1 && extensions.*bool2; -} - -InternalFormat::InternalFormat() - : redBits(0), - greenBits(0), - blueBits(0), - luminanceBits(0), - alphaBits(0), - sharedBits(0), - depthBits(0), - stencilBits(0), - pixelBytes(0), - componentCount(0), - compressedBlockWidth(0), - compressedBlockHeight(0), - format(GL_NONE), - type(GL_NONE), - componentType(GL_NONE), - colorEncoding(GL_NONE), - compressed(false), - textureSupport(NeverSupported), - renderSupport(NeverSupported), - filterSupport(NeverSupported) -{ -} - -static InternalFormat UnsizedFormat(GLenum format, InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) -{ - InternalFormat formatInfo; - formatInfo.format = format; - formatInfo.textureSupport = textureSupport; - formatInfo.renderSupport = renderSupport; - formatInfo.filterSupport = filterSupport; - return formatInfo; -} - -static InternalFormat RGBAFormat(GLuint red, GLuint green, GLuint blue, GLuint alpha, GLuint shared, - GLenum format, GLenum type, GLenum componentType, bool srgb, - InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) -{ - InternalFormat formatInfo; - formatInfo.redBits = red; - formatInfo.greenBits = green; - formatInfo.blueBits = blue; - formatInfo.alphaBits = alpha; - formatInfo.sharedBits = shared; - formatInfo.pixelBytes = (red + green + blue + alpha + shared) / 8; - formatInfo.componentCount = ((red > 0) ? 1 : 0) + ((green > 0) ? 1 : 0) + ((blue > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); - formatInfo.format = format; - formatInfo.type = type; - formatInfo.componentType = componentType; - formatInfo.colorEncoding = (srgb ? GL_SRGB : GL_LINEAR); - formatInfo.textureSupport = textureSupport; - formatInfo.renderSupport = renderSupport; - formatInfo.filterSupport = filterSupport; - return formatInfo; -} - -static InternalFormat LUMAFormat(GLuint luminance, GLuint alpha, GLenum format, GLenum type, GLenum componentType, - InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) -{ - InternalFormat formatInfo; - formatInfo.luminanceBits = luminance; - formatInfo.alphaBits = alpha; - formatInfo.pixelBytes = (luminance + alpha) / 8; - formatInfo.componentCount = ((luminance > 0) ? 1 : 0) + ((alpha > 0) ? 1 : 0); - formatInfo.format = format; - formatInfo.type = type; - formatInfo.componentType = componentType; - formatInfo.colorEncoding = GL_LINEAR; - formatInfo.textureSupport = textureSupport; - formatInfo.renderSupport = renderSupport; - formatInfo.filterSupport = filterSupport; - return formatInfo; -} - -static InternalFormat DepthStencilFormat(GLuint depthBits, GLuint stencilBits, GLuint unusedBits, GLenum format, - GLenum type, GLenum componentType, InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) -{ - InternalFormat formatInfo; - formatInfo.depthBits = depthBits; - formatInfo.stencilBits = stencilBits; - formatInfo.pixelBytes = (depthBits + stencilBits + unusedBits) / 8; - formatInfo.componentCount = ((depthBits > 0) ? 1 : 0) + ((stencilBits > 0) ? 1 : 0); - formatInfo.format = format; - formatInfo.type = type; - formatInfo.componentType = componentType; - formatInfo.colorEncoding = GL_LINEAR; - formatInfo.textureSupport = textureSupport; - formatInfo.renderSupport = renderSupport; - formatInfo.filterSupport = filterSupport; - return formatInfo; -} - -static InternalFormat CompressedFormat(GLuint compressedBlockWidth, GLuint compressedBlockHeight, GLuint compressedBlockSize, - GLuint componentCount, GLenum format, GLenum type, bool srgb, - InternalFormat::SupportCheckFunction textureSupport, - InternalFormat::SupportCheckFunction renderSupport, - InternalFormat::SupportCheckFunction filterSupport) -{ - InternalFormat formatInfo; - formatInfo.compressedBlockWidth = compressedBlockWidth; - formatInfo.compressedBlockHeight = compressedBlockHeight; - formatInfo.pixelBytes = compressedBlockSize / 8; - formatInfo.componentCount = componentCount; - formatInfo.format = format; - formatInfo.type = type; - formatInfo.componentType = GL_UNSIGNED_NORMALIZED; - formatInfo.colorEncoding = (srgb ? GL_SRGB : GL_LINEAR); - formatInfo.compressed = true; - formatInfo.textureSupport = textureSupport; - formatInfo.renderSupport = renderSupport; - formatInfo.filterSupport = filterSupport; - return formatInfo; -} - -typedef std::pair InternalFormatInfoPair; -typedef std::map InternalFormatInfoMap; - -static InternalFormatInfoMap BuildInternalFormatInfoMap() -{ - InternalFormatInfoMap map; - - // From ES 3.0.1 spec, table 3.12 - map.insert(InternalFormatInfoPair(GL_NONE, InternalFormat())); - - // | Internal format | | R | G | B | A |S | Format | Type | Component type | SRGB | Texture supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_R8, RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::textureRG>, RequireESOrExt<3, &Extensions::textureRG>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_R8_SNORM, RGBAFormat( 8, 0, 0, 0, 0, GL_RED, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RG8, RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::textureRG>, RequireESOrExt<3, &Extensions::textureRG>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RG8_SNORM, RGBAFormat( 8, 8, 0, 0, 0, GL_RG, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB8, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::rgb8rgba8>, RequireESOrExt<3, &Extensions::rgb8rgba8>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB8_SNORM, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB565, RGBAFormat( 5, 6, 5, 0, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA4, RGBAFormat( 4, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB5_A1, RGBAFormat( 5, 5, 5, 1, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_NORMALIZED, false, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA8, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireESOrExt<3, &Extensions::rgb8rgba8>, RequireESOrExt<3, &Extensions::rgb8rgba8>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA8_SNORM, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_BYTE, GL_SIGNED_NORMALIZED, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB10_A2, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_NORMALIZED, false, RequireES<3>, RequireES<3>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB10_A2UI, RGBAFormat(10, 10, 10, 2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_SRGB8, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_SRGB8_ALPHA8, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, true, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_R11F_G11F_B10F, RGBAFormat(11, 11, 10, 0, 0, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_FLOAT, false, RequireES<3>, RequireExt<&Extensions::colorBufferFloat>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB9_E5, RGBAFormat( 9, 9, 9, 0, 5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT, false, RequireES<3>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_R8I, RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R8UI, RGBAFormat( 8, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R16I, RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R16UI, RGBAFormat(16, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R32I, RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_R32UI, RGBAFormat(32, 0, 0, 0, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG8I, RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG8UI, RGBAFormat( 8, 8, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG16I, RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG16UI, RGBAFormat(16, 16, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG32I, RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RG32UI, RGBAFormat(32, 32, 0, 0, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB8I, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB8UI, RGBAFormat( 8, 8, 8, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB16I, RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB16UI, RGBAFormat(16, 16, 16, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB32I, RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_INT, GL_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGB32UI, RGBAFormat(32, 32, 32, 0, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, NeverSupported, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA8I, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_BYTE, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA8UI, RGBAFormat( 8, 8, 8, 8, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA16I, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_SHORT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA16UI, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA32I, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_INT, GL_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA32UI, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_UNSIGNED_INT, false, RequireES<3>, RequireES<3>, NeverSupported))); - - map.insert(InternalFormatInfoPair(GL_BGRA8_EXT, RGBAFormat( 8, 8, 8, 8, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_BGRA4_ANGLEX, RGBAFormat( 4, 4, 4, 4, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_BGR5_A1_ANGLEX, RGBAFormat( 5, 5, 5, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, GL_UNSIGNED_NORMALIZED, false, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); - - // Floating point renderability and filtering is provided by OES_texture_float and OES_texture_half_float - // | Internal format | | D |S | Format | Type | Comp | SRGB | Texture supported | Renderable | Filterable | - // | | | | | | | type | | | | | - map.insert(InternalFormatInfoPair(GL_R16F, RGBAFormat(16, 0, 0, 0, 0, GL_RED, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>))); - map.insert(InternalFormatInfoPair(GL_RG16F, RGBAFormat(16, 16, 0, 0, 0, GL_RG, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureHalfFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureHalfFloatLinear>))); - map.insert(InternalFormatInfoPair(GL_RGB16F, RGBAFormat(16, 16, 16, 0, 0, GL_RGB, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>))); - map.insert(InternalFormatInfoPair(GL_RGBA16F, RGBAFormat(16, 16, 16, 16, 0, GL_RGBA, GL_HALF_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireESOrExt<3, &Extensions::textureHalfFloat>, RequireExt<&Extensions::textureHalfFloatLinear>))); - map.insert(InternalFormatInfoPair(GL_R32F, RGBAFormat(32, 0, 0, 0, 0, GL_RED, GL_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear> ))); - map.insert(InternalFormatInfoPair(GL_RG32F, RGBAFormat(32, 32, 0, 0, 0, GL_RG, GL_FLOAT, GL_FLOAT, false, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireESOrExtAndExt<3, &Extensions::textureFloat, &Extensions::textureRG>, RequireExt<&Extensions::textureFloatLinear> ))); - map.insert(InternalFormatInfoPair(GL_RGB32F, RGBAFormat(32, 32, 32, 0, 0, GL_RGB, GL_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureFloat>, RequireESOrExt<3, &Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear> ))); - map.insert(InternalFormatInfoPair(GL_RGBA32F, RGBAFormat(32, 32, 32, 32, 0, GL_RGBA, GL_FLOAT, GL_FLOAT, false, RequireESOrExt<3, &Extensions::textureFloat>, RequireESOrExt<3, &Extensions::textureFloat>, RequireExt<&Extensions::textureFloatLinear> ))); - - // Depth stencil formats - // | Internal format | | D |S | X | Format | Type | Component type | Supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT16, DepthStencilFormat(16, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_UNSIGNED_NORMALIZED, RequireES<2>, RequireES<2>, RequireESOrExt<3, &Extensions::depthTextures>))); - map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT24, DepthStencilFormat(24, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireES<3>, RequireES<3>, RequireESOrExt<3, &Extensions::depthTextures>))); - map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32F, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_FLOAT, GL_FLOAT, RequireES<3>, RequireES<3>, RequireESOrExt<3, &Extensions::depthTextures>))); - map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT32_OES, DepthStencilFormat(32, 0, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::depthTextures>, RequireExt<&Extensions::depthTextures>, AlwaysSupported ))); - map.insert(InternalFormatInfoPair(GL_DEPTH24_STENCIL8, DepthStencilFormat(24, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_NORMALIZED, RequireESOrExt<3, &Extensions::depthTextures>, RequireESOrExtOrExt<3, &Extensions::depthTextures, &Extensions::packedDepthStencil>, AlwaysSupported ))); - map.insert(InternalFormatInfoPair(GL_DEPTH32F_STENCIL8, DepthStencilFormat(32, 8, 24, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_FLOAT, RequireES<3>, RequireES<3>, AlwaysSupported ))); - map.insert(InternalFormatInfoPair(GL_STENCIL_INDEX8, DepthStencilFormat( 0, 8, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, RequireES<2>, RequireES<2>, NeverSupported ))); - - // Luminance alpha formats - // | Internal format | | L | A | Format | Type | Component type | Supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_ALPHA8_EXT, LUMAFormat( 0, 8, GL_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE8_EXT, LUMAFormat( 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_ALPHA32F_EXT, LUMAFormat( 0, 32, GL_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE32F_EXT, LUMAFormat(32, 0, GL_LUMINANCE, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_ALPHA16F_EXT, LUMAFormat( 0, 16, GL_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE16F_EXT, LUMAFormat(16, 0, GL_LUMINANCE, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE8_ALPHA8_EXT, LUMAFormat( 8, 8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_UNSIGNED_NORMALIZED, RequireExt<&Extensions::textureStorage>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA32F_EXT, LUMAFormat(32, 32, GL_LUMINANCE_ALPHA, GL_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureFloat>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA16F_EXT, LUMAFormat(16, 16, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_FLOAT, RequireExtAndExt<&Extensions::textureStorage, &Extensions::textureHalfFloat>, NeverSupported, AlwaysSupported))); - - // Unsized formats - // | Internal format | | Format | Supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_ALPHA, UnsizedFormat(GL_ALPHA, RequireES<2>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE, UnsizedFormat(GL_LUMINANCE, RequireES<2>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_LUMINANCE_ALPHA, UnsizedFormat(GL_LUMINANCE_ALPHA, RequireES<2>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RED, UnsizedFormat(GL_RED, RequireESOrExt<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RG, UnsizedFormat(GL_RG, RequireESOrExt<3, &Extensions::textureRG>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGB, UnsizedFormat(GL_RGB, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RGBA, UnsizedFormat(GL_RGBA, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_RED_INTEGER, UnsizedFormat(GL_RED_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); - map.insert(InternalFormatInfoPair(GL_RG_INTEGER, UnsizedFormat(GL_RG_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); - map.insert(InternalFormatInfoPair(GL_RGB_INTEGER, UnsizedFormat(GL_RGB_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); - map.insert(InternalFormatInfoPair(GL_RGBA_INTEGER, UnsizedFormat(GL_RGBA_INTEGER, RequireES<3>, NeverSupported, NeverSupported ))); - map.insert(InternalFormatInfoPair(GL_BGRA_EXT, UnsizedFormat(GL_BGRA_EXT, RequireExt<&Extensions::textureFormatBGRA8888>, RequireExt<&Extensions::textureFormatBGRA8888>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_DEPTH_COMPONENT, UnsizedFormat(GL_DEPTH_COMPONENT, RequireES<2>, RequireES<2>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_DEPTH_STENCIL, UnsizedFormat(GL_DEPTH_STENCIL, RequireESOrExt<3, &Extensions::packedDepthStencil>, RequireESOrExt<3, &Extensions::packedDepthStencil>, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_SRGB_EXT, UnsizedFormat(GL_RGB, RequireESOrExt<3, &Extensions::sRGB>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_SRGB_ALPHA_EXT, UnsizedFormat(GL_RGBA, RequireESOrExt<3, &Extensions::sRGB>, RequireESOrExt<3, &Extensions::sRGB>, AlwaysSupported))); - - // Compressed formats, From ES 3.0.1 spec, table 3.16 - // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_COMPRESSED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_R11_EAC, CompressedFormat(4, 4, 64, 1, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SIGNED_RG11_EAC, CompressedFormat(4, 4, 128, 2, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, false, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, true, UnimplementedSupport, UnimplementedSupport, UnimplementedSupport))); - - // From GL_EXT_texture_compression_dxt1 - // | Internal format | |W |H | BS |CC| Format | Type | SRGB | Supported | Renderable | Filterable | - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 3, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported))); - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, CompressedFormat(4, 4, 64, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT1>, NeverSupported, AlwaysSupported))); - - // From GL_ANGLE_texture_compression_dxt3 - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported))); - - // From GL_ANGLE_texture_compression_dxt5 - map.insert(InternalFormatInfoPair(GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, CompressedFormat(4, 4, 128, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, false, RequireExt<&Extensions::textureCompressionDXT5>, NeverSupported, AlwaysSupported))); - - return map; -} - -static const InternalFormatInfoMap &GetInternalFormatMap() -{ - static const InternalFormatInfoMap formatMap = BuildInternalFormatInfoMap(); - return formatMap; -} - -static FormatSet BuildAllSizedInternalFormatSet() -{ - FormatSet result; - - const InternalFormatInfoMap &formats = GetInternalFormatMap(); - for (InternalFormatInfoMap::const_iterator i = formats.begin(); i != formats.end(); i++) - { - if (i->second.pixelBytes > 0) - { - result.insert(i->first); - } - } - - return result; -} - -const FormatType &GetFormatTypeInfo(GLenum format, GLenum type) -{ - static const FormatMap formatMap = BuildFormatMap(); - FormatMap::const_iterator iter = formatMap.find(FormatTypePair(format, type)); - if (iter != formatMap.end()) - { - return iter->second; - } - else - { - static const FormatType defaultInfo; - return defaultInfo; - } -} - -const Type &GetTypeInfo(GLenum type) -{ - static const TypeInfoMap infoMap = BuildTypeInfoMap(); - TypeInfoMap::const_iterator iter = infoMap.find(type); - if (iter != infoMap.end()) - { - return iter->second; - } - else - { - static const Type defaultInfo; - return defaultInfo; - } -} - -const InternalFormat &GetInternalFormatInfo(GLenum internalFormat) -{ - const InternalFormatInfoMap &formatMap = GetInternalFormatMap(); - InternalFormatInfoMap::const_iterator iter = formatMap.find(internalFormat); - if (iter != formatMap.end()) - { - return iter->second; - } - else - { - static const InternalFormat defaultInternalFormat; - return defaultInternalFormat; - } -} - -GLuint InternalFormat::computeRowPitch(GLenum type, GLsizei width, GLint alignment) const -{ - ASSERT(alignment > 0 && isPow2(alignment)); - return rx::roundUp(computeBlockSize(type, width, 1), static_cast(alignment)); -} - -GLuint InternalFormat::computeDepthPitch(GLenum type, GLsizei width, GLsizei height, GLint alignment) const -{ - return computeRowPitch(type, width, alignment) * height; -} - -GLuint InternalFormat::computeBlockSize(GLenum type, GLsizei width, GLsizei height) const -{ - if (compressed) - { - GLsizei numBlocksWide = (width + compressedBlockWidth - 1) / compressedBlockWidth; - GLsizei numBlocksHight = (height + compressedBlockHeight - 1) / compressedBlockHeight; - return (pixelBytes * numBlocksWide * numBlocksHight); - } - else - { - const Type &typeInfo = GetTypeInfo(type); - if (typeInfo.specialInterpretation) - { - return typeInfo.bytes * width * height; - } - else - { - return componentCount * typeInfo.bytes * width * height; - } - } -} - -GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type) -{ - const InternalFormat& formatInfo = GetInternalFormatInfo(internalFormat); - return (formatInfo.pixelBytes > 0) ? internalFormat : GetFormatTypeInfo(internalFormat, type).internalFormat; -} - -const FormatSet &GetAllSizedInternalFormats() -{ - static FormatSet formatSet = BuildAllSizedInternalFormatSet(); - return formatSet; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/formatutils.h b/src/3rdparty/angle/src/libGLESv2/formatutils.h deleted file mode 100644 index 25106a52e5..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/formatutils.h +++ /dev/null @@ -1,106 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// formatutils.h: Queries for GL image formats. - -#ifndef LIBGLESV2_FORMATUTILS_H_ -#define LIBGLESV2_FORMATUTILS_H_ - -#include "libGLESv2/Caps.h" -#include "libGLESv2/angletypes.h" - -#include "angle_gl.h" - -#include -#include - -typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); - -typedef void (*LoadImageFunction)(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -typedef void (*InitializeTextureDataFunction)(size_t width, size_t height, size_t depth, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -typedef void (*ColorReadFunction)(const uint8_t *source, uint8_t *dest); -typedef void (*ColorWriteFunction)(const uint8_t *source, uint8_t *dest); -typedef void (*ColorCopyFunction)(const uint8_t *source, uint8_t *dest); - -typedef void (*VertexCopyFunction)(const uint8_t *input, size_t stride, size_t count, uint8_t *output); - -namespace gl -{ - -struct FormatType -{ - FormatType(); - - GLenum internalFormat; - ColorWriteFunction colorWriteFunction; -}; -const FormatType &GetFormatTypeInfo(GLenum format, GLenum type); - -struct Type -{ - Type(); - - GLuint bytes; - bool specialInterpretation; -}; -const Type &GetTypeInfo(GLenum type); - -struct InternalFormat -{ - InternalFormat(); - - GLuint redBits; - GLuint greenBits; - GLuint blueBits; - - GLuint luminanceBits; - - GLuint alphaBits; - GLuint sharedBits; - - GLuint depthBits; - GLuint stencilBits; - - GLuint pixelBytes; - - GLuint componentCount; - - bool compressed; - GLuint compressedBlockWidth; - GLuint compressedBlockHeight; - - GLenum format; - GLenum type; - - GLenum componentType; - GLenum colorEncoding; - - typedef bool (*SupportCheckFunction)(GLuint, const Extensions &); - SupportCheckFunction textureSupport; - SupportCheckFunction renderSupport; - SupportCheckFunction filterSupport; - - GLuint computeRowPitch(GLenum type, GLsizei width, GLint alignment) const; - GLuint computeDepthPitch(GLenum type, GLsizei width, GLsizei height, GLint alignment) const; - GLuint computeBlockSize(GLenum type, GLsizei width, GLsizei height) const; -}; -const InternalFormat &GetInternalFormatInfo(GLenum internalFormat); - -GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type); - -typedef std::set FormatSet; -const FormatSet &GetAllSizedInternalFormats(); - -} - -#endif // LIBGLESV2_FORMATUTILS_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.cpp b/src/3rdparty/angle/src/libGLESv2/global_state.cpp new file mode 100644 index 0000000000..686f0bf49b --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/global_state.cpp @@ -0,0 +1,235 @@ +// +// Copyright(c) 2014 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. +// + +// global_state.cpp : Implements functions for querying the thread-local GL and EGL state. + +#include "libGLESv2/global_state.h" + +#include "libANGLE/Context.h" +#include "libANGLE/Error.h" + +#include "common/debug.h" +#include "common/platform.h" +#include "common/tls.h" + +namespace +{ + +static TLSIndex currentTLS = TLS_INVALID_INDEX; + +struct Current +{ + EGLint error; + EGLenum API; + egl::Display *display; + egl::Surface *drawSurface; + egl::Surface *readSurface; + gl::Context *context; +}; + +Current *AllocateCurrent() +{ + ASSERT(currentTLS != TLS_INVALID_INDEX); + if (currentTLS == TLS_INVALID_INDEX) + { + return NULL; + } + + Current *current = new Current(); + current->error = EGL_SUCCESS; + current->API = EGL_OPENGL_ES_API; + current->display = reinterpret_cast(EGL_NO_DISPLAY); + current->drawSurface = reinterpret_cast(EGL_NO_SURFACE); + current->readSurface = reinterpret_cast(EGL_NO_SURFACE); + current->context = reinterpret_cast(EGL_NO_CONTEXT); + + if (!SetTLSValue(currentTLS, current)) + { + ERR("Could not set thread local storage."); + return NULL; + } + + return current; +} + +void DeallocateCurrent() +{ + Current *current = reinterpret_cast(GetTLSValue(currentTLS)); + SafeDelete(current); + SetTLSValue(currentTLS, NULL); +} + +Current *GetCurrentData() +{ + // Create a TLS index if one has not been created for this DLL + if (currentTLS == TLS_INVALID_INDEX) + { + currentTLS = CreateTLSIndex(); + } + + Current *current = reinterpret_cast(GetTLSValue(currentTLS)); + + // ANGLE issue 488: when the dll is loaded after thread initialization, + // thread local storage (current) might not exist yet. + return (current ? current : AllocateCurrent()); +} + +#ifdef ANGLE_PLATFORM_WINDOWS +extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + currentTLS = CreateTLSIndex(); + if (currentTLS == TLS_INVALID_INDEX) + { + return FALSE; + } + AllocateCurrent(); + break; + + case DLL_THREAD_ATTACH: + AllocateCurrent(); + break; + + case DLL_THREAD_DETACH: + DeallocateCurrent(); + break; + + case DLL_PROCESS_DETACH: + DeallocateCurrent(); + if (currentTLS != TLS_INVALID_INDEX) + { + DestroyTLSIndex(currentTLS); + currentTLS = TLS_INVALID_INDEX; + } + break; + } + + return TRUE; +} +#endif + +} + +namespace gl +{ + +Context *GetGlobalContext() +{ + Current *current = GetCurrentData(); + + return current->context; +} + +Context *GetValidGlobalContext() +{ + gl::Context *context = GetGlobalContext(); + if (context) + { + if (context->isContextLost()) + { + context->recordError(gl::Error(GL_OUT_OF_MEMORY, "Context has been lost.")); + return nullptr; + } + else + { + return context; + } + } + return nullptr; +} + +} + +namespace egl +{ + +void SetGlobalError(const Error &error) +{ + Current *current = GetCurrentData(); + + current->error = error.getCode(); +} + +EGLint GetGlobalError() +{ + Current *current = GetCurrentData(); + + return current->error; +} + +EGLenum GetGlobalAPI() +{ + Current *current = GetCurrentData(); + + return current->API; +} + +void SetGlobalAPI(EGLenum API) +{ + Current *current = GetCurrentData(); + + current->API = API; +} + +void SetGlobalDisplay(Display *dpy) +{ + Current *current = GetCurrentData(); + + current->display = dpy; +} + +Display *GetGlobalDisplay() +{ + Current *current = GetCurrentData(); + + return current->display; +} + +void SetGlobalDrawSurface(Surface *surface) +{ + Current *current = GetCurrentData(); + + current->drawSurface = surface; +} + +Surface *GetGlobalDrawSurface() +{ + Current *current = GetCurrentData(); + + return current->drawSurface; +} + +void SetGlobalReadSurface(Surface *surface) +{ + Current *current = GetCurrentData(); + + current->readSurface = surface; +} + +Surface *GetGlobalReadSurface() +{ + Current *current = GetCurrentData(); + + return current->readSurface; +} + +void SetGlobalContext(gl::Context *context) +{ + Current *current = GetCurrentData(); + + current->context = context; +} + +gl::Context *GetGlobalContext() +{ + Current *current = GetCurrentData(); + + return current->context; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.h b/src/3rdparty/angle/src/libGLESv2/global_state.h new file mode 100644 index 0000000000..db202539cb --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/global_state.h @@ -0,0 +1,49 @@ +// +// Copyright(c) 2014 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. +// + +// global_state.h : Defines functions for querying the thread-local GL and EGL state. + +#ifndef LIBGLESV2_GLOBALSTATE_H_ +#define LIBGLESV2_GLOBALSTATE_H_ + +#include + +namespace gl +{ +class Context; + +Context *GetGlobalContext(); +Context *GetValidGlobalContext(); + +} + +namespace egl +{ +class Error; +class Display; +class Surface; + +void SetGlobalError(const Error &error); +EGLint GetGlobalError(); + +void SetGlobalAPI(EGLenum API); +EGLenum GetGlobalAPI(); + +void SetGlobalDisplay(Display *dpy); +Display *GetGlobalDisplay(); + +void SetGlobalDrawSurface(Surface *surface); +Surface *GetGlobalDrawSurface(); + +void SetGlobalReadSurface(Surface *surface); +Surface *GetGlobalReadSurface(); + +void SetGlobalContext(gl::Context *context); +gl::Context *GetGlobalContext(); + +} + +#endif // LIBGLESV2_GLOBALSTATE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp index 587950a139..e69e04aa60 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp @@ -6,8977 +6,1416 @@ // libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions. -#undef GL_APICALL -#define GL_APICALL -#define GL_GLEXT_PROTOTYPES - -#include "common/version.h" -#include "common/utilities.h" - -#include "libGLESv2/main.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/Fence.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/Program.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/Query.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/VertexArray.h" -#include "libGLESv2/VertexAttribute.h" -#include "libGLESv2/TransformFeedback.h" -#include "libGLESv2/FramebufferAttachment.h" - -#include "libGLESv2/validationES.h" -#include "libGLESv2/validationES2.h" -#include "libGLESv2/validationES3.h" -#include "libGLESv2/queryconversions.h" +#include "libGLESv2/entry_points_gles_2_0.h" +#include "libGLESv2/entry_points_gles_2_0_ext.h" +#include "libGLESv2/entry_points_gles_3_0.h" +#include "libGLESv2/entry_points_gles_3_0_ext.h" + +#include "common/event_tracer.h" extern "C" { -// OpenGL ES 2.0 functions - void GL_APIENTRY glActiveTexture(GLenum texture) { - EVENT("(GLenum texture = 0x%X)", texture); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getCaps().maxCombinedTextureImageUnits - 1) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setActiveSampler(texture - GL_TEXTURE0); - } + return gl::ActiveTexture(texture); } void GL_APIENTRY glAttachShader(GLuint program, GLuint shader) { - EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); - - 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)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - if (!shaderObject) - { - if (context->getProgram(shader)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - if (!programObject->attachShader(shaderObject)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } -} - -void GL_APIENTRY glBeginQueryEXT(GLenum target, GLuint id) -{ - EVENT("(GLenum target = 0x%X, GLuint %d)", target, id); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateBeginQuery(context, target, id)) - { - return; - } - - gl::Error error = context->beginQuery(target, id); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::AttachShader(program, shader); } void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) { - EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - if (strncmp(name, "gl_", 3) == 0) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - programObject->bindAttributeLocation(index, name); - } + return gl::BindAttribLocation(program, index, name); } void GL_APIENTRY glBindBuffer(GLenum target, GLuint buffer) { - EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (target) - { - case GL_ARRAY_BUFFER: - context->bindArrayBuffer(buffer); - return; - case GL_ELEMENT_ARRAY_BUFFER: - context->bindElementArrayBuffer(buffer); - return; - case GL_COPY_READ_BUFFER: - context->bindCopyReadBuffer(buffer); - return; - case GL_COPY_WRITE_BUFFER: - context->bindCopyWriteBuffer(buffer); - return; - case GL_PIXEL_PACK_BUFFER: - context->bindPixelPackBuffer(buffer); - return; - case GL_PIXEL_UNPACK_BUFFER: - context->bindPixelUnpackBuffer(buffer); - return; - case GL_UNIFORM_BUFFER: - context->bindGenericUniformBuffer(buffer); - return; - case GL_TRANSFORM_FEEDBACK_BUFFER: - context->bindGenericTransformFeedbackBuffer(buffer); - return; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::BindBuffer(target, buffer); } void GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer) { - EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidFramebufferTarget(target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) - { - context->bindReadFramebuffer(framebuffer); - } - - if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER) - { - context->bindDrawFramebuffer(framebuffer); - } - } + return gl::BindFramebuffer(target, framebuffer); } void GL_APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer) { - EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (target != GL_RENDERBUFFER) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - context->bindRenderbuffer(renderbuffer); - } + return gl::BindRenderbuffer(target, renderbuffer); } void GL_APIENTRY glBindTexture(GLenum target, GLuint texture) { - EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Texture *textureObject = context->getTexture(texture); - - if (textureObject && textureObject->getTarget() != target && texture != 0) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - switch (target) - { - case GL_TEXTURE_2D: - case GL_TEXTURE_CUBE_MAP: - break; - - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - context->bindTexture(target, texture); - } + return gl::BindTexture(target, texture); } -void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +void GL_APIENTRY glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { - EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", - red, green, blue, alpha); - - gl::Context* context = gl::getNonLostContext(); - - if (context) - { - context->getState().setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha)); - } + return gl::BlendColor(red, green, blue, alpha); } void GL_APIENTRY glBlendEquation(GLenum mode) { - glBlendEquationSeparate(mode, mode); + return gl::BlendEquation(mode); } void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { - EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (modeRGB) - { - case GL_FUNC_ADD: - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - case GL_MIN: - case GL_MAX: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (modeAlpha) - { - case GL_FUNC_ADD: - case GL_FUNC_SUBTRACT: - case GL_FUNC_REVERSE_SUBTRACT: - case GL_MIN: - case GL_MAX: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setBlendEquation(modeRGB, modeAlpha); - } + return gl::BlendEquationSeparate(modeRGB, modeAlpha); } void GL_APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) { - glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); + return gl::BlendFunc(sfactor, dfactor); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - 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: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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; - - case GL_SRC_ALPHA_SATURATE: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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; - - case GL_SRC_ALPHA_SATURATE: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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"); - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - context->getState().setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha); - } + return gl::BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (size < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (usage) - { - case GL_STREAM_DRAW: - case GL_STATIC_DRAW: - case GL_DYNAMIC_DRAW: - break; - - case GL_STREAM_READ: - case GL_STREAM_COPY: - case GL_STATIC_READ: - case GL_STATIC_COPY: - case GL_DYNAMIC_READ: - case GL_DYNAMIC_COPY: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::Error error = buffer->bufferData(data, size, usage); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::BufferData(target, size, data, usage); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (size < 0 || offset < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (data == NULL) - { - return; - } - - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (buffer->isMapped()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // Check for possible overflow of size + offset - if (!rx::IsUnsignedAdditionSafe(size, offset)) - { - context->recordError(gl::Error(GL_OUT_OF_MEMORY)); - return; - } - - if (size + offset > buffer->getSize()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Error error = buffer->bufferSubData(data, size, offset); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::BufferSubData(target, offset, size, data); } GLenum GL_APIENTRY glCheckFramebufferStatus(GLenum target) { - EVENT("(GLenum target = 0x%X)", target); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidFramebufferTarget(target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return 0; - } - - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); - - return framebuffer->completeness(context->getData()); - } - - return 0; + return gl::CheckFramebufferStatus(target); } void GL_APIENTRY glClear(GLbitfield mask) { - EVENT("(GLbitfield mask = 0x%X)", mask); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); - ASSERT(framebufferObject); - - if (framebufferObject->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) - { - context->recordError(gl::Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return; - } - - if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Error error = context->clear(mask); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::Clear(mask); } -void GL_APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +void GL_APIENTRY glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { - EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", - red, green, blue, alpha); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->getState().setClearColor(red, green, blue, alpha); - } + return gl::ClearColor(red, green, blue, alpha); } -void GL_APIENTRY glClearDepthf(GLclampf depth) +void GL_APIENTRY glClearDepthf(GLfloat depth) { - EVENT("(GLclampf depth = %f)", depth); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->getState().setClearDepth(depth); - } + return gl::ClearDepthf(depth); } void GL_APIENTRY glClearStencil(GLint s) { - EVENT("(GLint s = %d)", s); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->getState().setClearStencil(s); - } + return gl::ClearStencil(s); } void GL_APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { - EVENT("(GLboolean red = %d, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)", - red, green, blue, alpha); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->getState().setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE); - } + return gl::ColorMask(red, green, blue, alpha); } void GL_APIENTRY glCompileShader(GLuint shader) { - EVENT("(GLuint shader = %d)", shader); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) - { - if (context->getProgram(shader)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - shaderObject->compile(context->getData()); - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2TexImageParameters(context, target, level, internalformat, true, false, - 0, 0, width, height, border, GL_NONE, GL_NONE, data)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3TexImageParameters(context, target, level, internalformat, true, false, - 0, 0, 0, width, height, 1, border, GL_NONE, GL_NONE, data)) - { - return; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture = context->getTexture2D(); - gl::Error error = texture->setCompressedImage(level, internalformat, width, height, imageSize, context->getState().getUnpackState(), data); - if (error.isError()) - { - context->recordError(error); - return; - } - } - 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: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - gl::Error error = texture->setCompressedImage(target, level, internalformat, width, height, imageSize, context->getState().getUnpackState(), data); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2TexImageParameters(context, target, level, GL_NONE, true, true, - xoffset, yoffset, width, height, 0, GL_NONE, GL_NONE, data)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true, - xoffset, yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE, data)) - { - return; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); - if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture = context->getTexture2D(); - gl::Error error = texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, context->getState().getUnpackState(), data); - if (error.isError()) - { - context->recordError(error); - return; - } - } - 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: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - gl::Error error = texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, context->getState().getUnpackState(), data); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::CompileShader(shader); +} + +void GL_APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) +{ + return gl::CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +} + +void GL_APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) +{ + return gl::CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2CopyTexImageParameters(context, target, level, internalformat, false, - 0, 0, x, y, width, height, border)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3CopyTexImageParameters(context, target, level, internalformat, false, - 0, 0, 0, x, y, width, height, border)) - { - return; - } - - gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture = context->getTexture2D(); - gl::Error error = texture->copyImage(level, internalformat, x, y, width, height, framebuffer); - if (error.isError()) - { - context->recordError(error); - return; - } - } - 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: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - gl::Error error = texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::CopyTexImage2D(target, level, internalformat, x, y, width, height, border); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2CopyTexImageParameters(context, target, level, GL_NONE, true, - xoffset, yoffset, x, y, width, height, 0)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, - xoffset, yoffset, 0, x, y, width, height, 0)) - { - return; - } - - gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture = context->getTexture2D(); - gl::Error error = texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer); - if (error.isError()) - { - context->recordError(error); - return; - } - } - 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: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - gl::Error error = texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); } GLuint GL_APIENTRY glCreateProgram(void) { - EVENT("()"); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - return context->createProgram(); - } - - return 0; + return gl::CreateProgram(); } GLuint GL_APIENTRY glCreateShader(GLenum type) { - EVENT("(GLenum type = 0x%X)", type); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (type) - { - case GL_FRAGMENT_SHADER: - case GL_VERTEX_SHADER: - return context->createShader(type); - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return 0; - } - } - - return 0; + return gl::CreateShader(type); } void GL_APIENTRY glCullFace(GLenum mode) { - EVENT("(GLenum mode = 0x%X)", mode); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (mode) - { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setCullMode(mode); - } + return gl::CullFace(mode); } void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers) { - EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - context->deleteBuffer(buffers[i]); - } - } -} - -void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint* fences) -{ - EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - context->deleteFenceNV(fences[i]); - } - } + return gl::DeleteBuffers(n, buffers); } void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { - EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - if (framebuffers[i] != 0) - { - context->deleteFramebuffer(framebuffers[i]); - } - } - } + return gl::DeleteFramebuffers(n, framebuffers); } void GL_APIENTRY glDeleteProgram(GLuint program) { - EVENT("(GLuint program = %d)", program); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (program == 0) - { - return; - } - - if (!context->getProgram(program)) - { - if(context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - context->deleteProgram(program); - } -} - -void GL_APIENTRY glDeleteQueriesEXT(GLsizei n, const GLuint *ids) -{ - EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - context->deleteQuery(ids[i]); - } - } + return gl::DeleteProgram(program); } void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { - EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - context->deleteRenderbuffer(renderbuffers[i]); - } - } + return gl::DeleteRenderbuffers(n, renderbuffers); } void GL_APIENTRY glDeleteShader(GLuint shader) { - EVENT("(GLuint shader = %d)", shader); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (shader == 0) - { - return; - } - - if (!context->getShader(shader)) - { - if(context->getProgram(shader)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - context->deleteShader(shader); - } + return gl::DeleteShader(shader); } void GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures) { - EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - if (textures[i] != 0) - { - context->deleteTexture(textures[i]); - } - } - } + return gl::DeleteTextures(n, textures); } void GL_APIENTRY glDepthFunc(GLenum func) { - EVENT("(GLenum func = 0x%X)", func); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - 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: - context->getState().setDepthFunc(func); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::DepthFunc(func); } void GL_APIENTRY glDepthMask(GLboolean flag) { - EVENT("(GLboolean flag = %u)", flag); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->getState().setDepthMask(flag != GL_FALSE); - } + return gl::DepthMask(flag); } -void GL_APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar) +void GL_APIENTRY glDepthRangef(GLfloat n, GLfloat f) { - EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->getState().setDepthRange(zNear, zFar); - } + return gl::DepthRangef(n, f); } void GL_APIENTRY glDetachShader(GLuint program, GLuint shader) { - EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); - - 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) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } - - if (!shaderObject) - { - gl::Program *programByShaderHandle = context->getProgram(shader); - if (!programByShaderHandle) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } - - if (!programObject->detachShader(shaderObject)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } + return gl::DetachShader(program, shader); } void GL_APIENTRY glDisable(GLenum cap) { - EVENT("(GLenum cap = 0x%X)", cap); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidCap(context, cap)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setEnableFeature(cap, false); - } + return gl::Disable(cap); } void GL_APIENTRY glDisableVertexAttribArray(GLuint index) { - EVENT("(GLuint index = %d)", index); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setEnableVertexAttribArray(index, false); - } + return gl::DisableVertexAttribArray(index); } void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count) { - EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateDrawArrays(context, mode, first, count, 0)) - { - return; - } - - gl::Error error = context->drawArrays(mode, first, count, 0); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateDrawArraysInstancedANGLE(context, mode, first, count, primcount)) - { - return; - } - - gl::Error error = context->drawArrays(mode, first, count, primcount); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::DrawArrays(mode, first, count); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - rx::RangeUI indexRange; - if (!ValidateDrawElements(context, mode, count, type, indices, 0, &indexRange)) - { - return; - } - - gl::Error error = context->drawElements(mode, count, type, indices, 0, indexRange); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - rx::RangeUI indexRange; - if (!ValidateDrawElementsInstancedANGLE(context, mode, count, type, indices, primcount, &indexRange)) - { - return; - } - - gl::Error error = context->drawElements(mode, count, type, indices, primcount, indexRange); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::DrawElements(mode, count, type, indices); } void GL_APIENTRY glEnable(GLenum cap) { - EVENT("(GLenum cap = 0x%X)", cap); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidCap(context, cap)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - context->getState().setEnableFeature(cap, true); - } + return gl::Enable(cap); } void GL_APIENTRY glEnableVertexAttribArray(GLuint index) { - EVENT("(GLuint index = %d)", index); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setEnableVertexAttribArray(index, true); - } -} - -void GL_APIENTRY glEndQueryEXT(GLenum target) -{ - EVENT("GLenum target = 0x%X)", target); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateEndQuery(context, target)) - { - return; - } - - gl::Error error = context->endQuery(target); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY glFinishFenceNV(GLuint fence) -{ - EVENT("(GLuint fence = %d)", fence); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::FenceNV *fenceObject = context->getFenceNV(fence); - - if (fenceObject == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (fenceObject->isFence() != GL_TRUE) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - fenceObject->finishFence(); - } + return gl::EnableVertexAttribArray(index); } void GL_APIENTRY glFinish(void) { - EVENT("()"); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Error error = context->sync(true); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::Finish(); } void GL_APIENTRY glFlush(void) { - EVENT("()"); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Error error = context->sync(false); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::Flush(); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidFramebufferTarget(target) || (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (!gl::ValidateFramebufferRenderbufferParameters(context, target, attachment, renderbuffertarget, renderbuffer)) - { - return; - } - - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); - - if (renderbuffer != 0) - { - gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); - framebuffer->setRenderbufferAttachment(attachment, renderbufferObject); - } - else - { - framebuffer->setNULLAttachment(attachment); - } - } + return gl::FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateFramebufferTexture2D(context, target, attachment, textarget, texture, level)) - { - return; - } - - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); - - if (texture != 0) - { - gl::Texture *textureObj = context->getTexture(texture); - gl::ImageIndex index(textarget, level, gl::ImageIndex::ENTIRE_LEVEL); - framebuffer->setTextureAttachment(attachment, textureObj, index); - } - else - { - framebuffer->setNULLAttachment(attachment); - } - } + return gl::FramebufferTexture2D(target, attachment, textarget, texture, level); } void GL_APIENTRY glFrontFace(GLenum mode) { - EVENT("(GLenum mode = 0x%X)", mode); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (mode) - { - case GL_CW: - case GL_CCW: - context->getState().setFrontFace(mode); - break; - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::FrontFace(mode); } void GL_APIENTRY glGenBuffers(GLsizei n, GLuint* buffers) { - EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - buffers[i] = context->createBuffer(); - } - } + return gl::GenBuffers(n, buffers); } void GL_APIENTRY glGenerateMipmap(GLenum target) { - EVENT("(GLenum target = 0x%X)", target); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidTextureTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Texture *texture = context->getTargetTexture(target); - - if (texture == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - GLenum internalFormat = texture->getBaseLevelInternalFormat(); - const gl::TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - - // GenerateMipmap should not generate an INVALID_OPERATION for textures created with - // unsized formats or that are color renderable and filterable. Since we do not track if - // the texture was created with sized or unsized format (only sized formats are stored), - // it is not possible to make sure the the LUMA formats can generate mipmaps (they should - // be able to) because they aren't color renderable. Simply do a special case for LUMA - // textures since they're the only texture format that can be created with unsized formats - // that is not color renderable. New unsized formats are unlikely to be added, since ES2 - // was the last version to use add them. - bool isLUMA = internalFormat == GL_LUMINANCE8_EXT || - internalFormat == GL_LUMINANCE8_ALPHA8_EXT || - internalFormat == GL_ALPHA8_EXT; - - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0 || !formatCaps.filterable || - (!formatCaps.renderable && !isLUMA) || formatInfo.compressed) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // GL_EXT_sRGB does not support mipmap generation on sRGB textures - if (context->getClientVersion() == 2 && formatInfo.colorEncoding == GL_SRGB) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // Non-power of 2 ES2 check - if (!context->getExtensions().textureNPOT && (!gl::isPow2(texture->getBaseLevelWidth()) || !gl::isPow2(texture->getBaseLevelHeight()))) - { - ASSERT(context->getClientVersion() <= 2 && (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP)); - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // Cube completeness check - if (target == GL_TEXTURE_CUBE_MAP) - { - gl::TextureCubeMap *textureCube = static_cast(texture); - if (!textureCube->isCubeComplete()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } - - gl::Error error = texture->generateMipmaps(); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint* fences) -{ - EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - fences[i] = context->createFenceNV(); - } - } + return gl::GenerateMipmap(target); } void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers) { - EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - framebuffers[i] = context->createFramebuffer(); - } - } + return gl::GenFramebuffers(n, framebuffers); } -void GL_APIENTRY glGenQueriesEXT(GLsizei n, GLuint* ids) +void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) { - EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (GLsizei i = 0; i < n; i++) - { - ids[i] = context->createQuery(); - } - } + return gl::GenRenderbuffers(n, renderbuffers); } -void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures) { - EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - renderbuffers[i] = context->createRenderbuffer(); - } - } + return gl::GenTextures(n, textures); } -void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures) +void GL_APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { - EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < n; i++) - { - textures[i] = context->createTexture(); - } - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - if (index >= (GLuint)programObject->getActiveAttributeCount()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - programObject->getActiveAttribute(index, bufsize, length, size, type, name); - } + return gl::GetActiveAttrib(program, index, bufsize, length, size, type, name); } void GL_APIENTRY 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); - - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - if (index >= (GLuint)programObject->getActiveUniformCount()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - programObject->getActiveUniform(index, bufsize, length, size, type, name); - } + return gl::GetActiveUniform(program, index, bufsize, length, size, type, name); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (maxcount < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - return programObject->getAttachedShaders(maxcount, count, shaders); - } + return gl::GetAttachedShaders(program, maxcount, count, shaders); } GLint GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar* name) { - EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return -1; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return -1; - } - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programObject->isLinked() || !programBinary) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return -1; - } - - return programBinary->getAttributeLocation(name); - } - - return -1; + return gl::GetAttribLocation(program, name); } void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params) { - EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) - { - return; - } - - if (nativeType == GL_BOOL) - { - context->getBooleanv(pname, params); - } - else - { - CastStateValues(context, nativeType, pname, numParams, params); - } - } + return gl::GetBooleanv(pname, params); } void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (!gl::ValidBufferParameter(context, pname)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer) - { - // A null buffer means that "0" is bound to the requested buffer target - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - switch (pname) - { - case GL_BUFFER_USAGE: - *params = static_cast(buffer->getUsage()); - break; - case GL_BUFFER_SIZE: - *params = gl::clampCast(buffer->getSize()); - break; - case GL_BUFFER_ACCESS_FLAGS: - *params = buffer->getAccessFlags(); - break; - case GL_BUFFER_MAPPED: - *params = static_cast(buffer->isMapped()); - break; - case GL_BUFFER_MAP_OFFSET: - *params = gl::clampCast(buffer->getMapOffset()); - break; - case GL_BUFFER_MAP_LENGTH: - *params = gl::clampCast(buffer->getMapLength()); - break; - default: UNREACHABLE(); break; - } - } + return gl::GetBufferParameteriv(target, pname, params); } GLenum GL_APIENTRY glGetError(void) { - EVENT("()"); - - gl::Context *context = gl::getContext(); - - if (context) - { - return context->getError(); - } - - return GL_NO_ERROR; -} - -void GL_APIENTRY glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) -{ - EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::FenceNV *fenceObject = context->getFenceNV(fence); - - if (fenceObject == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (fenceObject->isFence() != GL_TRUE) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - 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. - GLboolean status = GL_TRUE; - if (fenceObject->getStatus() != GL_TRUE) - { - gl::Error error = fenceObject->testFence(&status); - if (error.isError()) - { - context->recordError(error); - return; - } - } - *params = status; - break; - } - - case GL_FENCE_CONDITION_NV: - { - *params = fenceObject->getCondition(); - break; - } - - default: - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } - } + return gl::GetError(); } void GL_APIENTRY glGetFloatv(GLenum pname, GLfloat* params) { - EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) - { - return; - } - - if (nativeType == GL_FLOAT) - { - context->getFloatv(pname, params); - } - else - { - CastStateValues(context, nativeType, pname, numParams, params); - } - } + return gl::GetFloatv(pname, params); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidFramebufferTarget(target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - int clientVersion = context->getClientVersion(); - - switch (pname) - { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: - break; - - case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: - if (clientVersion < 3 && !context->getExtensions().sRGB) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: - if (clientVersion < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - // Determine if the attachment is a valid enum - switch (attachment) - { - case GL_BACK: - case GL_FRONT: - case GL_DEPTH: - case GL_STENCIL: - case GL_DEPTH_STENCIL_ATTACHMENT: - if (clientVersion < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - break; - - default: - if (attachment < GL_COLOR_ATTACHMENT0_EXT || - (attachment - GL_COLOR_ATTACHMENT0_EXT) >= context->getCaps().maxColorAttachments) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - } - - GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); - gl::Framebuffer *framebuffer = context->getFramebuffer(framebufferHandle); - ASSERT(framebuffer); - - if (framebufferHandle == 0) - { - if (clientVersion < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - switch (attachment) - { - case GL_BACK: - case GL_DEPTH: - case GL_STENCIL: - break; - - default: - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } - else - { - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) - { - // Valid attachment query - } - else - { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - break; - - case GL_DEPTH_STENCIL_ATTACHMENT: - if (framebuffer->hasValidDepthStencil()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } - } - - GLenum attachmentType = GL_NONE; - GLuint attachmentHandle = 0; - GLuint attachmentLevel = 0; - GLuint attachmentLayer = 0; - - const gl::FramebufferAttachment *attachmentObject = framebuffer->getAttachment(attachment); - - if (attachmentObject) - { - attachmentType = attachmentObject->type(); - attachmentHandle = attachmentObject->id(); - attachmentLevel = attachmentObject->mipLevel(); - attachmentLayer = attachmentObject->layer(); - } - - GLenum attachmentObjectType; // Type category - if (framebufferHandle == 0) - { - attachmentObjectType = GL_FRAMEBUFFER_DEFAULT; - } - else if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER) - { - attachmentObjectType = attachmentType; - } - else if (gl::ValidTexture2DDestinationTarget(context, attachmentType)) - { - attachmentObjectType = GL_TEXTURE; - } - else - { - UNREACHABLE(); - return; - } - - if (attachmentObjectType == GL_NONE) - { - // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE - // is NONE, then querying any other pname will generate INVALID_ENUM. - - // ES 3.0.2 spec pg 235 states that if the attachment type is none, - // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an - // INVALID_OPERATION for all other pnames - - switch (pname) - { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: - *params = attachmentObjectType; - break; - - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: - if (clientVersion < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = 0; - break; - - default: - if (clientVersion < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } - } - else - { - ASSERT(attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE || - attachmentObjectType == GL_FRAMEBUFFER_DEFAULT); - ASSERT(attachmentObject != NULL); - - switch (pname) - { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: - *params = attachmentObjectType; - break; - - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: - if (attachmentObjectType != GL_RENDERBUFFER && attachmentObjectType != GL_TEXTURE) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = attachmentHandle; - break; - - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: - if (attachmentObjectType != GL_TEXTURE) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = attachmentLevel; - break; - - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: - if (attachmentObjectType != GL_TEXTURE) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = gl::IsCubemapTextureTarget(attachmentType) ? attachmentType : 0; - break; - - case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE: - *params = attachmentObject->getRedSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE: - *params = attachmentObject->getGreenSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE: - *params = attachmentObject->getBlueSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - *params = attachmentObject->getAlphaSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - *params = attachmentObject->getDepthSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - *params = attachmentObject->getStencilSize(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - *params = attachmentObject->getComponentType(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: - *params = attachmentObject->getColorEncoding(); - break; - - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: - if (attachmentObjectType != GL_TEXTURE) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = attachmentLayer; - break; - - default: - UNREACHABLE(); - break; - } - } - } -} - -GLenum GL_APIENTRY glGetGraphicsResetStatusEXT(void) -{ - EVENT("()"); - - gl::Context *context = gl::getContext(); - - if (context) - { - return context->getResetStatus(); - } - - return GL_NO_ERROR; + return gl::GetFramebufferAttachmentParameteriv(target, attachment, pname, params); } void GL_APIENTRY glGetIntegerv(GLenum pname, GLint* params) { - EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - GLenum nativeType; - unsigned int numParams = 0; - - if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) - { - return; - } - - if (nativeType == GL_INT) - { - context->getIntegerv(pname, params); - } - else - { - CastStateValues(context, nativeType, pname, numParams, params); - } - } + return gl::GetIntegerv(pname, params); } void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params) { - EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (context->getClientVersion() < 3) - { - switch (pname) - { - case GL_ACTIVE_UNIFORM_BLOCKS: - case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: - case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: - case GL_TRANSFORM_FEEDBACK_VARYINGS: - case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } - - 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; - case GL_ACTIVE_UNIFORM_BLOCKS: - *params = programObject->getActiveUniformBlockCount(); - return; - case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: - *params = programObject->getActiveUniformBlockMaxLength(); - break; - case GL_TRANSFORM_FEEDBACK_BUFFER_MODE: - *params = programObject->getTransformFeedbackBufferMode(); - break; - case GL_TRANSFORM_FEEDBACK_VARYINGS: - *params = programObject->getTransformFeedbackVaryingCount(); - break; - case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: - *params = programObject->getTransformFeedbackVaryingMaxLength(); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetProgramiv(program, pname, params); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - programObject->getInfoLog(bufsize, length, infolog); - } -} - -void GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) -{ - EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidQueryType(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (pname) - { - case GL_CURRENT_QUERY_EXT: - params[0] = context->getState().getActiveQueryId(target); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) -{ - EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Query *queryObject = context->getQuery(id, false, GL_NONE); - - if (!queryObject) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (context->getState().getActiveQueryId(queryObject->getType()) == id) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - switch(pname) - { - case GL_QUERY_RESULT_EXT: - { - gl::Error error = queryObject->getResult(params); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_QUERY_RESULT_AVAILABLE_EXT: - { - gl::Error error = queryObject->isResultAvailable(params); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetProgramInfoLog(program, bufsize, length, infolog); } void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (target != GL_RENDERBUFFER) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (context->getState().getRenderbufferId() == 0) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getState().getRenderbufferId()); - - 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->getExtensions().framebufferMultisample) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = renderbuffer->getSamples(); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetRenderbufferParameteriv(target, pname, params); } void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params) { - EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - 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: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetShaderiv(shader, pname, params); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - shaderObject->getInfoLog(bufsize, length, infolog); - } + return gl::GetShaderInfoLog(shader, bufsize, length, infolog); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (shadertype) - { - case GL_VERTEX_SHADER: - case GL_FRAGMENT_SHADER: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetShaderPrecisionFormat(shadertype, precisiontype, range, precision); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - shaderObject->getSource(bufsize, length, source); - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (bufsize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // Only returns extra info if ANGLE_GENERATE_SHADER_DEBUG_INFO is defined - shaderObject->getTranslatedSourceWithDebugInfo(bufsize, length, source); - } + return gl::GetShaderSource(shader, bufsize, length, source); } const GLubyte* GL_APIENTRY glGetString(GLenum name) { - EVENT("(GLenum name = 0x%X)", name); - - gl::Context *context = gl::getNonLostContext(); - - switch (name) - { - case GL_VENDOR: - return (GLubyte*)"Google Inc."; - - case GL_RENDERER: - return (GLubyte*)((context != NULL) ? context->getRendererString().c_str() : "ANGLE"); - - case GL_VERSION: - if (context->getClientVersion() == 2) - { - return (GLubyte*)"OpenGL ES 2.0 (ANGLE " ANGLE_VERSION_STRING ")"; - } - else - { - return (GLubyte*)"OpenGL ES 3.0 (ANGLE " ANGLE_VERSION_STRING ")"; - } - - case GL_SHADING_LANGUAGE_VERSION: - if (context->getClientVersion() == 2) - { - return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE " ANGLE_VERSION_STRING ")"; - } - else - { - return (GLubyte*)"OpenGL ES GLSL ES 3.00 (ANGLE " ANGLE_VERSION_STRING ")"; - } - - case GL_EXTENSIONS: - return (GLubyte*)((context != NULL) ? context->getExtensionString().c_str() : ""); - - default: - if (context) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - } - return NULL; - } + return gl::GetString(name); } void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Texture *texture = context->getTargetTexture(target); - - if (!texture) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (pname) - { - case GL_TEXTURE_MAG_FILTER: - *params = (GLfloat)texture->getSamplerState().magFilter; - break; - case GL_TEXTURE_MIN_FILTER: - *params = (GLfloat)texture->getSamplerState().minFilter; - break; - case GL_TEXTURE_WRAP_S: - *params = (GLfloat)texture->getSamplerState().wrapS; - break; - case GL_TEXTURE_WRAP_T: - *params = (GLfloat)texture->getSamplerState().wrapT; - break; - case GL_TEXTURE_WRAP_R: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSamplerState().wrapR; - break; - case GL_TEXTURE_IMMUTABLE_FORMAT: - // Exposed to ES2.0 through EXT_texture_storage, no client version validation. - *params = (GLfloat)(texture->isImmutable() ? GL_TRUE : GL_FALSE); - break; - case GL_TEXTURE_IMMUTABLE_LEVELS: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->immutableLevelCount(); - break; - case GL_TEXTURE_USAGE_ANGLE: - *params = (GLfloat)texture->getUsage(); - break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->getExtensions().textureFilterAnisotropic) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSamplerState().maxAnisotropy; - break; - case GL_TEXTURE_SWIZZLE_R: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSamplerState().swizzleRed; - break; - case GL_TEXTURE_SWIZZLE_G: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSamplerState().swizzleGreen; - break; - case GL_TEXTURE_SWIZZLE_B: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSamplerState().swizzleBlue; - break; - case GL_TEXTURE_SWIZZLE_A: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSamplerState().swizzleAlpha; - break; - case GL_TEXTURE_BASE_LEVEL: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSamplerState().baseLevel; - break; - case GL_TEXTURE_MAX_LEVEL: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLfloat)texture->getSamplerState().maxLevel; - break; - case GL_TEXTURE_MIN_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().minLod; - break; - case GL_TEXTURE_MAX_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().maxLod; - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetTexParameterfv(target, pname, params); } void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Texture *texture = context->getTargetTexture(target); - - if (!texture) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (pname) - { - case GL_TEXTURE_MAG_FILTER: - *params = texture->getSamplerState().magFilter; - break; - case GL_TEXTURE_MIN_FILTER: - *params = texture->getSamplerState().minFilter; - break; - case GL_TEXTURE_WRAP_S: - *params = texture->getSamplerState().wrapS; - break; - case GL_TEXTURE_WRAP_T: - *params = texture->getSamplerState().wrapT; - break; - case GL_TEXTURE_WRAP_R: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().wrapR; - break; - case GL_TEXTURE_IMMUTABLE_FORMAT: - // Exposed to ES2.0 through EXT_texture_storage, no client version validation. - *params = texture->isImmutable() ? GL_TRUE : GL_FALSE; - break; - case GL_TEXTURE_IMMUTABLE_LEVELS: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = static_cast(texture->immutableLevelCount()); - break; - case GL_TEXTURE_USAGE_ANGLE: - *params = texture->getUsage(); - break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->getExtensions().textureFilterAnisotropic) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLint)texture->getSamplerState().maxAnisotropy; - break; - case GL_TEXTURE_SWIZZLE_R: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().swizzleRed; - break; - case GL_TEXTURE_SWIZZLE_G: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().swizzleGreen; - break; - case GL_TEXTURE_SWIZZLE_B: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().swizzleBlue; - break; - case GL_TEXTURE_SWIZZLE_A: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().swizzleAlpha; - break; - case GL_TEXTURE_BASE_LEVEL: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().baseLevel; - break; - case GL_TEXTURE_MAX_LEVEL: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = texture->getSamplerState().maxLevel; - break; - case GL_TEXTURE_MIN_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLint)texture->getSamplerState().minLod; - break; - case GL_TEXTURE_MAX_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - *params = (GLint)texture->getSamplerState().maxLod; - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateGetnUniformfvEXT(context, program, location, bufSize, params)) - { - return; - } - - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - ASSERT(programBinary); - - programBinary->getUniformfv(location, params); - } + return gl::GetTexParameteriv(target, pname, params); } void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params) { - EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateGetUniformfv(context, program, location, params)) - { - return; - } - - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - ASSERT(programBinary); - - programBinary->getUniformfv(location, params); - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateGetnUniformivEXT(context, program, location, bufSize, params)) - { - return; - } - - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - ASSERT(programBinary); - - programBinary->getUniformiv(location, params); - } + return gl::GetUniformfv(program, location, params); } void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params) { - EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateGetUniformiv(context, program, location, params)) - { - return; - } - - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - ASSERT(programBinary); - - programBinary->getUniformiv(location, params); - } + return gl::GetUniformiv(program, location, params); } GLint GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* name) { - EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (strstr(name, "gl_") == name) - { - return -1; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return -1; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return -1; - } - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programObject->isLinked() || !programBinary) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return -1; - } - - return programBinary->getUniformLocation(name); - } - - return -1; + return gl::GetUniformLocation(program, name); } void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) { - EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index); - if (!gl::ValidateGetVertexAttribParameters(context, pname)) - { - return; - } - - if (pname == GL_CURRENT_VERTEX_ATTRIB) - { - const gl::VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); - for (int i = 0; i < 4; ++i) - { - params[i] = currentValueData.FloatValues[i]; - } - } - else - { - *params = gl::QuerySingleVertexAttributeParameter(attribState, pname); - } - } + return gl::GetVertexAttribfv(index, pname, params); } void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) { - EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index); - - if (!gl::ValidateGetVertexAttribParameters(context, pname)) - { - return; - } - - if (pname == GL_CURRENT_VERTEX_ATTRIB) - { - const gl::VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); - for (int i = 0; i < 4; ++i) - { - float currentValue = currentValueData.FloatValues[i]; - params[i] = gl::iround(currentValue); - } - } - else - { - *params = gl::QuerySingleVertexAttributeParameter(attribState, pname); - } - } + return gl::GetVertexAttribiv(index, pname, params); } void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) { - EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - *pointer = const_cast(context->getState().getVertexAttribPointer(index)); - } + return gl::GetVertexAttribPointerv(index, pname, pointer); } void GL_APIENTRY glHint(GLenum target, GLenum mode) { - EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (mode) - { - case GL_FASTEST: - case GL_NICEST: - case GL_DONT_CARE: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (target) - { - case GL_GENERATE_MIPMAP_HINT: - context->getState().setGenerateMipmapHint(mode); - break; - - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: - context->getState().setFragmentShaderDerivativeHint(mode); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::Hint(target, mode); } GLboolean GL_APIENTRY glIsBuffer(GLuint buffer) { - EVENT("(GLuint buffer = %d)", buffer); - - gl::Context *context = gl::getNonLostContext(); - if (context && buffer) - { - gl::Buffer *bufferObject = context->getBuffer(buffer); - - if (bufferObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; + return gl::IsBuffer(buffer); } GLboolean GL_APIENTRY glIsEnabled(GLenum cap) { - EVENT("(GLenum cap = 0x%X)", cap); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidCap(context, cap)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return GL_FALSE; - } - - return context->getState().getEnableFeature(cap); - } - - return false; -} - -GLboolean GL_APIENTRY glIsFenceNV(GLuint fence) -{ - EVENT("(GLuint fence = %d)", fence); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::FenceNV *fenceObject = context->getFenceNV(fence); - - if (fenceObject == NULL) - { - return GL_FALSE; - } - - return fenceObject->isFence(); - } - - return GL_FALSE; + return gl::IsEnabled(cap); } GLboolean GL_APIENTRY glIsFramebuffer(GLuint framebuffer) { - EVENT("(GLuint framebuffer = %d)", framebuffer); - - gl::Context *context = gl::getNonLostContext(); - if (context && framebuffer) - { - gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer); - - if (framebufferObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; + return gl::IsFramebuffer(framebuffer); } GLboolean GL_APIENTRY glIsProgram(GLuint program) { - EVENT("(GLuint program = %d)", program); - - gl::Context *context = gl::getNonLostContext(); - if (context && program) - { - gl::Program *programObject = context->getProgram(program); - - if (programObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; -} - -GLboolean GL_APIENTRY glIsQueryEXT(GLuint id) -{ - EVENT("(GLuint id = %d)", id); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE; - } - - return GL_FALSE; + return gl::IsProgram(program); } GLboolean GL_APIENTRY glIsRenderbuffer(GLuint renderbuffer) { - EVENT("(GLuint renderbuffer = %d)", renderbuffer); - - gl::Context *context = gl::getNonLostContext(); - if (context && renderbuffer) - { - gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); - - if (renderbufferObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; + return gl::IsRenderbuffer(renderbuffer); } GLboolean GL_APIENTRY glIsShader(GLuint shader) { - EVENT("(GLuint shader = %d)", shader); - - gl::Context *context = gl::getNonLostContext(); - if (context && shader) - { - gl::Shader *shaderObject = context->getShader(shader); - - if (shaderObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; + return gl::IsShader(shader); } GLboolean GL_APIENTRY glIsTexture(GLuint texture) { - EVENT("(GLuint texture = %d)", texture); - - gl::Context *context = gl::getNonLostContext(); - if (context && texture) - { - gl::Texture *textureObject = context->getTexture(texture); - - if (textureObject) - { - return GL_TRUE; - } - } - - return GL_FALSE; + return gl::IsTexture(texture); } void GL_APIENTRY glLineWidth(GLfloat width) { - EVENT("(GLfloat width = %f)", width); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (width <= 0.0f) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setLineWidth(width); - } + return gl::LineWidth(width); } void GL_APIENTRY glLinkProgram(GLuint program) { - EVENT("(GLuint program = %d)", program); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - gl::Error error = context->linkProgram(program); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::LinkProgram(program); } void GL_APIENTRY glPixelStorei(GLenum pname, GLint param) { - EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (pname) - { - case GL_UNPACK_ALIGNMENT: - if (param != 1 && param != 2 && param != 4 && param != 8) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setUnpackAlignment(param); - break; - - case GL_PACK_ALIGNMENT: - if (param != 1 && param != 2 && param != 4 && param != 8) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setPackAlignment(param); - break; - - case GL_PACK_REVERSE_ROW_ORDER_ANGLE: - context->getState().setPackReverseRowOrder(param != 0); - break; - - case GL_UNPACK_IMAGE_HEIGHT: - case GL_UNPACK_SKIP_IMAGES: - case GL_UNPACK_ROW_LENGTH: - case GL_UNPACK_SKIP_ROWS: - case GL_UNPACK_SKIP_PIXELS: - case GL_PACK_ROW_LENGTH: - case GL_PACK_SKIP_ROWS: - case GL_PACK_SKIP_PIXELS: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - UNIMPLEMENTED(); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::PixelStorei(pname, param); } void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units) { - EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - context->getState().setPolygonOffsetParams(factor, units); - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (width < 0 || height < 0 || bufSize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (!gl::ValidateReadPixelsParameters(context, x, y, width, height, - format, type, &bufSize, data)) - { - return; - } - - gl::Error error = context->readPixels(x, y, width, height, format, type, &bufSize, data); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (width < 0 || height < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (!gl::ValidateReadPixelsParameters(context, x, y, width, height, - format, type, NULL, pixels)) - { - return; - } - - gl::Error error = context->readPixels(x, y, width, height, format, type, NULL, pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::PolygonOffset(factor, units); } -void GL_APIENTRY glReleaseShaderCompiler(void) +void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) { - EVENT("()"); - - gl::Context *context = gl::getNonLostContext(); - - if (context) - { - context->releaseShaderCompiler(); - } + return gl::ReadPixels(x, y, width, height, format, type, pixels); } -void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glReleaseShaderCompiler(void) { - EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, samples, internalformat, width, height); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateRenderbufferStorageParameters(context, target, samples, internalformat, - width, height, true)) - { - return; - } - - gl::Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); - gl::Error error = renderbuffer->setStorage(width, height, internalformat, samples); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::ReleaseShaderCompiler(); } void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { - glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height); -} - -void GL_APIENTRY glSampleCoverage(GLclampf value, GLboolean invert) -{ - EVENT("(GLclampf value = %f, GLboolean invert = %u)", value, invert); - - gl::Context* context = gl::getNonLostContext(); - - if (context) - { - context->getState().setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE); - } + return gl::RenderbufferStorage(target, internalformat, width, height); } -void GL_APIENTRY glSetFenceNV(GLuint fence, GLenum condition) +void GL_APIENTRY glSampleCoverage(GLfloat value, GLboolean invert) { - EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (condition != GL_ALL_COMPLETED_NV) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::FenceNV *fenceObject = context->getFenceNV(fence); - - if (fenceObject == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::Error error = fenceObject->setFence(condition); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::SampleCoverage(value, invert); } void GL_APIENTRY 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); - - gl::Context* context = gl::getNonLostContext(); - if (context) - { - if (width < 0 || height < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setScissorParams(x, y, width, height); - } + return gl::Scissor(x, y, width, height); } void GL_APIENTRY 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); - - gl::Context* context = gl::getNonLostContext(); - if (context) - { - const std::vector &shaderBinaryFormats = context->getCaps().shaderBinaryFormats; - if (std::find(shaderBinaryFormats.begin(), shaderBinaryFormats.end(), binaryformat) == shaderBinaryFormats.end()) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - // No binary shader formats are supported. - UNIMPLEMENTED(); - } + return gl::ShaderBinary(n, shaders, binaryformat, binary, length); } void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar* const* 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (count < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Shader *shaderObject = context->getShader(shader); - - if (!shaderObject) - { - if (context->getProgram(shader)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - shaderObject->setSource(count, string, length); - } + return gl::ShaderSource(shader, count, string, length); } void GL_APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask) { - glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); + return gl::StencilFunc(func, ref, mask); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (face) - { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilParams(func, ref, mask); - } - - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilBackParams(func, ref, mask); - } - } + return gl::StencilFuncSeparate(face, func, ref, mask); } void GL_APIENTRY glStencilMask(GLuint mask) { - glStencilMaskSeparate(GL_FRONT_AND_BACK, mask); + return gl::StencilMask(mask); } void GL_APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask) { - EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (face) - { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilWritemask(mask); - } - - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilBackWritemask(mask); - } - } + return gl::StencilMaskSeparate(face, mask); } void GL_APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { - glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); + return gl::StencilOp(fail, zfail, zpass); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - switch (face) - { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - 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: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (face == GL_FRONT || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilOperations(fail, zfail, zpass); - } - - if (face == GL_BACK || face == GL_FRONT_AND_BACK) - { - context->getState().setStencilBackOperations(fail, zfail, zpass); - } - } + return gl::StencilOpSeparate(face, fail, zfail, zpass); } -GLboolean GL_APIENTRY glTestFenceNV(GLuint fence) +void GL_APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { - EVENT("(GLuint fence = %d)", fence); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::FenceNV *fenceObject = context->getFenceNV(fence); - - if (fenceObject == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_TRUE; - } - - if (fenceObject->isFence() != GL_TRUE) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_TRUE; - } - - GLboolean result; - gl::Error error = fenceObject->testFence(&result); - if (error.isError()) - { - context->recordError(error); - return GL_TRUE; - } - - return result; - } - - return GL_TRUE; -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2TexImageParameters(context, target, level, internalformat, false, false, - 0, 0, width, height, border, format, type, pixels)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3TexImageParameters(context, target, level, internalformat, false, false, - 0, 0, 0, width, height, 1, border, format, type, pixels)) - { - return; - } - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture = context->getTexture2D(); - gl::Error error = texture->setImage(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } - 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: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - gl::Error error = texture->setImage(target, level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: UNREACHABLE(); - } - } + return gl::TexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateTexParamParameters(context, pname, static_cast(param))) - { - return; - } - - gl::Texture *texture = context->getTargetTexture(target); - - if (!texture) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (pname) - { - case GL_TEXTURE_WRAP_S: texture->getSamplerState().wrapS = gl::uiround(param); break; - case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = gl::uiround(param); break; - case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = gl::uiround(param); break; - case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = gl::uiround(param); break; - case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = gl::uiround(param); break; - case GL_TEXTURE_USAGE_ANGLE: texture->setUsage(gl::uiround(param)); break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->getSamplerState().maxAnisotropy = std::min(param, context->getExtensions().maxTextureAnisotropy); break; - case GL_TEXTURE_COMPARE_MODE: texture->getSamplerState().compareMode = gl::uiround(param); break; - case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = gl::uiround(param); break; - case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = gl::uiround(param); break; - case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = gl::uiround(param); break; - case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = gl::uiround(param); break; - case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = gl::uiround(param); break; - case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = gl::iround(param); break; - case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = gl::iround(param); break; - case GL_TEXTURE_MIN_LOD: texture->getSamplerState().minLod = param; break; - case GL_TEXTURE_MAX_LOD: texture->getSamplerState().maxLod = param; break; - default: UNREACHABLE(); break; - } - } + return gl::TexParameterf(target, pname, param); } void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) { - glTexParameterf(target, pname, (GLfloat)*params); + return gl::TexParameterfv(target, pname, params); } void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateTexParamParameters(context, pname, param)) - { - return; - } - - gl::Texture *texture = context->getTargetTexture(target); - - if (!texture) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (pname) - { - case GL_TEXTURE_WRAP_S: texture->getSamplerState().wrapS = (GLenum)param; break; - case GL_TEXTURE_WRAP_T: texture->getSamplerState().wrapT = (GLenum)param; break; - case GL_TEXTURE_WRAP_R: texture->getSamplerState().wrapR = (GLenum)param; break; - case GL_TEXTURE_MIN_FILTER: texture->getSamplerState().minFilter = (GLenum)param; break; - case GL_TEXTURE_MAG_FILTER: texture->getSamplerState().magFilter = (GLenum)param; break; - case GL_TEXTURE_USAGE_ANGLE: texture->setUsage((GLenum)param); break; - case GL_TEXTURE_MAX_ANISOTROPY_EXT: texture->getSamplerState().maxAnisotropy = std::min((float)param, context->getExtensions().maxTextureAnisotropy); break; - case GL_TEXTURE_COMPARE_MODE: texture->getSamplerState().compareMode = (GLenum)param; break; - case GL_TEXTURE_COMPARE_FUNC: texture->getSamplerState().compareFunc = (GLenum)param; break; - case GL_TEXTURE_SWIZZLE_R: texture->getSamplerState().swizzleRed = (GLenum)param; break; - case GL_TEXTURE_SWIZZLE_G: texture->getSamplerState().swizzleGreen = (GLenum)param; break; - case GL_TEXTURE_SWIZZLE_B: texture->getSamplerState().swizzleBlue = (GLenum)param; break; - case GL_TEXTURE_SWIZZLE_A: texture->getSamplerState().swizzleAlpha = (GLenum)param; break; - case GL_TEXTURE_BASE_LEVEL: texture->getSamplerState().baseLevel = param; break; - case GL_TEXTURE_MAX_LEVEL: texture->getSamplerState().maxLevel = param; break; - case GL_TEXTURE_MIN_LOD: texture->getSamplerState().minLod = (GLfloat)param; break; - case GL_TEXTURE_MAX_LOD: texture->getSamplerState().maxLod = (GLfloat)param; break; - default: UNREACHABLE(); break; - } - } + return gl::TexParameteri(target, pname, param); } void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params) { - glTexParameteri(target, pname, *params); + return gl::TexParameteriv(target, pname, params); } -void GL_APIENTRY glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY 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, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, levels, internalformat, width, height); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!context->getExtensions().textureStorage) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (context->getClientVersion() < 3 && - !ValidateES2TexStorageParameters(context, target, levels, internalformat, width, height)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1)) - { - return; - } - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture2d = context->getTexture2D(); - gl::Error error = texture2d->storage(levels, internalformat, width, height); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_TEXTURE_CUBE_MAP: - { - gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); - gl::Error error = textureCube->storage(levels, internalformat, width); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3 && - !ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, - xoffset, yoffset, width, height, 0, format, type, pixels)) - { - return; - } - - if (context->getClientVersion() >= 3 && - !ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true, - xoffset, yoffset, 0, width, height, 1, 0, format, type, pixels)) - { - return; - } - - // Zero sized uploads are valid but no-ops - if (width == 0 || height == 0) - { - return; - } - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture = context->getTexture2D(); - gl::Error error = texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } - 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: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - gl::Error error = texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - UNREACHABLE(); - } - } + return gl::TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); } void GL_APIENTRY glUniform1f(GLint location, GLfloat x) { - glUniform1fv(location, 1, &x); + return gl::Uniform1f(location, x); } void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_FLOAT, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform1fv(location, count, v); - } + return gl::Uniform1fv(location, count, v); } void GL_APIENTRY glUniform1i(GLint location, GLint x) { - glUniform1iv(location, 1, &x); + return gl::Uniform1i(location, x); } void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_INT, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform1iv(location, count, v); - } + return gl::Uniform1iv(location, count, v); } void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y) { - GLfloat xy[2] = {x, y}; - - glUniform2fv(location, 1, xy); + return gl::Uniform2f(location, x, y); } void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_FLOAT_VEC2, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform2fv(location, count, v); - } + return gl::Uniform2fv(location, count, v); } void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y) { - GLint xy[2] = {x, y}; - - glUniform2iv(location, 1, xy); + return gl::Uniform2i(location, x, y); } void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_INT_VEC2, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform2iv(location, count, v); - } + return gl::Uniform2iv(location, count, v); } void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) { - GLfloat xyz[3] = {x, y, z}; - - glUniform3fv(location, 1, xyz); + return gl::Uniform3f(location, x, y, z); } void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_FLOAT_VEC3, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform3fv(location, count, v); - } + return gl::Uniform3fv(location, count, v); } void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z) { - GLint xyz[3] = {x, y, z}; - - glUniform3iv(location, 1, xyz); + return gl::Uniform3i(location, x, y, z); } void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_INT_VEC3, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform3iv(location, count, v); - } + return gl::Uniform3iv(location, count, v); } void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { - GLfloat xyzw[4] = {x, y, z, w}; - - glUniform4fv(location, 1, xyzw); + return gl::Uniform4f(location, x, y, z, w); } void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_FLOAT_VEC4, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform4fv(location, count, v); - } + return gl::Uniform4fv(location, count, v); } void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) { - GLint xyzw[4] = {x, y, z, w}; - - glUniform4iv(location, 1, xyzw); + return gl::Uniform4i(location, x, y, z, w); } void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_INT_VEC4, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform4iv(location, count, v); - } + return gl::Uniform4iv(location, count, v); } void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix2fv(location, count, transpose, value); - } + return gl::UniformMatrix2fv(location, count, transpose, value); } void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix3fv(location, count, transpose, value); - } + return gl::UniformMatrix3fv(location, count, transpose, value); } void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix4fv(location, count, transpose, value); - } + return gl::UniformMatrix4fv(location, count, transpose, value); } void GL_APIENTRY glUseProgram(GLuint program) { - EVENT("(GLuint program = %d)", program); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); - - if (!programObject && program != 0) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - if (program != 0 && !programObject->isLinked()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - context->useProgram(program); - } + return gl::UseProgram(program); } void GL_APIENTRY glValidateProgram(GLuint program) { - EVENT("(GLuint program = %d)", program); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - programObject->validate(context->getCaps()); - } + return gl::ValidateProgram(program); } -void GL_APIENTRY glVertexAttrib1f(GLuint index, GLfloat x) +void GL_APIENTRY glVertexAttrib1f(GLuint indx, GLfloat x) { - EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { x, 0, 0, 1 }; - context->getState().setVertexAttribf(index, vals); - } + return gl::VertexAttrib1f(indx, x); } -void GL_APIENTRY glVertexAttrib1fv(GLuint index, const GLfloat* values) +void GL_APIENTRY glVertexAttrib1fv(GLuint indx, const GLfloat* values) { - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { values[0], 0, 0, 1 }; - context->getState().setVertexAttribf(index, vals); - } + return gl::VertexAttrib1fv(indx, values); } -void GL_APIENTRY glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +void GL_APIENTRY glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) { - EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { x, y, 0, 1 }; - context->getState().setVertexAttribf(index, vals); - } + return gl::VertexAttrib2f(indx, x, y); } -void GL_APIENTRY glVertexAttrib2fv(GLuint index, const GLfloat* values) +void GL_APIENTRY glVertexAttrib2fv(GLuint indx, const GLfloat* values) { - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { values[0], values[1], 0, 1 }; - context->getState().setVertexAttribf(index, vals); - } + return gl::VertexAttrib2fv(indx, values); } -void GL_APIENTRY glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +void GL_APIENTRY glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) { - EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { x, y, z, 1 }; - context->getState().setVertexAttribf(index, vals); - } + return gl::VertexAttrib3f(indx, x, y, z); } -void GL_APIENTRY glVertexAttrib3fv(GLuint index, const GLfloat* values) +void GL_APIENTRY glVertexAttrib3fv(GLuint indx, const GLfloat* values) { - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { values[0], values[1], values[2], 1 }; - context->getState().setVertexAttribf(index, vals); - } + return gl::VertexAttrib3fv(indx, values); } -void GL_APIENTRY glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +void GL_APIENTRY glVertexAttrib4f(GLuint indx, 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLfloat vals[4] = { x, y, z, w }; - context->getState().setVertexAttribf(index, vals); - } + return gl::VertexAttrib4f(indx, x, y, z, w); } -void GL_APIENTRY glVertexAttrib4fv(GLuint index, const GLfloat* values) +void GL_APIENTRY glVertexAttrib4fv(GLuint indx, const GLfloat* values) { - EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setVertexAttribf(index, values); - } + return gl::VertexAttrib4fv(indx, values); } -void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) +void GL_APIENTRY glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) { - EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->setVertexAttribDivisor(index, divisor); - } -} - -void GL_APIENTRY 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 = %u, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)", - index, size, type, normalized, stride, ptr); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (size < 1 || size > 4) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (type) - { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_FIXED: - case GL_FLOAT: - break; - - case GL_HALF_FLOAT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_INT_2_10_10_10_REV: - case GL_UNSIGNED_INT_2_10_10_10_REV: - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (stride < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // [OpenGL ES 3.0.2] Section 2.8 page 24: - // An INVALID_OPERATION error is generated when a non-zero vertex array object - // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, - // and the pointer argument is not NULL. - if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && ptr != NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, - normalized == GL_TRUE, false, stride, ptr); - } + return gl::VertexAttribPointer(indx, size, type, normalized, stride, ptr); } void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (width < 0 || height < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setViewportParams(x, y, width, height); - } + return gl::Viewport(x, y, width, height); } -// OpenGL ES 3.0 functions - void GL_APIENTRY glReadBuffer(GLenum mode) { - EVENT("(GLenum mode = 0x%X)", mode); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // glReadBuffer - UNIMPLEMENTED(); - } + return gl::ReadBuffer(mode); } void GL_APIENTRY glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) { - EVENT("(GLenum mode = 0x%X, GLuint start = %u, GLuint end = %u, GLsizei count = %d, GLenum type = 0x%X, " - "const GLvoid* indices = 0x%0.8p)", mode, start, end, count, type, indices); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // glDrawRangeElements - UNIMPLEMENTED(); - } + return gl::DrawRangeElements(mode, start, end, count, type, indices); } void GL_APIENTRY glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, 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, 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // validateES3TexImageFormat sets the error code if there is an error - if (!ValidateES3TexImageParameters(context, target, level, internalformat, false, false, - 0, 0, 0, width, height, depth, border, format, type, pixels)) - { - return; - } - - switch(target) - { - case GL_TEXTURE_3D: - { - gl::Texture3D *texture = context->getTexture3D(); - gl::Error error = texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - gl::Texture2DArray *texture = context->getTexture2DArray(); - gl::Error error = texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); } void GL_APIENTRY glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) { - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " - "GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)", - target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // validateES3TexImageFormat sets the error code if there is an error - if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, false, true, - xoffset, yoffset, zoffset, width, height, depth, 0, - format, type, pixels)) - { - return; - } - - // Zero sized uploads are valid but no-ops - if (width == 0 || height == 0 || depth == 0) - { - return; - } - - switch(target) - { - case GL_TEXTURE_3D: - { - gl::Texture3D *texture = context->getTexture3D(); - gl::Error error = texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - gl::Texture2DArray *texture = context->getTexture2DArray(); - gl::Error error = texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); } void GL_APIENTRY glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) { - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", - target, level, xoffset, yoffset, zoffset, x, y, width, height); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateES3CopyTexImageParameters(context, target, level, GL_NONE, true, xoffset, yoffset, zoffset, - x, y, width, height, 0)) - { - return; - } - - gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - gl::Texture *texture = NULL; - switch (target) - { - case GL_TEXTURE_3D: - texture = context->getTexture3D(); - break; - - case GL_TEXTURE_2D_ARRAY: - texture = context->getTexture2DArray(); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Error error = texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); } void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, 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, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, " - "const GLvoid* data = 0x%0.8p)", - target, level, internalformat, width, height, depth, border, imageSize, data); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - // validateES3TexImageFormat sets the error code if there is an error - if (!ValidateES3TexImageParameters(context, target, level, internalformat, true, false, - 0, 0, 0, width, height, depth, border, GL_NONE, GL_NONE, data)) - { - return; - } - - switch(target) - { - case GL_TEXTURE_3D: - { - gl::Texture3D *texture = context->getTexture3D(); - gl::Error error = texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, context->getState().getUnpackState(), data); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - gl::Texture2DArray *texture = context->getTexture2DArray(); - gl::Error error = texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, context->getState().getUnpackState(), data); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::CompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); } void GL_APIENTRY glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) { - EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " - "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " - "GLenum format = 0x%X, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)", - target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); - if (imageSize < 0 || static_cast(imageSize) != formatInfo.computeBlockSize(GL_UNSIGNED_BYTE, width, height)) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (!data) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - // validateES3TexImageFormat sets the error code if there is an error - if (!ValidateES3TexImageParameters(context, target, level, GL_NONE, true, true, - 0, 0, 0, width, height, depth, 0, GL_NONE, GL_NONE, data)) - { - return; - } - - // Zero sized uploads are valid but no-ops - if (width == 0 || height == 0) - { - return; - } - - switch(target) - { - case GL_TEXTURE_3D: - { - gl::Texture3D *texture = context->getTexture3D(); - gl::Error error = texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, - format, imageSize, context->getState().getUnpackState(), data); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - gl::Texture2DArray *texture = context->getTexture2DArray(); - gl::Error error = texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, - format, imageSize, context->getState().getUnpackState(), data); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); } void GL_APIENTRY glGenQueries(GLsizei n, GLuint* ids) { - EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (GLsizei i = 0; i < n; i++) - { - ids[i] = context->createQuery(); - } - } + return gl::GenQueries(n, ids); } void GL_APIENTRY glDeleteQueries(GLsizei n, const GLuint* ids) { - EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (GLsizei i = 0; i < n; i++) - { - context->deleteQuery(ids[i]); - } - } + return gl::DeleteQueries(n, ids); } GLboolean GL_APIENTRY glIsQuery(GLuint id) { - EVENT("(GLuint id = %u)", id); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - return (context->getQuery(id, false, GL_NONE) != NULL) ? GL_TRUE : GL_FALSE; - } - - return GL_FALSE; + return gl::IsQuery(id); } void GL_APIENTRY glBeginQuery(GLenum target, GLuint id) { - EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateBeginQuery(context, target, id)) - { - return; - } - - gl::Error error = context->beginQuery(target, id); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::BeginQuery(target, id); } void GL_APIENTRY glEndQuery(GLenum target) { - EVENT("(GLenum target = 0x%X)", target); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateEndQuery(context, target)) - { - return; - } - - gl::Error error = context->endQuery(target); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::EndQuery(target); } void GL_APIENTRY glGetQueryiv(GLenum target, GLenum pname, GLint* params) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidQueryType(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (pname) - { - case GL_CURRENT_QUERY: - params[0] = static_cast(context->getState().getActiveQueryId(target)); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetQueryiv(target, pname, params); } void GL_APIENTRY glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) { - EVENT("(GLuint id = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", id, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::Query *queryObject = context->getQuery(id, false, GL_NONE); - - if (!queryObject) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (context->getState().getActiveQueryId(queryObject->getType()) == id) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - switch(pname) - { - case GL_QUERY_RESULT_EXT: - { - gl::Error error = queryObject->getResult(params); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_QUERY_RESULT_AVAILABLE_EXT: - { - gl::Error error = queryObject->isResultAvailable(params); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetQueryObjectuiv(id, pname, params); } GLboolean GL_APIENTRY glUnmapBuffer(GLenum target) { - EVENT("(GLenum target = 0x%X)", target); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - return glUnmapBufferOES(target); - } - - return GL_FALSE; + return gl::UnmapBuffer(target); } void GL_APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, GLvoid** params) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - glGetBufferPointervOES(target, pname, params); - } + return gl::GetBufferPointerv(target, pname, params); } void GL_APIENTRY glDrawBuffers(GLsizei n, const GLenum* bufs) { - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - glDrawBuffersEXT(n, bufs); - } + return gl::DrawBuffers(n, bufs); } void GL_APIENTRY glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x3, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix2x3fv(location, count, transpose, value); - } + return gl::UniformMatrix2x3fv(location, count, transpose, value); } void GL_APIENTRY glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x2, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix3x2fv(location, count, transpose, value); - } + return gl::UniformMatrix3x2fv(location, count, transpose, value); } void GL_APIENTRY glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT2x4, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix2x4fv(location, count, transpose, value); - } + return gl::UniformMatrix2x4fv(location, count, transpose, value); } void GL_APIENTRY glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x2, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix4x2fv(location, count, transpose, value); - } + return gl::UniformMatrix4x2fv(location, count, transpose, value); } void GL_APIENTRY glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT3x4, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix3x4fv(location, count, transpose, value); - } + return gl::UniformMatrix3x4fv(location, count, transpose, value); } void GL_APIENTRY glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", - location, count, transpose, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniformMatrix(context, GL_FLOAT_MAT4x3, location, count, transpose)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniformMatrix4x3fv(location, count, transpose, value); - } + return gl::UniformMatrix4x3fv(location, count, transpose, value); } void GL_APIENTRY glBlitFramebuffer(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, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter, - false)) - { - return; - } - - gl::Error error = context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, - mask, filter); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } void GL_APIENTRY glRenderbufferStorageMultisample(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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateRenderbufferStorageParameters(context, target, samples, internalformat, - width, height, false)) - { - return; - } - - gl::Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); - renderbuffer->setStorage(width, height, internalformat, samples); - } + return gl::RenderbufferStorageMultisample(target, samples, internalformat, width, height); } void GL_APIENTRY glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) { - EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, GLint layer = %d)", - target, attachment, texture, level, layer); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateFramebufferTextureLayer(context, target, attachment, texture, - level, layer)) - { - return; - } - - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); - - if (texture != 0) - { - gl::Texture *textureObject = context->getTexture(texture); - gl::ImageIndex index(textureObject->getTarget(), level, layer); - framebuffer->setTextureAttachment(attachment, textureObject, index); - } - else - { - framebuffer->setNULLAttachment(attachment); - } - } + return gl::FramebufferTextureLayer(target, attachment, texture, level, layer); } GLvoid* GL_APIENTRY glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", - target, offset, length, access); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - return glMapBufferRangeEXT(target, offset, length, access); - } - - return NULL; + return gl::MapBufferRange(target, offset, length, access); } void GL_APIENTRY glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) { - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - glFlushMappedBufferRangeEXT(target, offset, length); - } + return gl::FlushMappedBufferRange(target, offset, length); } void GL_APIENTRY glBindVertexArray(GLuint array) { - EVENT("(GLuint array = %u)", array); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::VertexArray *vao = context->getVertexArray(array); - - if (!vao) - { - // The default VAO should always exist - ASSERT(array != 0); - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - context->bindVertexArray(array); - } + return gl::BindVertexArray(array); } void GL_APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint* arrays) { - EVENT("(GLsizei n = %d, const GLuint* arrays = 0x%0.8p)", n, arrays); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) - { - if (arrays[arrayIndex] != 0) - { - context->deleteVertexArray(arrays[arrayIndex]); - } - } - } + return gl::DeleteVertexArrays(n, arrays); } void GL_APIENTRY glGenVertexArrays(GLsizei n, GLuint* arrays) { - EVENT("(GLsizei n = %d, GLuint* arrays = 0x%0.8p)", n, arrays); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (n < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int arrayIndex = 0; arrayIndex < n; arrayIndex++) - { - arrays[arrayIndex] = context->createVertexArray(); - } - } + return gl::GenVertexArrays(n, arrays); } GLboolean GL_APIENTRY glIsVertexArray(GLuint array) { - EVENT("(GLuint array = %u)", array); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - if (array == 0) - { - return GL_FALSE; - } - - gl::VertexArray *vao = context->getVertexArray(array); - - return (vao != NULL ? GL_TRUE : GL_FALSE); - } - - return GL_FALSE; + return gl::IsVertexArray(array); } void GL_APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint* data) { - EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint* data = 0x%0.8p)", - target, index, data); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - const gl::Caps &caps = context->getCaps(); - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER_START: - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (index >= caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_UNIFORM_BUFFER_START: - case GL_UNIFORM_BUFFER_SIZE: - case GL_UNIFORM_BUFFER_BINDING: - if (index >= caps.maxCombinedUniformBlocks) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (!(context->getIndexedIntegerv(target, index, data))) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (numParams == 0) - { - return; // it is known that pname is valid, but there are no parameters to return - } - - if (nativeType == GL_INT_64_ANGLEX) - { - GLint64 minIntValue = static_cast(std::numeric_limits::min()); - GLint64 maxIntValue = static_cast(std::numeric_limits::max()); - GLint64 *int64Params = new GLint64[numParams]; - - context->getIndexedInteger64v(target, index, int64Params); - - for (unsigned int i = 0; i < numParams; ++i) - { - GLint64 clampedValue = std::max(std::min(int64Params[i], maxIntValue), minIntValue); - data[i] = static_cast(clampedValue); - } - - delete [] int64Params; - } - else - { - UNREACHABLE(); - } - } - } + return gl::GetIntegeri_v(target, index, data); } void GL_APIENTRY glBeginTransformFeedback(GLenum primitiveMode) { - EVENT("(GLenum primitiveMode = 0x%X)", primitiveMode); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - switch (primitiveMode) - { - case GL_TRIANGLES: - case GL_LINES: - case GL_POINTS: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); - ASSERT(transformFeedback != NULL); - - if (transformFeedback->isStarted()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (transformFeedback->isPaused()) - { - transformFeedback->resume(); - } - else - { - transformFeedback->start(primitiveMode); - } - } + return gl::BeginTransformFeedback(primitiveMode); } void GL_APIENTRY glEndTransformFeedback(void) { - EVENT("(void)"); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); - ASSERT(transformFeedback != NULL); - - if (!transformFeedback->isStarted()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - transformFeedback->stop(); - } + return gl::EndTransformFeedback(); } void GL_APIENTRY glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) { - EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u, GLintptr offset = %d, GLsizeiptr size = %d)", - target, index, buffer, offset, size); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - const gl::Caps &caps = context->getCaps(); - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER: - if (index >= caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_UNIFORM_BUFFER: - if (index >= caps.maxUniformBufferBindings) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (buffer != 0 && size <= 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER: - - // size and offset must be a multiple of 4 - if (buffer != 0 && ((offset % 4) != 0 || (size % 4) != 0)) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size); - context->bindGenericTransformFeedbackBuffer(buffer); - break; - - case GL_UNIFORM_BUFFER: - - // it is an error to bind an offset not a multiple of the alignment - if (buffer != 0 && (offset % caps.uniformBufferOffsetAlignment) != 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->bindIndexedUniformBuffer(buffer, index, offset, size); - context->bindGenericUniformBuffer(buffer); - break; - - default: - UNREACHABLE(); - } - } + return gl::BindBufferRange(target, index, buffer, offset, size); } void GL_APIENTRY glBindBufferBase(GLenum target, GLuint index, GLuint buffer) { - EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u)", - target, index, buffer); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - const gl::Caps &caps = context->getCaps(); - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER: - if (index >= caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_UNIFORM_BUFFER: - if (index >= caps.maxUniformBufferBindings) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER: - context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0); - context->bindGenericTransformFeedbackBuffer(buffer); - break; - - case GL_UNIFORM_BUFFER: - context->bindIndexedUniformBuffer(buffer, index, 0, 0); - context->bindGenericUniformBuffer(buffer); - break; - - default: - UNREACHABLE(); - } - } + return gl::BindBufferBase(target, index, buffer); } void GL_APIENTRY glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) { - EVENT("(GLuint program = %u, GLsizei count = %d, const GLchar* const* varyings = 0x%0.8p, GLenum bufferMode = 0x%X)", - program, count, varyings, bufferMode); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (count < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - const gl::Caps &caps = context->getCaps(); - switch (bufferMode) - { - case GL_INTERLEAVED_ATTRIBS: - break; - case GL_SEPARATE_ATTRIBS: - if (static_cast(count) > caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (!gl::ValidProgram(context, program)) - { - return; - } - - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); - - programObject->setTransformFeedbackVaryings(count, varyings, bufferMode); - } + return gl::TransformFeedbackVaryings(program, count, varyings, bufferMode); } void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) { - EVENT("(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, " - "GLsizei* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", - program, index, bufSize, length, size, type, name); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (bufSize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (!gl::ValidProgram(context, program)) - { - return; - } - - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); - - if (index >= static_cast(programObject->getTransformFeedbackVaryingCount())) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name); - } + return gl::GetTransformFeedbackVarying(program, index, bufSize, length, size, type, name); } void GL_APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) { - EVENT("(GLuint index = %u, GLint size = %d, GLenum type = 0x%X, GLsizei stride = %d, const GLvoid* pointer = 0x%0.8p)", - index, size, type, stride, pointer); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (size < 1 || size > 4) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (type) - { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_INT_2_10_10_10_REV: - case GL_UNSIGNED_INT_2_10_10_10_REV: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (stride < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if ((type == GL_INT_2_10_10_10_REV || type == GL_UNSIGNED_INT_2_10_10_10_REV) && size != 4) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // [OpenGL ES 3.0.2] Section 2.8 page 24: - // An INVALID_OPERATION error is generated when a non-zero vertex array object - // is bound, zero is bound to the ARRAY_BUFFER buffer object binding point, - // and the pointer argument is not NULL. - if (context->getState().getVertexArray()->id() != 0 && context->getState().getArrayBufferId() == 0 && pointer != NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - context->getState().setVertexAttribState(index, context->getState().getTargetBuffer(GL_ARRAY_BUFFER), size, type, false, true, - stride, pointer); - } + return gl::VertexAttribIPointer(index, size, type, stride, pointer); } void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) { - EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", - index, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index); - - if (!gl::ValidateGetVertexAttribParameters(context, pname)) - { - return; - } - - if (pname == GL_CURRENT_VERTEX_ATTRIB) - { - const gl::VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); - for (int i = 0; i < 4; ++i) - { - params[i] = currentValueData.IntValues[i]; - } - } - else - { - *params = gl::QuerySingleVertexAttributeParameter(attribState, pname); - } - } + return gl::GetVertexAttribIiv(index, pname, params); } void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) { - EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLuint* params = 0x%0.8p)", - index, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - const gl::VertexAttribute &attribState = context->getState().getVertexAttribState(index); - - if (!gl::ValidateGetVertexAttribParameters(context, pname)) - { - return; - } - - if (pname == GL_CURRENT_VERTEX_ATTRIB) - { - const gl::VertexAttribCurrentValueData ¤tValueData = context->getState().getVertexAttribCurrentValue(index); - for (int i = 0; i < 4; ++i) - { - params[i] = currentValueData.UnsignedIntValues[i]; - } - } - else - { - *params = gl::QuerySingleVertexAttributeParameter(attribState, pname); - } - } + return gl::GetVertexAttribIuiv(index, pname, params); } void GL_APIENTRY glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) { - EVENT("(GLuint index = %u, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)", - index, x, y, z, w); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLint vals[4] = { x, y, z, w }; - context->getState().setVertexAttribi(index, vals); - } + return gl::VertexAttribI4i(index, x, y, z, w); } void GL_APIENTRY glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { - EVENT("(GLuint index = %u, GLuint x = %u, GLuint y = %u, GLuint z = %u, GLuint w = %u)", - index, x, y, z, w); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - GLuint vals[4] = { x, y, z, w }; - context->getState().setVertexAttribu(index, vals); - } + return gl::VertexAttribI4ui(index, x, y, z, w); } void GL_APIENTRY glVertexAttribI4iv(GLuint index, const GLint* v) { - EVENT("(GLuint index = %u, const GLint* v = 0x%0.8p)", index, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setVertexAttribi(index, v); - } + return gl::VertexAttribI4iv(index, v); } void GL_APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint* v) { - EVENT("(GLuint index = %u, const GLuint* v = 0x%0.8p)", index, v); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->getState().setVertexAttribu(index, v); - } + return gl::VertexAttribI4uiv(index, v); } void GL_APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint* params) { - EVENT("(GLuint program = %u, GLint location = %d, GLuint* params = 0x%0.8p)", - program, location, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateGetUniformuiv(context, program, location, params)) - { - return; - } - - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - ASSERT(programBinary); - - programBinary->getUniformuiv(location, params); - } + return gl::GetUniformuiv(program, location, params); } GLint GL_APIENTRY glGetFragDataLocation(GLuint program, const GLchar *name) { - EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)", - program, name); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return -1; - } - - if (program == 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return -1; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject || !programObject->isLinked()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return -1; - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programBinary) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return -1; - } - - return programBinary->getFragDataLocation(name); - } - - return 0; + return gl::GetFragDataLocation(program, name); } void GL_APIENTRY glUniform1ui(GLint location, GLuint v0) { - glUniform1uiv(location, 1, &v0); + return gl::Uniform1ui(location, v0); } void GL_APIENTRY glUniform2ui(GLint location, GLuint v0, GLuint v1) { - const GLuint xy[] = { v0, v1 }; - glUniform2uiv(location, 1, xy); + return gl::Uniform2ui(location, v0, v1); } void GL_APIENTRY glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) { - const GLuint xyz[] = { v0, v1, v2 }; - glUniform3uiv(location, 1, xyz); + return gl::Uniform3ui(location, v0, v1, v2); } void GL_APIENTRY glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { - const GLuint xyzw[] = { v0, v1, v2, v3 }; - glUniform4uiv(location, 1, xyzw); + return gl::Uniform4ui(location, v0, v1, v2, v3); } void GL_APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint* value) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", - location, count, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_UNSIGNED_INT, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform1uiv(location, count, value); - } + return gl::Uniform1uiv(location, count, value); } void GL_APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint* value) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", - location, count, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC2, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform2uiv(location, count, value); - } + return gl::Uniform2uiv(location, count, value); } void GL_APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint* value) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value)", - location, count, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC3, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform3uiv(location, count, value); - } + return gl::Uniform3uiv(location, count, value); } void GL_APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint* value) { - EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", - location, count, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateUniform(context, GL_UNSIGNED_INT_VEC4, location, count)) - { - return; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - programBinary->setUniform4uiv(location, count, value); - } + return gl::Uniform4uiv(location, count, value); } void GL_APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { - EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint* value = 0x%0.8p)", - buffer, drawbuffer, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateClearBuffer(context)) - { - return; - } - - switch (buffer) - { - case GL_COLOR: - if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_STENCIL: - if (drawbuffer != 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Error error = context->clearBufferiv(buffer, drawbuffer, value); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::ClearBufferiv(buffer, drawbuffer, value); } void GL_APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { - EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint* value = 0x%0.8p)", - buffer, drawbuffer, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateClearBuffer(context)) - { - return; - } - - switch (buffer) - { - case GL_COLOR: - if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Error error = context->clearBufferuiv(buffer, drawbuffer, value); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::ClearBufferuiv(buffer, drawbuffer, value); } void GL_APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { - EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat* value = 0x%0.8p)", - buffer, drawbuffer, value); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateClearBuffer(context)) - { - return; - } - - switch (buffer) - { - case GL_COLOR: - if (drawbuffer < 0 || static_cast(drawbuffer) >= context->getCaps().maxDrawBuffers) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_DEPTH: - if (drawbuffer != 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Error error = context->clearBufferfv(buffer, drawbuffer, value); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::ClearBufferfv(buffer, drawbuffer, value); } void GL_APIENTRY glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { - EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth, GLint stencil = %d)", - buffer, drawbuffer, depth, stencil); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateClearBuffer(context)) - { - return; - } - - switch (buffer) - { - case GL_DEPTH_STENCIL: - if (drawbuffer != 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Error error = context->clearBufferfi(buffer, drawbuffer, depth, stencil); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::ClearBufferfi(buffer, drawbuffer, depth, stencil); } const GLubyte* GL_APIENTRY glGetStringi(GLenum name, GLuint index) { - EVENT("(GLenum name = 0x%X, GLuint index = %u)", name, index); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - if (name != GL_EXTENSIONS) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return NULL; - } - - if (index >= context->getExtensionStringCount()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return NULL; - } - - return reinterpret_cast(context->getExtensionString(index).c_str()); - } - - return NULL; + return gl::GetStringi(name, index); } void GL_APIENTRY glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { - EVENT("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)", - readTarget, writeTarget, readOffset, writeOffset, size); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!gl::ValidBufferTarget(context, readTarget) || !gl::ValidBufferTarget(context, writeTarget)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Buffer *readBuffer = context->getState().getTargetBuffer(readTarget); - gl::Buffer *writeBuffer = context->getState().getTargetBuffer(writeTarget); - - if (!readBuffer || !writeBuffer) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // Verify that readBuffer and writeBuffer are not currently mapped - if (readBuffer->isMapped() || writeBuffer->isMapped()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (readOffset < 0 || writeOffset < 0 || size < 0 || - static_cast(readOffset + size) > readBuffer->getSize() || - static_cast(writeOffset + size) > writeBuffer->getSize()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (readBuffer == writeBuffer && std::abs(readOffset - writeOffset) < size) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - // if size is zero, the copy is a successful no-op - if (size > 0) - { - gl::Error error = writeBuffer->copyBufferSubData(readBuffer, readOffset, writeOffset, size); - if (error.isError()) - { - context->recordError(error); - return; - } - } - } + return gl::CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); } void GL_APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) { - EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLchar* const* uniformNames = 0x%0.8p, GLuint* uniformIndices = 0x%0.8p)", - program, uniformCount, uniformNames, uniformIndices); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (uniformCount < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programObject->isLinked() || !programBinary) - { - for (int uniformId = 0; uniformId < uniformCount; uniformId++) - { - uniformIndices[uniformId] = GL_INVALID_INDEX; - } - } - else - { - for (int uniformId = 0; uniformId < uniformCount; uniformId++) - { - uniformIndices[uniformId] = programBinary->getUniformIndex(uniformNames[uniformId]); - } - } - } + return gl::GetUniformIndices(program, uniformCount, uniformNames, uniformIndices); } void GL_APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) { - EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLuint* uniformIndices = 0x%0.8p, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", - program, uniformCount, uniformIndices, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (uniformCount < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - switch (pname) - { - case GL_UNIFORM_TYPE: - case GL_UNIFORM_SIZE: - case GL_UNIFORM_NAME_LENGTH: - case GL_UNIFORM_BLOCK_INDEX: - case GL_UNIFORM_OFFSET: - case GL_UNIFORM_ARRAY_STRIDE: - case GL_UNIFORM_MATRIX_STRIDE: - case GL_UNIFORM_IS_ROW_MAJOR: - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - - if (!programBinary && uniformCount > 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int uniformId = 0; uniformId < uniformCount; uniformId++) - { - const GLuint index = uniformIndices[uniformId]; - - if (index >= (GLuint)programBinary->getActiveUniformCount()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - for (int uniformId = 0; uniformId < uniformCount; uniformId++) - { - const GLuint index = uniformIndices[uniformId]; - params[uniformId] = programBinary->getActiveUniformi(index, pname); - } - } + return gl::GetActiveUniformsiv(program, uniformCount, uniformIndices, pname, params); } GLuint GL_APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) { - EVENT("(GLuint program = %u, const GLchar* uniformBlockName = 0x%0.8p)", program, uniformBlockName); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_INVALID_INDEX; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_INVALID_INDEX; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return GL_INVALID_INDEX; - } - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programBinary) - { - return GL_INVALID_INDEX; - } - - return programBinary->getUniformBlockIndex(uniformBlockName); - } - - return 0; + return gl::GetUniformBlockIndex(program, uniformBlockName); } void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) { - EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", - program, uniformBlockIndex, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - - if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (pname) - { - case GL_UNIFORM_BLOCK_BINDING: - *params = static_cast(programObject->getUniformBlockBinding(uniformBlockIndex)); - break; - - case GL_UNIFORM_BLOCK_DATA_SIZE: - case GL_UNIFORM_BLOCK_NAME_LENGTH: - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: - case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: - case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: - programBinary->getActiveUniformBlockiv(uniformBlockIndex, pname, params); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetActiveUniformBlockiv(program, uniformBlockIndex, pname, params); } void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) { - EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLchar* uniformBlockName = 0x%0.8p)", - program, uniformBlockIndex, bufSize, length, uniformBlockName); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - - if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - programBinary->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName); - } + return gl::GetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, uniformBlockName); } void GL_APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { - EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLuint uniformBlockBinding = %u)", - program, uniformBlockIndex, uniformBlockBinding); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (uniformBlockBinding >= context->getCaps().maxUniformBufferBindings) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject) - { - if (context->getShader(program)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - else - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - - // if never linked, there won't be any uniform blocks - if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount()) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding); - } + return gl::UniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); } void GL_APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) { - EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)", - mode, first, count, instanceCount); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // glDrawArraysInstanced - UNIMPLEMENTED(); - } + return gl::DrawArraysInstanced(mode, first, count, instanceCount); } void GL_APIENTRY glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) { - EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei instanceCount = %d)", - mode, count, type, indices, instanceCount); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // glDrawElementsInstanced - UNIMPLEMENTED(); - } + return gl::DrawElementsInstanced(mode, count, type, indices, instanceCount); } GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags) { - EVENT("(GLenum condition = 0x%X, GLbitfield flags = 0x%X)", condition, flags); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return 0; - } - - if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return 0; - } - - if (flags != 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return 0; - } - - GLsync fenceSync = context->createFenceSync(); - - gl::FenceSync *fenceSyncObject = context->getFenceSync(fenceSync); - gl::Error error = fenceSyncObject->set(condition); - if (error.isError()) - { - context->deleteFenceSync(fenceSync); - context->recordError(error); - return NULL; - } - - return fenceSync; - } - - return NULL; + return gl::FenceSync_(condition, flags); } GLboolean GL_APIENTRY glIsSync(GLsync sync) { - EVENT("(GLsync sync = 0x%0.8p)", sync); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - return (context->getFenceSync(sync) != NULL); - } - - return GL_FALSE; + return gl::IsSync(sync); } void GL_APIENTRY glDeleteSync(GLsync sync) { - EVENT("(GLsync sync = 0x%0.8p)", sync); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (sync != static_cast(0) && !context->getFenceSync(sync)) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->deleteFenceSync(sync); - } + return gl::DeleteSync(sync); } GLenum GL_APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { - EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", - sync, flags, timeout); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_WAIT_FAILED; - } - - if ((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return GL_WAIT_FAILED; - } - - gl::FenceSync *fenceSync = context->getFenceSync(sync); - - if (!fenceSync) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return GL_WAIT_FAILED; - } - - GLenum result = GL_WAIT_FAILED; - gl::Error error = fenceSync->clientWait(flags, timeout, &result); - if (error.isError()) - { - context->recordError(error); - return GL_WAIT_FAILED; - } - - return result; - } - - return GL_FALSE; + return gl::ClientWaitSync(sync, flags, timeout); } void GL_APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { - EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", - sync, flags, timeout); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (flags != 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (timeout != GL_TIMEOUT_IGNORED) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::FenceSync *fenceSync = context->getFenceSync(sync); - - if (!fenceSync) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::Error error = fenceSync->serverWait(flags, timeout); - if (error.isError()) - { - context->recordError(error); - } - } + return gl::WaitSync(sync, flags, timeout); } void GL_APIENTRY glGetInteger64v(GLenum pname, GLint64* params) { - EVENT("(GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", - pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - GLenum nativeType; - unsigned int numParams = 0; - if (!ValidateStateQuery(context, pname, &nativeType, &numParams)) - { - return; - } - - if (nativeType == GL_INT_64_ANGLEX) - { - context->getInteger64v(pname, params); - } - else - { - CastStateValues(context, nativeType, pname, numParams, params); - } - } + return gl::GetInteger64v(pname, params); } void GL_APIENTRY glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { - EVENT("(GLsync sync = 0x%0.8p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLint* values = 0x%0.8p)", - sync, pname, bufSize, length, values); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (bufSize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - gl::FenceSync *fenceSync = context->getFenceSync(sync); - - if (!fenceSync) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (pname) - { - case GL_OBJECT_TYPE: values[0] = static_cast(GL_SYNC_FENCE); break; - case GL_SYNC_CONDITION: values[0] = static_cast(fenceSync->getCondition()); break; - case GL_SYNC_FLAGS: values[0] = 0; break; - - case GL_SYNC_STATUS: - { - gl::Error error = fenceSync->getStatus(values); - if (error.isError()) - { - context->recordError(error); - return; - } - break; - } - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::GetSynciv(sync, pname, bufSize, length, values); } void GL_APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64* data) { - EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint64* data = 0x%0.8p)", - target, index, data); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - const gl::Caps &caps = context->getCaps(); - switch (target) - { - case GL_TRANSFORM_FEEDBACK_BUFFER_START: - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (index >= caps.maxTransformFeedbackSeparateAttributes) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - case GL_UNIFORM_BUFFER_START: - case GL_UNIFORM_BUFFER_SIZE: - case GL_UNIFORM_BUFFER_BINDING: - if (index >= caps.maxUniformBufferBindings) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (!(context->getIndexedInteger64v(target, index, data))) - { - GLenum nativeType; - unsigned int numParams = 0; - if (!context->getIndexedQueryParameterInfo(target, &nativeType, &numParams)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (numParams == 0) - return; // it is known that pname is valid, but there are no parameters to return - - if (nativeType == GL_INT) - { - GLint *intParams = new GLint[numParams]; - - context->getIndexedIntegerv(target, index, intParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - data[i] = static_cast(intParams[i]); - } - - delete [] intParams; - } - else - { - UNREACHABLE(); - } - } - } + return gl::GetInteger64i_v(target, index, data); } void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) { - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", - target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (!gl::ValidBufferParameter(context, pname)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer) - { - // A null buffer means that "0" is bound to the requested buffer target - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - switch (pname) - { - case GL_BUFFER_USAGE: - *params = static_cast(buffer->getUsage()); - break; - case GL_BUFFER_SIZE: - *params = buffer->getSize(); - break; - case GL_BUFFER_ACCESS_FLAGS: - *params = static_cast(buffer->getAccessFlags()); - break; - case GL_BUFFER_MAPPED: - *params = static_cast(buffer->isMapped()); - break; - case GL_BUFFER_MAP_OFFSET: - *params = buffer->getMapOffset(); - break; - case GL_BUFFER_MAP_LENGTH: - *params = buffer->getMapLength(); - break; - default: UNREACHABLE(); break; - } - } + return gl::GetBufferParameteri64v(target, pname, params); } void GL_APIENTRY glGenSamplers(GLsizei count, GLuint* samplers) { - EVENT("(GLsizei count = %d, GLuint* samplers = 0x%0.8p)", count, samplers); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (count < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < count; i++) - { - samplers[i] = context->createSampler(); - } - } + return gl::GenSamplers(count, samplers); } void GL_APIENTRY glDeleteSamplers(GLsizei count, const GLuint* samplers) { - EVENT("(GLsizei count = %d, const GLuint* samplers = 0x%0.8p)", count, samplers); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (count < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - for (int i = 0; i < count; i++) - { - context->deleteSampler(samplers[i]); - } - } + return gl::DeleteSamplers(count, samplers); } GLboolean GL_APIENTRY glIsSampler(GLuint sampler) { - EVENT("(GLuint sampler = %u)", sampler); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - return context->isSampler(sampler); - } - - return GL_FALSE; + return gl::IsSampler(sampler); } void GL_APIENTRY glBindSampler(GLuint unit, GLuint sampler) { - EVENT("(GLuint unit = %u, GLuint sampler = %u)", unit, sampler); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (sampler != 0 && !context->isSampler(sampler)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (unit >= context->getCaps().maxCombinedTextureImageUnits) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - context->bindSampler(unit, sampler); - } + return gl::BindSampler(unit, sampler); } void GL_APIENTRY glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) { - EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint param = %d)", sampler, pname, param); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!gl::ValidateSamplerObjectParameter(context, pname)) - { - return; - } - - if (!gl::ValidateTexParamParameters(context, pname, param)) - { - return; - } - - if (!context->isSampler(sampler)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - context->samplerParameteri(sampler, pname, param); - } + return gl::SamplerParameteri(sampler, pname, param); } void GL_APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) { - glSamplerParameteri(sampler, pname, *param); + return gl::SamplerParameteriv(sampler, pname, param); } void GL_APIENTRY glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) { - EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLfloat param = %g)", sampler, pname, param); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!gl::ValidateSamplerObjectParameter(context, pname)) - { - return; - } - - if (!gl::ValidateTexParamParameters(context, pname, static_cast(param))) - { - return; - } - - if (!context->isSampler(sampler)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - context->samplerParameterf(sampler, pname, param); - } + return gl::SamplerParameterf(sampler, pname, param); } void GL_APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) { - glSamplerParameterf(sampler, pname, *param); + return gl::SamplerParameterfv(sampler, pname, param); } void GL_APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) { - EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", sampler, pname, params); + return gl::GetSamplerParameteriv(sampler, pname, params); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) +{ + return gl::GetSamplerParameterfv(sampler, pname, params); +} - if (!gl::ValidateSamplerObjectParameter(context, pname)) - { - return; - } +void GL_APIENTRY glVertexAttribDivisor(GLuint index, GLuint divisor) +{ + return gl::VertexAttribDivisor(index, divisor); +} - if (!context->isSampler(sampler)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glBindTransformFeedback(GLenum target, GLuint id) +{ + return gl::BindTransformFeedback(target, id); +} - *params = context->getSamplerParameteri(sampler, pname); - } +void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) +{ + return gl::DeleteTransformFeedbacks(n, ids); } -void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) +void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint* ids) { - EVENT("(GLuint sample = %ur, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", sampler, pname, params); + return gl::GenTransformFeedbacks(n, ids); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +GLboolean GL_APIENTRY glIsTransformFeedback(GLuint id) +{ + return gl::IsTransformFeedback(id); +} - if (!gl::ValidateSamplerObjectParameter(context, pname)) - { - return; - } +void GL_APIENTRY glPauseTransformFeedback(void) +{ + return gl::PauseTransformFeedback(); +} - if (!context->isSampler(sampler)) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glResumeTransformFeedback(void) +{ + return gl::ResumeTransformFeedback(); +} - *params = context->getSamplerParameterf(sampler, pname); - } +void GL_APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary) +{ + return gl::GetProgramBinary(program, bufSize, length, binaryFormat, binary); } -void GL_APIENTRY glVertexAttribDivisor(GLuint index, GLuint divisor) +void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length) { - EVENT("(GLuint index = %u, GLuint divisor = %u)", index, divisor); + return gl::ProgramBinary(program, binaryFormat, binary, length); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value) +{ + return gl::ProgramParameteri(program, pname, value); +} - if (index >= gl::MAX_VERTEX_ATTRIBS) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } +void GL_APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) +{ + return gl::InvalidateFramebuffer(target, numAttachments, attachments); +} - context->setVertexAttribDivisor(index, divisor); - } +void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) +{ + return gl::InvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height); } -void GL_APIENTRY glBindTransformFeedback(GLenum target, GLuint id) +void GL_APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - switch (target) - { - case GL_TRANSFORM_FEEDBACK: - { - // Cannot bind a transform feedback object if the current one is started and not paused (3.0.2 pg 85 section 2.14.1) - gl::TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback(); - if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // Cannot bind a transform feedback object that does not exist (3.0.2 pg 85 section 2.14.1) - if (context->getTransformFeedback(id) == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - context->bindTransformFeedback(id); - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::TexStorage2D(target, levels, internalformat, width, height); } -void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) +void GL_APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { - EVENT("(GLsizei n = %d, const GLuint* ids = 0x%0.8p)", n, ids); + return gl::TexStorage3D(target, levels, internalformat, width, height, depth); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) +{ + return gl::GetInternalformativ(target, internalformat, pname, bufSize, params); +} - for (int i = 0; i < n; i++) - { - context->deleteTransformFeedback(ids[i]); - } - } +void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + return gl::BlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } -void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint* ids) +void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { - EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); + return gl::RenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint* fences) +{ + return gl::DeleteFencesNV(n, fences); +} - for (int i = 0; i < n; i++) - { - ids[i] = context->createTransformFeedback(); - } - } +void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint* fences) +{ + return gl::GenFencesNV(n, fences); } -GLboolean GL_APIENTRY glIsTransformFeedback(GLuint id) +GLboolean GL_APIENTRY glIsFenceNV(GLuint fence) { - EVENT("(GLuint id = %u)", id); + return gl::IsFenceNV(fence); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } +GLboolean GL_APIENTRY glTestFenceNV(GLuint fence) +{ + return gl::TestFenceNV(fence); +} - return ((context->getTransformFeedback(id) != NULL) ? GL_TRUE : GL_FALSE); - } +void GL_APIENTRY glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) +{ + return gl::GetFenceivNV(fence, pname, params); +} - return GL_FALSE; +void GL_APIENTRY glFinishFenceNV(GLuint fence) +{ + return gl::FinishFenceNV(fence); } -void GL_APIENTRY glPauseTransformFeedback(void) +void GL_APIENTRY glSetFenceNV(GLuint fence, GLenum condition) { - EVENT("(void)"); + return gl::SetFenceNV(fence, condition); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source) +{ + return gl::GetTranslatedShaderSourceANGLE(shader, bufsize, length, source); +} - gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); - ASSERT(transformFeedback != NULL); +void GL_APIENTRY glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +{ + return gl::TexStorage2DEXT(target, levels, internalformat, width, height); +} - // Current transform feedback must be started and not paused in order to pause (3.0.2 pg 86) - if (!transformFeedback->isStarted() || transformFeedback->isPaused()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +GLenum GL_APIENTRY glGetGraphicsResetStatusEXT(void) +{ + return gl::GetGraphicsResetStatusEXT(); +} - transformFeedback->pause(); - } +void GL_APIENTRY glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) +{ + return gl::ReadnPixelsEXT(x, y, width, height, format, type, bufSize, data); } -void GL_APIENTRY glResumeTransformFeedback(void) +void GL_APIENTRY glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, float *params) { - EVENT("(void)"); + return gl::GetnUniformfvEXT(program, location, bufSize, params); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint *params) +{ + return gl::GetnUniformivEXT(program, location, bufSize, params); +} - gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); - ASSERT(transformFeedback != NULL); +void GL_APIENTRY glGenQueriesEXT(GLsizei n, GLuint *ids) +{ + return gl::GenQueriesEXT(n, ids); +} - // Current transform feedback must be started and paused in order to resume (3.0.2 pg 86) - if (!transformFeedback->isStarted() || !transformFeedback->isPaused()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glDeleteQueriesEXT(GLsizei n, const GLuint *ids) +{ + return gl::DeleteQueriesEXT(n, ids); +} - transformFeedback->resume(); - } +GLboolean GL_APIENTRY glIsQueryEXT(GLuint id) +{ + return gl::IsQueryEXT(id); } -void GL_APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary) +void GL_APIENTRY glBeginQueryEXT(GLenum target, GLuint id) { - EVENT("(GLuint program = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLenum* binaryFormat = 0x%0.8p, GLvoid* binary = 0x%0.8p)", - program, bufSize, length, binaryFormat, binary); + return gl::BeginQueryEXT(target, id); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glEndQueryEXT(GLenum target) +{ + return gl::EndQueryEXT(target); +} - // glGetProgramBinary - UNIMPLEMENTED(); - } +void GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) +{ + return gl::GetQueryivEXT(target, pname, params); } -void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length) +void GL_APIENTRY glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) { - EVENT("(GLuint program = %u, GLenum binaryFormat = 0x%X, const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", - program, binaryFormat, binary, length); + return gl::GetQueryObjectuivEXT(id, pname, params); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs) +{ + return gl::DrawBuffersEXT(n, bufs); +} - // glProgramBinary - UNIMPLEMENTED(); - } +void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + return gl::DrawArraysInstancedANGLE(mode, first, count, primcount); } -void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value) +void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) { - EVENT("(GLuint program = %u, GLenum pname = 0x%X, GLint value = %d)", - program, pname, value); + return gl::DrawElementsInstancedANGLE(mode, count, type, indices, primcount); +} - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } +void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) +{ + return gl::VertexAttribDivisorANGLE(index, divisor); +} - // glProgramParameteri - UNIMPLEMENTED(); - } +void GL_APIENTRY glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) +{ + return gl::GetProgramBinaryOES(program, bufSize, length, binaryFormat, binary); } -void GL_APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) +void GL_APIENTRY glProgramBinaryOES(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length) { - EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p)", - target, numAttachments, attachments); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments)) - { - return; - } - - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); - - if (framebuffer->completeness(context->getData()) == GL_FRAMEBUFFER_COMPLETE) - { - gl::Error error = framebuffer->invalidate(context->getCaps(), numAttachments, attachments); - if (error.isError()) - { - context->recordError(error); - return; - } - } - } + return gl::ProgramBinaryOES(program, binaryFormat, binary, length); } -void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) +void* GL_APIENTRY glMapBufferOES(GLenum target, GLenum access) { - EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p, GLint x = %d, " - "GLint y = %d, GLsizei width = %d, GLsizei height = %d)", - target, numAttachments, attachments, x, y, width, height); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateInvalidateFramebufferParameters(context, target, numAttachments, attachments)) - { - return; - } - - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - ASSERT(framebuffer); - - if (framebuffer->completeness(context->getData()) == GL_FRAMEBUFFER_COMPLETE) - { - gl::Error error = framebuffer->invalidateSub(numAttachments, attachments, x, y, width, height); - if (error.isError()) - { - context->recordError(error); - return; - } - } - } + return gl::MapBufferOES(target, access); } -void GL_APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +GLboolean GL_APIENTRY glUnmapBufferOES(GLenum target) { - EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", - target, levels, internalformat, width, height); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, 1)) - { - return; - } - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture2d = context->getTexture2D(); - gl::Error error = texture2d->storage(levels, internalformat, width, height); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_TEXTURE_CUBE_MAP: - { - gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); - gl::Error error = textureCube->storage(levels, internalformat, width); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } + return gl::UnmapBufferOES(target); } -void GL_APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +void GL_APIENTRY glGetBufferPointervOES(GLenum target, GLenum pname, GLvoid **params) { - EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " - "GLsizei height = %d, GLsizei depth = %d)", - target, levels, internalformat, width, height, depth); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!ValidateES3TexStorageParameters(context, target, levels, internalformat, width, height, depth)) - { - return; - } - - switch (target) - { - case GL_TEXTURE_3D: - { - gl::Texture3D *texture3d = context->getTexture3D(); - gl::Error error = texture3d->storage(levels, internalformat, width, height, depth); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - gl::Texture2DArray *texture2darray = context->getTexture2DArray(); - gl::Error error = texture2darray->storage(levels, internalformat, width, height, depth); - if (error.isError()) - { - context->recordError(error); - return; - } - } - break; - - default: - UNREACHABLE(); - } - } + return gl::GetBufferPointervOES(target, pname, params); } -void GL_APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) +void* GL_APIENTRY glMapBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { - EVENT("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, " - "GLint* params = 0x%0.8p)", - target, internalformat, pname, bufSize, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (context->getClientVersion() < 3) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - const gl::TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); - if (!formatCaps.renderable) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (target != GL_RENDERBUFFER) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (bufSize < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - switch (pname) - { - case GL_NUM_SAMPLE_COUNTS: - if (bufSize != 0) - { - *params = formatCaps.sampleCounts.size(); - } - break; - - case GL_SAMPLES: - std::copy_n(formatCaps.sampleCounts.rbegin(), std::min(bufSize, formatCaps.sampleCounts.size()), params); - break; - - default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - } -} - -// Extension functions - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!ValidateBlitFramebufferParameters(context, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter, - true)) - { - return; - } - - gl::Error error = context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, - mask, filter); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -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) -{ - 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); - - UNIMPLEMENTED(); // FIXME -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Program *programObject = context->getProgram(program); - - if (!programObject || !programObject->isLinked()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - - if (!programBinary) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::Error error = programBinary->save(binaryFormat, binary, bufSize, length); - if (error.isError()) - { - context->recordError(error); - return; - } - } -} - -void GL_APIENTRY 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); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - const std::vector &programBinaryFormats = context->getCaps().programBinaryFormats; - if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) == programBinaryFormats.end()) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Program *programObject = context->getProgram(program); - if (!programObject) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - gl::Error error = context->setProgramBinary(program, binaryFormat, binary, length); - if (error.isError()) - { - context->recordError(error); - return; - } - } + return gl::MapBufferRangeEXT(target, offset, length, access); } -void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs) +void GL_APIENTRY glFlushMappedBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length) { - EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (n < 0 || static_cast(n) > context->getCaps().maxDrawBuffers) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - ASSERT(context->getState().getDrawFramebuffer()); - - if (context->getState().getDrawFramebuffer()->id() == 0) - { - if (n != 1) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (bufs[0] != GL_NONE && bufs[0] != GL_BACK) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } - else - { - for (int colorAttachment = 0; colorAttachment < n; colorAttachment++) - { - const GLenum attachment = GL_COLOR_ATTACHMENT0_EXT + colorAttachment; - if (bufs[colorAttachment] != GL_NONE && bufs[colorAttachment] != attachment) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - } - } - - gl::Framebuffer *framebuffer = context->getState().getDrawFramebuffer(); - ASSERT(framebuffer); - - for (unsigned int colorAttachment = 0; colorAttachment < static_cast(n); colorAttachment++) - { - framebuffer->setDrawBufferState(colorAttachment, bufs[colorAttachment]); - } - - for (unsigned int colorAttachment = n; colorAttachment < context->getCaps().maxDrawBuffers; colorAttachment++) - { - framebuffer->setDrawBufferState(colorAttachment, GL_NONE); - } - } -} - -void GL_APIENTRY glGetBufferPointervOES(GLenum target, GLenum pname, void** params) -{ - EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - if (pname != GL_BUFFER_MAP_POINTER) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (!buffer || !buffer->isMapped()) - { - *params = NULL; - } - else - { - *params = buffer->getMapPointer(); - } - } -} - -void * GL_APIENTRY glMapBufferOES(GLenum target, GLenum access) -{ - EVENT("(GLenum target = 0x%X, GLbitfield access = 0x%X)", target, access); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return NULL; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (buffer == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - if (access != GL_WRITE_ONLY_OES) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return NULL; - } - - if (buffer->isMapped()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - gl::Error error = buffer->mapRange(0, buffer->getSize(), GL_MAP_WRITE_BIT); - if (error.isError()) - { - context->recordError(error); - return NULL; - } - - return buffer->getMapPointer(); - } - - return NULL; + return gl::FlushMappedBufferRangeEXT(target, offset, length); } -GLboolean GL_APIENTRY glUnmapBufferOES(GLenum target) +void GL_APIENTRY SetTraceFunctionPointers(GetCategoryEnabledFlagFunc getCategoryEnabledFlag, + AddTraceEventFunc addTraceEvent) { - EVENT("(GLenum target = 0x%X)", target); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return GL_FALSE; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (buffer == NULL || !buffer->isMapped()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return GL_FALSE; - } - - // TODO: detect if we had corruption. if so, throw an error and return false. - - gl::Error error = buffer->unmap(); - if (error.isError()) - { - context->recordError(error); - return GL_FALSE; - } - - return GL_TRUE; - } - - return GL_FALSE; -} - -void* GL_APIENTRY glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) -{ - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", - target, offset, length, access); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return NULL; - } - - if (offset < 0 || length < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return NULL; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (buffer == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - // Check for buffer overflow - size_t offsetSize = static_cast(offset); - size_t lengthSize = static_cast(length); - - if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) || - offsetSize + lengthSize > static_cast(buffer->getSize())) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return NULL; - } - - // Check for invalid bits in the mask - GLbitfield allAccessBits = GL_MAP_READ_BIT | - GL_MAP_WRITE_BIT | - GL_MAP_INVALIDATE_RANGE_BIT | - GL_MAP_INVALIDATE_BUFFER_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT | - GL_MAP_UNSYNCHRONIZED_BIT; - - if (access & ~(allAccessBits)) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return NULL; - } - - if (length == 0 || buffer->isMapped()) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - // Check for invalid bit combinations - if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - GLbitfield writeOnlyBits = GL_MAP_INVALIDATE_RANGE_BIT | - GL_MAP_INVALIDATE_BUFFER_BIT | - GL_MAP_UNSYNCHRONIZED_BIT; - - if ((access & GL_MAP_READ_BIT) != 0 && (access & writeOnlyBits) != 0) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - if ((access & GL_MAP_WRITE_BIT) == 0 && (access & GL_MAP_FLUSH_EXPLICIT_BIT) != 0) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return NULL; - } - - gl::Error error = buffer->mapRange(offset, length, access); - if (error.isError()) - { - context->recordError(error); - return NULL; - } - - return buffer->getMapPointer(); - } - - return NULL; -} - -void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length) -{ - EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - if (offset < 0 || length < 0) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - if (!gl::ValidBufferTarget(context, target)) - { - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; - } - - gl::Buffer *buffer = context->getState().getTargetBuffer(target); - - if (buffer == NULL) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - if (!buffer->isMapped() || (buffer->getAccessFlags() & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) - { - context->recordError(gl::Error(GL_INVALID_OPERATION)); - return; - } - - // Check for buffer overflow - size_t offsetSize = static_cast(offset); - size_t lengthSize = static_cast(length); - - if (!rx::IsUnsignedAdditionSafe(offsetSize, lengthSize) || - offsetSize + lengthSize > static_cast(buffer->getMapLength())) - { - context->recordError(gl::Error(GL_INVALID_VALUE)); - return; - } - - // We do not currently support a non-trivial implementation of FlushMappedBufferRange - } -} - -__eglMustCastToProperFunctionPointerType EGLAPIENTRY 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}, - {"glDrawBuffersEXT", (__eglMustCastToProperFunctionPointerType)glDrawBuffersEXT}, - {"glVertexAttribDivisorANGLE", (__eglMustCastToProperFunctionPointerType)glVertexAttribDivisorANGLE}, - {"glDrawArraysInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawArraysInstancedANGLE}, - {"glDrawElementsInstancedANGLE", (__eglMustCastToProperFunctionPointerType)glDrawElementsInstancedANGLE}, - {"glGetProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glGetProgramBinaryOES}, - {"glProgramBinaryOES", (__eglMustCastToProperFunctionPointerType)glProgramBinaryOES}, - {"glGetBufferPointervOES", (__eglMustCastToProperFunctionPointerType)glGetBufferPointervOES}, - {"glMapBufferOES", (__eglMustCastToProperFunctionPointerType)glMapBufferOES}, - {"glUnmapBufferOES", (__eglMustCastToProperFunctionPointerType)glUnmapBufferOES}, - {"glMapBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)glMapBufferRangeEXT}, - {"glFlushMappedBufferRangeEXT", (__eglMustCastToProperFunctionPointerType)glFlushMappedBufferRangeEXT}, }; - - for (unsigned int ext = 0; ext < ArraySize(glExtensions); ext++) - { - if (strcmp(procname, glExtensions[ext].name) == 0) - { - return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address; - } - } - - return NULL; -} - -// Non-public functions used by EGL - -bool EGLAPIENTRY glBindTexImage(egl::Surface *surface) -{ - EVENT("(egl::Surface* surface = 0x%0.8p)", - surface); - - gl::Context *context = gl::getNonLostContext(); - if (context) - { - gl::Texture2D *textureObject = context->getTexture2D(); - ASSERT(textureObject != NULL); - - if (textureObject->isImmutable()) - { - return false; - } - - textureObject->bindTexImage(surface); - } - - return true; + gl::g_getCategoryEnabledFlag = getCategoryEnabledFlag; + gl::g_addTraceEvent = addTraceEvent; } } diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def index 33557eb1c9..9c6dc497d0 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def @@ -144,7 +144,6 @@ EXPORTS glViewport @142 ; Extensions - glTexImage3DOES @143 glBlitFramebufferANGLE @149 glRenderbufferStorageMultisampleANGLE @150 glDeleteFencesNV @151 @@ -285,12 +284,5 @@ EXPORTS glTexStorage3D @282 glGetInternalformativ @283 - ; EGL dependencies - glCreateContext @144 NONAME - glDestroyContext @145 NONAME - glMakeCurrent @146 NONAME - glGetCurrentContext @147 NONAME - glGetProcAddress @148 NONAME - glBindTexImage @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME + ; Setting up TRACE macro callbacks + SetTraceFunctionPointers @284 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.rc b/src/3rdparty/angle/src/libGLESv2/libGLESv2.rc deleted file mode 100644 index 76cd05566e..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.rc +++ /dev/null @@ -1,103 +0,0 @@ -// 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 ANGLE_MAJOR_VERSION,ANGLE_MINOR_VERSION,0,0 - PRODUCTVERSION ANGLE_MAJOR_VERSION,ANGLE_MINOR_VERSION,0,0 - 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", ANGLE_VERSION_STRING - VALUE "InternalName", "libGLESv2" - VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc." - VALUE "OriginalFilename", "libGLESv2.dll" - VALUE "PrivateBuild", ANGLE_VERSION_STRING - VALUE "ProductName", "ANGLE libGLESv2 Dynamic Link Library" - VALUE "ProductVersion", ANGLE_VERSION_STRING - VALUE "Comments", "Build Date: " ANGLE_COMMIT_DATE - 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/libGLESv2_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def index 18ffcf6a0d..e02b85bcf2 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def @@ -144,7 +144,6 @@ EXPORTS glViewport@16 @142 ; Extensions - glTexImage3DOES@40 @143 glBlitFramebufferANGLE@40 @149 glRenderbufferStorageMultisampleANGLE@20 @150 glDeleteFencesNV@8 @151 @@ -285,12 +284,5 @@ EXPORTS glTexStorage3D@24 @282 glGetInternalformativ@20 @283 - ; EGL dependencies - glCreateContext @144 NONAME - glDestroyContext @145 NONAME - glMakeCurrent @146 NONAME - glGetCurrentContext @147 NONAME - glGetProcAddress@4 @148 NONAME - glBindTexImage@4 @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME + ; Setting up TRACE macro callbacks + SetTraceFunctionPointers@8 @284 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def index 120371e013..d35309c6ce 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def @@ -144,7 +144,6 @@ EXPORTS glViewport @142 ; Extensions - glTexImage3DOES @143 glBlitFramebufferANGLE @149 glRenderbufferStorageMultisampleANGLE @150 glDeleteFencesNV @151 @@ -285,12 +284,5 @@ EXPORTS glTexStorage3D @282 glGetInternalformativ @283 - ; EGL dependencies - glCreateContext @144 NONAME - glDestroyContext @145 NONAME - glMakeCurrent @146 NONAME - glGetCurrentContext @147 NONAME - glGetProcAddress @148 NONAME - glBindTexImage @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME + ; Setting up TRACE macro callbacks + SetTraceFunctionPointers @284 diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def index 8c1306a703..e2b2c333a1 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def @@ -144,7 +144,6 @@ EXPORTS glViewport@16 @142 ; Extensions - glTexImage3DOES@40 @143 glBlitFramebufferANGLE@40 @149 glRenderbufferStorageMultisampleANGLE@20 @150 glDeleteFencesNV@8 @151 @@ -285,12 +284,5 @@ EXPORTS glTexStorage3D@24 @282 glGetInternalformativ@20 @283 - ; EGL dependencies - glCreateContext @144 NONAME - glDestroyContext @145 NONAME - glMakeCurrent @146 NONAME - glGetCurrentContext @147 NONAME - glGetProcAddress@4 @148 NONAME - glBindTexImage@4 @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME + ; Setting up TRACE macro callbacks + SetTraceFunctionPointers@8 @284 diff --git a/src/3rdparty/angle/src/libGLESv2/main.cpp b/src/3rdparty/angle/src/libGLESv2/main.cpp deleted file mode 100644 index 00f63ae079..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/main.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// -// 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/Context.h" - -#include "common/tls.h" - -static TLSIndex currentTLS = TLS_INVALID_INDEX; - -namespace gl -{ - -// TODO(kbr): figure out how these are going to be managed on -// non-Windows platforms. These routines would need to be exported -// from ANGLE and called cooperatively when users create and destroy -// threads -- or the initialization of the TLS index, and allocation -// of thread-local data, will have to be done lazily. Will have to use -// destructor function with pthread_create_key on POSIX platforms to -// clean up thread-local data. - -// Call this exactly once at process startup. -bool CreateThreadLocalIndex() -{ - currentTLS = CreateTLSIndex(); - if (currentTLS == TLS_INVALID_INDEX) - { - return false; - } - return true; -} - -// Call this exactly once at process shutdown. -void DestroyThreadLocalIndex() -{ - DestroyTLSIndex(currentTLS); - currentTLS = TLS_INVALID_INDEX; -} - -// Call this upon thread startup. -Current *AllocateCurrent() -{ - ASSERT(currentTLS != TLS_INVALID_INDEX); - if (currentTLS == TLS_INVALID_INDEX) - { - return NULL; - } - - Current *current = new Current(); - current->context = NULL; - current->display = NULL; - - if (!SetTLSValue(currentTLS, current)) - { - ERR("Could not set thread local storage."); - return NULL; - } - - return current; -} - -// Call this upon thread shutdown. -void DeallocateCurrent() -{ - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - SafeDelete(current); - SetTLSValue(currentTLS, NULL); -} - -} - -#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(QT_OPENGL_ES_2_ANGLE_STATIC) -extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) -{ - switch (reason) - { - case DLL_PROCESS_ATTACH: - { - if (!gl::CreateThreadLocalIndex()) - { - return FALSE; - } - -#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS - gl::InitializeDebugAnnotations(); -#endif - } - // Fall through to initialize index - case DLL_THREAD_ATTACH: - { - gl::AllocateCurrent(); - } - break; - case DLL_THREAD_DETACH: - { - gl::DeallocateCurrent(); - } - break; - case DLL_PROCESS_DETACH: - { - gl::DeallocateCurrent(); - gl::DestroyThreadLocalIndex(); - -#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS - gl::UninitializeDebugAnnotations(); -#endif - } - break; - default: - break; - } - - return TRUE; -} -#endif // ANGLE_PLATFORM_WINDOWS && !QT_OPENGL_ES_2_ANGLE_STATIC - -namespace gl -{ - -Current *GetCurrentData() -{ -#ifndef QT_OPENGL_ES_2_ANGLE_STATIC - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - - // ANGLE issue 488: when the dll is loaded after thread initialization, - // thread local storage (current) might not exist yet. - return (current ? current : AllocateCurrent()); -#else - // No precautions for thread safety taken as ANGLE is used single-threaded in Qt. - static Current current = { 0, 0 }; - return ¤t; -#endif -} - -void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface) -{ - Current *current = GetCurrentData(); - - current->context = context; - current->display = display; - - if (context && display && surface) - { - context->makeCurrent(surface); - } -} - -Context *getContext() -{ - Current *current = GetCurrentData(); - - return current->context; -} - -Context *getNonLostContext() -{ - Context *context = getContext(); - - if (context) - { - if (context->isContextLost()) - { - context->recordError(Error(GL_OUT_OF_MEMORY, "Context has been lost.")); - return NULL; - } - else - { - return context; - } - } - return NULL; -} - -egl::Display *getDisplay() -{ - Current *current = GetCurrentData(); - - return current->display; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/main.h b/src/3rdparty/angle/src/libGLESv2/main.h deleted file mode 100644 index dff02787f5..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/main.h +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) 2002-2013 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_ - -#include "common/debug.h" - -#include -#include - -namespace egl -{ -class Display; -class Surface; -class AttributeMap; -} - -namespace gl -{ -class Context; - -struct Current -{ - Context *context; - egl::Display *display; -}; - -void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface); - -Context *getContext(); -Context *getNonLostContext(); -egl::Display *getDisplay(); - -} - -namespace rx -{ -class Renderer; -} - -extern "C" -{ -// Exported functions for use by EGL -gl::Context *glCreateContext(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); -void glDestroyContext(gl::Context *context); -void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface); -gl::Context *glGetCurrentContext(); -rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, const egl::AttributeMap &attribMap); -void glDestroyRenderer(rx::Renderer *renderer); - -__eglMustCastToProperFunctionPointerType EGLAPIENTRY glGetProcAddress(const char *procname); -bool EGLAPIENTRY glBindTexImage(egl::Surface *surface); -} - -#endif // LIBGLESV2_MAIN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/queryconversions.cpp b/src/3rdparty/angle/src/libGLESv2/queryconversions.cpp deleted file mode 100644 index 7245902c51..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/queryconversions.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// queryconversions.cpp: Implementation of state query cast conversions - -#include "libGLESv2/Context.h" -#include "common/utilities.h" - -namespace gl -{ - -// Helper class for converting a GL type to a GLenum: -// We can't use CastStateValueEnum generally, because of GLboolean + GLubyte overlap. -// We restrict our use to CastStateValue, where it eliminates duplicate parameters. - -template -struct CastStateValueEnum { static GLenum mEnumForType; }; - -template <> GLenum CastStateValueEnum::mEnumForType = GL_INT; -template <> GLenum CastStateValueEnum::mEnumForType = GL_UNSIGNED_INT; -template <> GLenum CastStateValueEnum::mEnumForType = GL_BOOL; -template <> GLenum CastStateValueEnum::mEnumForType = GL_INT_64_ANGLEX; -template <> GLenum CastStateValueEnum::mEnumForType = GL_FLOAT; - -template -QueryT CastStateValueToInt(GLenum pname, NativeT value) -{ - GLenum queryType = CastStateValueEnum::mEnumForType; - GLenum nativeType = CastStateValueEnum::mEnumForType; - - if (nativeType == GL_FLOAT) - { - // RGBA color values and DepthRangeF values are converted to integer using Equation 2.4 from Table 4.5 - if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR) - { - return static_cast((static_cast(0xFFFFFFFF) * value - 1.0f) / 2.0f); - } - else - { - return gl::iround(value); - } - } - - // Clamp 64-bit int values when casting to int - if (nativeType == GL_INT_64_ANGLEX && queryType == GL_INT) - { - GLint64 minIntValue = static_cast(std::numeric_limits::min()); - GLint64 maxIntValue = static_cast(std::numeric_limits::max()); - GLint64 clampedValue = std::max(std::min(static_cast(value), maxIntValue), minIntValue); - return static_cast(clampedValue); - } - - return static_cast(value); -} - -template -QueryT CastStateValue(GLenum pname, NativeT value) -{ - GLenum queryType = CastStateValueEnum::mEnumForType; - - switch (queryType) - { - case GL_INT: return CastStateValueToInt(pname, value); - case GL_INT_64_ANGLEX: return CastStateValueToInt(pname, value); - case GL_FLOAT: return static_cast(value); - case GL_BOOL: return (value == static_cast(0) ? GL_FALSE : GL_TRUE); - default: UNREACHABLE(); return 0; - } -} - -template -void CastStateValues(Context *context, GLenum nativeType, GLenum pname, - unsigned int numParams, QueryT *outParams) -{ - if (nativeType == GL_INT) - { - GLint *intParams = NULL; - intParams = new GLint[numParams]; - - context->getIntegerv(pname, intParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - outParams[i] = CastStateValue(pname, intParams[i]); - } - - delete [] intParams; - } - else if (nativeType == GL_BOOL) - { - GLboolean *boolParams = NULL; - boolParams = new GLboolean[numParams]; - - context->getBooleanv(pname, boolParams); - - for (unsigned int i = 0; i < numParams; ++i) - { - outParams[i] = (boolParams[i] == GL_FALSE ? static_cast(0) : static_cast(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) - { - outParams[i] = CastStateValue(pname, floatParams[i]); - } - - delete [] floatParams; - } - else if (nativeType == GL_INT_64_ANGLEX) - { - GLint64 *int64Params = NULL; - int64Params = new GLint64[numParams]; - - context->getInteger64v(pname, int64Params); - - for (unsigned int i = 0; i < numParams; ++i) - { - outParams[i] = CastStateValue(pname, int64Params[i]); - } - - delete [] int64Params; - } - else UNREACHABLE(); -} - -// Explicit template instantiation (how we export template functions in different files) -// The calls below will make CastStateValues successfully link with the GL state query types -// The GL state query API types are: bool, int, uint, float, int64 - -template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLboolean *); -template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint *); -template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLuint *); -template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLfloat *); -template void CastStateValues(Context *, GLenum, GLenum, unsigned int, GLint64 *); - -} diff --git a/src/3rdparty/angle/src/libGLESv2/queryconversions.h b/src/3rdparty/angle/src/libGLESv2/queryconversions.h deleted file mode 100644 index da7047f730..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/queryconversions.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// queryconversions.h: Declaration of state query cast conversions - -namespace gl -{ - -// The GL state query API types are: bool, int, uint, float, int64 -template -void CastStateValues(Context *context, GLenum nativeType, GLenum pname, - unsigned int numParams, QueryT *outParams); - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h deleted file mode 100644 index c031effabd..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright 2014 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. -// - -// BufferImpl.h: Defines the abstract rx::BufferImpl class. - -#ifndef LIBGLESV2_RENDERER_BUFFERIMPL_H_ -#define LIBGLESV2_RENDERER_BUFFERIMPL_H_ - -#include "common/angleutils.h" -#include "libGLESv2/Buffer.h" - -#include - -namespace rx -{ - -class BufferImpl -{ - public: - virtual ~BufferImpl() { } - - virtual gl::Error setData(const void* data, size_t size, GLenum usage) = 0; - virtual gl::Error setSubData(const void* data, size_t size, size_t offset) = 0; - virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) = 0; - virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) = 0; - virtual gl::Error unmap() = 0; - virtual void markTransformFeedbackUsage() = 0; -}; - -} - -#endif // LIBGLESV2_RENDERER_BUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h deleted file mode 100644 index 1dd46785d9..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// FenceImpl.h: Defines the rx::FenceNVImpl and rx::FenceSyncImpl classes. - -#ifndef LIBGLESV2_RENDERER_FENCEIMPL_H_ -#define LIBGLESV2_RENDERER_FENCEIMPL_H_ - -#include "libGLESv2/Error.h" - -#include "common/angleutils.h" - -#include "angle_gl.h" - -namespace rx -{ - -class FenceNVImpl -{ - public: - FenceNVImpl() { }; - virtual ~FenceNVImpl() { }; - - virtual gl::Error set() = 0; - virtual gl::Error test(bool flushCommandBuffer, GLboolean *outFinished) = 0; - virtual gl::Error finishFence(GLboolean *outFinished) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(FenceNVImpl); -}; - -class FenceSyncImpl -{ - public: - FenceSyncImpl() { }; - virtual ~FenceSyncImpl() { }; - - virtual gl::Error set() = 0; - virtual gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) = 0; - virtual gl::Error serverWait(GLbitfield flags, GLuint64 timeout) = 0; - virtual gl::Error getStatus(GLint *outResult) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(FenceSyncImpl); -}; - -} - -#endif // LIBGLESV2_RENDERER_FENCEIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp deleted file mode 100644 index 5b9b75f562..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// 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. -// - -// Image.h: Implements the rx::Image class, an abstract base class for the -// renderer-specific classes which will define the interface to the underlying -// surfaces or resources. - -#include "libGLESv2/renderer/Image.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -Image::Image() -{ - mWidth = 0; - mHeight = 0; - mDepth = 0; - mInternalFormat = GL_NONE; - mActualFormat = GL_NONE; - mTarget = GL_NONE; - mRenderable = false; - mDirty = false; -} - -gl::Error Image::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, gl::Framebuffer *source) -{ - gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); - ASSERT(colorbuffer); - - RenderTarget *renderTarget = NULL; - gl::Error error = GetAttachmentRenderTarget(colorbuffer, &renderTarget); - if (error.isError()) - { - return error; - } - - ASSERT(renderTarget); - return copy(xoffset, yoffset, zoffset, area, renderTarget); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Image.h b/src/3rdparty/angle/src/libGLESv2/renderer/Image.h deleted file mode 100644 index 9071a88c67..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Image.h +++ /dev/null @@ -1,79 +0,0 @@ -// -// 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. -// - -// Image.h: Defines the rx::Image class, an abstract base class for the -// renderer-specific classes which will define the interface to the underlying -// surfaces or resources. - -#ifndef LIBGLESV2_RENDERER_IMAGE_H_ -#define LIBGLESV2_RENDERER_IMAGE_H_ - -#include "common/debug.h" -#include "libGLESv2/Error.h" - -#include - -namespace gl -{ -class Framebuffer; -struct Rectangle; -struct ImageIndex; -} - -namespace rx -{ -class RendererD3D; -class RenderTarget; -class TextureStorage; - -class Image -{ - public: - Image(); - virtual ~Image() {}; - - GLsizei getWidth() const { return mWidth; } - GLsizei getHeight() const { return mHeight; } - GLsizei getDepth() const { return mDepth; } - GLenum getInternalFormat() const { return mInternalFormat; } - GLenum getActualFormat() const { return mActualFormat; } - GLenum getTarget() const { return mTarget; } - bool isRenderableFormat() const { return mRenderable; } - - void markDirty() {mDirty = true;} - void markClean() {mDirty = false;} - virtual bool isDirty() const = 0; - - virtual bool redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) = 0; - - virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input) = 0; - virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input) = 0; - - gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, gl::Framebuffer *source); - virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) = 0; - virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, - const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; - - protected: - GLsizei mWidth; - GLsizei mHeight; - GLsizei mDepth; - GLenum mInternalFormat; - GLenum mActualFormat; - bool mRenderable; - GLenum mTarget; - - bool mDirty; - - private: - DISALLOW_COPY_AND_ASSIGN(Image); -}; - -} - -#endif // LIBGLESV2_RENDERER_IMAGE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp deleted file mode 100644 index d472e1499e..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp +++ /dev/null @@ -1,128 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// IndexRangeCache.cpp: Defines the rx::IndexRangeCache class which stores information about -// ranges of indices. - -#include "libGLESv2/renderer/IndexRangeCache.h" -#include "libGLESv2/formatutils.h" - -#include "common/debug.h" - -#include - -namespace rx -{ - -template -static RangeUI ComputeTypedRange(const IndexType *indices, GLsizei count) -{ - unsigned int minIndex = indices[0]; - unsigned int maxIndex = indices[0]; - - for (GLsizei i = 1; i < count; i++) - { - if (minIndex > indices[i]) minIndex = indices[i]; - if (maxIndex < indices[i]) maxIndex = indices[i]; - } - - return RangeUI(minIndex, maxIndex); -} - -RangeUI IndexRangeCache::ComputeRange(GLenum type, const GLvoid *indices, GLsizei count) -{ - switch (type) - { - case GL_UNSIGNED_BYTE: - return ComputeTypedRange(static_cast(indices), count); - case GL_UNSIGNED_INT: - return ComputeTypedRange(static_cast(indices), count); - case GL_UNSIGNED_SHORT: - return ComputeTypedRange(static_cast(indices), count); - default: - UNREACHABLE(); - return RangeUI(); - } -} - -void IndexRangeCache::addRange(GLenum type, unsigned int offset, GLsizei count, const RangeUI &range, - unsigned int streamOffset) -{ - mIndexRangeCache[IndexRange(type, offset, count)] = IndexBounds(range, streamOffset); -} - -void IndexRangeCache::invalidateRange(unsigned int offset, unsigned int size) -{ - unsigned int invalidateStart = offset; - unsigned int invalidateEnd = offset + size; - - IndexRangeMap::iterator i = mIndexRangeCache.begin(); - while (i != mIndexRangeCache.end()) - { - unsigned int rangeStart = i->second.streamOffset; - unsigned int rangeEnd = i->second.streamOffset + (gl::GetTypeInfo(i->first.type).bytes * i->first.count); - - if (invalidateEnd < rangeStart || invalidateStart > rangeEnd) - { - ++i; - } - else - { - i = mIndexRangeCache.erase(i); - } - } -} - -bool IndexRangeCache::findRange(GLenum type, unsigned int offset, GLsizei count, - RangeUI *outRange, unsigned int *outStreamOffset) const -{ - IndexRangeMap::const_iterator i = mIndexRangeCache.find(IndexRange(type, offset, count)); - if (i != mIndexRangeCache.end()) - { - if (outRange) *outRange = i->second.range; - if (outStreamOffset) *outStreamOffset = i->second.streamOffset; - return true; - } - else - { - if (outRange) *outRange = RangeUI(0, 0); - if (outStreamOffset) *outStreamOffset = 0; - return false; - } -} - -void IndexRangeCache::clear() -{ - mIndexRangeCache.clear(); -} - -IndexRangeCache::IndexRange::IndexRange() - : type(GL_NONE), offset(0), count(0) -{ -} - -IndexRangeCache::IndexRange::IndexRange(GLenum typ, intptr_t off, GLsizei c) - : type(typ), offset(off), count(c) -{ -} - -bool IndexRangeCache::IndexRange::operator<(const IndexRange& rhs) const -{ - return std::make_tuple(type, offset, count) < std::make_tuple(rhs.type, rhs.offset, rhs.count); -} - -IndexRangeCache::IndexBounds::IndexBounds() - : range(0, 0), - streamOffset(0) -{ -} - -IndexRangeCache::IndexBounds::IndexBounds(const RangeUI &rangeIn, unsigned int offset) - : range(rangeIn), streamOffset(offset) -{ -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.h deleted file mode 100644 index a7d91e035b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// IndexRangeCache.h: Defines the rx::IndexRangeCache class which stores information about -// ranges of indices. - -#ifndef LIBGLESV2_RENDERER_INDEXRANGECACHE_H_ -#define LIBGLESV2_RENDERER_INDEXRANGECACHE_H_ - -#include "common/angleutils.h" -#include "common/mathutil.h" - -#include "angle_gl.h" - -#include - -namespace rx -{ - -class IndexRangeCache -{ - public: - void addRange(GLenum type, unsigned int offset, GLsizei count, const RangeUI &range, - unsigned int streamOffset); - bool findRange(GLenum type, unsigned int offset, GLsizei count, RangeUI *rangeOut, - unsigned int *outStreamOffset) const; - - void invalidateRange(unsigned int offset, unsigned int size); - void clear(); - - static RangeUI ComputeRange(GLenum type, const GLvoid *indices, GLsizei count); - - private: - struct IndexRange - { - GLenum type; - unsigned int offset; - GLsizei count; - - IndexRange(); - IndexRange(GLenum type, intptr_t offset, GLsizei count); - - bool operator<(const IndexRange& rhs) const; - }; - - struct IndexBounds - { - RangeUI range; - unsigned int streamOffset; - - IndexBounds(); - IndexBounds(const RangeUI &range, unsigned int offset); - }; - - typedef std::map IndexRangeMap; - IndexRangeMap mIndexRangeCache; -}; - -} - -#endif // LIBGLESV2_RENDERER_INDEXRANGECACHE_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.cpp deleted file mode 100644 index f9fcad38a4..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. - -#include "libGLESv2/renderer/ProgramImpl.h" - -#include "common/utilities.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -namespace -{ - -unsigned int ParseAndStripArrayIndex(std::string* name) -{ - unsigned int subscript = GL_INVALID_INDEX; - - // 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); - } - - return subscript; -} - -} - -ProgramImpl::~ProgramImpl() -{ - // Ensure that reset was called by the inherited class during destruction - ASSERT(mUniformIndex.size() == 0); -} - -gl::LinkedUniform *ProgramImpl::getUniformByLocation(GLint location) const -{ - ASSERT(location >= 0 && static_cast(location) < mUniformIndex.size()); - return mUniforms[mUniformIndex[location].index]; -} - -gl::LinkedUniform *ProgramImpl::getUniformByName(const std::string &name) const -{ - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - if (mUniforms[uniformIndex]->name == name) - { - return mUniforms[uniformIndex]; - } - } - - return NULL; -} - -gl::UniformBlock *ProgramImpl::getUniformBlockByIndex(GLuint blockIndex) const -{ - ASSERT(blockIndex < mUniformBlocks.size()); - return mUniformBlocks[blockIndex]; -} - -GLint ProgramImpl::getUniformLocation(std::string name) -{ - unsigned int subscript = ParseAndStripArrayIndex(&name); - - unsigned int numUniforms = mUniformIndex.size(); - for (unsigned int location = 0; location < numUniforms; location++) - { - if (mUniformIndex[location].name == name) - { - const int index = mUniformIndex[location].index; - const bool isArray = mUniforms[index]->isArray(); - - if ((isArray && mUniformIndex[location].element == subscript) || - (subscript == GL_INVALID_INDEX)) - { - return location; - } - } - } - - return -1; -} - -GLuint ProgramImpl::getUniformIndex(std::string name) -{ - unsigned int subscript = ParseAndStripArrayIndex(&name); - - // The app is not allowed to specify array indices other than 0 for arrays of basic types - if (subscript != 0 && subscript != GL_INVALID_INDEX) - { - return GL_INVALID_INDEX; - } - - unsigned int numUniforms = mUniforms.size(); - for (unsigned int index = 0; index < numUniforms; index++) - { - if (mUniforms[index]->name == name) - { - if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX) - { - return index; - } - } - } - - return GL_INVALID_INDEX; -} - -GLuint ProgramImpl::getUniformBlockIndex(std::string name) const -{ - unsigned int subscript = ParseAndStripArrayIndex(&name); - - unsigned int numUniformBlocks = mUniformBlocks.size(); - for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) - { - const gl::UniformBlock &uniformBlock = *mUniformBlocks[blockIndex]; - if (uniformBlock.name == name) - { - const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0); - if (subscript == uniformBlock.elementIndex || arrayElementZero) - { - return blockIndex; - } - } - } - - return GL_INVALID_INDEX; -} - -void ProgramImpl::reset() -{ - SafeDeleteContainer(mUniforms); - mUniformIndex.clear(); - SafeDeleteContainer(mUniformBlocks); - mTransformFeedbackLinkedVaryings.clear(); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.h deleted file mode 100644 index 6aaa23cf89..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.h +++ /dev/null @@ -1,127 +0,0 @@ -// -// Copyright 2014 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. -// - -// ProgramImpl.h: Defines the abstract rx::ProgramImpl class. - -#ifndef LIBGLESV2_RENDERER_PROGRAMIMPL_H_ -#define LIBGLESV2_RENDERER_PROGRAMIMPL_H_ - -#include "common/angleutils.h" -#include "libGLESv2/BinaryStream.h" -#include "libGLESv2/Constants.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Shader.h" -#include "libGLESv2/renderer/Renderer.h" - -#include - -namespace rx -{ - -class ProgramImpl -{ - public: - ProgramImpl() { } - virtual ~ProgramImpl(); - - const std::vector &getUniforms() const { return mUniforms; } - const std::vector &getUniformIndices() const { return mUniformIndex; } - const std::vector &getUniformBlocks() const { return mUniformBlocks; } - const std::vector &getTransformFeedbackLinkedVaryings() const { return mTransformFeedbackLinkedVaryings; } - const sh::Attribute *getShaderAttributes() const { return mShaderAttributes; } - - std::vector &getUniforms() { return mUniforms; } - std::vector &getUniformIndices() { return mUniformIndex; } - std::vector &getUniformBlocks() { return mUniformBlocks; } - std::vector &getTransformFeedbackLinkedVaryings() { return mTransformFeedbackLinkedVaryings; } - sh::Attribute *getShaderAttributes() { return mShaderAttributes; } - - gl::LinkedUniform *getUniformByLocation(GLint location) const; - gl::LinkedUniform *getUniformByName(const std::string &name) const; - gl::UniformBlock *getUniformBlockByIndex(GLuint blockIndex) const; - - GLint getUniformLocation(std::string name); - GLuint getUniformIndex(std::string name); - GLuint getUniformBlockIndex(std::string name) const; - - virtual bool usesPointSize() const = 0; - virtual int getShaderVersion() const = 0; - virtual GLenum getTransformFeedbackBufferMode() const = 0; - - virtual GLenum getBinaryFormat() = 0; - virtual gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; - virtual gl::Error save(gl::BinaryOutputStream *stream) = 0; - - virtual gl::LinkResult link(const gl::Data &data, gl::InfoLog &infoLog, - gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode, - int *registers, std::vector *linkedVaryings, - std::map *outputVariables) = 0; - - virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0; - virtual void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) = 0; - virtual void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) = 0; - virtual void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) = 0; - virtual void setUniform1iv(GLint location, GLsizei count, const GLint *v) = 0; - virtual void setUniform2iv(GLint location, GLsizei count, const GLint *v) = 0; - virtual void setUniform3iv(GLint location, GLsizei count, const GLint *v) = 0; - virtual void setUniform4iv(GLint location, GLsizei count, const GLint *v) = 0; - virtual void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) = 0; - virtual void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) = 0; - virtual void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) = 0; - virtual void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) = 0; - virtual void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - - virtual void getUniformfv(GLint location, GLfloat *params) = 0; - virtual void getUniformiv(GLint location, GLint *params) = 0; - virtual void getUniformuiv(GLint location, GLuint *params) = 0; - - virtual void reset(); - - // TODO: The following functions are possibly only applicable to D3D backends. The should be carefully evaluated to - // determine if they can be removed from this interface. - virtual GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const = 0; - virtual GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const = 0; - virtual GLint getUsedSamplerRange(gl::SamplerType type) const = 0; - virtual void updateSamplerMapping() = 0; - virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0; - - virtual gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - int registers) = 0; - - virtual bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, - const gl::Caps &caps) = 0; - virtual bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, - const gl::Caps &caps) = 0; - - virtual gl::Error applyUniforms() = 0; - virtual gl::Error applyUniformBuffers(const std::vector boundBuffers, const gl::Caps &caps) = 0; - virtual bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, - unsigned int registerIndex, const gl::Caps &caps) = 0; - - protected: - DISALLOW_COPY_AND_ASSIGN(ProgramImpl); - - std::vector mUniforms; - std::vector mUniformIndex; - std::vector mUniformBlocks; - std::vector mTransformFeedbackLinkedVaryings; - - sh::Attribute mShaderAttributes[gl::MAX_VERTEX_ATTRIBS]; -}; - -} - -#endif // LIBGLESV2_RENDERER_PROGRAMIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/QueryImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/QueryImpl.h deleted file mode 100644 index 6b45810a3b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/QueryImpl.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// QueryImpl.h: Defines the abstract rx::QueryImpl class. - -#ifndef LIBGLESV2_RENDERER_QUERYIMPL_H_ -#define LIBGLESV2_RENDERER_QUERYIMPL_H_ - -#include "libGLESv2/Error.h" - -#include "common/angleutils.h" - -#include - -namespace rx -{ - -class QueryImpl -{ - public: - explicit QueryImpl(GLenum type) { mType = type; } - virtual ~QueryImpl() { } - - virtual gl::Error begin() = 0; - virtual gl::Error end() = 0; - virtual gl::Error getResult(GLuint *params) = 0; - virtual gl::Error isResultAvailable(GLuint *available) = 0; - - GLenum getType() const { return mType; } - - private: - DISALLOW_COPY_AND_ASSIGN(QueryImpl); - - GLenum mType; -}; - -} - -#endif // LIBGLESV2_RENDERER_QUERYIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.cpp deleted file mode 100644 index 857fdc9dae..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// -// 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. -// - -// RenderTarget.cpp: Implements serial handling for rx::RenderTarget - -#include "libGLESv2/renderer/RenderTarget.h" - -namespace rx -{ -unsigned int RenderTarget::mCurrentSerial = 1; - -RenderTarget::RenderTarget() - : mSerial(issueSerials(1)) -{ -} - -RenderTarget::~RenderTarget() -{ -} - -unsigned int RenderTarget::getSerial() const -{ - return mSerial; -} - -unsigned int RenderTarget::issueSerials(unsigned int count) -{ - unsigned int firstSerial = mCurrentSerial; - mCurrentSerial += count; - return firstSerial; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h b/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h deleted file mode 100644 index 3bdfb0cc98..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// 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. -// - -// RenderTarget.h: Defines an abstract wrapper class to manage IDirect3DSurface9 -// and ID3D11View objects belonging to renderbuffers. - -#ifndef LIBGLESV2_RENDERER_RENDERTARGET_H_ -#define LIBGLESV2_RENDERER_RENDERTARGET_H_ - -#include "common/angleutils.h" -#include "libGLESv2/angletypes.h" - -namespace rx -{ -class RenderTarget -{ - public: - RenderTarget(); - virtual ~RenderTarget(); - - virtual GLsizei getWidth() const = 0; - virtual GLsizei getHeight() const = 0; - virtual GLsizei getDepth() const = 0; - virtual GLenum getInternalFormat() const = 0; - virtual GLenum getActualFormat() const = 0; - virtual GLsizei getSamples() const = 0; - gl::Extents getExtents() const { return gl::Extents(getWidth(), getHeight(), getDepth()); } - - virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height) = 0; - - virtual unsigned int getSerial() const; - static unsigned int issueSerials(unsigned int count); - - struct Desc { - GLsizei width; - GLsizei height; - GLsizei depth; - GLenum format; - }; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderTarget); - - const unsigned int mSerial; - static unsigned int mCurrentSerial; -}; - -} - -#endif // LIBGLESV2_RENDERTARGET_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.cpp deleted file mode 100644 index 770ae8e9c6..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// RenderbufferImpl.h: Implements the shared methods of the abstract class gl::RenderbufferImpl - -#include "libGLESv2/renderer/RenderbufferImpl.h" - -namespace rx -{ -RenderbufferImpl::RenderbufferImpl() -{ -} - -RenderbufferImpl::~RenderbufferImpl() -{ -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.h deleted file mode 100644 index 52e070f1d3..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// RenderbufferImpl.h: Defines the abstract class gl::RenderbufferImpl - -#ifndef LIBGLESV2_RENDERER_RENDERBUFFERIMPL_H_ -#define LIBGLESV2_RENDERER_RENDERBUFFERIMPL_H_ - -#include "angle_gl.h" - -#include "libGLESv2/Error.h" - -#include "common/angleutils.h" - -namespace rx -{ - -class RenderbufferImpl -{ - public: - RenderbufferImpl(); - virtual ~RenderbufferImpl() = 0; - - virtual gl::Error setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) = 0; - - virtual GLsizei getWidth() const = 0; - virtual GLsizei getHeight() const = 0; - virtual GLenum getInternalFormat() const = 0; - virtual GLenum getActualFormat() const = 0; - virtual GLsizei getSamples() const = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderbufferImpl); -}; - -} - -#endif // LIBGLESV2_RENDERER_RENDERBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp deleted file mode 100644 index df3dae1e38..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// Renderer.cpp: Implements EGL dependencies for creating and destroying Renderer instances. - -#include "common/utilities.h" -#include "libEGL/AttributeMap.h" -#include "libGLESv2/main.h" -#include "libGLESv2/renderer/Renderer.h" - -#include - -#if defined (ANGLE_ENABLE_D3D9) -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#endif // ANGLE_ENABLE_D3D9 - -#if defined (ANGLE_ENABLE_D3D11) -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#endif // ANGLE_ENABLE_D3D11 - -#if defined (ANGLE_TEST_CONFIG) -#define ANGLE_DEFAULT_D3D11 1 -#endif - -#if !defined(ANGLE_DEFAULT_D3D11) -// Enables use of the Direct3D 11 API for a default display, when available -#define ANGLE_DEFAULT_D3D11 0 -#endif - -namespace rx -{ - -Renderer::Renderer() - : mCapsInitialized(false), - mWorkaroundsInitialized(false) -{ -} - -Renderer::~Renderer() -{ -} - -const gl::Caps &Renderer::getRendererCaps() const -{ - if (!mCapsInitialized) - { - generateCaps(&mCaps, &mTextureCaps, &mExtensions); - mCapsInitialized = true; - } - - return mCaps; -} - -const gl::TextureCapsMap &Renderer::getRendererTextureCaps() const -{ - if (!mCapsInitialized) - { - generateCaps(&mCaps, &mTextureCaps, &mExtensions); - mCapsInitialized = true; - } - - return mTextureCaps; -} - -const gl::Extensions &Renderer::getRendererExtensions() const -{ - if (!mCapsInitialized) - { - generateCaps(&mCaps, &mTextureCaps, &mExtensions); - mCapsInitialized = true; - } - - return mExtensions; -} - -const Workarounds &Renderer::getWorkarounds() const -{ - if (!mWorkaroundsInitialized) - { - mWorkarounds = generateWorkarounds(); - mWorkaroundsInitialized = true; - } - - return mWorkarounds; -} - -typedef Renderer *(*CreateRendererFunction)(egl::Display*, EGLNativeDisplayType, const egl::AttributeMap &); - -template -Renderer *CreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, const egl::AttributeMap &attributes) -{ - return new RendererType(display, nativeDisplay, attributes); -} - -} - -extern "C" -{ - -rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, const egl::AttributeMap &attribMap) -{ - std::vector rendererCreationFunctions; - - EGLint requestedDisplayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); - -# if defined(ANGLE_ENABLE_D3D11) - if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || - nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE || - requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) - { - rendererCreationFunctions.push_back(rx::CreateRenderer); - } -# endif - -# if defined(ANGLE_ENABLE_D3D9) - if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || - requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE) - { - rendererCreationFunctions.push_back(rx::CreateRenderer); - } -# endif - - if (nativeDisplay != EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE && - nativeDisplay != EGL_D3D11_ONLY_DISPLAY_ANGLE && - requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE) - { - // The default display is requested, try the D3D9 and D3D11 renderers, order them using - // the definition of ANGLE_DEFAULT_D3D11 -# if ANGLE_DEFAULT_D3D11 -# if defined(ANGLE_ENABLE_D3D11) - rendererCreationFunctions.push_back(rx::CreateRenderer); -# endif -# if defined(ANGLE_ENABLE_D3D9) - rendererCreationFunctions.push_back(rx::CreateRenderer); -# endif -# else -# if defined(ANGLE_ENABLE_D3D9) - rendererCreationFunctions.push_back(rx::CreateRenderer); -# endif -# if defined(ANGLE_ENABLE_D3D11) - rendererCreationFunctions.push_back(rx::CreateRenderer); -# endif -# endif - } - - for (size_t i = 0; i < rendererCreationFunctions.size(); i++) - { - rx::Renderer *renderer = rendererCreationFunctions[i](display, nativeDisplay, attribMap); - if (renderer->initialize() == EGL_SUCCESS) - { - return renderer; - } - else - { - // Failed to create the renderer, try the next - SafeDelete(renderer); - } - } - - return NULL; -} - -void glDestroyRenderer(rx::Renderer *renderer) -{ - ASSERT(renderer); - SafeDelete(renderer); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h deleted file mode 100644 index b85895a938..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h +++ /dev/null @@ -1,193 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// Renderer.h: Defines a back-end specific class that hides the details of the -// implementation-specific renderer. - -#ifndef LIBGLESV2_RENDERER_RENDERER_H_ -#define LIBGLESV2_RENDERER_RENDERER_H_ - -#include "libGLESv2/Caps.h" -#include "libGLESv2/Error.h" -#include "libGLESv2/Uniform.h" -#include "libGLESv2/angletypes.h" -#include "libGLESv2/renderer/Workarounds.h" -#include "common/NativeWindow.h" -#include "common/mathutil.h" - -#include - -#include - -#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) -// WARNING: D3DCOMPILE_OPTIMIZATION_LEVEL3 may lead to a DX9 shader compiler hang. -// It should only be used selectively to work around specific bugs. -#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL1 -#endif - -namespace egl -{ -class Display; -} - -namespace gl -{ -class Buffer; -class Framebuffer; -struct Data; -} - -namespace rx -{ -class QueryImpl; -class FenceNVImpl; -class FenceSyncImpl; -class BufferImpl; -class VertexArrayImpl; -class ShaderImpl; -class ProgramImpl; -class TextureImpl; -class TransformFeedbackImpl; -class RenderbufferImpl; -struct TranslatedIndexData; -struct Workarounds; -class SwapChain; - -struct ConfigDesc -{ - GLenum renderTargetFormat; - GLenum depthStencilFormat; - GLint multiSample; - bool fastConfig; - bool es3Capable; -}; - -class Renderer -{ - public: - Renderer(); - virtual ~Renderer(); - - virtual EGLint initialize() = 0; - virtual bool resetDevice() = 0; - - virtual int generateConfigs(ConfigDesc **configDescList) = 0; - virtual void deleteConfigs(ConfigDesc *configDescList) = 0; - - virtual gl::Error sync(bool block) = 0; - - virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, - GLint first, GLsizei count, GLsizei instances) = 0; - virtual gl::Error drawElements(const gl::Data &data, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei instances, - const RangeUI &indexRange) = 0; - - virtual gl::Error clear(const gl::Data &data, GLbitfield mask) = 0; - virtual gl::Error clearBufferfv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLfloat *values) = 0; - virtual gl::Error clearBufferuiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLuint *values) = 0; - virtual gl::Error clearBufferiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLint *values) = 0; - virtual gl::Error clearBufferfi(const gl::Data &data, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) = 0; - - virtual gl::Error readPixels(const gl::Data &data, GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei *bufSize, void* pixels) = 0; - - virtual gl::Error blitFramebuffer(const gl::Data &data, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) = 0; - - // TODO(jmadill): caps? and virtual for egl::Display - virtual bool getShareHandleSupport() const = 0; - virtual bool getPostSubBufferSupport() const = 0; - - // Shader creation - virtual ShaderImpl *createShader(const gl::Data &data, GLenum type) = 0; - virtual ProgramImpl *createProgram() = 0; - - // Shader operations - virtual void releaseShaderCompiler() = 0; - - // Texture creation - virtual TextureImpl *createTexture(GLenum target) = 0; - - // Renderbuffer creation - virtual RenderbufferImpl *createRenderbuffer() = 0; - virtual RenderbufferImpl *createRenderbuffer(SwapChain *swapChain, bool depth) = 0; - - // Buffer creation - virtual BufferImpl *createBuffer() = 0; - - // Vertex Array creation - virtual VertexArrayImpl *createVertexArray() = 0; - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type) = 0; - virtual FenceNVImpl *createFenceNV() = 0; - virtual FenceSyncImpl *createFenceSync() = 0; - - // Transform Feedback creation - virtual TransformFeedbackImpl *createTransformFeedback() = 0; - - // lost device - //TODO(jmadill): investigate if this stuff is necessary in GL - virtual void notifyDeviceLost() = 0; - virtual bool isDeviceLost() = 0; - virtual bool testDeviceLost(bool notify) = 0; - virtual bool testDeviceResettable() = 0; - - virtual DWORD getAdapterVendor() const = 0; - virtual std::string getRendererDescription() const = 0; - virtual GUID getAdapterIdentifier() const = 0; - - // Renderer capabilities (virtual because of egl::Display) - virtual const gl::Caps &getRendererCaps() const; - const gl::TextureCapsMap &getRendererTextureCaps() const; - virtual const gl::Extensions &getRendererExtensions() const; - const Workarounds &getWorkarounds() const; - - // TODO(jmadill): needed by egl::Display, probably should be removed - virtual int getMajorShaderModel() const = 0; - virtual int getMinSwapInterval() const = 0; - virtual int getMaxSwapInterval() const = 0; - virtual bool getLUID(LUID *adapterLuid) const = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Renderer); - - virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const = 0; - virtual Workarounds generateWorkarounds() const = 0; - - mutable bool mCapsInitialized; - mutable gl::Caps mCaps; - mutable gl::TextureCapsMap mTextureCaps; - mutable gl::Extensions mExtensions; - - mutable bool mWorkaroundsInitialized; - mutable Workarounds mWorkarounds; -}; - -struct dx_VertexConstants -{ - float depthRange[4]; - float viewAdjust[4]; -}; - -struct dx_PixelConstants -{ - float depthRange[4]; - float viewCoords[4]; - float depthFront[4]; -}; - -enum ShaderType -{ - SHADER_VERTEX, - SHADER_PIXEL, - SHADER_GEOMETRY -}; - -} -#endif // LIBGLESV2_RENDERER_RENDERER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h b/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h deleted file mode 100644 index f1a96d74fb..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h +++ /dev/null @@ -1,78 +0,0 @@ -// -// 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. -// - -// ShaderExecutable.h: Defines a renderer-agnostic class to contain shader -// executable implementation details. - -#ifndef LIBGLESV2_RENDERER_SHADEREXECUTABLE_H_ -#define LIBGLESV2_RENDERER_SHADEREXECUTABLE_H_ - -#include "common/angleutils.h" -#include "common/debug.h" - -#include -#include - -namespace rx -{ - -class ShaderExecutable -{ - public: - ShaderExecutable(const void *function, size_t length) - : mFunctionBuffer(length) - { - memcpy(mFunctionBuffer.data(), function, length); - } - - virtual ~ShaderExecutable() {} - - const uint8_t *getFunction() const - { - return mFunctionBuffer.data(); - } - - size_t getLength() const - { - return mFunctionBuffer.size(); - } - - const std::string &getDebugInfo() const - { - return mDebugInfo; - } - - void appendDebugInfo(const std::string &info) - { - mDebugInfo += info; - } - - private: - DISALLOW_COPY_AND_ASSIGN(ShaderExecutable); - - std::vector mFunctionBuffer; - std::string mDebugInfo; -}; - -class UniformStorage -{ - public: - UniformStorage(size_t initialSize) - : mSize(initialSize) - { - } - - virtual ~UniformStorage() {} - - size_t size() const { return mSize; } - - private: - size_t mSize; -}; - -} - -#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/ShaderImpl.h deleted file mode 100644 index cb0d360f0b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderImpl.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright 2014 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. -// - -// ShaderImpl.h: Defines the abstract rx::ShaderImpl class. - -#ifndef LIBGLESV2_RENDERER_SHADERIMPL_H_ -#define LIBGLESV2_RENDERER_SHADERIMPL_H_ - -#include - -#include "common/angleutils.h" -#include "libGLESv2/Shader.h" - -namespace rx -{ - -class ShaderImpl -{ - public: - ShaderImpl() { } - virtual ~ShaderImpl() { } - - virtual bool compile(const gl::Data &data, const std::string &source) = 0; - virtual const std::string &getInfoLog() const = 0; - virtual const std::string &getTranslatedSource() const = 0; - virtual std::string getDebugInfo() const = 0; - - const std::vector &getVaryings() const { return mVaryings; } - const std::vector &getUniforms() const { return mUniforms; } - const std::vector &getInterfaceBlocks() const { return mInterfaceBlocks; } - const std::vector &getActiveAttributes() const { return mActiveAttributes; } - const std::vector &getActiveOutputVariables() const { return mActiveOutputVariables; } - - std::vector &getVaryings() { return mVaryings; } - std::vector &getUniforms() { return mUniforms; } - std::vector &getInterfaceBlocks() { return mInterfaceBlocks; } - std::vector &getActiveAttributes() { return mActiveAttributes; } - std::vector &getActiveOutputVariables() { return mActiveOutputVariables; } - - protected: - DISALLOW_COPY_AND_ASSIGN(ShaderImpl); - - std::vector mVaryings; - std::vector mUniforms; - std::vector mInterfaceBlocks; - std::vector mActiveAttributes; - std::vector mActiveOutputVariables; -}; - -} - -#endif // LIBGLESV2_RENDERER_SHADERIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h deleted file mode 100644 index 1417e0bdf6..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// 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. -// - -// SwapChain.h: Defines a back-end specific class that hides the details of the -// implementation-specific swapchain. - -#ifndef LIBGLESV2_RENDERER_SWAPCHAIN_H_ -#define LIBGLESV2_RENDERER_SWAPCHAIN_H_ - -#include "common/angleutils.h" -#include "common/NativeWindow.h" -#include "common/platform.h" - -#include -#include - -#if !defined(ANGLE_FORCE_VSYNC_OFF) -#define ANGLE_FORCE_VSYNC_OFF 0 -#endif - -namespace rx -{ - -class SwapChain -{ - public: - SwapChain(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) - : mNativeWindow(nativeWindow), mShareHandle(shareHandle), mBackBufferFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat) - { - } - - virtual ~SwapChain() {}; - - virtual EGLint resize(EGLint backbufferWidth, EGLint backbufferSize) = 0; - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0; - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0; - virtual void recreate() = 0; - - GLenum GetBackBufferInternalFormat() const { return mBackBufferFormat; } - GLenum GetDepthBufferInternalFormat() const { return mDepthBufferFormat; } - - virtual HANDLE getShareHandle() {return mShareHandle;}; - - protected: - rx::NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. - const GLenum mBackBufferFormat; - const GLenum mDepthBufferFormat; - - HANDLE mShareHandle; -}; - -} -#endif // LIBGLESV2_RENDERER_SWAPCHAIN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h deleted file mode 100644 index 3e662557e4..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright 2014 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. -// - -// TextureImpl.h: Defines the abstract rx::TextureImpl classes. - -#ifndef LIBGLESV2_RENDERER_TEXTUREIMPL_H_ -#define LIBGLESV2_RENDERER_TEXTUREIMPL_H_ - -#include "common/angleutils.h" -#include "libGLESv2/Error.h" - -#include "angle_gl.h" - -#include "libGLESv2/ImageIndex.h" - -namespace egl -{ -class Surface; -} - -namespace gl -{ -class Framebuffer; -struct PixelUnpackState; -struct SamplerState; -} - -namespace rx -{ - -class Image; - -class TextureImpl -{ - public: - virtual ~TextureImpl() {}; - - // Deprecated in favour of the ImageIndex method - virtual Image *getImage(int level, int layer) const = 0; - virtual Image *getImage(const gl::ImageIndex &index) const = 0; - virtual GLsizei getLayerCount(int level) const = 0; - - virtual void setUsage(GLenum usage) = 0; - - virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; - virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) = 0; - virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; - virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) = 0; - virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; - virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; - virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) = 0; - - virtual gl::Error generateMipmaps() = 0; - - virtual void bindTexImage(egl::Surface *surface) = 0; - virtual void releaseTexImage() = 0; -}; - -} - -#endif // LIBGLESV2_RENDERER_TEXTUREIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/TransformFeedbackImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/TransformFeedbackImpl.h deleted file mode 100644 index 8425604d87..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/TransformFeedbackImpl.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright 2014 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. -// - -// TransformFeedbackImpl.h: Defines the abstract rx::TransformFeedbackImpl class. - -#ifndef LIBGLESV2_RENDERER_TRANSFORMFEEDBACKIMPL_H_ -#define LIBGLESV2_RENDERER_TRANSFORMFEEDBACKIMPL_H_ - -#include "common/angleutils.h" -#include "libGLESv2/TransformFeedback.h" - -namespace rx -{ - -class TransformFeedbackImpl -{ - public: - virtual ~TransformFeedbackImpl() { } - - virtual void begin(GLenum primitiveMode) = 0; - virtual void end() = 0; - virtual void pause() = 0; - virtual void resume() = 0; -}; - -} - -#endif // LIBGLESV2_RENDERER_TRANSFORMFEEDBACKIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/VertexArrayImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/VertexArrayImpl.h deleted file mode 100644 index b013f9cdf4..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/VertexArrayImpl.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright 2014 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. -// - -// VertexAttribImpl.h: Defines the abstract rx::VertexAttribImpl class. - -#ifndef LIBGLESV2_RENDERER_VERTEXARRAYIMPL_H_ -#define LIBGLESV2_RENDERER_VERTEXARRAYIMPL_H_ - -#include "common/angleutils.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/VertexAttribute.h" - -namespace rx -{ - -class VertexArrayImpl -{ - public: - virtual ~VertexArrayImpl() { } - - virtual void setElementArrayBuffer(const gl::Buffer *buffer) = 0; - virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) = 0; - virtual void setAttributeDivisor(size_t idx, GLuint divisor) = 0; - virtual void enableAttribute(size_t idx, bool enabledState) = 0; -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXARRAYIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Workarounds.h b/src/3rdparty/angle/src/libGLESv2/renderer/Workarounds.h deleted file mode 100644 index 20a166fb7a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Workarounds.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// angletypes.h: Workarounds for driver bugs and other issues. - -#ifndef LIBGLESV2_RENDERER_WORKAROUNDS_H_ -#define LIBGLESV2_RENDERER_WORKAROUNDS_H_ - -// TODO(jmadill,zmo,geofflang): make a workarounds library that can operate -// independent of ANGLE's renderer. Workarounds should also be accessible -// outside of the Renderer. - -namespace rx -{ - -enum D3DWorkaroundType -{ - ANGLE_D3D_WORKAROUND_NONE, - ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION, - ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION -}; - -struct Workarounds -{ - Workarounds() - : mrtPerfWorkaround(false), - setDataFasterThanImageUpload(false) - {} - - bool mrtPerfWorkaround; - bool setDataFasterThanImageUpload; -}; - -} - -#endif // LIBGLESV2_RENDERER_WORKAROUNDS_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp deleted file mode 100644 index aabc9f04e9..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// copyimage.cpp: Defines image copying functions - -#include "libGLESv2/renderer/copyimage.h" - -namespace rx -{ - -void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest) -{ - uint32_t argb = *reinterpret_cast(source); - *reinterpret_cast(dest) = (argb & 0xFF00FF00) | // Keep alpha and green - (argb & 0x00FF0000) >> 16 | // Move red to blue - (argb & 0x000000FF) << 16; // Move blue to red -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.h b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.h deleted file mode 100644 index 513eb5cb3d..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// copyimage.h: Defines image copying functions - -#ifndef LIBGLESV2_RENDERER_COPYIMAGE_H_ -#define LIBGLESV2_RENDERER_COPYIMAGE_H_ - -#include "common/mathutil.h" -#include "libGLESv2/angletypes.h" - -#include - -namespace rx -{ - -template -void ReadColor(const uint8_t *source, uint8_t *dest); - -template -void WriteColor(const uint8_t *source, uint8_t *dest); - -template -void CopyPixel(const uint8_t *source, uint8_t *dest); - -void CopyBGRA8ToRGBA8(const uint8_t *source, uint8_t *dest); - -} - -#include "copyimage.inl" - -#endif // LIBGLESV2_RENDERER_COPYIMAGE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.inl b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.inl deleted file mode 100644 index 0498cf7750..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.inl +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// copyimage.inl: Defines image copying functions - -namespace rx -{ - -template -inline void ReadColor(const uint8_t *source, uint8_t *dest) -{ - sourceType::readColor(reinterpret_cast*>(dest), reinterpret_cast(source)); -} - -template -inline void WriteColor(const uint8_t *source, uint8_t *dest) -{ - destType::writeColor(reinterpret_cast(dest), reinterpret_cast*>(source)); -} - -template -inline void CopyPixel(const uint8_t *source, uint8_t *dest) -{ - colorDataType temp; - ReadColor(source, &temp); - WriteColor(&temp, dest); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.h b/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.h deleted file mode 100644 index e0e8af166b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// copyvertex.h: Defines vertex buffer copying and conversion functions - -#ifndef LIBGLESV2_RENDERER_COPYVERTEX_H_ -#define LIBGLESV2_RENDERER_COPYVERTEX_H_ - -#include "common/mathutil.h" - -namespace rx -{ - -// 'widenDefaultValueBits' gives the default value for the alpha channel (4th component) -// the sentinel value 0 means we do not want to widen the input or add an alpha channel -template -inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); - -template -inline void Copy32FixedTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); - -template -inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); - -template -inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output); - -} - -#include "copyvertex.inl" - -#endif // LIBGLESV2_RENDERER_COPYVERTEX_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.inl b/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.inl deleted file mode 100644 index 7eef17b22b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/copyvertex.inl +++ /dev/null @@ -1,288 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -namespace rx -{ - -template -inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) -{ - const size_t attribSize = sizeof(T)* componentCount; - const T defaultValue = gl::bitCast(widenDefaultValueBits); - const bool widen = (widenDefaultValueBits != 0); - - if (attribSize == stride && !widen) - { - memcpy(output, input, count * attribSize); - } - else - { - size_t outputStride = widen ? 4 : componentCount; - - for (size_t i = 0; i < count; i++) - { - const T *offsetInput = reinterpret_cast(input + (i * stride)); - T *offsetOutput = reinterpret_cast(output) + i * outputStride; - - for (size_t j = 0; j < componentCount; j++) - { - offsetOutput[j] = offsetInput[j]; - } - - if (widen) - { - offsetOutput[3] = defaultValue; - } - } - } -} - -template -inline void Copy32FixedTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) -{ - static const float divisor = 1.0f / (1 << 16); - - for (size_t i = 0; i < count; i++) - { - const GLfixed* offsetInput = reinterpret_cast(input + (stride * i)); - float* offsetOutput = reinterpret_cast(output) + i * componentCount; - - for (size_t j = 0; j < componentCount; j++) - { - offsetOutput[j] = static_cast(offsetInput[j]) * divisor; - } - } -} - -template -inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) -{ - typedef std::numeric_limits NL; - - for (size_t i = 0; i < count; i++) - { - const T *offsetInput = reinterpret_cast(input + (stride * i)); - float *offsetOutput = reinterpret_cast(output) + i * componentCount; - - for (size_t j = 0; j < componentCount; j++) - { - if (normalized) - { - if (NL::is_signed) - { - const float divisor = 1.0f / (2 * static_cast(NL::max()) + 1); - offsetOutput[j] = (2 * static_cast(offsetInput[j]) + 1) * divisor; - } - else - { - offsetOutput[j] = static_cast(offsetInput[j]) / NL::max(); - } - } - else - { - offsetOutput[j] = static_cast(offsetInput[j]); - } - } - } -} - -namespace priv -{ - -template -static inline void CopyPackedRGB(uint32_t data, uint8_t *output) -{ - const uint32_t rgbSignMask = 0x200; // 1 set at the 9 bit - const uint32_t negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1 - - if (toFloat) - { - GLfloat *floatOutput = reinterpret_cast(output); - if (isSigned) - { - GLfloat finalValue = 0; - if (data & rgbSignMask) - { - int negativeNumber = data | negativeMask; - finalValue = static_cast(negativeNumber); - } - else - { - finalValue = static_cast(data); - } - - if (normalized) - { - const int32_t maxValue = 0x1FF; // 1 set in bits 0 through 8 - const int32_t minValue = 0xFFFFFE01; // Inverse of maxValue - - // A 10-bit two's complement number has the possibility of being minValue - 1 but - // OpenGL's normalization rules dictate that it should be clamped to minValue in this - // case. - if (finalValue < minValue) - { - finalValue = minValue; - } - - const int32_t halfRange = (maxValue - minValue) >> 1; - *floatOutput = ((finalValue - minValue) / halfRange) - 1.0f; - } - else - { - *floatOutput = finalValue; - } - } - else - { - if (normalized) - { - const uint32_t maxValue = 0x3FF; // 1 set in bits 0 through 9 - *floatOutput = static_cast(data) / static_cast(maxValue); - } - else - { - *floatOutput = static_cast(data); - } - } - } - else - { - if (isSigned) - { - GLshort *intOutput = reinterpret_cast(output); - - if (data & rgbSignMask) - { - *intOutput = data | negativeMask; - } - else - { - *intOutput = data; - } - } - else - { - GLushort *uintOutput = reinterpret_cast(output); - *uintOutput = data; - } - } -} - -template -inline void CopyPackedAlpha(uint32_t data, uint8_t *output) -{ - if (toFloat) - { - GLfloat *floatOutput = reinterpret_cast(output); - if (isSigned) - { - if (normalized) - { - switch (data) - { - case 0x0: *floatOutput = 0.0f; break; - case 0x1: *floatOutput = 1.0f; break; - case 0x2: *floatOutput = -1.0f; break; - case 0x3: *floatOutput = -1.0f; break; - default: UNREACHABLE(); - } - } - else - { - switch (data) - { - case 0x0: *floatOutput = 0.0f; break; - case 0x1: *floatOutput = 1.0f; break; - case 0x2: *floatOutput = -2.0f; break; - case 0x3: *floatOutput = -1.0f; break; - default: UNREACHABLE(); - } - } - } - else - { - if (normalized) - { - switch (data) - { - case 0x0: *floatOutput = 0.0f / 3.0f; break; - case 0x1: *floatOutput = 1.0f / 3.0f; break; - case 0x2: *floatOutput = 2.0f / 3.0f; break; - case 0x3: *floatOutput = 3.0f / 3.0f; break; - default: UNREACHABLE(); - } - } - else - { - switch (data) - { - case 0x0: *floatOutput = 0.0f; break; - case 0x1: *floatOutput = 1.0f; break; - case 0x2: *floatOutput = 2.0f; break; - case 0x3: *floatOutput = 3.0f; break; - default: UNREACHABLE(); - } - } - } - } - else - { - if (isSigned) - { - GLshort *intOutput = reinterpret_cast(output); - switch (data) - { - case 0x0: *intOutput = 0; break; - case 0x1: *intOutput = 1; break; - case 0x2: *intOutput = -2; break; - case 0x3: *intOutput = -1; break; - default: UNREACHABLE(); - } - } - else - { - GLushort *uintOutput = reinterpret_cast(output); - switch (data) - { - case 0x0: *uintOutput = 0; break; - case 0x1: *uintOutput = 1; break; - case 0x2: *uintOutput = 2; break; - case 0x3: *uintOutput = 3; break; - default: UNREACHABLE(); - } - } - } -} - -} - -template -inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output) -{ - const size_t outputComponentSize = toFloat ? 4 : 2; - const size_t componentCount = 4; - - const uint32_t rgbMask = 0x3FF; // 1 set in bits 0 through 9 - const size_t redShift = 0; // red is bits 0 through 9 - const size_t greenShift = 10; // green is bits 10 through 19 - const size_t blueShift = 20; // blue is bits 20 through 29 - - const uint32_t alphaMask = 0x3; // 1 set in bits 0 and 1 - const size_t alphaShift = 30; // Alpha is the 30 and 31 bits - - for (size_t i = 0; i < count; i++) - { - GLuint packedValue = *reinterpret_cast(input + (i * stride)); - uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount); - - priv::CopyPackedRGB( (packedValue >> redShift) & rgbMask, offsetOutput + (0 * outputComponentSize)); - priv::CopyPackedRGB( (packedValue >> greenShift) & rgbMask, offsetOutput + (1 * outputComponentSize)); - priv::CopyPackedRGB( (packedValue >> blueShift) & rgbMask, offsetOutput + (2 * outputComponentSize)); - priv::CopyPackedAlpha((packedValue >> alphaShift) & alphaMask, offsetOutput + (3 * outputComponentSize)); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp deleted file mode 100644 index dd0d3f52ad..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright 2014 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. -// - -// BufferD3D.cpp Defines common functionality between the Buffer9 and Buffer11 classes. - -#include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/renderer/d3d/VertexBuffer.h" -#include "libGLESv2/renderer/d3d/IndexBuffer.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -unsigned int BufferD3D::mNextSerial = 1; - -BufferD3D::BufferD3D() - : BufferImpl(), - mStaticVertexBuffer(NULL), - mStaticIndexBuffer(NULL) -{ - updateSerial(); -} - -BufferD3D::~BufferD3D() -{ - SafeDelete(mStaticVertexBuffer); - SafeDelete(mStaticIndexBuffer); -} - -BufferD3D *BufferD3D::makeBufferD3D(BufferImpl *buffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(BufferD3D*, buffer)); - return static_cast(buffer); -} - -BufferD3D *BufferD3D::makeFromBuffer(gl::Buffer *buffer) -{ - BufferImpl *impl = buffer->getImplementation(); - ASSERT(impl); - return makeBufferD3D(impl); -} - -void BufferD3D::updateSerial() -{ - mSerial = mNextSerial++; -} - -void BufferD3D::initializeStaticData() -{ - if (!mStaticVertexBuffer) - { - mStaticVertexBuffer = new StaticVertexBufferInterface(getRenderer()); - } - if (!mStaticIndexBuffer) - { - mStaticIndexBuffer = new StaticIndexBufferInterface(getRenderer()); - } -} - -void BufferD3D::invalidateStaticData() -{ - if ((mStaticVertexBuffer && mStaticVertexBuffer->getBufferSize() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->getBufferSize() != 0)) - { - SafeDelete(mStaticVertexBuffer); - SafeDelete(mStaticIndexBuffer); - } - - mUnmodifiedDataUse = 0; -} - -// Creates static buffers if sufficient used data has been left unmodified -void BufferD3D::promoteStaticUsage(int dataSize) -{ - if (!mStaticVertexBuffer && !mStaticIndexBuffer) - { - mUnmodifiedDataUse += dataSize; - - if (mUnmodifiedDataUse > 3 * getSize()) - { - initializeStaticData(); - } - } -} - -} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h deleted file mode 100644 index 1a1308c545..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h +++ /dev/null @@ -1,59 +0,0 @@ -// -// Copyright 2014 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. -// - -// BufferImpl.h: Defines the abstract rx::BufferImpl class. - -#ifndef LIBGLESV2_RENDERER_BUFFERD3D_H_ -#define LIBGLESV2_RENDERER_BUFFERD3D_H_ - -#include "libGLESv2/renderer/BufferImpl.h" -#include "libGLESv2/angletypes.h" - -#include - -namespace rx -{ -class RendererD3D; -class StaticIndexBufferInterface; -class StaticVertexBufferInterface; - -class BufferD3D : public BufferImpl -{ - public: - BufferD3D(); - virtual ~BufferD3D(); - - static BufferD3D *makeBufferD3D(BufferImpl *buffer); - static BufferD3D *makeFromBuffer(gl::Buffer *buffer); - - unsigned int getSerial() const { return mSerial; } - - virtual gl::Error getData(const uint8_t **outData) = 0; - virtual size_t getSize() const = 0; - virtual bool supportsDirectBinding() const = 0; - virtual RendererD3D *getRenderer() = 0; - - StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; } - StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; } - - void initializeStaticData(); - void invalidateStaticData(); - void promoteStaticUsage(int dataSize); - - protected: - unsigned int mSerial; - static unsigned int mNextSerial; - - void updateSerial(); - - StaticVertexBufferInterface *mStaticVertexBuffer; - StaticIndexBufferInterface *mStaticIndexBuffer; - unsigned int mUnmodifiedDataUse; -}; - -} - -#endif // LIBGLESV2_RENDERER_BUFFERIMPLD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp deleted file mode 100644 index 3d5bfe0cbe..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp +++ /dev/null @@ -1,1148 +0,0 @@ -// -// Copyright (c) 2014 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. -// -// DynamicHLSL.cpp: Implementation for link and run-time HLSL generation -// - -#include "libGLESv2/renderer/d3d/DynamicHLSL.h" -#include "libGLESv2/renderer/d3d/ShaderD3D.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/Program.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Shader.h" -#include "libGLESv2/formatutils.h" - -#include "common/utilities.h" -#include "common/blocklayout.h" - -// For use with ArrayString, see angleutils.h -META_ASSERT(GL_INVALID_INDEX == UINT_MAX); - -using namespace gl; - -namespace rx -{ - -namespace -{ - -std::string HLSLComponentTypeString(GLenum componentType) -{ - switch (componentType) - { - case GL_UNSIGNED_INT: return "uint"; - case GL_INT: return "int"; - case GL_UNSIGNED_NORMALIZED: - case GL_SIGNED_NORMALIZED: - case GL_FLOAT: return "float"; - default: UNREACHABLE(); return "not-component-type"; - } -} - -std::string HLSLComponentTypeString(GLenum componentType, int componentCount) -{ - return HLSLComponentTypeString(componentType) + (componentCount > 1 ? Str(componentCount) : ""); -} - -std::string HLSLMatrixTypeString(GLenum type) -{ - switch (type) - { - case GL_FLOAT_MAT2: return "float2x2"; - case GL_FLOAT_MAT3: return "float3x3"; - case GL_FLOAT_MAT4: return "float4x4"; - case GL_FLOAT_MAT2x3: return "float2x3"; - case GL_FLOAT_MAT3x2: return "float3x2"; - case GL_FLOAT_MAT2x4: return "float2x4"; - case GL_FLOAT_MAT4x2: return "float4x2"; - case GL_FLOAT_MAT3x4: return "float3x4"; - case GL_FLOAT_MAT4x3: return "float4x3"; - default: UNREACHABLE(); return "not-matrix-type"; - } -} - -std::string HLSLTypeString(GLenum type) -{ - if (gl::IsMatrixType(type)) - { - return HLSLMatrixTypeString(type); - } - - return HLSLComponentTypeString(gl::VariableComponentType(type), gl::VariableComponentCount(type)); -} - -const PixelShaderOutputVariable &GetOutputAtLocation(const std::vector &outputVariables, - unsigned int location) -{ - for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex) - { - if (outputVariables[variableIndex].outputIndex == location) - { - return outputVariables[variableIndex]; - } - } - - UNREACHABLE(); - return outputVariables[0]; -} - -const std::string VERTEX_ATTRIBUTE_STUB_STRING = "@@ VERTEX ATTRIBUTES @@"; -const std::string PIXEL_OUTPUT_STUB_STRING = "@@ PIXEL OUTPUT @@"; - -} - -DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) - : mRenderer(renderer) -{ -} - -static bool packVarying(PackedVarying *varying, const int maxVaryingVectors, VaryingPacking packing) -{ - GLenum transposedType = TransposeMatrixType(varying->type); - - // matrices within varying structs are not transposed - int registers = (varying->isStruct() ? HLSLVariableRegisterCount(*varying) : VariableRowCount(transposedType)) * varying->elementCount(); - int elements = (varying->isStruct() ? 4 : VariableColumnCount(transposedType)); - - if (elements >= 2 && elements <= 4) - { - for (int r = 0; r <= maxVaryingVectors - registers; r++) - { - bool available = true; - - for (int y = 0; y < registers && available; y++) - { - for (int x = 0; x < elements && available; x++) - { - if (packing[r + y][x]) - { - available = false; - } - } - } - - if (available) - { - varying->registerIndex = r; - varying->columnIndex = 0; - - for (int y = 0; y < registers; y++) - { - for (int x = 0; x < elements; x++) - { - packing[r + y][x] = &*varying; - } - } - - return true; - } - } - - if (elements == 2) - { - for (int r = maxVaryingVectors - registers; r >= 0; r--) - { - bool available = true; - - for (int y = 0; y < registers && available; y++) - { - for (int x = 2; x < 4 && available; x++) - { - if (packing[r + y][x]) - { - available = false; - } - } - } - - if (available) - { - varying->registerIndex = r; - varying->columnIndex = 2; - - for (int y = 0; y < registers; y++) - { - for (int x = 2; x < 4; x++) - { - packing[r + y][x] = &*varying; - } - } - - return true; - } - } - } - } - else if (elements == 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] >= registers && (space[column] < registers || space[x] < space[column])) - { - column = x; - } - } - - if (space[column] >= registers) - { - for (int r = 0; r < maxVaryingVectors; r++) - { - if (!packing[r][column]) - { - varying->registerIndex = r; - varying->columnIndex = column; - - for (int y = r; y < r + registers; y++) - { - packing[y][column] = &*varying; - } - - break; - } - } - - return true; - } - } - else UNREACHABLE(); - - return false; -} - -// 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 DynamicHLSL::packVaryings(InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader, - ShaderD3D *vertexShader, const std::vector &transformFeedbackVaryings) -{ - // TODO (geofflang): Use context's caps - const int maxVaryingVectors = mRenderer->getRendererCaps().maxVaryingVectors; - - vertexShader->resetVaryingsRegisterAssignment(); - fragmentShader->resetVaryingsRegisterAssignment(); - - std::set packedVaryings; - - std::vector &fragmentVaryings = fragmentShader->getVaryings(); - std::vector &vertexVaryings = vertexShader->getVaryings(); - for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++) - { - PackedVarying *varying = &fragmentVaryings[varyingIndex]; - - // Do not assign registers to built-in or unreferenced varyings - if (varying->isBuiltIn() || !varying->staticUse) - { - continue; - } - - if (packVarying(varying, maxVaryingVectors, packing)) - { - packedVaryings.insert(varying->name); - } - else - { - infoLog.append("Could not pack varying %s", varying->name.c_str()); - return -1; - } - } - - for (unsigned int feedbackVaryingIndex = 0; feedbackVaryingIndex < transformFeedbackVaryings.size(); feedbackVaryingIndex++) - { - const std::string &transformFeedbackVarying = transformFeedbackVaryings[feedbackVaryingIndex]; - - if (transformFeedbackVarying == "gl_Position" || transformFeedbackVarying == "gl_PointSize") - { - // do not pack builtin XFB varyings - continue; - } - - if (packedVaryings.find(transformFeedbackVarying) == packedVaryings.end()) - { - bool found = false; - for (unsigned int varyingIndex = 0; varyingIndex < vertexVaryings.size(); varyingIndex++) - { - PackedVarying *varying = &vertexVaryings[varyingIndex]; - if (transformFeedbackVarying == varying->name) - { - if (!packVarying(varying, maxVaryingVectors, packing)) - { - infoLog.append("Could not pack varying %s", varying->name.c_str()); - return -1; - } - - found = true; - break; - } - } - - if (!found) - { - infoLog.append("Transform feedback varying %s does not exist in the vertex shader.", transformFeedbackVarying.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; -} - -std::string DynamicHLSL::generateVaryingHLSL(const ShaderD3D *shader) const -{ - std::string varyingSemantic = getVaryingSemantic(shader->mUsesPointSize); - std::string varyingHLSL; - - const std::vector &varyings = shader->getVaryings(); - - for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++) - { - const PackedVarying &varying = varyings[varyingIndex]; - if (varying.registerAssigned()) - { - ASSERT(!varying.isBuiltIn()); - GLenum transposedType = TransposeMatrixType(varying.type); - int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); - - for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) - { - for (int row = 0; row < variableRows; row++) - { - // TODO: Add checks to ensure D3D interpolation modifiers don't result in too many registers being used. - // For example, if there are N registers, and we have N vec3 varyings and 1 float varying, then D3D will pack them into N registers. - // If the float varying has the 'nointerpolation' modifier on it then we would need N + 1 registers, and D3D compilation will fail. - - switch (varying.interpolation) - { - case sh::INTERPOLATION_SMOOTH: varyingHLSL += " "; break; - case sh::INTERPOLATION_FLAT: varyingHLSL += " nointerpolation "; break; - case sh::INTERPOLATION_CENTROID: varyingHLSL += " centroid "; break; - default: UNREACHABLE(); - } - - unsigned int semanticIndex = elementIndex * variableRows + varying.columnIndex * mRenderer->getRendererCaps().maxVaryingVectors + varying.registerIndex + row; - std::string n = Str(semanticIndex); - - std::string typeString; - - if (varying.isStruct()) - { - // matrices within structs are not transposed, so - // do not use the special struct prefix "rm" - typeString = decorateVariable(varying.structName); - } - else - { - GLenum componentType = VariableComponentType(transposedType); - int columnCount = VariableColumnCount(transposedType); - typeString = HLSLComponentTypeString(componentType, columnCount); - } - varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n"; - } - } - } - } - - return varyingHLSL; -} - -std::string DynamicHLSL::generateVertexShaderForInputLayout(const std::string &sourceShader, - const VertexFormat inputLayout[], - const sh::Attribute shaderAttributes[]) const -{ - std::string structHLSL, initHLSL; - - int semanticIndex = 0; - unsigned int inputIndex = 0; - - for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) - { - const sh::Attribute &shaderAttribute = shaderAttributes[attributeIndex]; - if (!shaderAttribute.name.empty()) - { - ASSERT(inputIndex < MAX_VERTEX_ATTRIBS); - const VertexFormat &vertexFormat = inputLayout[inputIndex]; - - // HLSL code for input structure - if (IsMatrixType(shaderAttribute.type)) - { - // Matrix types are always transposed - structHLSL += " " + HLSLMatrixTypeString(TransposeMatrixType(shaderAttribute.type)); - } - else - { - GLenum componentType = mRenderer->getVertexComponentType(vertexFormat); - structHLSL += " " + HLSLComponentTypeString(componentType, VariableComponentCount(shaderAttribute.type)); - } - - structHLSL += " " + decorateVariable(shaderAttribute.name) + " : TEXCOORD" + Str(semanticIndex) + ";\n"; - semanticIndex += VariableRegisterCount(shaderAttribute.type); - - // HLSL code for initialization - initHLSL += " " + decorateVariable(shaderAttribute.name) + " = "; - - // Mismatched vertex attribute to vertex input may result in an undefined - // data reinterpretation (eg for pure integer->float, float->pure integer) - // TODO: issue warning with gl debug info extension, when supported - if (IsMatrixType(shaderAttribute.type) || - (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0) - { - initHLSL += generateAttributeConversionHLSL(vertexFormat, shaderAttribute); - } - else - { - initHLSL += "input." + decorateVariable(shaderAttribute.name); - } - - initHLSL += ";\n"; - - inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type)); - } - } - - std::string replacementHLSL = "struct VS_INPUT\n" - "{\n" + - structHLSL + - "};\n" - "\n" - "void initAttributes(VS_INPUT input)\n" - "{\n" + - initHLSL + - "}\n"; - - std::string vertexHLSL(sourceShader); - - size_t copyInsertionPos = vertexHLSL.find(VERTEX_ATTRIBUTE_STUB_STRING); - vertexHLSL.replace(copyInsertionPos, VERTEX_ATTRIBUTE_STUB_STRING.length(), replacementHLSL); - - return vertexHLSL; -} - -std::string DynamicHLSL::generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector &outputVariables, - bool usesFragDepth, const std::vector &outputLayout) const -{ - const int shaderModel = mRenderer->getMajorShaderModel(); - std::string targetSemantic = (shaderModel >= 4) ? "SV_TARGET" : "COLOR"; - std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH"; - - std::string declarationHLSL; - std::string copyHLSL; - - for (size_t layoutIndex = 0; layoutIndex < outputLayout.size(); ++layoutIndex) - { - GLenum binding = outputLayout[layoutIndex]; - - if (binding != GL_NONE) - { - unsigned int location = (binding - GL_COLOR_ATTACHMENT0); - - const PixelShaderOutputVariable &outputVariable = GetOutputAtLocation(outputVariables, location); - - declarationHLSL += " " + HLSLTypeString(outputVariable.type) + " " + outputVariable.name + - " : " + targetSemantic + Str(layoutIndex) + ";\n"; - - copyHLSL += " output." + outputVariable.name + " = " + outputVariable.source + ";\n"; - } - } - - if (usesFragDepth) - { - declarationHLSL += " float gl_Depth : " + depthSemantic + ";\n"; - copyHLSL += " output.gl_Depth = gl_Depth; \n"; - } - - std::string replacementHLSL = "struct PS_OUTPUT\n" - "{\n" + - declarationHLSL + - "};\n" - "\n" - "PS_OUTPUT generateOutput()\n" - "{\n" - " PS_OUTPUT output;\n" + - copyHLSL + - " return output;\n" - "}\n"; - - std::string pixelHLSL(sourceShader); - - size_t outputInsertionPos = pixelHLSL.find(PIXEL_OUTPUT_STUB_STRING); - pixelHLSL.replace(outputInsertionPos, PIXEL_OUTPUT_STUB_STRING.length(), replacementHLSL); - - return pixelHLSL; -} - -std::string DynamicHLSL::getVaryingSemantic(bool pointSize) const -{ - // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) - // In D3D11 we manually compute gl_PointCoord in the GS. - int shaderModel = mRenderer->getMajorShaderModel(); - return ((pointSize && shaderModel < 4) ? "COLOR" : "TEXCOORD"); -} - -struct DynamicHLSL::SemanticInfo -{ - struct BuiltinInfo - { - BuiltinInfo() - : enabled(false), - index(0), - systemValue(false) - {} - - bool enabled; - std::string semantic; - unsigned int index; - bool systemValue; - - std::string str() const - { - return (systemValue ? semantic : (semantic + Str(index))); - } - - void enableSystem(const std::string &systemValueSemantic) - { - enabled = true; - semantic = systemValueSemantic; - systemValue = true; - } - - void enable(const std::string &semanticVal, unsigned int indexVal) - { - enabled = true; - semantic = semanticVal; - index = indexVal; - } - }; - - BuiltinInfo dxPosition; - BuiltinInfo glPosition; - BuiltinInfo glFragCoord; - BuiltinInfo glPointCoord; - BuiltinInfo glPointSize; -}; - -DynamicHLSL::SemanticInfo DynamicHLSL::getSemanticInfo(int startRegisters, bool fragCoord, bool pointCoord, - bool pointSize, bool pixelShader) const -{ - SemanticInfo info; - bool hlsl4 = (mRenderer->getMajorShaderModel() >= 4); - const std::string &varyingSemantic = getVaryingSemantic(pointSize); - - int reservedRegisterIndex = startRegisters; - - if (hlsl4) - { - info.dxPosition.enableSystem("SV_Position"); - } - else if (pixelShader) - { - info.dxPosition.enableSystem("VPOS"); - } - else - { - info.dxPosition.enableSystem("POSITION"); - } - - info.glPosition.enable(varyingSemantic, reservedRegisterIndex++); - - if (fragCoord) - { - info.glFragCoord.enable(varyingSemantic, reservedRegisterIndex++); - } - - if (pointCoord) - { - // SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord) - // In D3D11 we manually compute gl_PointCoord in the GS. - if (hlsl4) - { - info.glPointCoord.enable(varyingSemantic, reservedRegisterIndex++); - } - else - { - info.glPointCoord.enable("TEXCOORD", 0); - } - } - - // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders - if (pointSize && (!pixelShader || hlsl4)) - { - info.glPointSize.enableSystem("PSIZE"); - } - - return info; -} - -std::string DynamicHLSL::generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const -{ - std::string linkHLSL = "{\n"; - - ASSERT(info.dxPosition.enabled && info.glPosition.enabled); - - linkHLSL += " float4 dx_Position : " + info.dxPosition.str() + ";\n"; - linkHLSL += " float4 gl_Position : " + info.glPosition.str() + ";\n"; - - if (info.glFragCoord.enabled) - { - linkHLSL += " float4 gl_FragCoord : " + info.glFragCoord.str() + ";\n"; - } - - if (info.glPointCoord.enabled) - { - linkHLSL += " float2 gl_PointCoord : " + info.glPointCoord.str() + ";\n"; - } - - linkHLSL += varyingHLSL; - - if (info.glPointSize.enabled) - { - linkHLSL += " float gl_PointSize : " + info.glPointSize.str() + ";\n"; - } - - linkHLSL += "};\n"; - - return linkHLSL; -} - -void DynamicHLSL::storeBuiltinLinkedVaryings(const SemanticInfo &info, - std::vector *linkedVaryings) const -{ - ASSERT(info.glPosition.enabled); - - linkedVaryings->push_back(LinkedVarying("gl_Position", GL_FLOAT_VEC4, 1, info.glPosition.semantic, - info.glPosition.index, 1)); - - if (info.glFragCoord.enabled) - { - linkedVaryings->push_back(LinkedVarying("gl_FragCoord", GL_FLOAT_VEC4, 1, info.glFragCoord.semantic, - info.glFragCoord.index, 1)); - } - - if (info.glPointSize.enabled) - { - linkedVaryings->push_back(LinkedVarying("gl_PointSize", GL_FLOAT, 1, "PSIZE", 0, 1)); - } -} - -void DynamicHLSL::storeUserLinkedVaryings(const ShaderD3D *vertexShader, - std::vector *linkedVaryings) const -{ - const std::string &varyingSemantic = getVaryingSemantic(vertexShader->mUsesPointSize); - const std::vector &varyings = vertexShader->getVaryings(); - - for (unsigned int varyingIndex = 0; varyingIndex < varyings.size(); varyingIndex++) - { - const PackedVarying &varying = varyings[varyingIndex]; - - if (varying.registerAssigned()) - { - ASSERT(!varying.isBuiltIn()); - GLenum transposedType = TransposeMatrixType(varying.type); - int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); - - linkedVaryings->push_back(LinkedVarying(varying.name, varying.type, varying.elementCount(), - varyingSemantic, varying.registerIndex, - variableRows * varying.elementCount())); - } - } -} - -bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog, int registers, - const VaryingPacking packing, - std::string &pixelHLSL, std::string &vertexHLSL, - ShaderD3D *fragmentShader, ShaderD3D *vertexShader, - const std::vector &transformFeedbackVaryings, - std::vector *linkedVaryings, - std::map *programOutputVars, - std::vector *outPixelShaderKey, - bool *outUsesFragDepth) const -{ - if (pixelHLSL.empty() || vertexHLSL.empty()) - { - return false; - } - - bool usesMRT = fragmentShader->mUsesMultipleRenderTargets; - bool usesFragColor = fragmentShader->mUsesFragColor; - bool usesFragData = fragmentShader->mUsesFragData; - bool usesFragCoord = fragmentShader->mUsesFragCoord; - bool usesPointCoord = fragmentShader->mUsesPointCoord; - bool usesPointSize = vertexShader->mUsesPointSize; - - if (usesFragColor && usesFragData) - { - infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader."); - return false; - } - - // Write the HLSL input/output declarations - const int shaderModel = mRenderer->getMajorShaderModel(); - const int registersNeeded = registers + (usesFragCoord ? 1 : 0) + (usesPointCoord ? 1 : 0); - - // Two cases when writing to gl_FragColor and using ESSL 1.0: - // - with a 3.0 context, the output color is copied to channel 0 - // - with a 2.0 context, the output color is broadcast to all channels - const bool broadcast = (fragmentShader->mUsesFragColor && data.clientVersion < 3); - const unsigned int numRenderTargets = (broadcast || usesMRT ? data.caps->maxDrawBuffers : 1); - - int shaderVersion = vertexShader->getShaderVersion(); - - if (static_cast(registersNeeded) > data.caps->maxVaryingVectors) - { - infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord"); - return false; - } - - const std::string &varyingHLSL = generateVaryingHLSL(vertexShader); - const SemanticInfo &vertexSemantics = getSemanticInfo(registers, usesFragCoord, - false, usesPointSize, false); - - storeUserLinkedVaryings(vertexShader, linkedVaryings); - storeBuiltinLinkedVaryings(vertexSemantics, linkedVaryings); - - // Add stub string to be replaced when shader is dynamically defined by its layout - vertexHLSL += "\n" + VERTEX_ATTRIBUTE_STUB_STRING + "\n" - "struct VS_OUTPUT\n" + generateVaryingLinkHLSL(vertexSemantics, varyingHLSL) + "\n" - "VS_OUTPUT main(VS_INPUT input)\n" - "{\n" - " initAttributes(input);\n"; - - if (shaderModel >= 4) - { - vertexHLSL += "\n" - " gl_main();\n" - "\n" - " VS_OUTPUT output;\n" - " output.gl_Position = gl_Position;\n" - " output.dx_Position.x = gl_Position.x;\n" - " output.dx_Position.y = -gl_Position.y;\n" - " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" - " output.dx_Position.w = gl_Position.w;\n"; - } - else - { - vertexHLSL += "\n" - " gl_main();\n" - "\n" - " VS_OUTPUT output;\n" - " output.gl_Position = gl_Position;\n" - " output.dx_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n" - " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n" - " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" - " output.dx_Position.w = gl_Position.w;\n"; - } - - if (usesPointSize && shaderModel >= 3) - { - vertexHLSL += " output.gl_PointSize = gl_PointSize;\n"; - } - - if (usesFragCoord) - { - vertexHLSL += " output.gl_FragCoord = gl_Position;\n"; - } - - const std::vector &vertexVaryings = vertexShader->getVaryings(); - for (unsigned int vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++) - { - const PackedVarying &varying = vertexVaryings[vertVaryingIndex]; - if (varying.registerAssigned()) - { - for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) - { - int variableRows = (varying.isStruct() ? 1 : VariableRowCount(TransposeMatrixType(varying.type))); - - for (int row = 0; row < variableRows; row++) - { - int r = varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row; - vertexHLSL += " output.v" + Str(r); - - vertexHLSL += " = _" + varying.name; - - if (varying.isArray()) - { - vertexHLSL += ArrayString(elementIndex); - } - - if (variableRows > 1) - { - vertexHLSL += ArrayString(row); - } - - vertexHLSL += ";\n"; - } - } - } - } - - vertexHLSL += "\n" - " return output;\n" - "}\n"; - - const SemanticInfo &pixelSemantics = getSemanticInfo(registers, usesFragCoord, usesPointCoord, - usesPointSize, true); - - pixelHLSL += "struct PS_INPUT\n" + generateVaryingLinkHLSL(pixelSemantics, varyingHLSL) + "\n"; - - if (shaderVersion < 300) - { - for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++) - { - PixelShaderOutputVariable outputKeyVariable; - outputKeyVariable.type = GL_FLOAT_VEC4; - outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex); - outputKeyVariable.source = broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]"; - outputKeyVariable.outputIndex = renderTargetIndex; - - outPixelShaderKey->push_back(outputKeyVariable); - } - - *outUsesFragDepth = fragmentShader->mUsesFragDepth; - } - else - { - defineOutputVariables(fragmentShader, programOutputVars); - - const std::vector &shaderOutputVars = fragmentShader->getActiveOutputVariables(); - for (auto locationIt = programOutputVars->begin(); locationIt != programOutputVars->end(); locationIt++) - { - const VariableLocation &outputLocation = locationIt->second; - const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index]; - const std::string &variableName = "out_" + outputLocation.name; - const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : Str(outputLocation.element)); - - ASSERT(outputVariable.staticUse); - - PixelShaderOutputVariable outputKeyVariable; - outputKeyVariable.type = outputVariable.type; - outputKeyVariable.name = variableName + elementString; - outputKeyVariable.source = variableName + ArrayString(outputLocation.element); - outputKeyVariable.outputIndex = locationIt->first; - - outPixelShaderKey->push_back(outputKeyVariable); - } - - *outUsesFragDepth = false; - } - - pixelHLSL += PIXEL_OUTPUT_STUB_STRING + "\n"; - - if (fragmentShader->mUsesFrontFacing) - { - if (shaderModel >= 4) - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n" - "{\n"; - } - else - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n" - "{\n"; - } - } - else - { - pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n" - "{\n"; - } - - if (usesFragCoord) - { - pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n"; - - if (shaderModel >= 4) - { - pixelHLSL += " gl_FragCoord.x = input.dx_Position.x;\n" - " gl_FragCoord.y = input.dx_Position.y;\n"; - } - else if (shaderModel >= 3) - { - pixelHLSL += " gl_FragCoord.x = input.dx_Position.x + 0.5;\n" - " gl_FragCoord.y = input.dx_Position.y + 0.5;\n"; - } - else - { - // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport() - pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n" - " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n"; - } - - pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n" - " gl_FragCoord.w = rhw;\n"; - } - - if (usesPointCoord && shaderModel >= 3) - { - pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n"; - pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n"; - } - - if (fragmentShader->mUsesFrontFacing) - { - if (shaderModel <= 3) - { - pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n"; - } - else - { - pixelHLSL += " gl_FrontFacing = isFrontFace;\n"; - } - } - - const std::vector &fragmentVaryings = fragmentShader->getVaryings(); - for (unsigned int varyingIndex = 0; varyingIndex < fragmentVaryings.size(); varyingIndex++) - { - const PackedVarying &varying = fragmentVaryings[varyingIndex]; - if (varying.registerAssigned()) - { - ASSERT(!varying.isBuiltIn()); - for (unsigned int elementIndex = 0; elementIndex < varying.elementCount(); elementIndex++) - { - GLenum transposedType = TransposeMatrixType(varying.type); - int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); - for (int row = 0; row < variableRows; row++) - { - std::string n = Str(varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row); - pixelHLSL += " _" + varying.name; - - if (varying.isArray()) - { - pixelHLSL += ArrayString(elementIndex); - } - - if (variableRows > 1) - { - pixelHLSL += ArrayString(row); - } - - if (varying.isStruct()) - { - pixelHLSL += " = input.v" + n + ";\n"; break; - } - else - { - switch (VariableColumnCount(transposedType)) - { - case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break; - case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break; - case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break; - case 4: pixelHLSL += " = input.v" + n + ";\n"; break; - default: UNREACHABLE(); - } - } - } - } - } - else - { - ASSERT(varying.isBuiltIn() || !varying.staticUse); - } - } - - pixelHLSL += "\n" - " gl_main();\n" - "\n" - " return generateOutput();\n" - "}\n"; - - return true; -} - -void DynamicHLSL::defineOutputVariables(ShaderD3D *fragmentShader, std::map *programOutputVars) const -{ - const std::vector &shaderOutputVars = fragmentShader->getActiveOutputVariables(); - - for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size(); outputVariableIndex++) - { - const sh::Attribute &outputVariable = shaderOutputVars[outputVariableIndex]; - const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location; - - ASSERT(outputVariable.staticUse); - - if (outputVariable.arraySize > 0) - { - for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++) - { - const int location = baseLocation + elementIndex; - ASSERT(programOutputVars->count(location) == 0); - (*programOutputVars)[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex); - } - } - else - { - ASSERT(programOutputVars->count(baseLocation) == 0); - (*programOutputVars)[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex); - } - } -} - -std::string DynamicHLSL::generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const -{ - // for now we only handle point sprite emulation - ASSERT(vertexShader->mUsesPointSize && mRenderer->getMajorShaderModel() >= 4); - return generatePointSpriteHLSL(registers, fragmentShader, vertexShader); -} - -std::string DynamicHLSL::generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const -{ - ASSERT(registers >= 0); - ASSERT(vertexShader->mUsesPointSize); - ASSERT(mRenderer->getMajorShaderModel() >= 4); - - std::string geomHLSL; - - const SemanticInfo &inSemantics = getSemanticInfo(registers, fragmentShader->mUsesFragCoord, - false, true, false); - const SemanticInfo &outSemantics = getSemanticInfo(registers, fragmentShader->mUsesFragCoord, - fragmentShader->mUsesPointCoord, true, false); - - std::string varyingHLSL = generateVaryingHLSL(vertexShader); - std::string inLinkHLSL = generateVaryingLinkHLSL(inSemantics, varyingHLSL); - std::string outLinkHLSL = generateVaryingLinkHLSL(outSemantics, varyingHLSL); - - // TODO(geofflang): use context's caps - geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n" - "\n" - "struct GS_INPUT\n" + inLinkHLSL + "\n" + - "struct GS_OUTPUT\n" + outLinkHLSL + "\n" + - "\n" - "static float2 pointSpriteCorners[] = \n" - "{\n" - " float2( 0.5f, -0.5f),\n" - " float2( 0.5f, 0.5f),\n" - " float2(-0.5f, -0.5f),\n" - " float2(-0.5f, 0.5f)\n" - "};\n" - "\n" - "static float2 pointSpriteTexcoords[] = \n" - "{\n" - " float2(1.0f, 1.0f),\n" - " float2(1.0f, 0.0f),\n" - " float2(0.0f, 1.0f),\n" - " float2(0.0f, 0.0f)\n" - "};\n" - "\n" - "static float minPointSize = " + Str(mRenderer->getRendererCaps().minAliasedPointSize) + ".0f;\n" - "static float maxPointSize = " + Str(mRenderer->getRendererCaps().maxAliasedPointSize) + ".0f;\n" - "\n" - "[maxvertexcount(4)]\n" - "void main(point GS_INPUT input[1], inout TriangleStream outStream)\n" - "{\n" - " GS_OUTPUT output = (GS_OUTPUT)0;\n" - " output.gl_Position = input[0].gl_Position;\n" - " output.gl_PointSize = input[0].gl_PointSize;\n"; - - for (int r = 0; r < registers; r++) - { - geomHLSL += " output.v" + Str(r) + " = input[0].v" + Str(r) + ";\n"; - } - - if (fragmentShader->mUsesFragCoord) - { - geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n"; - } - - geomHLSL += " \n" - " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n" - " float4 dx_Position = input[0].dx_Position;\n" - " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * dx_Position.w;\n"; - - for (int corner = 0; corner < 4; corner++) - { - geomHLSL += " \n" - " output.dx_Position = dx_Position + float4(pointSpriteCorners[" + Str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n"; - - if (fragmentShader->mUsesPointCoord) - { - geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + Str(corner) + "];\n"; - } - - geomHLSL += " outStream.Append(output);\n"; - } - - geomHLSL += " \n" - " outStream.RestartStrip();\n" - "}\n"; - - return geomHLSL; -} - -// This method needs to match OutputHLSL::decorate -std::string DynamicHLSL::decorateVariable(const std::string &name) -{ - if (name.compare(0, 3, "gl_") != 0) - { - return "_" + name; - } - - return name; -} - -std::string DynamicHLSL::generateAttributeConversionHLSL(const VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const -{ - std::string attribString = "input." + decorateVariable(shaderAttrib.name); - - // Matrix - if (IsMatrixType(shaderAttrib.type)) - { - return "transpose(" + attribString + ")"; - } - - GLenum shaderComponentType = VariableComponentType(shaderAttrib.type); - int shaderComponentCount = VariableComponentCount(shaderAttrib.type); - - // Perform integer to float conversion (if necessary) - bool requiresTypeConversion = (shaderComponentType == GL_FLOAT && vertexFormat.mType != GL_FLOAT); - - if (requiresTypeConversion) - { - // TODO: normalization for 32-bit integer formats - ASSERT(!vertexFormat.mNormalized && !vertexFormat.mPureInteger); - return "float" + Str(shaderComponentCount) + "(" + attribString + ")"; - } - - // No conversion necessary - return attribString; -} - -void DynamicHLSL::getInputLayoutSignature(const VertexFormat inputLayout[], GLenum signature[]) const -{ - for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++) - { - const VertexFormat &vertexFormat = inputLayout[inputIndex]; - - if (vertexFormat.mType == GL_NONE) - { - signature[inputIndex] = GL_NONE; - } - else - { - bool gpuConverted = ((mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0); - signature[inputIndex] = (gpuConverted ? GL_TRUE : GL_FALSE); - } - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h deleted file mode 100644 index c46bbf6ce0..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright (c) 2014 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. -// -// DynamicHLSL.h: Interface for link and run-time HLSL generation -// - -#ifndef LIBGLESV2_RENDERER_DYNAMIC_HLSL_H_ -#define LIBGLESV2_RENDERER_DYNAMIC_HLSL_H_ - -#include "common/angleutils.h" -#include "libGLESv2/Constants.h" - -#include "angle_gl.h" - -#include -#include - -namespace sh -{ -struct Attribute; -struct ShaderVariable; -} - -namespace gl -{ -class InfoLog; -struct VariableLocation; -struct LinkedVarying; -struct VertexAttribute; -struct VertexFormat; -struct PackedVarying; -struct Data; -} - -namespace rx -{ -class RendererD3D; -class ShaderD3D; - -typedef const gl::PackedVarying *VaryingPacking[gl::IMPLEMENTATION_MAX_VARYING_VECTORS][4]; - -struct PixelShaderOutputVariable -{ - GLenum type; - std::string name; - std::string source; - size_t outputIndex; -}; - -class DynamicHLSL -{ - public: - explicit DynamicHLSL(RendererD3D *const renderer); - - int packVaryings(gl::InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader, - ShaderD3D *vertexShader, const std::vector& transformFeedbackVaryings); - std::string generateVertexShaderForInputLayout(const std::string &sourceShader, const gl::VertexFormat inputLayout[], - const sh::Attribute shaderAttributes[]) const; - std::string generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector &outputVariables, - bool usesFragDepth, const std::vector &outputLayout) const; - bool generateShaderLinkHLSL(const gl::Data &data, gl::InfoLog &infoLog, int registers, - const VaryingPacking packing, - std::string &pixelHLSL, std::string &vertexHLSL, - ShaderD3D *fragmentShader, ShaderD3D *vertexShader, - const std::vector &transformFeedbackVaryings, - std::vector *linkedVaryings, - std::map *programOutputVars, - std::vector *outPixelShaderKey, - bool *outUsesFragDepth) const; - - std::string generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const; - void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; - - private: - DISALLOW_COPY_AND_ASSIGN(DynamicHLSL); - - RendererD3D *const mRenderer; - - struct SemanticInfo; - - std::string getVaryingSemantic(bool pointSize) const; - SemanticInfo getSemanticInfo(int startRegisters, bool fragCoord, bool pointCoord, bool pointSize, - bool pixelShader) const; - std::string generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const; - std::string generateVaryingHLSL(const ShaderD3D *shader) const; - void storeUserLinkedVaryings(const ShaderD3D *vertexShader, std::vector *linkedVaryings) const; - void storeBuiltinLinkedVaryings(const SemanticInfo &info, std::vector *linkedVaryings) const; - void defineOutputVariables(ShaderD3D *fragmentShader, std::map *programOutputVars) const; - std::string generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const; - - // Prepend an underscore - static std::string decorateVariable(const std::string &name); - - std::string generateAttributeConversionHLSL(const gl::VertexFormat &vertexFormat, const sh::ShaderVariable &shaderAttrib) const; -}; - -} - -#endif // LIBGLESV2_RENDERER_DYNAMIC_HLSL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp deleted file mode 100644 index 776d92b202..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp +++ /dev/null @@ -1,333 +0,0 @@ -// -// Copyright 2014 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 "libGLESv2/renderer/d3d/HLSLCompiler.h" -#include "libGLESv2/Program.h" -#include "libGLESv2/main.h" - -#include "common/features.h" -#include "common/utilities.h" - -#ifndef QT_D3DCOMPILER_DLL -#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL -#endif -#ifndef D3DCOMPILE_RESERVED16 -#define D3DCOMPILE_RESERVED16 (1 << 16) -#endif -#ifndef D3DCOMPILE_RESERVED17 -#define D3DCOMPILE_RESERVED17 (1 << 17) -#endif - -// Definitions local to the translation unit -namespace -{ - -#ifdef CREATE_COMPILER_FLAG_INFO - #undef CREATE_COMPILER_FLAG_INFO -#endif - -#define CREATE_COMPILER_FLAG_INFO(flag) { flag, #flag } - -struct CompilerFlagInfo -{ - UINT mFlag; - const char *mName; -}; - -CompilerFlagInfo CompilerFlagInfos[] = -{ - // NOTE: The data below is copied from d3dcompiler.h - // If something changes there it should be changed here as well - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_DEBUG), // (1 << 0) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_VALIDATION), // (1 << 1) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_OPTIMIZATION), // (1 << 2) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_ROW_MAJOR), // (1 << 3) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR), // (1 << 4) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PARTIAL_PRECISION), // (1 << 5) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT), // (1 << 6) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT), // (1 << 7) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_NO_PRESHADER), // (1 << 8) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_AVOID_FLOW_CONTROL), // (1 << 9) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PREFER_FLOW_CONTROL), // (1 << 10) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_STRICTNESS), // (1 << 11) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY), // (1 << 12) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_IEEE_STRICTNESS), // (1 << 13) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL0), // (1 << 14) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL1), // 0 - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL2), // ((1 << 14) | (1 << 15)) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL3), // (1 << 15) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED16), // (1 << 16) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED17), // (1 << 17) - CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_WARNINGS_ARE_ERRORS) // (1 << 18) -}; - -#undef CREATE_COMPILER_FLAG_INFO - -bool IsCompilerFlagSet(UINT mask, UINT flag) -{ - bool isFlagSet = IsMaskFlagSet(mask, flag); - - switch(flag) - { - case D3DCOMPILE_OPTIMIZATION_LEVEL0: - return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL3)); - - case D3DCOMPILE_OPTIMIZATION_LEVEL1: - return (mask & D3DCOMPILE_OPTIMIZATION_LEVEL2) == UINT(0); - - case D3DCOMPILE_OPTIMIZATION_LEVEL3: - return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL0)); - - default: - return isFlagSet; - } -} - -const char *GetCompilerFlagName(UINT mask, size_t flagIx) -{ - const CompilerFlagInfo &flagInfo = CompilerFlagInfos[flagIx]; - if (IsCompilerFlagSet(mask, flagInfo.mFlag)) - { - return flagInfo.mName; - } - - return nullptr; -} - -} - -namespace rx -{ - -CompileConfig::CompileConfig() - : flags(0), - name() -{ -} - -CompileConfig::CompileConfig(UINT flags, const std::string &name) - : flags(flags), - name(name) -{ -} - -HLSLCompiler::HLSLCompiler() - : mD3DCompilerModule(NULL), - mD3DCompileFunc(NULL), - mD3DDisassembleFunc(NULL) -{ -} - -HLSLCompiler::~HLSLCompiler() -{ - release(); -} - -bool HLSLCompiler::initialize() -{ -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) -#if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) - // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. - static const char *d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES; - - for (size_t i = 0; i < ArraySize(d3dCompilerNames); ++i) - { - if (GetModuleHandleExA(0, d3dCompilerNames[i], &mD3DCompilerModule)) - { - break; - } - } -#endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES - - // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL - const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); - if (!defaultCompiler) - defaultCompiler = QT_D3DCOMPILER_DLL; - - const wchar_t *compilerDlls[] = { - defaultCompiler, - L"d3dcompiler_47.dll", - L"d3dcompiler_46.dll", - L"d3dcompiler_45.dll", - L"d3dcompiler_44.dll", - L"d3dcompiler_43.dll", - 0 - }; - - // Load the first available known compiler DLL - for (int i = 0; compilerDlls[i]; ++i) - { - mD3DCompilerModule = LoadLibrary(compilerDlls[i]); - if (mD3DCompilerModule) - break; - } - - if (!mD3DCompilerModule) - { - // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. - mD3DCompilerModule = LoadLibrary(D3DCOMPILER_DLL); - } - - if (!mD3DCompilerModule) - { - ERR("No D3D compiler module found - aborting!\n"); - return false; - } - - mD3DCompileFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DCompile")); - ASSERT(mD3DCompileFunc); - - mD3DDisassembleFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DDisassemble")); - ASSERT(mD3DDisassembleFunc); - -#else - // D3D Shader compiler is linked already into this module, so the export - // can be directly assigned. - mD3DCompilerModule = NULL; - mD3DCompileFunc = reinterpret_cast(D3DCompile); - mD3DDisassembleFunc = reinterpret_cast(D3DDisassemble); -#endif - - return mD3DCompileFunc != NULL; -} - -void HLSLCompiler::release() -{ - if (mD3DCompilerModule) - { - FreeLibrary(mD3DCompilerModule); - mD3DCompilerModule = NULL; - mD3DCompileFunc = NULL; - mD3DDisassembleFunc = NULL; - } -} - -gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, - const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, - ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const -{ -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - ASSERT(mD3DCompilerModule); -#endif - ASSERT(mD3DCompileFunc); - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - if (gl::perfActive()) - { - std::string sourcePath = getTempPath(); - std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str()); - writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); - } -#endif - - const D3D_SHADER_MACRO *macros = overrideMacros ? overrideMacros : NULL; - - for (size_t i = 0; i < configs.size(); ++i) - { - ID3DBlob *errorMessage = NULL; - ID3DBlob *binary = NULL; - - HRESULT result = mD3DCompileFunc(hlsl.c_str(), hlsl.length(), gl::g_fakepath, macros, NULL, "main", profile.c_str(), - configs[i].flags, 0, &binary, &errorMessage); - - if (errorMessage) - { - std::string message = reinterpret_cast(errorMessage->GetBufferPointer()); - SafeRelease(errorMessage); - - infoLog.appendSanitized(message.c_str()); - TRACE("\n%s", hlsl.c_str()); - TRACE("\n%s", message.c_str()); - - if (message.find("error X3531:") != std::string::npos) // "can't unroll loops marked with loop attribute" - { - macros = NULL; // Disable [loop] and [flatten] - - // Retry without changing compiler flags - i--; - continue; - } - } - - if (SUCCEEDED(result)) - { - *outCompiledBlob = binary; - -#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED - (*outDebugInfo) += "// COMPILER INPUT HLSL BEGIN\n\n" + hlsl + "\n// COMPILER INPUT HLSL END\n"; - (*outDebugInfo) += "\n\n// ASSEMBLY BEGIN\n\n"; - (*outDebugInfo) += "// Compiler configuration: " + configs[i].name + "\n// Flags:\n"; - for (size_t fIx = 0; fIx < ArraySize(CompilerFlagInfos); ++fIx) - { - const char *flagName = GetCompilerFlagName(configs[i].flags, fIx); - if (flagName != nullptr) - { - (*outDebugInfo) += std::string("// ") + flagName + "\n"; - } - } - - (*outDebugInfo) += "// Macros:\n"; - if (macros == nullptr) - { - (*outDebugInfo) += "// - : -\n"; - } - else - { - for (const D3D_SHADER_MACRO *mIt = macros; mIt->Name != nullptr; ++mIt) - { - (*outDebugInfo) += std::string("// ") + mIt->Name + " : " + mIt->Definition + "\n"; - } - } - - (*outDebugInfo) += "\n" + disassembleBinary(binary) + "\n// ASSEMBLY END\n"; -#endif - - return gl::Error(GL_NO_ERROR); - } - else - { - if (result == E_OUTOFMEMORY) - { - *outCompiledBlob = NULL; - return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result); - } - - infoLog.append("Warning: D3D shader compilation failed with %s flags.", configs[i].name.c_str()); - - if (i + 1 < configs.size()) - { - infoLog.append(" Retrying with %s.\n", configs[i + 1].name.c_str()); - } - } - } - - // None of the configurations succeeded in compiling this shader but the compiler is still intact - *outCompiledBlob = NULL; - return gl::Error(GL_NO_ERROR); -} - -std::string HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary) const -{ - // Retrieve disassembly - UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING; - ID3DBlob *disassembly = NULL; - pD3DDisassemble disassembleFunc = reinterpret_cast(mD3DDisassembleFunc); - LPCVOID buffer = shaderBinary->GetBufferPointer(); - SIZE_T bufSize = shaderBinary->GetBufferSize(); - HRESULT result = disassembleFunc(buffer, bufSize, flags, "", &disassembly); - - std::string asmSrc; - if (SUCCEEDED(result)) - { - asmSrc = reinterpret_cast(disassembly->GetBufferPointer()); - } - - SafeRelease(disassembly); - - return asmSrc; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h deleted file mode 100644 index ff56f8035a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ -#define LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ - -#include "libGLESv2/Error.h" - -#include "common/angleutils.h" -#include "common/platform.h" - -#include -#include - -namespace gl -{ -class InfoLog; -} - -namespace rx -{ - -struct CompileConfig -{ - UINT flags; - std::string name; - - CompileConfig(); - CompileConfig(UINT flags, const std::string &name); -}; - -class HLSLCompiler -{ - public: - HLSLCompiler(); - ~HLSLCompiler(); - - bool initialize(); - void release(); - - // Attempt to compile a HLSL shader using the supplied configurations, may output a NULL compiled blob - // even if no GL errors are returned. - gl::Error compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, - const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, - ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const; - - std::string disassembleBinary(ID3DBlob* shaderBinary) const; - - private: - DISALLOW_COPY_AND_ASSIGN(HLSLCompiler); - - HMODULE mD3DCompilerModule; - pD3DCompile mD3DCompileFunc; - pD3DDisassemble mD3DDisassembleFunc; -}; - -} - -#endif // LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp deleted file mode 100644 index 12b919ab5a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// -// 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. -// - -// Image.h: Implements the rx::Image class, an abstract base class for the -// renderer-specific classes which will define the interface to the underlying -// surfaces or resources. - -#include "libGLESv2/renderer/d3d/ImageD3D.h" - -namespace rx -{ - -ImageD3D::ImageD3D() -{ -} - -ImageD3D *ImageD3D::makeImageD3D(Image *img) -{ - ASSERT(HAS_DYNAMIC_TYPE(ImageD3D*, img)); - return static_cast(img); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h deleted file mode 100644 index 554ca0cee0..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// 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. -// - -// Image.h: Defines the rx::Image class, an abstract base class for the -// renderer-specific classes which will define the interface to the underlying -// surfaces or resources. - -#ifndef LIBGLESV2_RENDERER_IMAGED3D_H_ -#define LIBGLESV2_RENDERER_IMAGED3D_H_ - -#include "common/debug.h" -#include "libGLESv2/renderer/Image.h" - -namespace gl -{ -class Framebuffer; -struct ImageIndex; -struct Box; -} - -namespace rx -{ -class TextureStorage; - -class ImageD3D : public Image -{ - public: - ImageD3D(); - virtual ~ImageD3D() {}; - - static ImageD3D *makeImageD3D(Image *img); - - virtual bool isDirty() const = 0; - - virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; - virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level) { return gl::Error(GL_NO_ERROR); }; - virtual gl::Error setManagedSurface3D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; - virtual gl::Error setManagedSurface2DArray(TextureStorage *storage, int layer, int level) { return gl::Error(GL_NO_ERROR); }; - virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(ImageD3D); -}; - -} - -#endif // LIBGLESV2_RENDERER_IMAGED3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp deleted file mode 100644 index aa614f6cc4..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp +++ /dev/null @@ -1,199 +0,0 @@ -// -// 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. -// - -// IndexBuffer.cpp: Defines the abstract IndexBuffer class and IndexBufferInterface -// class with derivations, classes that perform graphics API agnostic index buffer operations. - -#include "libGLESv2/renderer/d3d/IndexBuffer.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" - -namespace rx -{ - -unsigned int IndexBuffer::mNextSerial = 1; - -IndexBuffer::IndexBuffer() -{ - updateSerial(); -} - -IndexBuffer::~IndexBuffer() -{ -} - -unsigned int IndexBuffer::getSerial() const -{ - return mSerial; -} - -void IndexBuffer::updateSerial() -{ - mSerial = mNextSerial++; -} - - -IndexBufferInterface::IndexBufferInterface(RendererD3D *renderer, bool dynamic) : mRenderer(renderer) -{ - mIndexBuffer = renderer->createIndexBuffer(); - - mDynamic = dynamic; - mWritePosition = 0; -} - -IndexBufferInterface::~IndexBufferInterface() -{ - if (mIndexBuffer) - { - delete mIndexBuffer; - } -} - -GLenum IndexBufferInterface::getIndexType() const -{ - return mIndexBuffer->getIndexType(); -} - -unsigned int IndexBufferInterface::getBufferSize() const -{ - return mIndexBuffer->getBufferSize(); -} - -unsigned int IndexBufferInterface::getSerial() const -{ - return mIndexBuffer->getSerial(); -} - -gl::Error IndexBufferInterface::mapBuffer(unsigned int size, void** outMappedMemory, unsigned int *streamOffset) -{ - // Protect against integer overflow - if (mWritePosition + size < mWritePosition) - { - return gl::Error(GL_OUT_OF_MEMORY, "Mapping of internal index buffer would cause an integer overflow."); - } - - gl::Error error = mIndexBuffer->mapBuffer(mWritePosition, size, outMappedMemory); - if (error.isError()) - { - if (outMappedMemory) - { - *outMappedMemory = NULL; - } - return error; - } - - if (streamOffset) - { - *streamOffset = mWritePosition; - } - - mWritePosition += size; - return gl::Error(GL_NO_ERROR); -} - -gl::Error IndexBufferInterface::unmapBuffer() -{ - return mIndexBuffer->unmapBuffer(); -} - -IndexBuffer * IndexBufferInterface::getIndexBuffer() const -{ - return mIndexBuffer; -} - -unsigned int IndexBufferInterface::getWritePosition() const -{ - return mWritePosition; -} - -void IndexBufferInterface::setWritePosition(unsigned int writePosition) -{ - mWritePosition = writePosition; -} - -gl::Error IndexBufferInterface::discard() -{ - return mIndexBuffer->discard(); -} - -gl::Error IndexBufferInterface::setBufferSize(unsigned int bufferSize, GLenum indexType) -{ - if (mIndexBuffer->getBufferSize() == 0) - { - return mIndexBuffer->initialize(bufferSize, indexType, mDynamic); - } - else - { - return mIndexBuffer->setSize(bufferSize, indexType); - } -} - -StreamingIndexBufferInterface::StreamingIndexBufferInterface(RendererD3D *renderer) : IndexBufferInterface(renderer, true) -{ -} - -StreamingIndexBufferInterface::~StreamingIndexBufferInterface() -{ -} - -gl::Error StreamingIndexBufferInterface::reserveBufferSpace(unsigned int size, GLenum indexType) -{ - unsigned int curBufferSize = getBufferSize(); - unsigned int writePos = getWritePosition(); - if (size > curBufferSize) - { - gl::Error error = setBufferSize(std::max(size, 2 * curBufferSize), indexType); - if (error.isError()) - { - return error; - } - setWritePosition(0); - } - else if (writePos + size > curBufferSize || writePos + size < writePos) - { - gl::Error error = discard(); - if (error.isError()) - { - return error; - } - setWritePosition(0); - } - - return gl::Error(GL_NO_ERROR); -} - - -StaticIndexBufferInterface::StaticIndexBufferInterface(RendererD3D *renderer) : IndexBufferInterface(renderer, false) -{ -} - -StaticIndexBufferInterface::~StaticIndexBufferInterface() -{ -} - -gl::Error StaticIndexBufferInterface::reserveBufferSpace(unsigned int size, GLenum indexType) -{ - unsigned int curSize = getBufferSize(); - if (curSize == 0) - { - return setBufferSize(size, indexType); - } - else if (curSize >= size && indexType == getIndexType()) - { - return gl::Error(GL_NO_ERROR); - } - else - { - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Internal static index buffers can't be resized"); - } -} - -IndexRangeCache *StaticIndexBufferInterface::getIndexRangeCache() -{ - return &mIndexRangeCache; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h deleted file mode 100644 index a34d30bbf3..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h +++ /dev/null @@ -1,112 +0,0 @@ -// -// 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. -// - -// IndexBuffer.h: Defines the abstract IndexBuffer class and IndexBufferInterface -// class with derivations, classes that perform graphics API agnostic index buffer operations. - -#ifndef LIBGLESV2_RENDERER_INDEXBUFFER_H_ -#define LIBGLESV2_RENDERER_INDEXBUFFER_H_ - -#include "common/angleutils.h" -#include "libGLESv2/Error.h" -#include "libGLESv2/renderer/IndexRangeCache.h" - -namespace rx -{ -class RendererD3D; - -class IndexBuffer -{ - public: - IndexBuffer(); - virtual ~IndexBuffer(); - - virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) = 0; - - virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) = 0; - virtual gl::Error unmapBuffer() = 0; - - virtual gl::Error discard() = 0; - - virtual GLenum getIndexType() const = 0; - virtual unsigned int getBufferSize() const = 0; - virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType) = 0; - - unsigned int getSerial() const; - - protected: - void updateSerial(); - - private: - DISALLOW_COPY_AND_ASSIGN(IndexBuffer); - - unsigned int mSerial; - static unsigned int mNextSerial; -}; - -class IndexBufferInterface -{ - public: - IndexBufferInterface(RendererD3D *renderer, bool dynamic); - virtual ~IndexBufferInterface(); - - virtual gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) = 0; - - GLenum getIndexType() const; - unsigned int getBufferSize() const; - - unsigned int getSerial() const; - - gl::Error mapBuffer(unsigned int size, void** outMappedMemory, unsigned int *streamOffset); - gl::Error unmapBuffer(); - - IndexBuffer *getIndexBuffer() const; - - protected: - unsigned int getWritePosition() const; - void setWritePosition(unsigned int writePosition); - - gl::Error discard(); - - gl::Error setBufferSize(unsigned int bufferSize, GLenum indexType); - - private: - DISALLOW_COPY_AND_ASSIGN(IndexBufferInterface); - - RendererD3D *const mRenderer; - - IndexBuffer* mIndexBuffer; - - unsigned int mWritePosition; - bool mDynamic; -}; - -class StreamingIndexBufferInterface : public IndexBufferInterface -{ - public: - StreamingIndexBufferInterface(RendererD3D *renderer); - ~StreamingIndexBufferInterface(); - - virtual gl::Error reserveBufferSpace(unsigned int size, GLenum indexType); -}; - -class StaticIndexBufferInterface : public IndexBufferInterface -{ - public: - explicit StaticIndexBufferInterface(RendererD3D *renderer); - ~StaticIndexBufferInterface(); - - virtual gl::Error reserveBufferSpace(unsigned int size, GLenum indexType); - - IndexRangeCache *getIndexRangeCache(); - - private: - IndexRangeCache mIndexRangeCache; -}; - -} - -#endif // LIBGLESV2_RENDERER_INDEXBUFFER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp deleted file mode 100644 index eddd9de887..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp +++ /dev/null @@ -1,271 +0,0 @@ -// -// Copyright (c) 2002-2014 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/renderer/d3d/IndexDataManager.h" -#include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/renderer/d3d/IndexBuffer.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/main.h" -#include "libGLESv2/formatutils.h" - -namespace rx -{ - -static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output) -{ - if (sourceType == GL_UNSIGNED_BYTE) - { - ASSERT(destinationType == GL_UNSIGNED_SHORT); - const GLubyte *in = static_cast(input); - GLushort *out = static_cast(output); - - for (GLsizei i = 0; i < count; i++) - { - out[i] = in[i]; - } - } - else if (sourceType == GL_UNSIGNED_INT) - { - ASSERT(destinationType == GL_UNSIGNED_INT); - memcpy(output, input, count * sizeof(GLuint)); - } - else if (sourceType == GL_UNSIGNED_SHORT) - { - if (destinationType == GL_UNSIGNED_SHORT) - { - memcpy(output, input, count * sizeof(GLushort)); - } - else if (destinationType == GL_UNSIGNED_INT) - { - const GLushort *in = static_cast(input); - GLuint *out = static_cast(output); - - for (GLsizei i = 0; i < count; i++) - { - out[i] = in[i]; - } - } - else UNREACHABLE(); - } - else UNREACHABLE(); -} - -IndexDataManager::IndexDataManager(RendererD3D *renderer) - : mRenderer(renderer), - mStreamingBufferShort(NULL), - mStreamingBufferInt(NULL) -{ -} - -IndexDataManager::~IndexDataManager() -{ - SafeDelete(mStreamingBufferShort); - SafeDelete(mStreamingBufferInt); -} - -gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated) -{ - const gl::Type &typeInfo = gl::GetTypeInfo(type); - - GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; - - unsigned int offset = 0; - bool alignedOffset = false; - - BufferD3D *storage = NULL; - - if (buffer != NULL) - { - offset = static_cast(reinterpret_cast(indices)); - - storage = BufferD3D::makeBufferD3D(buffer->getImplementation()); - - 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; - } - - ASSERT(typeInfo.bytes * static_cast(count) + offset <= storage->getSize()); - - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); - if (error.isError()) - { - return error; - } - - indices = bufferData + offset; - } - - StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL; - IndexBufferInterface *indexBuffer = NULL; - bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() && - destinationIndexType == type; - unsigned int streamOffset = 0; - - if (directStorage) - { - streamOffset = offset; - - if (!buffer->getIndexRangeCache()->findRange(type, offset, count, NULL, NULL)) - { - buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset); - } - } - else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) - { - indexBuffer = staticBuffer; - - if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, NULL, &streamOffset)) - { - streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes; - staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset); - } - } - - // Avoid D3D11's primitive restart index value - // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx - if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3) - { - destinationIndexType = GL_UNSIGNED_INT; - directStorage = false; - indexBuffer = NULL; - } - - const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType); - - if (!directStorage && !indexBuffer) - { - gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer); - if (error.isError()) - { - return error; - } - - unsigned int convertCount = count; - - if (staticBuffer) - { - if (staticBuffer->getBufferSize() == 0 && alignedOffset) - { - indexBuffer = staticBuffer; - convertCount = storage->getSize() / typeInfo.bytes; - } - else - { - storage->invalidateStaticData(); - staticBuffer = NULL; - } - } - - ASSERT(indexBuffer); - - if (convertCount > std::numeric_limits::max() / destTypeInfo.bytes) - { - return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.", - convertCount, destTypeInfo.bytes); - } - - unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes; - error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type); - if (error.isError()) - { - return error; - } - - void* output = NULL; - error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset); - if (error.isError()) - { - return error; - } - - const uint8_t *dataPointer = reinterpret_cast(indices); - if (staticBuffer) - { - error = storage->getData(&dataPointer); - if (error.isError()) - { - return error; - } - } - ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output); - - error = indexBuffer->unmapBuffer(); - if (error.isError()) - { - return error; - } - - if (staticBuffer) - { - streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes; - staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset); - } - } - - translated->storage = directStorage ? storage : NULL; - translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL; - translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); - translated->startIndex = streamOffset / destTypeInfo.bytes; - translated->startOffset = streamOffset; - translated->indexType = destinationIndexType; - - if (storage) - { - storage->promoteStaticUsage(count * typeInfo.bytes); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer) -{ - ASSERT(outBuffer); - if (destinationIndexType == GL_UNSIGNED_INT) - { - if (!mStreamingBufferInt) - { - mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer); - gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); - if (error.isError()) - { - SafeDelete(mStreamingBufferInt); - return error; - } - } - - *outBuffer = mStreamingBufferInt; - return gl::Error(GL_NO_ERROR); - } - else - { - ASSERT(destinationIndexType == GL_UNSIGNED_SHORT); - - if (!mStreamingBufferShort) - { - mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer); - gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); - if (error.isError()) - { - SafeDelete(mStreamingBufferShort); - return error; - } - } - - *outBuffer = mStreamingBufferShort; - return gl::Error(GL_NO_ERROR); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h deleted file mode 100644 index a1aee1588b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright (c) 2002-2014 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 "common/angleutils.h" -#include "common/mathutil.h" -#include "libGLESv2/Error.h" - -#include - -namespace -{ - enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) }; -} - -namespace gl -{ -class Buffer; -} - -namespace rx -{ -class IndexBufferInterface; -class StaticIndexBufferInterface; -class StreamingIndexBufferInterface; -class IndexBuffer; -class BufferD3D; -class RendererD3D; - -struct TranslatedIndexData -{ - RangeUI indexRange; - unsigned int startIndex; - unsigned int startOffset; // In bytes - - IndexBuffer *indexBuffer; - BufferD3D *storage; - GLenum indexType; - unsigned int serial; -}; - -class IndexDataManager -{ - public: - explicit IndexDataManager(RendererD3D *renderer); - virtual ~IndexDataManager(); - - gl::Error prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated); - - private: - gl::Error getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer); - - DISALLOW_COPY_AND_ASSIGN(IndexDataManager); - - RendererD3D *const mRenderer; - - StreamingIndexBufferInterface *mStreamingBufferShort; - StreamingIndexBufferInterface *mStreamingBufferInt; -}; - -} - -#endif // LIBGLESV2_INDEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp deleted file mode 100644 index 2b5b09a324..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (c) 2014 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 "libGLESv2/renderer/d3d/MemoryBuffer.h" -#include "common/debug.h" - -#include -#include - -namespace rx -{ - -MemoryBuffer::MemoryBuffer() - : mSize(0), - mData(NULL) -{ -} - -MemoryBuffer::~MemoryBuffer() -{ - free(mData); - mData = NULL; -} - -bool MemoryBuffer::resize(size_t size) -{ - if (size == 0) - { - free(mData); - mData = NULL; - mSize = 0; - } - else - { - uint8_t *newMemory = reinterpret_cast(malloc(sizeof(uint8_t) * size)); - if (newMemory == NULL) - { - return false; - } - - if (mData) - { - // Copy the intersection of the old data and the new data - std::copy(mData, mData + std::min(mSize, size), newMemory); - free(mData); - } - - mData = newMemory; - mSize = size; - } - - return true; -} - -size_t MemoryBuffer::size() const -{ - return mSize; -} - -const uint8_t *MemoryBuffer::data() const -{ - return mData; -} - -uint8_t *MemoryBuffer::data() -{ - ASSERT(mData); - return mData; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.h deleted file mode 100644 index c65f79fe10..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/MemoryBuffer.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (c) 2014 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 LIBGLESV2_RENDERER_D3D_MEMORYBUFFER_H_ -#define LIBGLESV2_RENDERER_D3D_MEMORYBUFFER_H_ - -#include -#include - -namespace rx -{ - -class MemoryBuffer -{ - public: - MemoryBuffer(); - ~MemoryBuffer(); - - bool resize(size_t size); - size_t size() const; - bool empty() const { return mSize == 0; } - - const uint8_t *data() const; - uint8_t *data(); - - private: - size_t mSize; - uint8_t *mData; -}; - -} - -#endif // LIBGLESV2_RENDERER_D3D_MEMORYBUFFER_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp deleted file mode 100644 index 75da78110e..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp +++ /dev/null @@ -1,1925 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. - -#include "libGLESv2/renderer/d3d/ProgramD3D.h" - -#include "common/features.h" -#include "common/utilities.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/Program.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/main.h" -#include "libGLESv2/renderer/ShaderExecutable.h" -#include "libGLESv2/renderer/d3d/DynamicHLSL.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/renderer/d3d/ShaderD3D.h" - -namespace rx -{ - -namespace -{ - -GLenum GetTextureType(GLenum samplerType) -{ - switch (samplerType) - { - case GL_SAMPLER_2D: - case GL_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_SAMPLER_2D_SHADOW: - return GL_TEXTURE_2D; - case GL_SAMPLER_3D: - case GL_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_3D: - return GL_TEXTURE_3D; - case GL_SAMPLER_CUBE: - case GL_SAMPLER_CUBE_SHADOW: - return GL_TEXTURE_CUBE_MAP; - case GL_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - return GL_TEXTURE_CUBE_MAP; - case GL_SAMPLER_2D_ARRAY: - case GL_INT_SAMPLER_2D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - case GL_SAMPLER_2D_ARRAY_SHADOW: - return GL_TEXTURE_2D_ARRAY; - default: UNREACHABLE(); - } - - return GL_TEXTURE_2D; -} - -void GetDefaultInputLayoutFromShader(const std::vector &shaderAttributes, gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) -{ - size_t layoutIndex = 0; - for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) - { - ASSERT(layoutIndex < gl::MAX_VERTEX_ATTRIBS); - - const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex]; - - if (shaderAttr.type != GL_NONE) - { - GLenum transposedType = gl::TransposeMatrixType(shaderAttr.type); - - for (size_t rowIndex = 0; static_cast(rowIndex) < gl::VariableRowCount(transposedType); rowIndex++, layoutIndex++) - { - gl::VertexFormat *defaultFormat = &inputLayout[layoutIndex]; - - defaultFormat->mType = gl::VariableComponentType(transposedType); - defaultFormat->mNormalized = false; - defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool - defaultFormat->mComponents = gl::VariableColumnCount(transposedType); - } - } - } -} - -std::vector GetDefaultOutputLayoutFromShader(const std::vector &shaderOutputVars) -{ - std::vector defaultPixelOutput(1); - - ASSERT(!shaderOutputVars.empty()); - defaultPixelOutput[0] = GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex; - - return defaultPixelOutput; -} - -bool IsRowMajorLayout(const sh::InterfaceBlockField &var) -{ - return var.isRowMajorLayout; -} - -bool IsRowMajorLayout(const sh::ShaderVariable &var) -{ - return false; -} - -} - -ProgramD3D::VertexExecutable::VertexExecutable(const gl::VertexFormat inputLayout[], - const GLenum signature[], - ShaderExecutable *shaderExecutable) - : mShaderExecutable(shaderExecutable) -{ - for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) - { - mInputs[attributeIndex] = inputLayout[attributeIndex]; - mSignature[attributeIndex] = signature[attributeIndex]; - } -} - -ProgramD3D::VertexExecutable::~VertexExecutable() -{ - SafeDelete(mShaderExecutable); -} - -bool ProgramD3D::VertexExecutable::matchesSignature(const GLenum signature[]) const -{ - for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) - { - if (mSignature[attributeIndex] != signature[attributeIndex]) - { - return false; - } - } - - return true; -} - -ProgramD3D::PixelExecutable::PixelExecutable(const std::vector &outputSignature, ShaderExecutable *shaderExecutable) - : mOutputSignature(outputSignature), - mShaderExecutable(shaderExecutable) -{ -} - -ProgramD3D::PixelExecutable::~PixelExecutable() -{ - SafeDelete(mShaderExecutable); -} - -ProgramD3D::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(GL_TEXTURE_2D) -{ -} - -ProgramD3D::ProgramD3D(RendererD3D *renderer) - : ProgramImpl(), - mRenderer(renderer), - mDynamicHLSL(NULL), - mGeometryExecutable(NULL), - mVertexWorkarounds(ANGLE_D3D_WORKAROUND_NONE), - mPixelWorkarounds(ANGLE_D3D_WORKAROUND_NONE), - mUsesPointSize(false), - mVertexUniformStorage(NULL), - mFragmentUniformStorage(NULL), - mUsedVertexSamplerRange(0), - mUsedPixelSamplerRange(0), - mDirtySamplerMapping(true), - mShaderVersion(100) -{ - mDynamicHLSL = new DynamicHLSL(renderer); -} - -ProgramD3D::~ProgramD3D() -{ - reset(); - SafeDelete(mDynamicHLSL); -} - -ProgramD3D *ProgramD3D::makeProgramD3D(ProgramImpl *impl) -{ - ASSERT(HAS_DYNAMIC_TYPE(ProgramD3D*, impl)); - return static_cast(impl); -} - -const ProgramD3D *ProgramD3D::makeProgramD3D(const ProgramImpl *impl) -{ - ASSERT(HAS_DYNAMIC_TYPE(const ProgramD3D*, impl)); - return static_cast(impl); -} - -bool ProgramD3D::usesPointSpriteEmulation() const -{ - return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; -} - -bool ProgramD3D::usesGeometryShader() const -{ - return usesPointSpriteEmulation(); -} - -GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const -{ - GLint logicalTextureUnit = -1; - - switch (type) - { - case gl::SAMPLER_PIXEL: - ASSERT(samplerIndex < caps.maxTextureImageUnits); - if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active) - { - logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; - } - break; - case gl::SAMPLER_VERTEX: - ASSERT(samplerIndex < caps.maxVertexTextureImageUnits); - if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active) - { - logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; - } - break; - default: UNREACHABLE(); - } - - if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast(caps.maxCombinedTextureImageUnits)) - { - 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). -GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const -{ - switch (type) - { - case gl::SAMPLER_PIXEL: - ASSERT(samplerIndex < mSamplersPS.size()); - ASSERT(mSamplersPS[samplerIndex].active); - return mSamplersPS[samplerIndex].textureType; - case gl::SAMPLER_VERTEX: - ASSERT(samplerIndex < mSamplersVS.size()); - ASSERT(mSamplersVS[samplerIndex].active); - return mSamplersVS[samplerIndex].textureType; - default: UNREACHABLE(); - } - - return GL_TEXTURE_2D; -} - -GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const -{ - switch (type) - { - case gl::SAMPLER_PIXEL: - return mUsedPixelSamplerRange; - case gl::SAMPLER_VERTEX: - return mUsedVertexSamplerRange; - default: - UNREACHABLE(); - return 0; - } -} - -void ProgramD3D::updateSamplerMapping() -{ - if (!mDirtySamplerMapping) - { - return; - } - - mDirtySamplerMapping = false; - - // Retrieve sampler uniform values - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - gl::LinkedUniform *targetUniform = mUniforms[uniformIndex]; - - if (targetUniform->dirty) - { - if (gl::IsSampler(targetUniform->type)) - { - int count = targetUniform->elementCount(); - GLint (*v)[4] = reinterpret_cast(targetUniform->data); - - if (targetUniform->isReferencedByFragmentShader()) - { - unsigned int firstIndex = targetUniform->psRegisterIndex; - - for (int i = 0; i < count; i++) - { - unsigned int samplerIndex = firstIndex + i; - - if (samplerIndex < mSamplersPS.size()) - { - ASSERT(mSamplersPS[samplerIndex].active); - mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; - } - } - } - - if (targetUniform->isReferencedByVertexShader()) - { - unsigned int firstIndex = targetUniform->vsRegisterIndex; - - for (int i = 0; i < count; i++) - { - unsigned int samplerIndex = firstIndex + i; - - if (samplerIndex < mSamplersVS.size()) - { - ASSERT(mSamplersVS[samplerIndex].active); - mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; - } - } - } - } - } - } -} - -bool ProgramD3D::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) -{ - // 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. - updateSamplerMapping(); - - std::vector textureUnitTypes(caps.maxCombinedTextureImageUnits, GL_NONE); - - for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) - { - if (mSamplersPS[i].active) - { - unsigned int unit = mSamplersPS[i].logicalTextureUnit; - - if (unit >= textureUnitTypes.size()) - { - if (infoLog) - { - infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size()); - } - - return false; - } - - if (textureUnitTypes[unit] != GL_NONE) - { - if (mSamplersPS[i].textureType != textureUnitTypes[unit]) - { - if (infoLog) - { - infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); - } - - return false; - } - } - else - { - textureUnitTypes[unit] = mSamplersPS[i].textureType; - } - } - } - - for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) - { - if (mSamplersVS[i].active) - { - unsigned int unit = mSamplersVS[i].logicalTextureUnit; - - if (unit >= textureUnitTypes.size()) - { - if (infoLog) - { - infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size()); - } - - return false; - } - - if (textureUnitTypes[unit] != GL_NONE) - { - if (mSamplersVS[i].textureType != textureUnitTypes[unit]) - { - if (infoLog) - { - infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); - } - - return false; - } - } - else - { - textureUnitTypes[unit] = mSamplersVS[i].textureType; - } - } - } - - return true; -} - -gl::LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) -{ - stream->readInt(&mShaderVersion); - - const unsigned int psSamplerCount = stream->readInt(); - for (unsigned int i = 0; i < psSamplerCount; ++i) - { - Sampler sampler; - stream->readBool(&sampler.active); - stream->readInt(&sampler.logicalTextureUnit); - stream->readInt(&sampler.textureType); - mSamplersPS.push_back(sampler); - } - const unsigned int vsSamplerCount = stream->readInt(); - for (unsigned int i = 0; i < vsSamplerCount; ++i) - { - Sampler sampler; - stream->readBool(&sampler.active); - stream->readInt(&sampler.logicalTextureUnit); - stream->readInt(&sampler.textureType); - mSamplersVS.push_back(sampler); - } - - stream->readInt(&mUsedVertexSamplerRange); - stream->readInt(&mUsedPixelSamplerRange); - - const unsigned int uniformCount = stream->readInt(); - if (stream->error()) - { - infoLog.append("Invalid program binary."); - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - mUniforms.resize(uniformCount); - for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) - { - GLenum type = stream->readInt(); - GLenum precision = stream->readInt(); - std::string name = stream->readString(); - unsigned int arraySize = stream->readInt(); - int blockIndex = stream->readInt(); - - int offset = stream->readInt(); - int arrayStride = stream->readInt(); - int matrixStride = stream->readInt(); - bool isRowMajorMatrix = stream->readBool(); - - const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); - - gl::LinkedUniform *uniform = new gl::LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo); - - stream->readInt(&uniform->psRegisterIndex); - stream->readInt(&uniform->vsRegisterIndex); - stream->readInt(&uniform->registerCount); - stream->readInt(&uniform->registerElement); - - mUniforms[uniformIndex] = uniform; - } - - const unsigned int uniformIndexCount = stream->readInt(); - if (stream->error()) - { - infoLog.append("Invalid program binary."); - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - mUniformIndex.resize(uniformIndexCount); - for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) - { - stream->readString(&mUniformIndex[uniformIndexIndex].name); - stream->readInt(&mUniformIndex[uniformIndexIndex].element); - stream->readInt(&mUniformIndex[uniformIndexIndex].index); - } - - unsigned int uniformBlockCount = stream->readInt(); - if (stream->error()) - { - infoLog.append("Invalid program binary."); - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - mUniformBlocks.resize(uniformBlockCount); - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) - { - std::string name = stream->readString(); - unsigned int elementIndex = stream->readInt(); - unsigned int dataSize = stream->readInt(); - - gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize); - - stream->readInt(&uniformBlock->psRegisterIndex); - stream->readInt(&uniformBlock->vsRegisterIndex); - - unsigned int numMembers = stream->readInt(); - uniformBlock->memberUniformIndexes.resize(numMembers); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) - { - stream->readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]); - } - - mUniformBlocks[uniformBlockIndex] = uniformBlock; - } - - stream->readInt(&mTransformFeedbackBufferMode); - const unsigned int transformFeedbackVaryingCount = stream->readInt(); - mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); - for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) - { - gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex]; - - stream->readString(&varying.name); - stream->readInt(&varying.type); - stream->readInt(&varying.size); - stream->readString(&varying.semanticName); - stream->readInt(&varying.semanticIndex); - stream->readInt(&varying.semanticIndexCount); - } - - stream->readString(&mVertexHLSL); - stream->readInt(&mVertexWorkarounds); - stream->readString(&mPixelHLSL); - stream->readInt(&mPixelWorkarounds); - stream->readBool(&mUsesFragDepth); - stream->readBool(&mUsesPointSize); - - const size_t pixelShaderKeySize = stream->readInt(); - mPixelShaderKey.resize(pixelShaderKeySize); - for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKeySize; pixelShaderKeyIndex++) - { - stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].type); - stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].name); - stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].source); - stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex); - } - - const unsigned char* binary = reinterpret_cast(stream->data()); - - const unsigned int vertexShaderCount = stream->readInt(); - for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) - { - gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; - - for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) - { - gl::VertexFormat *vertexInput = &inputLayout[inputIndex]; - stream->readInt(&vertexInput->mType); - stream->readInt(&vertexInput->mNormalized); - stream->readInt(&vertexInput->mComponents); - stream->readBool(&vertexInput->mPureInteger); - } - - unsigned int vertexShaderSize = stream->readInt(); - const unsigned char *vertexShaderFunction = binary + stream->offset(); - - ShaderExecutable *shaderExecutable = NULL; - gl::Error error = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, - SHADER_VERTEX, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - &shaderExecutable); - if (error.isError()) - { - return gl::LinkResult(false, error); - } - - if (!shaderExecutable) - { - infoLog.append("Could not create vertex shader."); - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - // generated converted input layout - GLenum signature[gl::MAX_VERTEX_ATTRIBS]; - getInputLayoutSignature(inputLayout, signature); - - // add new binary - mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); - - stream->skip(vertexShaderSize); - } - - const size_t pixelShaderCount = stream->readInt(); - for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++) - { - const size_t outputCount = stream->readInt(); - std::vector outputs(outputCount); - for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++) - { - stream->readInt(&outputs[outputIndex]); - } - - const size_t pixelShaderSize = stream->readInt(); - const unsigned char *pixelShaderFunction = binary + stream->offset(); - ShaderExecutable *shaderExecutable = NULL; - gl::Error error = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - &shaderExecutable); - if (error.isError()) - { - return gl::LinkResult(false, error); - } - - if (!shaderExecutable) - { - infoLog.append("Could not create pixel shader."); - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - // add new binary - mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); - - stream->skip(pixelShaderSize); - } - - unsigned int geometryShaderSize = stream->readInt(); - - if (geometryShaderSize > 0) - { - const unsigned char *geometryShaderFunction = binary + stream->offset(); - gl::Error error = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - &mGeometryExecutable); - if (error.isError()) - { - return gl::LinkResult(false, error); - } - - if (!mGeometryExecutable) - { - infoLog.append("Could not create geometry shader."); - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - stream->skip(geometryShaderSize); - } - - GUID binaryIdentifier = {0}; - stream->readBytes(reinterpret_cast(&binaryIdentifier), sizeof(GUID)); - - GUID identifier = mRenderer->getAdapterIdentifier(); - if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0) - { - infoLog.append("Invalid program binary."); - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - initializeUniformStorage(); - - return gl::LinkResult(true, gl::Error(GL_NO_ERROR)); -} - -gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) -{ - stream->writeInt(mShaderVersion); - - stream->writeInt(mSamplersPS.size()); - for (unsigned int i = 0; i < mSamplersPS.size(); ++i) - { - stream->writeInt(mSamplersPS[i].active); - stream->writeInt(mSamplersPS[i].logicalTextureUnit); - stream->writeInt(mSamplersPS[i].textureType); - } - - stream->writeInt(mSamplersVS.size()); - for (unsigned int i = 0; i < mSamplersVS.size(); ++i) - { - stream->writeInt(mSamplersVS[i].active); - stream->writeInt(mSamplersVS[i].logicalTextureUnit); - stream->writeInt(mSamplersVS[i].textureType); - } - - stream->writeInt(mUsedVertexSamplerRange); - stream->writeInt(mUsedPixelSamplerRange); - - stream->writeInt(mUniforms.size()); - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) - { - const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; - - stream->writeInt(uniform.type); - stream->writeInt(uniform.precision); - stream->writeString(uniform.name); - stream->writeInt(uniform.arraySize); - stream->writeInt(uniform.blockIndex); - - stream->writeInt(uniform.blockInfo.offset); - stream->writeInt(uniform.blockInfo.arrayStride); - stream->writeInt(uniform.blockInfo.matrixStride); - stream->writeInt(uniform.blockInfo.isRowMajorMatrix); - - stream->writeInt(uniform.psRegisterIndex); - stream->writeInt(uniform.vsRegisterIndex); - stream->writeInt(uniform.registerCount); - stream->writeInt(uniform.registerElement); - } - - stream->writeInt(mUniformIndex.size()); - for (size_t i = 0; i < mUniformIndex.size(); ++i) - { - stream->writeString(mUniformIndex[i].name); - stream->writeInt(mUniformIndex[i].element); - stream->writeInt(mUniformIndex[i].index); - } - - stream->writeInt(mUniformBlocks.size()); - for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) - { - const gl::UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex]; - - stream->writeString(uniformBlock.name); - stream->writeInt(uniformBlock.elementIndex); - stream->writeInt(uniformBlock.dataSize); - - stream->writeInt(uniformBlock.memberUniformIndexes.size()); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) - { - stream->writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]); - } - - stream->writeInt(uniformBlock.psRegisterIndex); - stream->writeInt(uniformBlock.vsRegisterIndex); - } - - stream->writeInt(mTransformFeedbackBufferMode); - stream->writeInt(mTransformFeedbackLinkedVaryings.size()); - for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) - { - const gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i]; - - stream->writeString(varying.name); - stream->writeInt(varying.type); - stream->writeInt(varying.size); - stream->writeString(varying.semanticName); - stream->writeInt(varying.semanticIndex); - stream->writeInt(varying.semanticIndexCount); - } - - stream->writeString(mVertexHLSL); - stream->writeInt(mVertexWorkarounds); - stream->writeString(mPixelHLSL); - stream->writeInt(mPixelWorkarounds); - stream->writeInt(mUsesFragDepth); - stream->writeInt(mUsesPointSize); - - const std::vector &pixelShaderKey = mPixelShaderKey; - stream->writeInt(pixelShaderKey.size()); - for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); pixelShaderKeyIndex++) - { - const PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex]; - stream->writeInt(variable.type); - stream->writeString(variable.name); - stream->writeString(variable.source); - stream->writeInt(variable.outputIndex); - } - - stream->writeInt(mVertexExecutables.size()); - for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) - { - VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; - - for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) - { - const gl::VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex]; - stream->writeInt(vertexInput.mType); - stream->writeInt(vertexInput.mNormalized); - stream->writeInt(vertexInput.mComponents); - stream->writeInt(vertexInput.mPureInteger); - } - - size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); - stream->writeInt(vertexShaderSize); - - const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction(); - stream->writeBytes(vertexBlob, vertexShaderSize); - } - - stream->writeInt(mPixelExecutables.size()); - for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) - { - PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; - - const std::vector outputs = pixelExecutable->outputSignature(); - stream->writeInt(outputs.size()); - for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++) - { - stream->writeInt(outputs[outputIndex]); - } - - size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength(); - stream->writeInt(pixelShaderSize); - - const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction(); - stream->writeBytes(pixelBlob, pixelShaderSize); - } - - size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; - stream->writeInt(geometryShaderSize); - - if (mGeometryExecutable != NULL && geometryShaderSize > 0) - { - const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); - stream->writeBytes(geometryBlob, geometryShaderSize); - } - - GUID binaryIdentifier = mRenderer->getAdapterIdentifier(); - stream->writeBytes(reinterpret_cast(&binaryIdentifier), sizeof(GUID)); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExecutable) -{ - std::vector outputs; - - const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender(mRenderer->getWorkarounds()); - - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) - { - const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - - if (colorbuffer) - { - outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding()); - } - else - { - outputs.push_back(GL_NONE); - } - } - - return getPixelExecutableForOutputLayout(outputs, outExecutable); -} - -gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector &outputSignature, ShaderExecutable **outExectuable) -{ - for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) - { - if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) - { - *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable(); - return gl::Error(GL_NO_ERROR); - } - } - - std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth, - outputSignature); - - // Generate new pixel executable - gl::InfoLog tempInfoLog; - ShaderExecutable *pixelExecutable = NULL; - gl::Error error = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL, SHADER_PIXEL, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - mPixelWorkarounds, &pixelExecutable); - if (error.isError()) - { - return error; - } - - if (!pixelExecutable) - { - std::vector tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); - } - else - { - mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); - } - - *outExectuable = pixelExecutable; - return gl::Error(GL_NO_ERROR); -} - -gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable) -{ - GLenum signature[gl::MAX_VERTEX_ATTRIBS]; - getInputLayoutSignature(inputLayout, signature); - - for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) - { - if (mVertexExecutables[executableIndex]->matchesSignature(signature)) - { - *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); - return gl::Error(GL_NO_ERROR); - } - } - - // Generate new dynamic layout with attribute conversions - std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes); - - // Generate new vertex executable - gl::InfoLog tempInfoLog; - ShaderExecutable *vertexExecutable = NULL; - gl::Error error = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL, SHADER_VERTEX, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - mVertexWorkarounds, &vertexExecutable); - if (error.isError()) - { - return error; - } - - if (!vertexExecutable) - { - std::vector tempCharBuffer(tempInfoLog.getLength()+3); - tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); - } - else - { - mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); - } - - *outExectuable = vertexExecutable; - return gl::Error(GL_NO_ERROR); -} - -gl::LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - int registers) -{ - ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); - ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); - - gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS]; - GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout); - ShaderExecutable *defaultVertexExecutable = NULL; - gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable); - if (error.isError()) - { - return gl::LinkResult(false, error); - } - - std::vector defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); - ShaderExecutable *defaultPixelExecutable = NULL; - error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable); - if (error.isError()) - { - return gl::LinkResult(false, error); - } - - if (usesGeometryShader()) - { - std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D); - - - error = mRenderer->compileToExecutable(infoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - ANGLE_D3D_WORKAROUND_NONE, &mGeometryExecutable); - if (error.isError()) - { - return gl::LinkResult(false, error); - } - } - -#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED - if (usesGeometryShader() && mGeometryExecutable) - { - // Geometry shaders are currently only used internally, so there is no corresponding shader object at the interface level - // For now the geometry shader debug info is pre-pended to the vertex shader, this is a bit of a clutch - vertexShaderD3D->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n"); - vertexShaderD3D->appendDebugInfo(mGeometryExecutable->getDebugInfo()); - vertexShaderD3D->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n"); - } - - if (defaultVertexExecutable) - { - vertexShaderD3D->appendDebugInfo(defaultVertexExecutable->getDebugInfo()); - } - - if (defaultPixelExecutable) - { - fragmentShaderD3D->appendDebugInfo(defaultPixelExecutable->getDebugInfo()); - } -#endif - - bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable)); - return gl::LinkResult(linkSuccess, gl::Error(GL_NO_ERROR)); -} - -gl::LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog, - gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode, - int *registers, std::vector *linkedVaryings, - std::map *outputVariables) -{ - ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); - ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); - - mSamplersPS.resize(data.caps->maxTextureImageUnits); - mSamplersVS.resize(data.caps->maxVertexTextureImageUnits); - - mTransformFeedbackBufferMode = transformFeedbackBufferMode; - - mPixelHLSL = fragmentShaderD3D->getTranslatedSource(); - mPixelWorkarounds = fragmentShaderD3D->getD3DWorkarounds(); - - mVertexHLSL = vertexShaderD3D->getTranslatedSource(); - mVertexWorkarounds = vertexShaderD3D->getD3DWorkarounds(); - mShaderVersion = vertexShaderD3D->getShaderVersion(); - - // Map the varyings to the register file - VaryingPacking packing = { NULL }; - *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings); - - if (*registers < 0) - { - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - if (!gl::ProgramBinary::linkVaryings(infoLog, fragmentShader, vertexShader)) - { - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - if (!mDynamicHLSL->generateShaderLinkHLSL(data, infoLog, *registers, packing, mPixelHLSL, mVertexHLSL, - fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings, - linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth)) - { - return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); - } - - mUsesPointSize = vertexShaderD3D->usesPointSize(); - - return gl::LinkResult(true, gl::Error(GL_NO_ERROR)); -} - -void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const -{ - mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); -} - -void ProgramD3D::initializeUniformStorage() -{ - // Compute total default block size - unsigned int vertexRegisters = 0; - unsigned int fragmentRegisters = 0; - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; - - if (!gl::IsSampler(uniform.type)) - { - if (uniform.isReferencedByVertexShader()) - { - vertexRegisters = std::max(vertexRegisters, uniform.vsRegisterIndex + uniform.registerCount); - } - if (uniform.isReferencedByFragmentShader()) - { - fragmentRegisters = std::max(fragmentRegisters, uniform.psRegisterIndex + uniform.registerCount); - } - } - } - - mVertexUniformStorage = mRenderer->createUniformStorage(vertexRegisters * 16u); - mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); -} - -gl::Error ProgramD3D::applyUniforms() -{ - updateSamplerMapping(); - - gl::Error error = mRenderer->applyUniforms(*this, mUniforms); - if (error.isError()) - { - return error; - } - - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - mUniforms[uniformIndex]->dirty = false; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error ProgramD3D::applyUniformBuffers(const std::vector boundBuffers, const gl::Caps &caps) -{ - ASSERT(boundBuffers.size() == mUniformBlocks.size()); - - const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL}; - const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL}; - - const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); - const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); - - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++) - { - gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex]; - gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex]; - - ASSERT(uniformBlock && uniformBuffer); - - if (uniformBuffer->getSize() < uniformBlock->dataSize) - { - // undefined behaviour - return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."); - } - - // Unnecessary to apply an unreferenced standard or shared UBO - if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader()) - { - continue; - } - - if (uniformBlock->isReferencedByVertexShader()) - { - unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS; - ASSERT(vertexUniformBuffers[registerIndex] == NULL); - ASSERT(registerIndex < caps.maxVertexUniformBlocks); - vertexUniformBuffers[registerIndex] = uniformBuffer; - } - - if (uniformBlock->isReferencedByFragmentShader()) - { - unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS; - ASSERT(fragmentUniformBuffers[registerIndex] == NULL); - ASSERT(registerIndex < caps.maxFragmentUniformBlocks); - fragmentUniformBuffers[registerIndex] = uniformBuffer; - } - } - - return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers); -} - -bool ProgramD3D::assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, - unsigned int registerIndex, const gl::Caps &caps) -{ - if (shader == GL_VERTEX_SHADER) - { - uniformBlock->vsRegisterIndex = registerIndex; - if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks) - { - infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks); - return false; - } - } - else if (shader == GL_FRAGMENT_SHADER) - { - uniformBlock->psRegisterIndex = registerIndex; - if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks) - { - infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks); - return false; - } - } - else UNREACHABLE(); - - return true; -} - -void ProgramD3D::dirtyAllUniforms() -{ - unsigned int numUniforms = mUniforms.size(); - for (unsigned int index = 0; index < numUniforms; index++) - { - mUniforms[index]->dirty = true; - } -} - -void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) -{ - setUniform(location, count, v, GL_FLOAT); -} - -void ProgramD3D::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) -{ - setUniform(location, count, v, GL_FLOAT_VEC2); -} - -void ProgramD3D::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) -{ - setUniform(location, count, v, GL_FLOAT_VEC3); -} - -void ProgramD3D::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) -{ - setUniform(location, count, v, GL_FLOAT_VEC4); -} - -void ProgramD3D::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); -} - -void ProgramD3D::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); -} - -void ProgramD3D::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); -} - -void ProgramD3D::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); -} - -void ProgramD3D::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); -} - -void ProgramD3D::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); -} - -void ProgramD3D::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); -} - -void ProgramD3D::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); -} - -void ProgramD3D::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); -} - -void ProgramD3D::setUniform1iv(GLint location, GLsizei count, const GLint *v) -{ - setUniform(location, count, v, GL_INT); -} - -void ProgramD3D::setUniform2iv(GLint location, GLsizei count, const GLint *v) -{ - setUniform(location, count, v, GL_INT_VEC2); -} - -void ProgramD3D::setUniform3iv(GLint location, GLsizei count, const GLint *v) -{ - setUniform(location, count, v, GL_INT_VEC3); -} - -void ProgramD3D::setUniform4iv(GLint location, GLsizei count, const GLint *v) -{ - setUniform(location, count, v, GL_INT_VEC4); -} - -void ProgramD3D::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) -{ - setUniform(location, count, v, GL_UNSIGNED_INT); -} - -void ProgramD3D::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) -{ - setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); -} - -void ProgramD3D::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) -{ - setUniform(location, count, v, GL_UNSIGNED_INT_VEC3); -} - -void ProgramD3D::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) -{ - setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); -} - -void ProgramD3D::getUniformfv(GLint location, GLfloat *params) -{ - getUniformv(location, params, GL_FLOAT); -} - -void ProgramD3D::getUniformiv(GLint location, GLint *params) -{ - getUniformv(location, params, GL_INT); -} - -void ProgramD3D::getUniformuiv(GLint location, GLuint *params) -{ - getUniformv(location, params, GL_UNSIGNED_INT); -} - -bool ProgramD3D::linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, - const gl::Caps &caps) -{ - const ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader.getImplementation()); - const ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader.getImplementation()); - - const std::vector &vertexUniforms = vertexShader.getUniforms(); - const std::vector &fragmentUniforms = fragmentShader.getUniforms(); - - // Check that uniforms defined in the vertex and fragment shaders are identical - typedef std::map UniformMap; - UniformMap linkedUniforms; - - for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++) - { - const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex]; - linkedUniforms[vertexUniform.name] = &vertexUniform; - } - - for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++) - { - const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex]; - UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name); - if (entry != linkedUniforms.end()) - { - const sh::Uniform &vertexUniform = *entry->second; - const std::string &uniformName = "uniform '" + vertexUniform.name + "'"; - if (!gl::ProgramBinary::linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform)) - { - return false; - } - } - } - - for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++) - { - const sh::Uniform &uniform = vertexUniforms[uniformIndex]; - - if (uniform.staticUse) - { - defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShaderD3D->getUniformRegister(uniform.name)); - } - } - - for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++) - { - const sh::Uniform &uniform = fragmentUniforms[uniformIndex]; - - if (uniform.staticUse) - { - defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShaderD3D->getUniformRegister(uniform.name)); - } - } - - if (!indexUniforms(infoLog, caps)) - { - return false; - } - - initializeUniformStorage(); - - // special case for gl_DepthRange, the only built-in uniform (also a struct) - if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange()) - { - const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); - - mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); - mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); - mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); - } - - return true; -} - -void ProgramD3D::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister) -{ - ShShaderOutput outputType = ShaderD3D::getCompilerOutputType(shader); - sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); - encoder.skipRegisters(uniformRegister); - - defineUniform(shader, uniform, uniform.name, &encoder); -} - -void ProgramD3D::defineUniform(GLenum shader, const sh::ShaderVariable &uniform, - const std::string &fullName, sh::HLSLBlockEncoder *encoder) -{ - if (uniform.isStruct()) - { - for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) - { - const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); - - encoder->enterAggregateType(); - - for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) - { - const sh::ShaderVariable &field = uniform.fields[fieldIndex]; - const std::string &fieldFullName = (fullName + elementString + "." + field.name); - - defineUniform(shader, field, fieldFullName, encoder); - } - - encoder->exitAggregateType(); - } - } - else // Not a struct - { - // Arrays are treated as aggregate types - if (uniform.isArray()) - { - encoder->enterAggregateType(); - } - - gl::LinkedUniform *linkedUniform = getUniformByName(fullName); - - if (!linkedUniform) - { - linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, - -1, sh::BlockMemberInfo::getDefaultBlockInfo()); - ASSERT(linkedUniform); - linkedUniform->registerElement = encoder->getCurrentElement(); - mUniforms.push_back(linkedUniform); - } - - ASSERT(linkedUniform->registerElement == encoder->getCurrentElement()); - - if (shader == GL_FRAGMENT_SHADER) - { - linkedUniform->psRegisterIndex = encoder->getCurrentRegister(); - } - else if (shader == GL_VERTEX_SHADER) - { - linkedUniform->vsRegisterIndex = encoder->getCurrentRegister(); - } - else UNREACHABLE(); - - // Advance the uniform offset, to track registers allocation for structs - encoder->encodeType(uniform.type, uniform.arraySize, false); - - // Arrays are treated as aggregate types - if (uniform.isArray()) - { - encoder->exitAggregateType(); - } - } -} - -template -static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag) -{ - ASSERT(dest != NULL); - ASSERT(dirtyFlag != NULL); - - *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); - *dest = source; -} - -template -void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType) -{ - const int components = gl::VariableComponentCount(targetUniformType); - const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType); - - gl::LinkedUniform *targetUniform = getUniformByLocation(location); - - int elementCount = targetUniform->elementCount(); - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == targetUniformType) - { - T *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - T *dest = target + (i * 4); - const T *source = v + (i * components); - - for (int c = 0; c < components; c++) - { - SetIfDirty(dest + c, source[c], &targetUniform->dirty); - } - for (int c = components; c < 4; c++) - { - SetIfDirty(dest + c, T(0), &targetUniform->dirty); - } - } - } - else if (targetUniform->type == targetBoolType) - { - GLint *boolParams = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - GLint *dest = boolParams + (i * 4); - const T *source = v + (i * components); - - for (int c = 0; c < components; c++) - { - SetIfDirty(dest + c, (source[c] == static_cast(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); - } - for (int c = components; c < 4; c++) - { - SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty); - } - } - } - else if (gl::IsSampler(targetUniform->type)) - { - ASSERT(targetUniformType == GL_INT); - - GLint *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; - - bool wasDirty = targetUniform->dirty; - - for (int i = 0; i < count; i++) - { - GLint *dest = target + (i * 4); - const GLint *source = reinterpret_cast(v) + (i * components); - - SetIfDirty(dest + 0, source[0], &targetUniform->dirty); - SetIfDirty(dest + 1, 0, &targetUniform->dirty); - SetIfDirty(dest + 2, 0, &targetUniform->dirty); - SetIfDirty(dest + 3, 0, &targetUniform->dirty); - } - - if (!wasDirty && targetUniform->dirty) - { - mDirtySamplerMapping = true; - } - } - else UNREACHABLE(); -} - -template -bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) -{ - bool dirty = false; - int copyWidth = std::min(targetHeight, srcWidth); - int copyHeight = std::min(targetWidth, srcHeight); - - for (int x = 0; x < copyWidth; x++) - { - for (int y = 0; y < copyHeight; y++) - { - SetIfDirty(target + (x * targetWidth + y), static_cast(value[y * srcWidth + x]), &dirty); - } - } - // clear unfilled right side - for (int y = 0; y < copyWidth; y++) - { - for (int x = copyHeight; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } - } - // clear unfilled bottom. - for (int y = copyWidth; y < targetHeight; y++) - { - for (int x = 0; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } - } - - return dirty; -} - -template -bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) -{ - bool dirty = false; - int copyWidth = std::min(targetWidth, srcWidth); - int copyHeight = std::min(targetHeight, srcHeight); - - for (int y = 0; y < copyHeight; y++) - { - for (int x = 0; x < copyWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(value[y * srcWidth + x]), &dirty); - } - } - // clear unfilled right side - for (int y = 0; y < copyHeight; y++) - { - for (int x = copyWidth; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } - } - // clear unfilled bottom. - for (int y = copyHeight; y < targetHeight; y++) - { - for (int x = 0; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } - } - - return dirty; -} - -template -void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType) -{ - gl::LinkedUniform *targetUniform = getUniformByLocation(location); - - int elementCount = targetUniform->elementCount(); - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - const unsigned int targetMatrixStride = (4 * rows); - GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride); - - for (int i = 0; i < count; i++) - { - // Internally store matrices as transposed versions to accomodate HLSL matrix indexing - if (transpose == GL_FALSE) - { - targetUniform->dirty = transposeMatrix(target, value, 4, rows, rows, cols) || targetUniform->dirty; - } - else - { - targetUniform->dirty = expandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; - } - target += targetMatrixStride; - value += cols * rows; - } -} - -template -void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType) -{ - gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - if (gl::IsMatrixType(targetUniform->type)) - { - const int rows = gl::VariableRowCount(targetUniform->type); - const int cols = gl::VariableColumnCount(targetUniform->type); - transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows); - } - else if (uniformType == gl::VariableComponentType(targetUniform->type)) - { - unsigned int size = gl::VariableComponentCount(targetUniform->type); - memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T), - size * sizeof(T)); - } - else - { - unsigned int size = gl::VariableComponentCount(targetUniform->type); - switch (gl::VariableComponentType(targetUniform->type)) - { - case GL_BOOL: - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = (boolParams[i] == GL_FALSE) ? static_cast(0) : static_cast(1); - } - } - break; - - case GL_FLOAT: - { - GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast(floatParams[i]); - } - } - break; - - case GL_INT: - { - GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast(intParams[i]); - } - } - break; - - case GL_UNSIGNED_INT: - { - GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast(uintParams[i]); - } - } - break; - - default: UNREACHABLE(); - } - } -} - -template -void ProgramD3D::defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, - sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, - bool inRowMajorLayout) -{ - for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++) - { - const VarT &field = fields[uniformIndex]; - const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); - - if (field.isStruct()) - { - bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); - - for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) - { - encoder->enterAggregateType(); - - const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); - defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout); - - encoder->exitAggregateType(); - } - } - else - { - bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); - - sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); - - gl::LinkedUniform *newUniform = new gl::LinkedUniform(field.type, field.precision, fieldName, field.arraySize, - blockIndex, memberInfo); - - // add to uniform list, but not index, since uniform block uniforms have no location - blockUniformIndexes->push_back(mUniforms.size()); - mUniforms.push_back(newUniform); - } - } -} - -bool ProgramD3D::defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, - const gl::Caps &caps) -{ - const ShaderD3D* shaderD3D = ShaderD3D::makeShaderD3D(shader.getImplementation()); - - // create uniform block entries if they do not exist - if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX) - { - std::vector blockUniformIndexes; - const unsigned int blockIndex = mUniformBlocks.size(); - - // define member uniforms - sh::BlockLayoutEncoder *encoder = NULL; - - if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) - { - encoder = new sh::Std140BlockEncoder; - } - else - { - encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); - } - ASSERT(encoder); - - defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout); - - size_t dataSize = encoder->getBlockSize(); - - // create all the uniform blocks - if (interfaceBlock.arraySize > 0) - { - for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++) - { - gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize); - newUniformBlock->memberUniformIndexes = blockUniformIndexes; - mUniformBlocks.push_back(newUniformBlock); - } - } - else - { - gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize); - newUniformBlock->memberUniformIndexes = blockUniformIndexes; - mUniformBlocks.push_back(newUniformBlock); - } - } - - if (interfaceBlock.staticUse) - { - // Assign registers to the uniform blocks - const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name); - const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize); - ASSERT(blockIndex != GL_INVALID_INDEX); - ASSERT(blockIndex + elementCount <= mUniformBlocks.size()); - - unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name); - - for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++) - { - gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement]; - ASSERT(uniformBlock->name == interfaceBlock.name); - - if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(), - interfaceBlockRegister + uniformBlockElement, caps)) - { - return false; - } - } - } - - return true; -} - -bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex, - GLenum samplerType, - unsigned int samplerCount, - std::vector &outSamplers, - GLuint *outUsedRange) -{ - unsigned int samplerIndex = startSamplerIndex; - - do - { - if (samplerIndex < outSamplers.size()) - { - Sampler& sampler = outSamplers[samplerIndex]; - sampler.active = true; - sampler.textureType = GetTextureType(samplerType); - sampler.logicalTextureUnit = 0; - *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); - } - else - { - return false; - } - - samplerIndex++; - } while (samplerIndex < startSamplerIndex + samplerCount); - - return true; -} - -bool ProgramD3D::indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps) -{ - ASSERT(gl::IsSampler(uniform.type)); - ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX); - - if (uniform.vsRegisterIndex != GL_INVALID_INDEX) - { - if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS, - &mUsedVertexSamplerRange)) - { - infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", - mSamplersVS.size()); - return false; - } - - unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors; - if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors) - { - infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", - caps.maxVertexUniformVectors); - return false; - } - } - - if (uniform.psRegisterIndex != GL_INVALID_INDEX) - { - if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS, - &mUsedPixelSamplerRange)) - { - infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", - mSamplersPS.size()); - return false; - } - - unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors; - if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors) - { - infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", - caps.maxFragmentUniformVectors); - return false; - } - } - - return true; -} - -bool ProgramD3D::indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) -{ - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; - - if (gl::IsSampler(uniform.type)) - { - if (!indexSamplerUniform(uniform, infoLog, caps)) - { - return false; - } - } - - for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++) - { - mUniformIndex.push_back(gl::VariableLocation(uniform.name, arrayElementIndex, uniformIndex)); - } - } - - return true; -} - -void ProgramD3D::reset() -{ - ProgramImpl::reset(); - - SafeDeleteContainer(mVertexExecutables); - SafeDeleteContainer(mPixelExecutables); - SafeDelete(mGeometryExecutable); - - mTransformFeedbackBufferMode = GL_NONE; - - mVertexHLSL.clear(); - mVertexWorkarounds = ANGLE_D3D_WORKAROUND_NONE; - mShaderVersion = 100; - - mPixelHLSL.clear(); - mPixelWorkarounds = ANGLE_D3D_WORKAROUND_NONE; - mUsesFragDepth = false; - mPixelShaderKey.clear(); - mUsesPointSize = false; - - SafeDelete(mVertexUniformStorage); - SafeDelete(mFragmentUniformStorage); - - mSamplersPS.clear(); - mSamplersVS.clear(); - - mUsedVertexSamplerRange = 0; - mUsedPixelSamplerRange = 0; - mDirtySamplerMapping = true; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h deleted file mode 100644 index 4baab9aa19..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h +++ /dev/null @@ -1,219 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// ProgramD3D.h: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. - -#ifndef LIBGLESV2_RENDERER_PROGRAMD3D_H_ -#define LIBGLESV2_RENDERER_PROGRAMD3D_H_ - -#include "libGLESv2/renderer/ProgramImpl.h" -#include "libGLESv2/renderer/Workarounds.h" - -#include -#include - -namespace gl -{ -struct LinkedUniform; -struct VariableLocation; -struct VertexFormat; -} - -namespace rx -{ -class RendererD3D; -class UniformStorage; - -class ProgramD3D : public ProgramImpl -{ - public: - ProgramD3D(RendererD3D *renderer); - virtual ~ProgramD3D(); - - static ProgramD3D *makeProgramD3D(ProgramImpl *impl); - static const ProgramD3D *makeProgramD3D(const ProgramImpl *impl); - - const std::vector &getPixelShaderKey() { return mPixelShaderKey; } - int getShaderVersion() const { return mShaderVersion; } - GLenum getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } - - GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const; - GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const; - GLint getUsedSamplerRange(gl::SamplerType type) const; - void updateSamplerMapping(); - bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps); - - bool usesPointSize() const { return mUsesPointSize; } - bool usesPointSpriteEmulation() const; - bool usesGeometryShader() const; - - GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; } - gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream); - gl::Error save(gl::BinaryOutputStream *stream); - - gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExectuable); - gl::Error getPixelExecutableForOutputLayout(const std::vector &outputLayout, ShaderExecutable **outExectuable); - gl::Error getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable); - ShaderExecutable *getGeometryExecutable() const { return mGeometryExecutable; } - - gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - int registers); - - gl::LinkResult link(const gl::Data &data, gl::InfoLog &infoLog, - gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector &transformFeedbackVaryings, - GLenum transformFeedbackBufferMode, - int *registers, std::vector *linkedVaryings, - std::map *outputVariables); - - void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; - - void initializeUniformStorage(); - gl::Error applyUniforms(); - gl::Error applyUniformBuffers(const std::vector boundBuffers, const gl::Caps &caps); - bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, - unsigned int registerIndex, const gl::Caps &caps); - void dirtyAllUniforms(); - - void setUniform1fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); - void setUniform1iv(GLint location, GLsizei count, const GLint *v); - void setUniform2iv(GLint location, GLsizei count, const GLint *v); - void setUniform3iv(GLint location, GLsizei count, const GLint *v); - void setUniform4iv(GLint location, GLsizei count, const GLint *v); - void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); - void setUniform2uiv(GLint location, GLsizei count, const GLuint *v); - void setUniform3uiv(GLint location, GLsizei count, const GLuint *v); - void setUniform4uiv(GLint location, GLsizei count, const GLuint *v); - void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); - - void getUniformfv(GLint location, GLfloat *params); - void getUniformiv(GLint location, GLint *params); - void getUniformuiv(GLint location, GLuint *params); - - const UniformStorage &getVertexUniformStorage() const { return *mVertexUniformStorage; } - const UniformStorage &getFragmentUniformStorage() const { return *mFragmentUniformStorage; } - - bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, - const gl::Caps &caps); - bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, const gl::Caps &caps); - - void reset(); - - private: - DISALLOW_COPY_AND_ASSIGN(ProgramD3D); - - class VertexExecutable - { - public: - VertexExecutable(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], - const GLenum signature[gl::MAX_VERTEX_ATTRIBS], - ShaderExecutable *shaderExecutable); - ~VertexExecutable(); - - bool matchesSignature(const GLenum convertedLayout[gl::MAX_VERTEX_ATTRIBS]) const; - - const gl::VertexFormat *inputs() const { return mInputs; } - const GLenum *signature() const { return mSignature; } - ShaderExecutable *shaderExecutable() const { return mShaderExecutable; } - - private: - gl::VertexFormat mInputs[gl::MAX_VERTEX_ATTRIBS]; - GLenum mSignature[gl::MAX_VERTEX_ATTRIBS]; - ShaderExecutable *mShaderExecutable; - }; - - class PixelExecutable - { - public: - PixelExecutable(const std::vector &outputSignature, ShaderExecutable *shaderExecutable); - ~PixelExecutable(); - - bool matchesSignature(const std::vector &signature) const { return mOutputSignature == signature; } - - const std::vector &outputSignature() const { return mOutputSignature; } - ShaderExecutable *shaderExecutable() const { return mShaderExecutable; } - - private: - std::vector mOutputSignature; - ShaderExecutable *mShaderExecutable; - }; - - struct Sampler - { - Sampler(); - - bool active; - GLint logicalTextureUnit; - GLenum textureType; - }; - - void defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister); - void defineUniform(GLenum shader, const sh::ShaderVariable &uniform, const std::string &fullName, - sh::HLSLBlockEncoder *encoder); - bool indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps); - bool indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps); - static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount, - std::vector &outSamplers, GLuint *outUsedRange); - - template - void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType); - - template - void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType); - - template - void getUniformv(GLint location, T *params, GLenum uniformType); - - template - void defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, - sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, - bool inRowMajorLayout); - - RendererD3D *mRenderer; - DynamicHLSL *mDynamicHLSL; - - std::vector mVertexExecutables; - std::vector mPixelExecutables; - ShaderExecutable *mGeometryExecutable; - - std::string mVertexHLSL; - D3DWorkaroundType mVertexWorkarounds; - - std::string mPixelHLSL; - D3DWorkaroundType mPixelWorkarounds; - bool mUsesFragDepth; - std::vector mPixelShaderKey; - - bool mUsesPointSize; - - UniformStorage *mVertexUniformStorage; - UniformStorage *mFragmentUniformStorage; - - GLenum mTransformFeedbackBufferMode; - - std::vector mSamplersPS; - std::vector mSamplersVS; - GLuint mUsedVertexSamplerRange; - GLuint mUsedPixelSamplerRange; - bool mDirtySamplerMapping; - - int mShaderVersion; -}; - -} - -#endif // LIBGLESV2_RENDERER_PROGRAMD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp deleted file mode 100644 index cb4af367a2..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// RenderbufferD3d.cpp: Implements the RenderbufferD3D class, a specialization of RenderbufferImpl - - -#include "libGLESv2/renderer/d3d/RenderbufferD3D.h" - -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/renderer/RenderTarget.h" - -namespace rx -{ -RenderbufferD3D::RenderbufferD3D(RendererD3D *renderer) : mRenderer(renderer) -{ - mRenderTarget = NULL; -} - -RenderbufferD3D::~RenderbufferD3D() -{ - SafeDelete(mRenderTarget); -} - -RenderbufferD3D *RenderbufferD3D::makeRenderbufferD3D(RenderbufferImpl *renderbuffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(RenderbufferD3D*, renderbuffer)); - return static_cast(renderbuffer); -} - -gl::Error RenderbufferD3D::setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) -{ - // If the renderbuffer parameters are queried, the calling function - // will expect one of the valid renderbuffer formats for use in - // glRenderbufferStorage, but we should create depth and stencil buffers - // as DEPTH24_STENCIL8 - GLenum creationFormat = internalformat; - if (internalformat == GL_DEPTH_COMPONENT16 || internalformat == GL_STENCIL_INDEX8) - { - creationFormat = GL_DEPTH24_STENCIL8_OES; - } - - RenderTarget *newRT = NULL; - gl::Error error = mRenderer->createRenderTarget(width, height, creationFormat, samples, &newRT); - if (error.isError()) - { - return error; - } - - SafeDelete(mRenderTarget); - mRenderTarget = newRT; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RenderbufferD3D::setStorage(SwapChain *swapChain, bool depth) -{ - RenderTarget *newRT = NULL; - gl::Error error = mRenderer->createRenderTarget(swapChain, depth, &newRT); - if (error.isError()) - { - return error; - } - - SafeDelete(mRenderTarget); - mRenderTarget = newRT; - - return gl::Error(GL_NO_ERROR); -} - -GLsizei RenderbufferD3D::getWidth() const -{ - return (mRenderTarget ? mRenderTarget->getWidth() : 0); -} - -GLsizei RenderbufferD3D::getHeight() const -{ - return (mRenderTarget ? mRenderTarget->getHeight() : 0); -} - -GLenum RenderbufferD3D::getInternalFormat() const -{ - return (mRenderTarget ? mRenderTarget->getInternalFormat() : GL_RGBA4); -} - -GLenum RenderbufferD3D::getActualFormat() const -{ - return (mRenderTarget ? mRenderTarget->getActualFormat() : GL_RGBA4); -} - -GLsizei RenderbufferD3D::getSamples() const -{ - return (mRenderTarget ? mRenderTarget->getSamples() : 0); -} - -RenderTarget *RenderbufferD3D::getRenderTarget() -{ - return mRenderTarget; -} - -unsigned int RenderbufferD3D::getRenderTargetSerial() const -{ - return (mRenderTarget ? mRenderTarget->getSerial() : 0); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.h deleted file mode 100644 index 9440a449f2..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// RenderbufferD3d.h: Defines the RenderbufferD3D class which implements RenderbufferImpl. - -#ifndef LIBGLESV2_RENDERER_RENDERBUFFERD3D_H_ -#define LIBGLESV2_RENDERER_RENDERBUFFERD3D_H_ - -#include "angle_gl.h" - -#include "common/angleutils.h" -#include "libGLESv2/renderer/RenderbufferImpl.h" - -namespace rx -{ -class RendererD3D; -class RenderTarget; -class SwapChain; - -class RenderbufferD3D : public RenderbufferImpl -{ - public: - RenderbufferD3D(RendererD3D *renderer); - virtual ~RenderbufferD3D(); - - static RenderbufferD3D *makeRenderbufferD3D(RenderbufferImpl *renderbuffer); - - virtual gl::Error setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) override; - gl::Error setStorage(SwapChain *swapChain, bool depth); - - virtual GLsizei getWidth() const; - virtual GLsizei getHeight() const; - virtual GLenum getInternalFormat() const; - virtual GLenum getActualFormat() const; - virtual GLsizei getSamples() const; - - RenderTarget *getRenderTarget(); - unsigned int getRenderTargetSerial() const; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderbufferD3D); - - RendererD3D *mRenderer; - RenderTarget *mRenderTarget; -}; -} - -#endif // LIBGLESV2_RENDERER_RENDERBUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp deleted file mode 100644 index 5cddd8ab5e..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp +++ /dev/null @@ -1,801 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// RendererD3D.cpp: Implementation of the base D3D Renderer. - -#include "libGLESv2/renderer/d3d/RendererD3D.h" - -#include "libGLESv2/renderer/d3d/IndexDataManager.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/ResourceManager.h" -#include "libGLESv2/State.h" -#include "libGLESv2/VertexArray.h" -#include "libGLESv2/formatutils.h" -#include "common/utilities.h" - -namespace rx -{ - -RendererD3D::RendererD3D(egl::Display *display) - : mDisplay(display) -{ -} - -RendererD3D::~RendererD3D() -{ - cleanup(); -} - -void RendererD3D::cleanup() -{ - for (gl::TextureMap::iterator i = mIncompleteTextures.begin(); i != mIncompleteTextures.end(); ++i) - { - i->second.set(NULL); - } - mIncompleteTextures.clear(); -} - -// static -RendererD3D *RendererD3D::makeRendererD3D(Renderer *renderer) -{ - ASSERT(HAS_DYNAMIC_TYPE(RendererD3D*, renderer)); - return static_cast(renderer); -} - -gl::Error RendererD3D::drawElements(const gl::Data &data, - GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei instances, - const RangeUI &indexRange) -{ - ASSERT(data.state->getCurrentProgramId() != 0); - - gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); - programBinary->updateSamplerMapping(); - - gl::Error error = generateSwizzles(data); - if (error.isError()) - { - return error; - } - - if (!applyPrimitiveType(mode, count)) - { - return gl::Error(GL_NO_ERROR); - } - - error = applyRenderTarget(data, mode, false); - if (error.isError()) - { - return error; - } - - error = applyState(data, mode); - if (error.isError()) - { - return error; - } - - gl::VertexArray *vao = data.state->getVertexArray(); - TranslatedIndexData indexInfo; - indexInfo.indexRange = indexRange; - error = applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); - if (error.isError()) - { - return error; - } - - GLsizei vertexCount = indexInfo.indexRange.length() + 1; - error = applyVertexBuffer(*data.state, indexInfo.indexRange.start, vertexCount, instances); - if (error.isError()) - { - return error; - } - - bool transformFeedbackActive = applyTransformFeedbackBuffers(data); - // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation - // layer. - ASSERT(!transformFeedbackActive); - - error = applyShaders(data, transformFeedbackActive); - if (error.isError()) - { - return error; - } - - error = applyTextures(data); - if (error.isError()) - { - return error; - } - - error = applyUniformBuffers(data); - if (error.isError()) - { - return error; - } - - if (!skipDraw(data, mode)) - { - error = drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::drawArrays(const gl::Data &data, - GLenum mode, GLint first, - GLsizei count, GLsizei instances) -{ - ASSERT(data.state->getCurrentProgramId() != 0); - - gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); - programBinary->updateSamplerMapping(); - - gl::Error error = generateSwizzles(data); - if (error.isError()) - { - return error; - } - - if (!applyPrimitiveType(mode, count)) - { - return gl::Error(GL_NO_ERROR); - } - - error = applyRenderTarget(data, mode, false); - if (error.isError()) - { - return error; - } - - error = applyState(data, mode); - if (error.isError()) - { - return error; - } - - error = applyVertexBuffer(*data.state, first, count, instances); - if (error.isError()) - { - return error; - } - - bool transformFeedbackActive = applyTransformFeedbackBuffers(data); - - error = applyShaders(data, transformFeedbackActive); - if (error.isError()) - { - return error; - } - - error = applyTextures(data); - if (error.isError()) - { - return error; - } - - error = applyUniformBuffers(data); - if (error.isError()) - { - return error; - } - - if (!skipDraw(data, mode)) - { - error = drawArrays(mode, count, instances, transformFeedbackActive); - if (error.isError()) - { - return error; - } - - if (transformFeedbackActive) - { - markTransformFeedbackUsage(data); - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::generateSwizzles(const gl::Data &data, gl::SamplerType type) -{ - gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); - - size_t samplerRange = programBinary->getUsedSamplerRange(type); - - for (size_t i = 0; i < samplerRange; i++) - { - GLenum textureType = programBinary->getSamplerTextureType(type, i); - GLint textureUnit = programBinary->getSamplerMapping(type, i, *data.caps); - if (textureUnit != -1) - { - gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); - ASSERT(texture); - if (texture->getSamplerState().swizzleRequired()) - { - gl::Error error = generateSwizzle(texture); - if (error.isError()) - { - return error; - } - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::generateSwizzles(const gl::Data &data) -{ - gl::Error error = generateSwizzles(data, gl::SAMPLER_VERTEX); - if (error.isError()) - { - return error; - } - - error = generateSwizzles(data, gl::SAMPLER_PIXEL); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -// Applies the render target surface, depth stencil surface, viewport rectangle and -// scissor rectangle to the renderer -gl::Error RendererD3D::applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport) -{ - const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); - ASSERT(framebufferObject && framebufferObject->completeness(data) == GL_FRAMEBUFFER_COMPLETE); - - gl::Error error = applyRenderTarget(framebufferObject); - if (error.isError()) - { - return error; - } - - float nearZ, farZ; - data.state->getDepthRange(&nearZ, &farZ); - setViewport(data.state->getViewport(), nearZ, farZ, drawMode, - data.state->getRasterizerState().frontFace, ignoreViewport); - - setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); - - return gl::Error(GL_NO_ERROR); -} - -// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D device -gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode) -{ - const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); - int samples = framebufferObject->getSamples(data); - - gl::RasterizerState rasterizer = data.state->getRasterizerState(); - rasterizer.pointDrawMode = (drawMode == GL_POINTS); - rasterizer.multiSample = (samples != 0); - - gl::Error error = setRasterizerState(rasterizer); - if (error.isError()) - { - return error; - } - - unsigned int mask = 0; - if (data.state->isSampleCoverageEnabled()) - { - GLclampf coverageValue; - bool coverageInvert = false; - data.state->getSampleCoverageParams(&coverageValue, &coverageInvert); - if (coverageValue != 0) - { - float threshold = 0.5f; - - for (int i = 0; i < samples; ++i) - { - mask <<= 1; - - if ((i + 1) * coverageValue >= threshold) - { - threshold += 1.0f; - mask |= 1; - } - } - } - - if (coverageInvert) - { - mask = ~mask; - } - } - else - { - mask = 0xFFFFFFFF; - } - error = setBlendState(framebufferObject, data.state->getBlendState(), data.state->getBlendColor(), mask); - if (error.isError()) - { - return error; - } - - error = setDepthStencilState(data.state->getDepthStencilState(), data.state->getStencilRef(), - data.state->getStencilBackRef(), rasterizer.frontFace == GL_CCW); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -bool RendererD3D::applyTransformFeedbackBuffers(const gl::Data &data) -{ - gl::TransformFeedback *curTransformFeedback = data.state->getCurrentTransformFeedback(); - if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) - { - applyTransformFeedbackBuffers(*data.state); - return true; - } - else - { - return false; - } -} - -// Applies the shaders and shader constants to the Direct3D device -gl::Error RendererD3D::applyShaders(const gl::Data &data, bool transformFeedbackActive) -{ - gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); - - gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; - gl::VertexFormat::GetInputLayout(inputLayout, programBinary, *data.state); - - const gl::Framebuffer *fbo = data.state->getDrawFramebuffer(); - - gl::Error error = applyShaders(programBinary, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, transformFeedbackActive); - if (error.isError()) - { - return error; - } - - return programBinary->applyUniforms(); -} - -// For each Direct3D 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). -gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType, - const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount) -{ - gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); - - size_t samplerRange = programBinary->getUsedSamplerRange(shaderType); - for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) - { - GLenum textureType = programBinary->getSamplerTextureType(shaderType, samplerIndex); - GLint textureUnit = programBinary->getSamplerMapping(shaderType, samplerIndex, *data.caps); - if (textureUnit != -1) - { - gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); - ASSERT(texture); - gl::SamplerState sampler = texture->getSamplerState(); - - gl::Sampler *samplerObject = data.state->getSampler(textureUnit); - if (samplerObject) - { - samplerObject->getState(&sampler); - } - - // TODO: std::binary_search may become unavailable using older versions of GCC - if (texture->isSamplerComplete(sampler, *data.textureCaps, *data.extensions, data.clientVersion) && - !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial())) - { - gl::Error error = setSamplerState(shaderType, samplerIndex, texture, sampler); - if (error.isError()) - { - return error; - } - - error = setTexture(shaderType, samplerIndex, texture); - if (error.isError()) - { - return error; - } - } - else - { - // Texture is not sampler complete or it is in use by the framebuffer. Bind the incomplete texture. - gl::Texture *incompleteTexture = getIncompleteTexture(textureType); - gl::Error error = setTexture(shaderType, samplerIndex, incompleteTexture); - if (error.isError()) - { - return error; - } - } - } - else - { - // No texture bound to this slot even though it is used by the shader, bind a NULL texture - gl::Error error = setTexture(shaderType, samplerIndex, NULL); - if (error.isError()) - { - return error; - } - } - } - - // Set all the remaining textures to NULL - size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits - : data.caps->maxVertexTextureImageUnits; - for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) - { - gl::Error error = setTexture(shaderType, samplerIndex, NULL); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::applyTextures(const gl::Data &data) -{ - FramebufferTextureSerialArray framebufferSerials; - size_t framebufferSerialCount = getBoundFramebufferTextureSerials(data, &framebufferSerials); - - gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferSerials, framebufferSerialCount); - if (error.isError()) - { - return error; - } - - error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferSerials, framebufferSerialCount); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::applyUniformBuffers(const gl::Data &data) -{ - gl::Program *programObject = data.resourceManager->getProgram(data.state->getCurrentProgramId()); - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - - std::vector boundBuffers; - - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < programBinary->getActiveUniformBlockCount(); uniformBlockIndex++) - { - GLuint blockBinding = programObject->getUniformBlockBinding(uniformBlockIndex); - - if (data.state->getIndexedUniformBuffer(blockBinding)->id() == 0) - { - // undefined behaviour - return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."); - } - else - { - gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(blockBinding); - ASSERT(uniformBuffer); - boundBuffers.push_back(uniformBuffer); - } - } - - return programBinary->applyUniformBuffers(boundBuffers, *data.caps); -} - -bool RendererD3D::skipDraw(const gl::Data &data, 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 (!data.state->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 (gl::IsTriangleMode(drawMode)) - { - if (data.state->getRasterizerState().cullFace && data.state->getRasterizerState().cullMode == GL_FRONT_AND_BACK) - { - return true; - } - } - - return false; -} - -void RendererD3D::markTransformFeedbackUsage(const gl::Data &data) -{ - for (size_t i = 0; i < data.caps->maxTransformFeedbackSeparateAttributes; i++) - { - gl::Buffer *buffer = data.state->getIndexedTransformFeedbackBuffer(i); - if (buffer) - { - buffer->markTransformFeedbackUsage(); - } - } -} - -size_t RendererD3D::getBoundFramebufferTextureSerials(const gl::Data &data, - FramebufferTextureSerialArray *outSerialArray) -{ - size_t serialCount = 0; - - const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) - { - gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); - if (attachment && attachment->isTexture()) - { - gl::Texture *texture = attachment->getTexture(); - (*outSerialArray)[serialCount++] = texture->getTextureSerial(); - } - } - - gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); - if (depthStencilAttachment && depthStencilAttachment->isTexture()) - { - gl::Texture *depthStencilTexture = depthStencilAttachment->getTexture(); - (*outSerialArray)[serialCount++] = depthStencilTexture->getTextureSerial(); - } - - std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount); - - return serialCount; -} - -gl::Texture *RendererD3D::getIncompleteTexture(GLenum type) -{ - if (mIncompleteTextures.find(type) == mIncompleteTextures.end()) - { - const GLubyte color[] = { 0, 0, 0, 255 }; - const gl::PixelUnpackState incompleteUnpackState(1); - - gl::Texture* t = NULL; - switch (type) - { - default: - UNREACHABLE(); - // default falls through to TEXTURE_2D - - case GL_TEXTURE_2D: - { - gl::Texture2D *incomplete2d = new gl::Texture2D(createTexture(GL_TEXTURE_2D), gl::Texture::INCOMPLETE_TEXTURE_ID); - incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - t = incomplete2d; - } - break; - - case GL_TEXTURE_CUBE_MAP: - { - gl::TextureCubeMap *incompleteCube = new gl::TextureCubeMap(createTexture(GL_TEXTURE_CUBE_MAP), gl::Texture::INCOMPLETE_TEXTURE_ID); - - incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - - t = incompleteCube; - } - break; - - case GL_TEXTURE_3D: - { - gl::Texture3D *incomplete3d = new gl::Texture3D(createTexture(GL_TEXTURE_3D), gl::Texture::INCOMPLETE_TEXTURE_ID); - incomplete3d->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - - t = incomplete3d; - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - gl::Texture2DArray *incomplete2darray = new gl::Texture2DArray(createTexture(GL_TEXTURE_2D_ARRAY), gl::Texture::INCOMPLETE_TEXTURE_ID); - incomplete2darray->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - - t = incomplete2darray; - } - break; - } - - mIncompleteTextures[type].set(t); - } - - return mIncompleteTextures[type].get(); -} - -gl::Error RendererD3D::clear(const gl::Data &data, GLbitfield mask) -{ - gl::ClearParameters clearParams = data.state->getClearParameters(mask); - - // Clips the clear to the scissor rectangle but not the viewport - gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); - if (error.isError()) - { - return error; - } - - return clear(clearParams, data.state->getDrawFramebuffer()); -} - -gl::Error RendererD3D::clearBufferfv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLfloat *values) -{ - // glClearBufferfv can be called to clear the color buffer or depth buffer - gl::ClearParameters clearParams = data.state->getClearParameters(0); - - if (buffer == GL_COLOR) - { - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - clearParams.clearColor[i] = (drawbuffer == static_cast(i)); - } - clearParams.colorFClearValue = gl::ColorF(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_FLOAT; - } - - if (buffer == GL_DEPTH) - { - clearParams.clearDepth = true; - clearParams.depthClearValue = values[0]; - } - - // Clips the clear to the scissor rectangle but not the viewport - gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); - if (error.isError()) - { - return error; - } - - return clear(clearParams, data.state->getDrawFramebuffer()); -} - -gl::Error RendererD3D::clearBufferuiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLuint *values) -{ - // glClearBufferuiv can only be called to clear a color buffer - gl::ClearParameters clearParams = data.state->getClearParameters(0); - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - clearParams.clearColor[i] = (drawbuffer == static_cast(i)); - } - clearParams.colorUIClearValue = gl::ColorUI(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_UNSIGNED_INT; - - // Clips the clear to the scissor rectangle but not the viewport - gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); - if (error.isError()) - { - return error; - } - - return clear(clearParams, data.state->getDrawFramebuffer()); -} - -gl::Error RendererD3D::clearBufferiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLint *values) -{ - // glClearBufferiv can be called to clear the color buffer or stencil buffer - gl::ClearParameters clearParams = data.state->getClearParameters(0); - - if (buffer == GL_COLOR) - { - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - clearParams.clearColor[i] = (drawbuffer == static_cast(i)); - } - clearParams.colorIClearValue = gl::ColorI(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_INT; - } - - if (buffer == GL_STENCIL) - { - clearParams.clearStencil = true; - clearParams.stencilClearValue = values[1]; - } - - // Clips the clear to the scissor rectangle but not the viewport - gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); - if (error.isError()) - { - return error; - } - - return clear(clearParams, data.state->getDrawFramebuffer()); -} - -gl::Error RendererD3D::clearBufferfi(const gl::Data &data, GLenum buffer, GLint drawbuffer, - GLfloat depth, GLint stencil) -{ - if (data.state->isRasterizerDiscardEnabled()) - { - return gl::Error(GL_NO_ERROR); - } - - // glClearBufferfi can only be called to clear a depth stencil buffer - gl::ClearParameters clearParams = data.state->getClearParameters(0); - clearParams.clearDepth = true; - clearParams.depthClearValue = depth; - clearParams.clearStencil = true; - clearParams.stencilClearValue = stencil; - - // Clips the clear to the scissor rectangle but not the viewport - gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); - if (error.isError()) - { - return error; - } - - return clear(clearParams, data.state->getDrawFramebuffer()); -} - -gl::Error RendererD3D::blitFramebuffer(const gl::Data &data, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) -{ - const gl::Framebuffer *readFramebuffer = data.state->getReadFramebuffer(); - const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); - - bool blitRenderTarget = false; - bool blitDepth = false; - bool blitStencil = false; - if ((mask & GL_COLOR_BUFFER_BIT) && readFramebuffer->getReadColorbuffer() && drawFramebuffer->getFirstColorbuffer()) - { - blitRenderTarget = true; - } - if ((mask & GL_STENCIL_BUFFER_BIT) && readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) - { - blitStencil = true; - } - if ((mask & GL_DEPTH_BUFFER_BIT) && readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) - { - blitDepth = true; - } - - gl::Rectangle srcRect(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); - gl::Rectangle dstRect(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); - if (blitRenderTarget || blitDepth || blitStencil) - { - const gl::Rectangle *scissor = data.state->isScissorTestEnabled() ? &data.state->getScissor() : NULL; - gl::Error error = blitRect(readFramebuffer, srcRect, drawFramebuffer, dstRect, scissor, - blitRenderTarget, blitDepth, blitStencil, filter); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error RendererD3D::readPixels(const gl::Data &data, GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei *bufSize, void* pixels) -{ - const gl::Framebuffer *framebuffer = data.state->getReadFramebuffer(); - - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, type); - const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); - GLuint outputPitch = sizedFormatInfo.computeRowPitch(type, width, data.state->getPackAlignment()); - - return readPixels(framebuffer, x, y, width, height, format, type, outputPitch, data.state->getPackState(), - reinterpret_cast(pixels)); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h deleted file mode 100644 index a2f778763c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h +++ /dev/null @@ -1,197 +0,0 @@ - -// Copyright (c) 2014 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. -// - -// RendererD3D.h: Defines a back-end specific class for the DirectX renderer. - -#ifndef LIBGLESV2_RENDERER_RENDERERD3D_H_ -#define LIBGLESV2_RENDERER_RENDERERD3D_H_ - -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/Data.h" - -//FIXME(jmadill): std::array is currently prohibited by Chromium style guide -#include - -namespace gl -{ -class InfoLog; -struct LinkedVarying; -class Texture; -} - -namespace rx -{ -class TextureStorage; -class VertexBuffer; -class IndexBuffer; -class ShaderExecutable; -class SwapChain; -class RenderTarget; -class Image; -class TextureStorage; -class UniformStorage; - -class RendererD3D : public Renderer -{ - public: - explicit RendererD3D(egl::Display *display); - virtual ~RendererD3D(); - - static RendererD3D *makeRendererD3D(Renderer *renderer); - - gl::Error drawArrays(const gl::Data &data, - GLenum mode, GLint first, - GLsizei count, GLsizei instances) override; - - gl::Error drawElements(const gl::Data &data, - GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei instances, - const RangeUI &indexRange) override; - - gl::Error clear(const gl::Data &data, GLbitfield mask) override; - gl::Error clearBufferfv(const gl::Data &data, GLenum buffer, int drawbuffer, const GLfloat *values) override; - gl::Error clearBufferuiv(const gl::Data &data, GLenum buffer, int drawbuffer, const GLuint *values) override; - gl::Error clearBufferiv(const gl::Data &data, GLenum buffer, int drawbuffer, const GLint *values) override; - gl::Error clearBufferfi(const gl::Data &data, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) override; - - gl::Error readPixels(const gl::Data &data, GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei *bufSize, void* pixels) override; - - gl::Error blitFramebuffer(const gl::Data &data, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) override; - - // Direct3D Specific methods - virtual SwapChain *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0; - - virtual gl::Error generateSwizzle(gl::Texture *texture) = 0; - virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler) = 0; - virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0; - - virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) = 0; - - virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState) = 0; - virtual gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask) = 0; - virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, - int stencilBackRef, bool frontFaceCCW) = 0; - - virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled) = 0; - virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, - bool ignoreViewport) = 0; - - virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 0; - virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, - bool rasterizerDiscard, bool transformFeedbackActive) = 0; - virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) = 0; - virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0; - virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) = 0; - virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0; - virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0; - - virtual void markAllStateDirty() = 0; - - virtual unsigned int getReservedVertexUniformVectors() const = 0; - virtual unsigned int getReservedFragmentUniformVectors() const = 0; - virtual unsigned int getReservedVertexUniformBuffers() const = 0; - virtual unsigned int getReservedFragmentUniformBuffers() const = 0; - virtual bool getShareHandleSupport() const = 0; - virtual bool getPostSubBufferSupport() const = 0; - - // Pixel operations - virtual gl::Error copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) = 0; - virtual gl::Error copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) = 0; - virtual gl::Error copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) = 0; - virtual gl::Error copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) = 0; - - virtual gl::Error readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) = 0; - - // RenderTarget creation - virtual gl::Error createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT) = 0; - virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT) = 0; - - // Shader operations - virtual void releaseShaderCompiler() = 0; - virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutable **outExecutable) = 0; - virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround, - ShaderExecutable **outExectuable) = 0; - virtual UniformStorage *createUniformStorage(size_t storageSize) = 0; - - // Image operations - virtual Image *createImage() = 0; - virtual gl::Error generateMipmap(Image *dest, Image *source) = 0; - virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain) = 0; - virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) = 0; - virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) = 0; - virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; - virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; - - // Buffer-to-texture and Texture-to-buffer copies - virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const = 0; - virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) = 0; - - virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const = 0; - virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const = 0; - - virtual VertexBuffer *createVertexBuffer() = 0; - virtual IndexBuffer *createIndexBuffer() = 0; - - protected: - virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0; - virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, - gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0; - virtual gl::Error clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) = 0; - virtual gl::Error blitRect(const gl::Framebuffer *readTarget, const gl::Rectangle &readRect, - const gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, - bool blitDepth, bool blitStencil, GLenum filter) = 0; - - void cleanup(); - - egl::Display *mDisplay; - - private: - DISALLOW_COPY_AND_ASSIGN(RendererD3D); - - //FIXME(jmadill): std::array is currently prohibited by Chromium style guide - typedef std::array FramebufferTextureSerialArray; - - gl::Error generateSwizzles(const gl::Data &data, gl::SamplerType type); - gl::Error generateSwizzles(const gl::Data &data); - - gl::Error applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport); - gl::Error applyState(const gl::Data &data, GLenum drawMode); - bool applyTransformFeedbackBuffers(const gl::Data &data); - gl::Error applyShaders(const gl::Data &data, bool transformFeedbackActive); - gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType, - const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount); - gl::Error applyTextures(const gl::Data &data); - gl::Error applyUniformBuffers(const gl::Data &data); - - bool skipDraw(const gl::Data &data, GLenum drawMode); - void markTransformFeedbackUsage(const gl::Data &data); - - size_t getBoundFramebufferTextureSerials(const gl::Data &data, - FramebufferTextureSerialArray *outSerialArray); - gl::Texture *getIncompleteTexture(GLenum type); - - gl::TextureMap mIncompleteTextures; -}; - -} - -#endif // LIBGLESV2_RENDERER_RENDERERD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp deleted file mode 100644 index 8a97579e16..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp +++ /dev/null @@ -1,481 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// ShaderD3D.cpp: Defines the rx::ShaderD3D class which implements rx::ShaderImpl. - -#include "libGLESv2/Shader.h" -#include "libGLESv2/main.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/renderer/d3d/ShaderD3D.h" - -#include "common/features.h" -#include "common/utilities.h" - -// Definitions local to the translation unit -namespace -{ - -const char *GetShaderTypeString(GLenum type) -{ - switch (type) - { - case GL_VERTEX_SHADER: - return "VERTEX"; - - case GL_FRAGMENT_SHADER: - return "FRAGMENT"; - - default: - UNREACHABLE(); - return ""; - } -} - -} - -namespace rx -{ - -template -void FilterInactiveVariables(std::vector *variableList) -{ - ASSERT(variableList); - - for (size_t varIndex = 0; varIndex < variableList->size();) - { - if (!(*variableList)[varIndex].staticUse) - { - variableList->erase(variableList->begin() + varIndex); - } - else - { - varIndex++; - } - } -} - -void *ShaderD3D::mFragmentCompiler = NULL; -void *ShaderD3D::mVertexCompiler = NULL; - -template -const std::vector *GetShaderVariables(const std::vector *variableList) -{ - ASSERT(variableList); - return variableList; -} - -ShaderD3D::ShaderD3D(const gl::Data &data, GLenum type, RendererD3D *renderer) - : mType(type), - mRenderer(renderer), - mShaderVersion(100) -{ - uncompile(); - initializeCompiler(data); -} - -ShaderD3D::~ShaderD3D() -{ -} - -ShaderD3D *ShaderD3D::makeShaderD3D(ShaderImpl *impl) -{ - ASSERT(HAS_DYNAMIC_TYPE(ShaderD3D*, impl)); - return static_cast(impl); -} - -const ShaderD3D *ShaderD3D::makeShaderD3D(const ShaderImpl *impl) -{ - ASSERT(HAS_DYNAMIC_TYPE(const ShaderD3D*, impl)); - return static_cast(impl); -} - -std::string ShaderD3D::getDebugInfo() const -{ - return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mType) + " SHADER END\n"; -} - -// Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler) -void ShaderD3D::initializeCompiler(const gl::Data &data) -{ - if (!mFragmentCompiler) - { - bool result = ShInitialize(); - - if (result) - { - ShShaderSpec specVersion = (data.clientVersion >= 3) ? SH_GLES3_SPEC : SH_GLES2_SPEC; - ShShaderOutput hlslVersion = (mRenderer->getMajorShaderModel() >= 4) ? SH_HLSL11_OUTPUT : SH_HLSL9_OUTPUT; - - ShBuiltInResources resources; - ShInitBuiltInResources(&resources); - - const gl::Caps &caps = *data.caps; - const gl::Extensions &extensions = *data.extensions; - - resources.MaxVertexAttribs = caps.maxVertexAttributes; - resources.MaxVertexUniformVectors = caps.maxVertexUniformVectors; - resources.MaxVaryingVectors = caps.maxVaryingVectors; - resources.MaxVertexTextureImageUnits = caps.maxVertexTextureImageUnits; - resources.MaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; - resources.MaxTextureImageUnits = caps.maxTextureImageUnits; - resources.MaxFragmentUniformVectors = caps.maxFragmentUniformVectors; - resources.MaxDrawBuffers = caps.maxDrawBuffers; - resources.OES_standard_derivatives = extensions.standardDerivatives; - resources.EXT_draw_buffers = extensions.drawBuffers; - resources.EXT_shader_texture_lod = 1; - // resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported. - resources.FragmentPrecisionHigh = 1; // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp - resources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output - // GLSL ES 3.0 constants - resources.MaxVertexOutputVectors = caps.maxVertexOutputComponents / 4; - resources.MaxFragmentInputVectors = caps.maxFragmentInputComponents / 4; - resources.MinProgramTexelOffset = caps.minProgramTexelOffset; - resources.MaxProgramTexelOffset = caps.maxProgramTexelOffset; - - mFragmentCompiler = ShConstructCompiler(GL_FRAGMENT_SHADER, specVersion, hlslVersion, &resources); - mVertexCompiler = ShConstructCompiler(GL_VERTEX_SHADER, specVersion, hlslVersion, &resources); - } - } -} - -void ShaderD3D::releaseCompiler() -{ - ShDestruct(mFragmentCompiler); - ShDestruct(mVertexCompiler); - - mFragmentCompiler = NULL; - mVertexCompiler = NULL; - - ShFinalize(); -} - -void ShaderD3D::parseVaryings(void *compiler) -{ - if (!mHlsl.empty()) - { - const std::vector *varyings = ShGetVaryings(compiler); - ASSERT(varyings); - - for (size_t varyingIndex = 0; varyingIndex < varyings->size(); varyingIndex++) - { - mVaryings.push_back(gl::PackedVarying((*varyings)[varyingIndex])); - } - - mUsesMultipleRenderTargets = mHlsl.find("GL_USES_MRT") != std::string::npos; - mUsesFragColor = mHlsl.find("GL_USES_FRAG_COLOR") != std::string::npos; - mUsesFragData = mHlsl.find("GL_USES_FRAG_DATA") != std::string::npos; - mUsesFragCoord = mHlsl.find("GL_USES_FRAG_COORD") != std::string::npos; - mUsesFrontFacing = mHlsl.find("GL_USES_FRONT_FACING") != std::string::npos; - mUsesPointSize = mHlsl.find("GL_USES_POINT_SIZE") != std::string::npos; - mUsesPointCoord = mHlsl.find("GL_USES_POINT_COORD") != std::string::npos; - mUsesDepthRange = mHlsl.find("GL_USES_DEPTH_RANGE") != std::string::npos; - mUsesFragDepth = mHlsl.find("GL_USES_FRAG_DEPTH") != std::string::npos; - mUsesDiscardRewriting = mHlsl.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; - mUsesNestedBreak = mHlsl.find("ANGLE_USES_NESTED_BREAK") != std::string::npos; - } -} - -void ShaderD3D::resetVaryingsRegisterAssignment() -{ - for (size_t varyingIndex = 0; varyingIndex < mVaryings.size(); varyingIndex++) - { - mVaryings[varyingIndex].resetRegisterAssignment(); - } -} - -// initialize/clean up previous state -void ShaderD3D::uncompile() -{ - // set by compileToHLSL - mHlsl.clear(); - mInfoLog.clear(); - - mUsesMultipleRenderTargets = false; - mUsesFragColor = false; - mUsesFragData = false; - mUsesFragCoord = false; - mUsesFrontFacing = false; - mUsesPointSize = false; - mUsesPointCoord = false; - mUsesDepthRange = false; - mUsesFragDepth = false; - mShaderVersion = 100; - mUsesDiscardRewriting = false; - mUsesNestedBreak = false; - - mVaryings.clear(); - mUniforms.clear(); - mInterfaceBlocks.clear(); - mActiveAttributes.clear(); - mActiveOutputVariables.clear(); - mDebugInfo.clear(); -} - -void ShaderD3D::compileToHLSL(const gl::Data &data, void *compiler, const std::string &source) -{ - // ensure the compiler is loaded - initializeCompiler(data); - - int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES); - std::string sourcePath; - -#if !defined (ANGLE_ENABLE_WINDOWS_STORE) - if (gl::perfActive()) - { - sourcePath = getTempPath(); - writeFile(sourcePath.c_str(), source.c_str(), source.length()); - compileOptions |= SH_LINE_DIRECTIVES; - } -#endif - - int result; - if (sourcePath.empty()) - { - const char* sourceStrings[] = - { - source.c_str(), - }; - - result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions); - } - else - { - const char* sourceStrings[] = - { - sourcePath.c_str(), - source.c_str(), - }; - - result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions | SH_SOURCE_PATH); - } - - mShaderVersion = ShGetShaderVersion(compiler); - - if (mShaderVersion == 300 && data.clientVersion < 3) - { - mInfoLog = "GLSL ES 3.00 is not supported by OpenGL ES 2.0 contexts"; - TRACE("\n%s", mInfoLog.c_str()); - } - else if (result) - { - mHlsl = ShGetObjectCode(compiler); - -#ifdef _DEBUG - // Prefix hlsl shader with commented out glsl shader - // Useful in diagnostics tools like pix which capture the hlsl shaders - std::ostringstream hlslStream; - hlslStream << "// GLSL\n"; - hlslStream << "//\n"; - - size_t curPos = 0; - while (curPos != std::string::npos) - { - size_t nextLine = source.find("\n", curPos); - size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1); - - hlslStream << "// " << source.substr(curPos, len); - - curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); - } - hlslStream << "\n\n"; - hlslStream << mHlsl; - mHlsl = hlslStream.str(); -#endif - - mUniforms = *GetShaderVariables(ShGetUniforms(compiler)); - - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - const sh::Uniform &uniform = mUniforms[uniformIndex]; - - if (uniform.staticUse) - { - unsigned int index = -1; - bool result = ShGetUniformRegister(compiler, uniform.name, &index); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(result); - - mUniformRegisterMap[uniform.name] = index; - } - } - - mInterfaceBlocks = *GetShaderVariables(ShGetInterfaceBlocks(compiler)); - - for (size_t blockIndex = 0; blockIndex < mInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &interfaceBlock = mInterfaceBlocks[blockIndex]; - - if (interfaceBlock.staticUse) - { - unsigned int index = -1; - bool result = ShGetInterfaceBlockRegister(compiler, interfaceBlock.name, &index); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(result); - - mInterfaceBlockRegisterMap[interfaceBlock.name] = index; - } - } - } - else - { - mInfoLog = ShGetInfoLog(compiler); - - TRACE("\n%s", mInfoLog.c_str()); - } -} - -D3DWorkaroundType ShaderD3D::getD3DWorkarounds() const -{ - if (mUsesDiscardRewriting) - { - // ANGLE issue 486: - // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization - return ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION; - } - - if (mUsesNestedBreak) - { - // ANGLE issue 603: - // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop, by maximizing optimization - // We want to keep the use of ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes precedence - return ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION; - } - - return ANGLE_D3D_WORKAROUND_NONE; -} - -// true if varying x has a higher priority in packing than y -bool ShaderD3D::compareVarying(const gl::PackedVarying &x, const gl::PackedVarying &y) -{ - if (x.type == y.type) - { - return x.arraySize > y.arraySize; - } - - // Special case for handling structs: we sort these to the end of the list - if (x.type == GL_STRUCT_ANGLEX) - { - return false; - } - - if (y.type == GL_STRUCT_ANGLEX) - { - return true; - } - - return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type); -} - -unsigned int ShaderD3D::getUniformRegister(const std::string &uniformName) const -{ - ASSERT(mUniformRegisterMap.count(uniformName) > 0); - return mUniformRegisterMap.find(uniformName)->second; -} - -unsigned int ShaderD3D::getInterfaceBlockRegister(const std::string &blockName) const -{ - ASSERT(mInterfaceBlockRegisterMap.count(blockName) > 0); - return mInterfaceBlockRegisterMap.find(blockName)->second; -} - -void *ShaderD3D::getCompiler() -{ - if (mType == GL_VERTEX_SHADER) - { - return mVertexCompiler; - } - else - { - ASSERT(mType == GL_FRAGMENT_SHADER); - return mFragmentCompiler; - } -} - -ShShaderOutput ShaderD3D::getCompilerOutputType(GLenum shader) -{ - void *compiler = NULL; - - switch (shader) - { - case GL_VERTEX_SHADER: compiler = mVertexCompiler; break; - case GL_FRAGMENT_SHADER: compiler = mFragmentCompiler; break; - default: UNREACHABLE(); return SH_HLSL9_OUTPUT; - } - - return ShGetShaderOutputType(compiler); -} - -bool ShaderD3D::compile(const gl::Data &data, const std::string &source) -{ - uncompile(); - - void *compiler = getCompiler(); - - compileToHLSL(data, compiler, source); - - if (mType == GL_VERTEX_SHADER) - { - parseAttributes(compiler); - } - - parseVaryings(compiler); - - if (mType == GL_FRAGMENT_SHADER) - { - std::sort(mVaryings.begin(), mVaryings.end(), compareVarying); - - const std::string &hlsl = getTranslatedSource(); - if (!hlsl.empty()) - { - mActiveOutputVariables = *GetShaderVariables(ShGetOutputVariables(compiler)); - FilterInactiveVariables(&mActiveOutputVariables); - } - } - -#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED - mDebugInfo += std::string("// ") + GetShaderTypeString(mType) + " SHADER BEGIN\n"; - mDebugInfo += "\n// GLSL BEGIN\n\n" + source + "\n\n// GLSL END\n\n\n"; - mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + getTranslatedSource() + "\n// INITIAL HLSL END\n\n\n"; - // Successive steps will append more info -#else - mDebugInfo += getTranslatedSource(); -#endif - - return !getTranslatedSource().empty(); -} - -void ShaderD3D::parseAttributes(void *compiler) -{ - const std::string &hlsl = getTranslatedSource(); - if (!hlsl.empty()) - { - mActiveAttributes = *GetShaderVariables(ShGetAttributes(compiler)); - FilterInactiveVariables(&mActiveAttributes); - } -} - -int ShaderD3D::getSemanticIndex(const std::string &attributeName) const -{ - if (!attributeName.empty()) - { - int semanticIndex = 0; - for (size_t attributeIndex = 0; attributeIndex < mActiveAttributes.size(); attributeIndex++) - { - const sh::ShaderVariable &attribute = mActiveAttributes[attributeIndex]; - - if (attribute.name == attributeName) - { - return semanticIndex; - } - - semanticIndex += gl::VariableRegisterCount(attribute.type); - } - } - - return -1; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.h deleted file mode 100644 index 3c9aac2c12..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// ShaderD3D.h: Defines the rx::ShaderD3D class which implements rx::ShaderImpl. - -#ifndef LIBGLESV2_RENDERER_SHADERD3D_H_ -#define LIBGLESV2_RENDERER_SHADERD3D_H_ - -#include "libGLESv2/renderer/ShaderImpl.h" -#include "libGLESv2/renderer/Workarounds.h" -#include "libGLESv2/Shader.h" - -#include - -namespace rx -{ -class DynamicHLSL; -class RendererD3D; - -class ShaderD3D : public ShaderImpl -{ - friend class DynamicHLSL; - - public: - ShaderD3D(const gl::Data &data, GLenum type, RendererD3D *renderer); - virtual ~ShaderD3D(); - - static ShaderD3D *makeShaderD3D(ShaderImpl *impl); - static const ShaderD3D *makeShaderD3D(const ShaderImpl *impl); - - // ShaderImpl implementation - virtual const std::string &getInfoLog() const { return mInfoLog; } - virtual const std::string &getTranslatedSource() const { return mHlsl; } - virtual std::string getDebugInfo() const; - - // D3D-specific methods - virtual void uncompile(); - void resetVaryingsRegisterAssignment(); - unsigned int getUniformRegister(const std::string &uniformName) const; - unsigned int getInterfaceBlockRegister(const std::string &blockName) const; - int getSemanticIndex(const std::string &attributeName) const; - void appendDebugInfo(const std::string &info) { mDebugInfo += info; } - - D3DWorkaroundType getD3DWorkarounds() const; - int getShaderVersion() const { return mShaderVersion; } - bool usesDepthRange() const { return mUsesDepthRange; } - bool usesPointSize() const { return mUsesPointSize; } - - static void releaseCompiler(); - static ShShaderOutput getCompilerOutputType(GLenum shader); - - virtual bool compile(const gl::Data &data, const std::string &source); - - private: - DISALLOW_COPY_AND_ASSIGN(ShaderD3D); - - void compileToHLSL(const gl::Data &data, void *compiler, const std::string &source); - void parseVaryings(void *compiler); - - void initializeCompiler(const gl::Data &data); - void parseAttributes(void *compiler); - void *getCompiler(); - - static bool compareVarying(const gl::PackedVarying &x, const gl::PackedVarying &y); - - static void *mFragmentCompiler; - static void *mVertexCompiler; - - GLenum mType; - RendererD3D *mRenderer; - - int mShaderVersion; - - bool mUsesMultipleRenderTargets; - bool mUsesFragColor; - bool mUsesFragData; - bool mUsesFragCoord; - bool mUsesFrontFacing; - bool mUsesPointSize; - bool mUsesPointCoord; - bool mUsesDepthRange; - bool mUsesFragDepth; - bool mUsesDiscardRewriting; - bool mUsesNestedBreak; - - std::string mHlsl; - std::string mInfoLog; - std::string mDebugInfo; - std::map mUniformRegisterMap; - std::map mInterfaceBlockRegisterMap; -}; - -} - -#endif // LIBGLESV2_RENDERER_SHADERD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp deleted file mode 100644 index 4a67701fdf..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp +++ /dev/null @@ -1,2813 +0,0 @@ -// -// Copyright 2014 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. -// - -// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends. - -#include "libGLESv2/Buffer.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/main.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/renderer/BufferImpl.h" -#include "libGLESv2/renderer/RenderTarget.h" -#include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/renderer/d3d/TextureD3D.h" -#include "libGLESv2/renderer/d3d/TextureStorage.h" -#include "libGLESv2/renderer/d3d/ImageD3D.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" - -#include "libEGL/Surface.h" - -#include "common/mathutil.h" -#include "common/utilities.h" - -namespace rx -{ - -namespace -{ - -gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const void *pixels, const uint8_t **pointerOut) -{ - if (unpack.pixelBuffer.id() != 0) - { - // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported - gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); - ptrdiff_t offset = reinterpret_cast(pixels); - - // TODO: this is the only place outside of renderer that asks for a buffers raw data. - // This functionality should be moved into renderer and the getData method of BufferImpl removed. - BufferD3D *bufferD3D = BufferD3D::makeBufferD3D(pixelBuffer->getImplementation()); - ASSERT(bufferD3D); - const uint8_t *bufferData = NULL; - gl::Error error = bufferD3D->getData(&bufferData); - if (error.isError()) - { - return error; - } - - *pointerOut = bufferData + offset; - } - else - { - *pointerOut = static_cast(pixels); - } - - return gl::Error(GL_NO_ERROR); -} - -bool IsRenderTargetUsage(GLenum usage) -{ - return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); -} - -} - -TextureD3D::TextureD3D(RendererD3D *renderer) - : mRenderer(renderer), - mUsage(GL_NONE), - mDirtyImages(true), - mImmutable(false), - mTexStorage(NULL) -{ -} - -TextureD3D::~TextureD3D() -{ -} - -TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture)); - return static_cast(texture); -} - -TextureStorage *TextureD3D::getNativeTexture() -{ - // ensure the underlying texture is created - initializeStorage(false); - - if (mTexStorage) - { - updateStorage(); - } - - return mTexStorage; -} - -GLint TextureD3D::getBaseLevelWidth() const -{ - const Image *baseImage = getBaseLevelImage(); - return (baseImage ? baseImage->getWidth() : 0); -} - -GLint TextureD3D::getBaseLevelHeight() const -{ - const Image *baseImage = getBaseLevelImage(); - return (baseImage ? baseImage->getHeight() : 0); -} - -GLint TextureD3D::getBaseLevelDepth() const -{ - const Image *baseImage = getBaseLevelImage(); - return (baseImage ? baseImage->getDepth() : 0); -} - -// Note: "base level image" is loosely defined to be any image from the base level, -// where in the base of 2D array textures and cube maps there are several. Don't use -// the base level image for anything except querying texture format and size. -GLenum TextureD3D::getBaseLevelInternalFormat() const -{ - const Image *baseImage = getBaseLevelImage(); - return (baseImage ? baseImage->getInternalFormat() : GL_NONE); -} - -bool TextureD3D::shouldUseSetData(const Image *image) const -{ - if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload) - { - return false; - } - - gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); - - // We can only handle full updates for depth-stencil textures, so to avoid complications - // disable them entirely. - if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0) - { - return false; - } - - // TODO(jmadill): Handle compressed internal formats - return (mTexStorage && !internalFormat.compressed); -} - -gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index) -{ - Image *image = getImage(index); - ASSERT(image); - - // No-op - if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) - { - return gl::Error(GL_NO_ERROR); - } - - // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. - // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData); - if (error.isError()) - { - return error; - } - - if (pixelData != NULL) - { - gl::Error error(GL_NO_ERROR); - - if (shouldUseSetData(image)) - { - error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData); - } - else - { - error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData); - } - - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index) -{ - // CPU readback & copy where direct GPU copy is not supported - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData); - if (error.isError()) - { - return error; - } - - if (pixelData != NULL) - { - Image *image = getImage(index); - ASSERT(image); - - gl::Box region(xoffset, yoffset, zoffset, width, height, depth); - if (shouldUseSetData(image)) - { - return mTexStorage->setData(index, image, ®ion, type, unpack, pixelData); - } - - gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, - type, pixelData); - if (error.isError()) - { - return error; - } - - error = commitRegion(index, region); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D::setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image) -{ - // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. - // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData); - if (error.isError()) - { - return error; - } - - if (pixelData != NULL) - { - gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixelData); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image) -{ - const uint8_t *pixelData = NULL; - gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData); - if (error.isError()) - { - return error; - } - - if (pixelData != NULL) - { - gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixelData); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - - return gl::Error(GL_NO_ERROR); -} - -bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) -{ - return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); -} - -gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, - GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget) -{ - // No-op - if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) - { - return gl::Error(GL_NO_ERROR); - } - - // In order to perform the fast copy through the shader, we must have the right format, and be able - // to create a render target. - ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); - - uintptr_t offset = reinterpret_cast(pixels); - - gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const -{ - if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT) - { - // Maximum number of levels - return gl::log2(std::max(std::max(width, height), depth)) + 1; - } - else - { - // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps. - return 1; - } -} - -int TextureD3D::mipLevels() const -{ - return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; -} - -TextureStorage *TextureD3D::getStorage() -{ - ASSERT(mTexStorage); - return mTexStorage; -} - -Image *TextureD3D::getBaseLevelImage() const -{ - return getImage(getImageIndex(0, 0)); -} - -gl::Error TextureD3D::generateMipmaps() -{ - GLint mipCount = mipLevels(); - - if (mipCount == 1) - { - return gl::Error(GL_NO_ERROR); // no-op - } - - // Set up proper mipmap chain in our Image array. - initMipmapsImages(); - - // We know that all layers have the same dimension, for the texture to be complete - GLint layerCount = static_cast(getLayerCount(0)); - - // When making mipmaps with the setData workaround enabled, the texture storage has - // the image data already. For non-render-target storage, we have to pull it out into - // an image layer. - if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage) - { - if (!mTexStorage->isRenderTarget()) - { - // Copy from the storage mip 0 to Image mip 0 - for (GLint layer = 0; layer < layerCount; ++layer) - { - gl::ImageIndex srcIndex = getImageIndex(0, layer); - - Image *image = getImage(srcIndex); - gl::Rectangle area(0, 0, image->getWidth(), image->getHeight()); - gl::Error error = image->copy(0, 0, 0, area, srcIndex, mTexStorage); - if (error.isError()) - { - return error; - } - } - } - else - { - gl::Error error = updateStorage(); - if (error.isError()) - { - return error; - } - } - } - - bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget()); - - for (GLint layer = 0; layer < layerCount; ++layer) - { - for (GLint mip = 1; mip < mipCount; ++mip) - { - ASSERT(getLayerCount(mip) == layerCount); - - gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer); - gl::ImageIndex destIndex = getImageIndex(mip, layer); - - if (renderableStorage) - { - // GPU-side mipmapping - gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex); - if (error.isError()) - { - return error; - } - } - else - { - // CPU-side mipmapping - gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex)); - if (error.isError()) - { - return error; - } - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -bool TextureD3D::isBaseImageZeroSize() const -{ - Image *baseImage = getBaseLevelImage(); - - if (!baseImage || baseImage->getWidth() <= 0) - { - return true; - } - - if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0) - { - return true; - } - - if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0) - { - return true; - } - - if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0) - { - return true; - } - - return false; -} - -gl::Error TextureD3D::ensureRenderTarget() -{ - gl::Error error = initializeStorage(true); - if (error.isError()) - { - return error; - } - - if (!isBaseImageZeroSize()) - { - ASSERT(mTexStorage); - if (!mTexStorage->isRenderTarget()) - { - TextureStorage *newRenderTargetStorage = NULL; - error = createCompleteStorage(true, &newRenderTargetStorage); - if (error.isError()) - { - return error; - } - - error = mTexStorage->copyToStorage(newRenderTargetStorage); - if (error.isError()) - { - SafeDelete(newRenderTargetStorage); - return error; - } - - error = setCompleteTexStorage(newRenderTargetStorage); - if (error.isError()) - { - SafeDelete(newRenderTargetStorage); - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const -{ - Image *image = getImage(index); - bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0))); - return (image->isRenderableFormat() && levelsComplete); -} - -gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) -{ - if (mTexStorage) - { - ASSERT(isValidIndex(index)); - Image *image = getImage(index); - ImageD3D *imageD3D = ImageD3D::makeImageD3D(image); - gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region); - if (error.isError()) - { - return error; - } - - image->markClean(); - } - - return gl::Error(GL_NO_ERROR); -} - -TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer) - : TextureD3D(renderer) -{ - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) - { - mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage()); - } -} - -TextureD3D_2D::~TextureD3D_2D() -{ - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) - { - delete mImageArray[i]; - } - - SafeDelete(mTexStorage); -} - -Image *TextureD3D_2D::getImage(int level, int layer) const -{ - ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(layer == 0); - return mImageArray[level]; -} - -Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const -{ - ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(!index.hasLayer()); - ASSERT(index.type == GL_TEXTURE_2D); - return mImageArray[index.mipIndex]; -} - -GLsizei TextureD3D_2D::getLayerCount(int level) const -{ - ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - return 1; -} - -GLsizei TextureD3D_2D::getWidth(GLint level) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getWidth(); - else - return 0; -} - -GLsizei TextureD3D_2D::getHeight(GLint level) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getHeight(); - else - return 0; -} - -GLenum TextureD3D_2D::getInternalFormat(GLint level) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getInternalFormat(); - else - return GL_NONE; -} - -GLenum TextureD3D_2D::getActualFormat(GLint level) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getActualFormat(); - else - return GL_NONE; -} - -bool TextureD3D_2D::isDepth(GLint level) const -{ - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; -} - -gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, - GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, - const void *pixels) -{ - ASSERT(target == GL_TEXTURE_2D && depth == 1); - - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); - - bool fastUnpacked = false; - - redefineImage(level, sizedInternalFormat, width, height); - - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - - // Attempt a fast gpu copy of the pixel data to the surface - if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) - { - // Will try to create RT storage if it does not exist - RenderTarget *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - - gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); - - error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); - if (error.isError()) - { - return error; - } - - // Ensure we don't overwrite our newly initialized data - mImageArray[level]->markClean(); - - fastUnpacked = true; - } - - if (!fastUnpacked) - { - gl::Error error = TextureD3D::setImage(unpack, type, pixels, index); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format, - GLsizei width, GLsizei height, GLsizei depth, - GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_2D && depth == 1); - - // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, format, width, height); - - return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]); -} - -gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0); - - bool fastUnpacked = false; - - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - gl::Box destArea(xoffset, yoffset, 0, width, height, 1); - if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) - { - RenderTarget *renderTarget = NULL; - gl::Error error = getRenderTarget(index, &renderTarget); - if (error.isError()) - { - return error; - } - - error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget); - if (error.isError()) - { - return error; - } - - // Ensure we don't overwrite our newly initialized data - mImageArray[level]->markClean(); - - fastUnpacked = true; - } - - if (!fastUnpacked) - { - return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, - unpack, pixels, index); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, - GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0); - - gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[level]); - if (error.isError()) - { - return error; - } - - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - gl::Box region(xoffset, yoffset, 0, width, height, 1); - return commitRegion(index, region); -} - -gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, - gl::Framebuffer *source) -{ - ASSERT(target == GL_TEXTURE_2D); - - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); - redefineImage(level, sizedInternalFormat, width, height); - - gl::Rectangle sourceRect(x, y, width, height); - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - - if (!canCreateRenderTargetForImage(index)) - { - gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - else - { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - mImageArray[level]->markClean(); - - if (width != 0 && height != 0 && isValidLevel(level)) - { - gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) -{ - ASSERT(target == GL_TEXTURE_2D && zoffset == 0); - - // can only make our texture storage to a render target if level 0 is defined (with a width & height) and - // the current level we're copying to is defined (with appropriate format, width & height) - - gl::Rectangle sourceRect(x, y, width, height); - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - - if (!canCreateRenderTargetForImage(index)) - { - gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - else - { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - if (isValidLevel(level)) - { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - - error = mRenderer->copyImage2D(source, sourceRect, - gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - xoffset, yoffset, mTexStorage, level); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - ASSERT(target == GL_TEXTURE_2D && depth == 1); - - for (int level = 0; level < levels; level++) - { - GLsizei levelWidth = std::max(1, width >> level); - GLsizei levelHeight = std::max(1, height >> level); - mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true); - } - - for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); - } - - // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels); - - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - mImmutable = true; - - return gl::Error(GL_NO_ERROR); -} - -void TextureD3D_2D::bindTexImage(egl::Surface *surface) -{ - GLenum internalformat = surface->getFormat(); - - mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true); - - if (mTexStorage) - { - SafeDelete(mTexStorage); - } - - mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain()); - - mDirtyImages = true; -} - -void TextureD3D_2D::releaseTexImage() -{ - if (mTexStorage) - { - SafeDelete(mTexStorage); - } - - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); - } -} - -void TextureD3D_2D::initMipmapsImages() -{ - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) - { - redefineImage(level, getBaseLevelInternalFormat(), - std::max(getBaseLevelWidth() >> level, 1), - std::max(getBaseLevelHeight() >> level, 1)); - } -} - -unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index) -{ - ASSERT(!index.hasLayer()); - return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); -} - -gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - ASSERT(!index.hasLayer()); - - // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } - - return mTexStorage->getRenderTarget(index, outRT); -} - -bool TextureD3D_2D::isValidLevel(int level) const -{ - return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false); -} - -bool TextureD3D_2D::isLevelComplete(int level) const -{ - if (isImmutable()) - { - return true; - } - - const Image *baseImage = getBaseLevelImage(); - - GLsizei width = baseImage->getWidth(); - GLsizei height = baseImage->getHeight(); - - if (width <= 0 || height <= 0) - { - return false; - } - - // The base image level is complete if the width and height are positive - if (level == 0) - { - return true; - } - - ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); - ImageD3D *image = mImageArray[level]; - - if (image->getInternalFormat() != baseImage->getInternalFormat()) - { - return false; - } - - if (image->getWidth() != std::max(1, width >> level)) - { - return false; - } - - if (image->getHeight() != std::max(1, height >> level)) - { - return false; - } - - return true; -} - -bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const -{ - return isLevelComplete(index.mipIndex); -} - -// Constructs a native texture resource from the texture images -gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) -{ - // Only initialize the first time this texture is used as a render target or shader resource - if (mTexStorage) - { - return gl::Error(GL_NO_ERROR); - } - - // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) - { - return gl::Error(GL_NO_ERROR); - } - - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); - - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } - - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - ASSERT(mTexStorage); - - // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const -{ - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLenum internalFormat = getBaseLevelInternalFormat(); - - ASSERT(width > 0 && height > 0); - - // use existing storage level count, when previously specified by TexStorage*D - GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); - - // TODO(geofflang): Determine if the texture creation succeeded - *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) -{ - if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) - { - for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) - { - gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level); - if (error.isError()) - { - return error; - } - } - } - - SafeDelete(mTexStorage); - mTexStorage = newCompleteTexStorage; - - mDirtyImages = true; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2D::updateStorage() -{ - ASSERT(mTexStorage != NULL); - GLint storageLevels = mTexStorage->getLevelCount(); - for (int level = 0; level < storageLevels; level++) - { - if (mImageArray[level]->isDirty() && isLevelComplete(level)) - { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2D::updateStorageLevel(int level) -{ - ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); - ASSERT(isLevelComplete(level)); - - if (mImageArray[level]->isDirty()) - { - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) -{ - // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const GLenum storageFormat = getBaseLevelInternalFormat(); - - mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false); - - if (mTexStorage) - { - const int storageLevels = mTexStorage->getLevelCount(); - - if ((level >= storageLevels && storageLevels != 0) || - width != storageWidth || - height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage - { - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - SafeDelete(mTexStorage); - mDirtyImages = true; - } - } -} - -gl::ImageIndexIterator TextureD3D_2D::imageIterator() const -{ - return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); -} - -gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const -{ - // "layer" does not apply to 2D Textures. - return gl::ImageIndex::Make2D(mip); -} - -bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const -{ - return (mTexStorage && index.type == GL_TEXTURE_2D && - index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); -} - -TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer) - : TextureD3D(renderer) -{ - for (int i = 0; i < 6; i++) - { - for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) - { - mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage()); - } - } -} - -TextureD3D_Cube::~TextureD3D_Cube() -{ - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. - for (int i = 0; i < 6; i++) - { - for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) - { - SafeDelete(mImageArray[i][j]); - } - } - - SafeDelete(mTexStorage); -} - -Image *TextureD3D_Cube::getImage(int level, int layer) const -{ - ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(layer < 6); - return mImageArray[layer][level]; -} - -Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const -{ - ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(index.layerIndex < 6); - return mImageArray[index.layerIndex][index.mipIndex]; -} - -GLsizei TextureD3D_Cube::getLayerCount(int level) const -{ - ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - return 6; -} - -GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[layer][level]->getInternalFormat(); - else - return GL_NONE; -} - -bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const -{ - return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; -} - -gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, - GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, - const void *pixels) -{ - ASSERT(depth == 1); - - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - - redefineImage(index.layerIndex, level, sizedInternalFormat, width, height); - - return TextureD3D::setImage(unpack, type, pixels, index); -} - -gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, - GLsizei width, GLsizei height, GLsizei depth, - GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(depth == 1); - - // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); - - redefineImage(faceIndex, level, format, width, height); - - return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]); -} - -gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(depth == 1 && zoffset == 0); - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index); -} - -gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, - GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(depth == 1 && zoffset == 0); - - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - - gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[index.layerIndex][level]); - if (error.isError()) - { - return error; - } - - gl::Box region(xoffset, yoffset, 0, width, height, 1); - return commitRegion(index, region); -} - -gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, - GLsizei width, GLsizei height, gl::Framebuffer *source) -{ - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); - - redefineImage(faceIndex, level, sizedInternalFormat, width, height); - - gl::Rectangle sourceRect(x, y, width, height); - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - - if (!canCreateRenderTargetForImage(index)) - { - gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - else - { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - mImageArray[faceIndex][level]->markClean(); - - ASSERT(width == height); - - if (width > 0 && isValidFaceLevel(faceIndex, level)) - { - error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) -{ - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); - - gl::Rectangle sourceRect(x, y, width, height); - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - - if (!canCreateRenderTargetForImage(index)) - { - gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - else - { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - if (isValidFaceLevel(faceIndex, level)) - { - error = updateStorageFaceLevel(faceIndex, level); - if (error.isError()) - { - return error; - } - - error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - xoffset, yoffset, mTexStorage, target, level); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - ASSERT(width == height); - ASSERT(depth == 1); - - for (int level = 0; level < levels; level++) - { - GLsizei mipSize = std::max(1, width >> level); - for (int faceIndex = 0; faceIndex < 6; faceIndex++) - { - mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true); - } - } - - for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - for (int faceIndex = 0; faceIndex < 6; faceIndex++) - { - mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true); - } - } - - // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels); - - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - mImmutable = true; - - return gl::Error(GL_NO_ERROR); -} - -// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. -bool TextureD3D_Cube::isCubeComplete() const -{ - int baseWidth = getBaseLevelWidth(); - int baseHeight = getBaseLevelHeight(); - GLenum baseFormat = getBaseLevelInternalFormat(); - - if (baseWidth <= 0 || baseWidth != baseHeight) - { - return false; - } - - for (int faceIndex = 1; faceIndex < 6; faceIndex++) - { - const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0]; - - if (faceBaseImage.getWidth() != baseWidth || - faceBaseImage.getHeight() != baseHeight || - faceBaseImage.getInternalFormat() != baseFormat ) - { - return false; - } - } - - return true; -} - -void TextureD3D_Cube::bindTexImage(egl::Surface *surface) -{ - UNREACHABLE(); -} - -void TextureD3D_Cube::releaseTexImage() -{ - UNREACHABLE(); -} - - -void TextureD3D_Cube::initMipmapsImages() -{ - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int faceIndex = 0; faceIndex < 6; faceIndex++) - { - for (int level = 1; level < levelCount; level++) - { - int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1)); - redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize); - } - } -} - -unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index) -{ - return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); -} - -gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - ASSERT(gl::IsCubemapTextureTarget(index.type)); - - // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - error = updateStorageFaceLevel(index.layerIndex, index.mipIndex); - if (error.isError()) - { - return error; - } - - return mTexStorage->getRenderTarget(index, outRT); -} - -gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) -{ - // Only initialize the first time this texture is used as a render target or shader resource - if (mTexStorage) - { - return gl::Error(GL_NO_ERROR); - } - - // do not attempt to create storage for nonexistant data - if (!isFaceLevelComplete(0, 0)) - { - return gl::Error(GL_NO_ERROR); - } - - bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); - - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } - - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - ASSERT(mTexStorage); - - // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const -{ - GLsizei size = getBaseLevelWidth(); - - ASSERT(size > 0); - - // use existing storage level count, when previously specified by TexStorage*D - GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1)); - - // TODO (geofflang): detect if storage creation succeeded - *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) -{ - if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) - { - for (int faceIndex = 0; faceIndex < 6; faceIndex++) - { - for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) - { - gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level); - if (error.isError()) - { - return error; - } - } - } - } - - SafeDelete(mTexStorage); - mTexStorage = newCompleteTexStorage; - - mDirtyImages = true; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_Cube::updateStorage() -{ - ASSERT(mTexStorage != NULL); - GLint storageLevels = mTexStorage->getLevelCount(); - for (int face = 0; face < 6; face++) - { - for (int level = 0; level < storageLevels; level++) - { - if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) - { - gl::Error error = updateStorageFaceLevel(face, level); - if (error.isError()) - { - return error; - } - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const -{ - return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); -} - -bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const -{ - ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); - - if (isImmutable()) - { - return true; - } - - int baseSize = getBaseLevelWidth(); - - if (baseSize <= 0) - { - return false; - } - - // "isCubeComplete" checks for base level completeness and we must call that - // to determine if any face at level 0 is complete. We omit that check here - // to avoid re-checking cube-completeness for every face at level 0. - if (level == 0) - { - return true; - } - - // Check that non-zero levels are consistent with the base level. - const ImageD3D *faceLevelImage = mImageArray[faceIndex][level]; - - if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat()) - { - return false; - } - - if (faceLevelImage->getWidth() != std::max(1, baseSize >> level)) - { - return false; - } - - return true; -} - -bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const -{ - return isFaceLevelComplete(index.layerIndex, index.mipIndex); -} - -gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) -{ - ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); - ImageD3D *image = mImageArray[faceIndex][level]; - - if (image->isDirty()) - { - GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex); - gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level); - gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height) -{ - // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const GLenum storageFormat = getBaseLevelInternalFormat(); - - mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false); - - if (mTexStorage) - { - const int storageLevels = mTexStorage->getLevelCount(); - - if ((level >= storageLevels && storageLevels != 0) || - width != storageWidth || - height != storageHeight || - internalformat != storageFormat) // Discard mismatched storage - { - for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - for (int faceIndex = 0; faceIndex < 6; faceIndex++) - { - mImageArray[faceIndex][level]->markDirty(); - } - } - - SafeDelete(mTexStorage); - - mDirtyImages = true; - } - } -} - -gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const -{ - return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount()); -} - -gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const -{ - // The "layer" of the image index corresponds to the cube face - return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip); -} - -bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const -{ - return (mTexStorage && gl::IsCubemapTextureTarget(index.type) && - index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); -} - -TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer) - : TextureD3D(renderer) -{ - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) - { - mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage()); - } -} - -TextureD3D_3D::~TextureD3D_3D() -{ - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) - { - delete mImageArray[i]; - } - - SafeDelete(mTexStorage); -} - -Image *TextureD3D_3D::getImage(int level, int layer) const -{ - ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(layer == 0); - return mImageArray[level]; -} - -Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const -{ - ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(!index.hasLayer()); - ASSERT(index.type == GL_TEXTURE_3D); - return mImageArray[index.mipIndex]; -} - -GLsizei TextureD3D_3D::getLayerCount(int level) const -{ - ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - return 1; -} - -GLsizei TextureD3D_3D::getWidth(GLint level) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getWidth(); - else - return 0; -} - -GLsizei TextureD3D_3D::getHeight(GLint level) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getHeight(); - else - return 0; -} - -GLsizei TextureD3D_3D::getDepth(GLint level) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getDepth(); - else - return 0; -} - -GLenum TextureD3D_3D::getInternalFormat(GLint level) const -{ - if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - return mImageArray[level]->getInternalFormat(); - else - return GL_NONE; -} - -bool TextureD3D_3D::isDepth(GLint level) const -{ - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; -} - -gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, - GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, - const void *pixels) -{ - ASSERT(target == GL_TEXTURE_3D); - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); - - redefineImage(level, sizedInternalFormat, width, height, depth); - - bool fastUnpacked = false; - - gl::ImageIndex index = gl::ImageIndex::Make3D(level); - - // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer - if (isFastUnpackable(unpack, sizedInternalFormat)) - { - // Will try to create RT storage if it does not exist - RenderTarget *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - - gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); - - error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); - if (error.isError()) - { - return error; - } - - // Ensure we don't overwrite our newly initialized data - mImageArray[level]->markClean(); - - fastUnpacked = true; - } - - if (!fastUnpacked) - { - gl::Error error = TextureD3D::setImage(unpack, type, pixels, index); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format, - GLsizei width, GLsizei height,GLsizei depth, - GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_3D); - - // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, format, width, height, depth); - - return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]); -} - -gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_3D); - - bool fastUnpacked = false; - - gl::ImageIndex index = gl::ImageIndex::Make3D(level); - - // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer - if (isFastUnpackable(unpack, getInternalFormat(level))) - { - RenderTarget *destRenderTarget = NULL; - gl::Error error = getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - - gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth); - error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget); - if (error.isError()) - { - return error; - } - - // Ensure we don't overwrite our newly initialized data - mImageArray[level]->markClean(); - - fastUnpacked = true; - } - - if (!fastUnpacked) - { - return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, - unpack, pixels, index); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, - GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_3D); - - gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, - format, imageSize, unpack, pixels, mImageArray[level]); - if (error.isError()) - { - return error; - } - - gl::ImageIndex index = gl::ImageIndex::Make3D(level); - gl::Box region(xoffset, yoffset, zoffset, width, height, depth); - return commitRegion(index, region); -} - -gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, - GLsizei width, GLsizei height, gl::Framebuffer *source) -{ - UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented."); -} - -gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) -{ - ASSERT(target == GL_TEXTURE_3D); - - gl::Rectangle sourceRect(x, y, width, height); - gl::ImageIndex index = gl::ImageIndex::Make3D(level); - - if (canCreateRenderTargetForImage(index)) - { - gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - else - { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - if (isValidLevel(level)) - { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - - error = mRenderer->copyImage3D(source, sourceRect, - gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - xoffset, yoffset, zoffset, mTexStorage, level); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - ASSERT(target == GL_TEXTURE_3D); - - for (int level = 0; level < levels; level++) - { - GLsizei levelWidth = std::max(1, width >> level); - GLsizei levelHeight = std::max(1, height >> level); - GLsizei levelDepth = std::max(1, depth >> level); - mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true); - } - - for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true); - } - - // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels); - - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - mImmutable = true; - - return gl::Error(GL_NO_ERROR); -} - -void TextureD3D_3D::bindTexImage(egl::Surface *surface) -{ - UNREACHABLE(); -} - -void TextureD3D_3D::releaseTexImage() -{ - UNREACHABLE(); -} - - -void TextureD3D_3D::initMipmapsImages() -{ - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) - { - redefineImage(level, getBaseLevelInternalFormat(), - std::max(getBaseLevelWidth() >> level, 1), - std::max(getBaseLevelHeight() >> level, 1), - std::max(getBaseLevelDepth() >> level, 1)); - } -} - -unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index) -{ - return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); -} - -gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - if (index.hasLayer()) - { - error = updateStorage(); - if (error.isError()) - { - return error; - } - } - else - { - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } - } - - return mTexStorage->getRenderTarget(index, outRT); -} - -gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) -{ - // Only initialize the first time this texture is used as a render target or shader resource - if (mTexStorage) - { - return gl::Error(GL_NO_ERROR); - } - - // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) - { - return gl::Error(GL_NO_ERROR); - } - - bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } - - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - ASSERT(mTexStorage); - - // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const -{ - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); - GLenum internalFormat = getBaseLevelInternalFormat(); - - ASSERT(width > 0 && height > 0 && depth > 0); - - // use existing storage level count, when previously specified by TexStorage*D - GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); - - // TODO: Verify creation of the storage succeeded - *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) -{ - SafeDelete(mTexStorage); - mTexStorage = newCompleteTexStorage; - mDirtyImages = true; - - // We do not support managed 3D storage, as that is D3D9/ES2-only - ASSERT(!mTexStorage->isManaged()); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_3D::updateStorage() -{ - ASSERT(mTexStorage != NULL); - GLint storageLevels = mTexStorage->getLevelCount(); - for (int level = 0; level < storageLevels; level++) - { - if (mImageArray[level]->isDirty() && isLevelComplete(level)) - { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -bool TextureD3D_3D::isValidLevel(int level) const -{ - return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); -} - -bool TextureD3D_3D::isLevelComplete(int level) const -{ - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); - - if (isImmutable()) - { - return true; - } - - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getBaseLevelDepth(); - - if (width <= 0 || height <= 0 || depth <= 0) - { - return false; - } - - if (level == 0) - { - return true; - } - - ImageD3D *levelImage = mImageArray[level]; - - if (levelImage->getInternalFormat() != getBaseLevelInternalFormat()) - { - return false; - } - - if (levelImage->getWidth() != std::max(1, width >> level)) - { - return false; - } - - if (levelImage->getHeight() != std::max(1, height >> level)) - { - return false; - } - - if (levelImage->getDepth() != std::max(1, depth >> level)) - { - return false; - } - - return true; -} - -bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const -{ - return isLevelComplete(index.mipIndex); -} - -gl::Error TextureD3D_3D::updateStorageLevel(int level) -{ - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); - ASSERT(isLevelComplete(level)); - - if (mImageArray[level]->isDirty()) - { - gl::ImageIndex index = gl::ImageIndex::Make3D(level); - gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const int storageDepth = std::max(1, getBaseLevelDepth() >> level); - const GLenum storageFormat = getBaseLevelInternalFormat(); - - mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false); - - if (mTexStorage) - { - const int storageLevels = mTexStorage->getLevelCount(); - - if ((level >= storageLevels && storageLevels != 0) || - width != storageWidth || - height != storageHeight || - depth != storageDepth || - internalformat != storageFormat) // Discard mismatched storage - { - for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mImageArray[i]->markDirty(); - } - - SafeDelete(mTexStorage); - mDirtyImages = true; - } - } -} - -gl::ImageIndexIterator TextureD3D_3D::imageIterator() const -{ - return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(), - gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL); -} - -gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const -{ - // The "layer" here does not apply to 3D images. We use one Image per mip. - return gl::ImageIndex::Make3D(mip); -} - -bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const -{ - return (mTexStorage && index.type == GL_TEXTURE_3D && - index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); -} - -TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer) - : TextureD3D(renderer) -{ - for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) - { - mLayerCounts[level] = 0; - mImageArray[level] = NULL; - } -} - -TextureD3D_2DArray::~TextureD3D_2DArray() -{ - // Delete the Images before the TextureStorage. - // Images might be relying on the TextureStorage for some of their data. - // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images. - deleteImages(); - SafeDelete(mTexStorage); -} - -Image *TextureD3D_2DArray::getImage(int level, int layer) const -{ - ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(layer < mLayerCounts[level]); - return mImageArray[level][layer]; -} - -Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const -{ - ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]); - ASSERT(index.type == GL_TEXTURE_2D_ARRAY); - return mImageArray[index.mipIndex][index.layerIndex]; -} - -GLsizei TextureD3D_2DArray::getLayerCount(int level) const -{ - ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - return mLayerCounts[level]; -} - -GLsizei TextureD3D_2DArray::getWidth(GLint level) const -{ - return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0; -} - -GLsizei TextureD3D_2DArray::getHeight(GLint level) const -{ - return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0; -} - -GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const -{ - return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE; -} - -bool TextureD3D_2DArray::isDepth(GLint level) const -{ - return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; -} - -gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, - GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, - const void *pixels) -{ - ASSERT(target == GL_TEXTURE_2D_ARRAY); - - GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); - - redefineImage(level, sizedInternalFormat, width, height, depth); - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment); - - for (int i = 0; i < depth; i++) - { - const void *layerPixels = pixels ? (reinterpret_cast(pixels) + (inputDepthPitch * i)) : NULL; - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); - gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format, - GLsizei width, GLsizei height, GLsizei depth, - GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_2D_ARRAY); - - // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly - redefineImage(level, format, width, height, depth); - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1); - - for (int i = 0; i < depth; i++) - { - const void *layerPixels = pixels ? (reinterpret_cast(pixels) + (inputDepthPitch * i)) : NULL; - gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, - const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_2D_ARRAY); - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level)); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment); - - for (int i = 0; i < depth; i++) - { - int layer = zoffset + i; - const void *layerPixels = pixels ? (reinterpret_cast(pixels) + (inputDepthPitch * i)) : NULL; - - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); - gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, - unpack, layerPixels, index); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, - GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) -{ - ASSERT(target == GL_TEXTURE_2D_ARRAY); - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1); - - for (int i = 0; i < depth; i++) - { - int layer = zoffset + i; - const void *layerPixels = pixels ? (reinterpret_cast(pixels) + (inputDepthPitch * i)) : NULL; - - gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, unpack, layerPixels, mImageArray[level][layer]); - if (error.isError()) - { - return error; - } - - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); - gl::Box region(xoffset, yoffset, 0, width, height, 1); - error = commitRegion(index, region); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) -{ - UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented."); -} - -gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) -{ - ASSERT(target == GL_TEXTURE_2D_ARRAY); - - gl::Rectangle sourceRect(x, y, width, height); - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset); - - if (canCreateRenderTargetForImage(index)) - { - gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source); - if (error.isError()) - { - return error; - } - - mDirtyImages = true; - } - else - { - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - if (isValidLevel(level)) - { - error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - - error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format, - xoffset, yoffset, zoffset, mTexStorage, level); - if (error.isError()) - { - return error; - } - } - } - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - ASSERT(target == GL_TEXTURE_2D_ARRAY); - - deleteImages(); - - for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - GLsizei levelWidth = std::max(1, width >> level); - GLsizei levelHeight = std::max(1, height >> level); - - mLayerCounts[level] = (level < levels ? depth : 0); - - if (mLayerCounts[level] > 0) - { - // Create new images for this level - mImageArray[level] = new ImageD3D*[mLayerCounts[level]]; - - for (int layer = 0; layer < mLayerCounts[level]; layer++) - { - mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage()); - mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth, - levelHeight, 1, true); - } - } - } - - // TODO(geofflang): Verify storage creation had no errors - bool renderTarget = IsRenderTargetUsage(mUsage); - TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels); - - gl::Error error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - mImmutable = true; - - return gl::Error(GL_NO_ERROR); -} - -void TextureD3D_2DArray::bindTexImage(egl::Surface *surface) -{ - UNREACHABLE(); -} - -void TextureD3D_2DArray::releaseTexImage() -{ - UNREACHABLE(); -} - - -void TextureD3D_2DArray::initMipmapsImages() -{ - int baseWidth = getBaseLevelWidth(); - int baseHeight = getBaseLevelHeight(); - int baseDepth = getBaseLevelDepth(); - GLenum baseFormat = getBaseLevelInternalFormat(); - - // Purge array levels 1 through q and reset them to represent the generated mipmap levels. - int levelCount = mipLevels(); - for (int level = 1; level < levelCount; level++) - { - redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth); - } -} - -unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index) -{ - return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); -} - -gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - // ensure the underlying texture is created - gl::Error error = ensureRenderTarget(); - if (error.isError()) - { - return error; - } - - error = updateStorageLevel(index.mipIndex); - if (error.isError()) - { - return error; - } - - return mTexStorage->getRenderTarget(index, outRT); -} - -gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) -{ - // Only initialize the first time this texture is used as a render target or shader resource - if (mTexStorage) - { - return gl::Error(GL_NO_ERROR); - } - - // do not attempt to create storage for nonexistant data - if (!isLevelComplete(0)) - { - return gl::Error(GL_NO_ERROR); - } - - bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - - TextureStorage *storage = NULL; - gl::Error error = createCompleteStorage(createRenderTarget, &storage); - if (error.isError()) - { - return error; - } - - error = setCompleteTexStorage(storage); - if (error.isError()) - { - SafeDelete(storage); - return error; - } - - ASSERT(mTexStorage); - - // flush image data to the storage - error = updateStorage(); - if (error.isError()) - { - return error; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const -{ - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei depth = getLayerCount(0); - GLenum internalFormat = getBaseLevelInternalFormat(); - - ASSERT(width > 0 && height > 0 && depth > 0); - - // use existing storage level count, when previously specified by TexStorage*D - GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); - - // TODO(geofflang): Verify storage creation succeeds - *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) -{ - SafeDelete(mTexStorage); - mTexStorage = newCompleteTexStorage; - mDirtyImages = true; - - // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only - ASSERT(!mTexStorage->isManaged()); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureD3D_2DArray::updateStorage() -{ - ASSERT(mTexStorage != NULL); - GLint storageLevels = mTexStorage->getLevelCount(); - for (int level = 0; level < storageLevels; level++) - { - if (isLevelComplete(level)) - { - gl::Error error = updateStorageLevel(level); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -bool TextureD3D_2DArray::isValidLevel(int level) const -{ - return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0); -} - -bool TextureD3D_2DArray::isLevelComplete(int level) const -{ - ASSERT(level >= 0 && level < (int)ArraySize(mImageArray)); - - if (isImmutable()) - { - return true; - } - - GLsizei width = getBaseLevelWidth(); - GLsizei height = getBaseLevelHeight(); - GLsizei layers = getLayerCount(0); - - if (width <= 0 || height <= 0 || layers <= 0) - { - return false; - } - - if (level == 0) - { - return true; - } - - if (getInternalFormat(level) != getInternalFormat(0)) - { - return false; - } - - if (getWidth(level) != std::max(1, width >> level)) - { - return false; - } - - if (getHeight(level) != std::max(1, height >> level)) - { - return false; - } - - if (getLayerCount(level) != layers) - { - return false; - } - - return true; -} - -bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const -{ - return isLevelComplete(index.mipIndex); -} - -gl::Error TextureD3D_2DArray::updateStorageLevel(int level) -{ - ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); - ASSERT(isLevelComplete(level)); - - for (int layer = 0; layer < mLayerCounts[level]; layer++) - { - ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); - if (mImageArray[level][layer]->isDirty()) - { - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); - gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); - gl::Error error = commitRegion(index, region); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -void TextureD3D_2DArray::deleteImages() -{ - for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) - { - for (int layer = 0; layer < mLayerCounts[level]; ++layer) - { - delete mImageArray[level][layer]; - } - delete[] mImageArray[level]; - mImageArray[level] = NULL; - mLayerCounts[level] = 0; - } -} - -void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) -{ - // If there currently is a corresponding storage texture image, it has these parameters - const int storageWidth = std::max(1, getBaseLevelWidth() >> level); - const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const int storageDepth = getLayerCount(0); - const GLenum storageFormat = getBaseLevelInternalFormat(); - - for (int layer = 0; layer < mLayerCounts[level]; layer++) - { - delete mImageArray[level][layer]; - } - delete[] mImageArray[level]; - mImageArray[level] = NULL; - mLayerCounts[level] = depth; - - if (depth > 0) - { - mImageArray[level] = new ImageD3D*[depth](); - - for (int layer = 0; layer < mLayerCounts[level]; layer++) - { - mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage()); - mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false); - } - } - - if (mTexStorage) - { - const int storageLevels = mTexStorage->getLevelCount(); - - if ((level >= storageLevels && storageLevels != 0) || - width != storageWidth || - height != storageHeight || - depth != storageDepth || - internalformat != storageFormat) // Discard mismatched storage - { - for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - for (int layer = 0; layer < mLayerCounts[level]; layer++) - { - mImageArray[level][layer]->markDirty(); - } - } - - delete mTexStorage; - mTexStorage = NULL; - mDirtyImages = true; - } - } -} - -gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const -{ - return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts); -} - -gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const -{ - return gl::ImageIndex::Make2DArray(mip, layer); -} - -bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const -{ - // Check for having a storage and the right type of index - if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY) - { - return false; - } - - // Check the mip index - if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount()) - { - return false; - } - - // Check the layer index - return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex])); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h deleted file mode 100644 index 083a6335b9..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h +++ /dev/null @@ -1,335 +0,0 @@ -// -// Copyright 2014 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. -// - -// TextureD3D.h: Implementations of the Texture interfaces shared betweeen the D3D backends. - -#ifndef LIBGLESV2_RENDERER_TEXTURED3D_H_ -#define LIBGLESV2_RENDERER_TEXTURED3D_H_ - -#include "libGLESv2/renderer/TextureImpl.h" -#include "libGLESv2/angletypes.h" -#include "libGLESv2/Constants.h" - -namespace gl -{ -class Framebuffer; -} - -namespace rx -{ - -class Image; -class ImageD3D; -class RendererD3D; -class RenderTarget; -class TextureStorage; - -class TextureD3D : public TextureImpl -{ - public: - TextureD3D(RendererD3D *renderer); - virtual ~TextureD3D(); - - static TextureD3D *makeTextureD3D(TextureImpl *texture); - - TextureStorage *getNativeTexture(); - - virtual void setUsage(GLenum usage) { mUsage = usage; } - bool hasDirtyImages() const { return mDirtyImages; } - void resetDirty() { mDirtyImages = false; } - - GLint getBaseLevelWidth() const; - GLint getBaseLevelHeight() const; - GLint getBaseLevelDepth() const; - GLenum getBaseLevelInternalFormat() const; - - bool isImmutable() const { return mImmutable; } - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) = 0; - virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index) = 0; - - // Returns an iterator over all "Images" for this particular Texture. - virtual gl::ImageIndexIterator imageIterator() const = 0; - - // Returns an ImageIndex for a particular "Image". 3D Textures do not have images for - // slices of their depth texures, so 3D textures ignore the layer parameter. - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0; - virtual bool isValidIndex(const gl::ImageIndex &index) const = 0; - - virtual gl::Error generateMipmaps(); - TextureStorage *getStorage(); - Image *getBaseLevelImage() const; - - protected: - gl::Error setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index); - gl::Error subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index); - gl::Error setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image); - gl::Error subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image); - bool isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat); - gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, - GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget); - - GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const; - int mipLevels() const; - virtual void initMipmapsImages() = 0; - bool isBaseImageZeroSize() const; - virtual bool isImageComplete(const gl::ImageIndex &index) const = 0; - - bool canCreateRenderTargetForImage(const gl::ImageIndex &index) const; - virtual gl::Error ensureRenderTarget(); - - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const = 0; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0; - gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); - - RendererD3D *mRenderer; - - GLenum mUsage; - - bool mDirtyImages; - - bool mImmutable; - TextureStorage *mTexStorage; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureD3D); - - virtual gl::Error initializeStorage(bool renderTarget) = 0; - - virtual gl::Error updateStorage() = 0; - - bool shouldUseSetData(const Image *image) const; -}; - -class TextureD3D_2D : public TextureD3D -{ - public: - TextureD3D_2D(RendererD3D *renderer); - virtual ~TextureD3D_2D(); - - virtual Image *getImage(int level, int layer) const; - virtual Image *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; - - GLsizei getWidth(GLint level) const; - GLsizei getHeight(GLint level) const; - GLenum getInternalFormat(GLint level) const; - GLenum getActualFormat(GLint level) const; - bool isDepth(GLint level) const; - - virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); - - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureD3D_2D); - - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); - - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); - - bool isValidLevel(int level) const; - bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - - gl::Error updateStorageLevel(int level); - - void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height); - - ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -class TextureD3D_Cube : public TextureD3D -{ - public: - TextureD3D_Cube(RendererD3D *renderer); - virtual ~TextureD3D_Cube(); - - virtual Image *getImage(int level, int layer) const; - virtual Image *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; - - virtual bool hasDirtyImages() const { return mDirtyImages; } - virtual void resetDirty() { mDirtyImages = false; } - virtual void setUsage(GLenum usage) { mUsage = usage; } - - GLenum getInternalFormat(GLint level, GLint layer) const; - bool isDepth(GLint level, GLint layer) const; - - virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); - - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureD3D_Cube); - - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); - - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); - - bool isValidFaceLevel(int faceIndex, int level) const; - bool isFaceLevelComplete(int faceIndex, int level) const; - bool isCubeComplete() const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - gl::Error updateStorageFaceLevel(int faceIndex, int level); - - void redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height); - - ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -class TextureD3D_3D : public TextureD3D -{ - public: - TextureD3D_3D(RendererD3D *renderer); - virtual ~TextureD3D_3D(); - - virtual Image *getImage(int level, int layer) const; - virtual Image *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; - - GLsizei getWidth(GLint level) const; - GLsizei getHeight(GLint level) const; - GLsizei getDepth(GLint level) const; - GLenum getInternalFormat(GLint level) const; - bool isDepth(GLint level) const; - - virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); - - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureD3D_3D); - - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); - - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); - - bool isValidLevel(int level) const; - bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - gl::Error updateStorageLevel(int level); - - void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - - ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -class TextureD3D_2DArray : public TextureD3D -{ - public: - TextureD3D_2DArray(RendererD3D *renderer); - virtual ~TextureD3D_2DArray(); - - virtual Image *getImage(int level, int layer) const; - virtual Image *getImage(const gl::ImageIndex &index) const; - virtual GLsizei getLayerCount(int level) const; - - GLsizei getWidth(GLint level) const; - GLsizei getHeight(GLint level) const; - GLenum getInternalFormat(GLint level) const; - bool isDepth(GLint level) const; - - virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); - virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - - virtual void bindTexImage(egl::Surface *surface); - virtual void releaseTexImage(); - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); - - virtual gl::ImageIndexIterator imageIterator() const; - virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; - virtual bool isValidIndex(const gl::ImageIndex &index) const; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureD3D_2DArray); - - virtual gl::Error initializeStorage(bool renderTarget); - virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; - virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); - - virtual gl::Error updateStorage(); - virtual void initMipmapsImages(); - - bool isValidLevel(int level) const; - bool isLevelComplete(int level) const; - virtual bool isImageComplete(const gl::ImageIndex &index) const; - gl::Error updateStorageLevel(int level); - - void deleteImages(); - void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - - // Storing images as an array of single depth textures since D3D11 treats each array level of a - // Texture2D object as a separate subresource. Each layer would have to be looped over - // to update all the texture layers since they cannot all be updated at once and it makes the most - // sense for the Image class to not have to worry about layer subresource as well as mip subresources. - GLsizei mLayerCounts[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -} - -#endif // LIBGLESV2_RENDERER_TEXTURED3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp deleted file mode 100644 index 320b74b8ed..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2002-2013 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. -// - -// TextureStorage.cpp: Shared members of abstract rx::TextureStorage class. - -#include "libGLESv2/renderer/d3d/TextureStorage.h" -#include "libGLESv2/renderer/d3d/TextureD3D.h" -#include "libGLESv2/renderer/RenderTarget.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/Texture.h" - -#include "common/debug.h" -#include "common/mathutil.h" - -namespace rx -{ - -TextureStorage::TextureStorage() - : mFirstRenderTargetSerial(0), - mRenderTargetSerialsLayerStride(0) -{} - -void TextureStorage::initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride) -{ - mFirstRenderTargetSerial = RenderTarget::issueSerials(rtSerialsToReserve); - mRenderTargetSerialsLayerStride = rtSerialsLayerStride; -} - -unsigned int TextureStorage::getRenderTargetSerial(const gl::ImageIndex &index) const -{ - unsigned int layerOffset = (index.hasLayer() ? (static_cast(index.layerIndex) * mRenderTargetSerialsLayerStride) : 0); - return mFirstRenderTargetSerial + static_cast(index.mipIndex) + layerOffset; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h deleted file mode 100644 index da92be3c74..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (c) 2002-2013 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. -// - -// TextureStorage.h: Defines the abstract rx::TextureStorage class. - -#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ -#define LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ - -#include "libGLESv2/Error.h" - -#include "common/debug.h" -#include "libGLESv2/Error.h" - -#include -#include - -namespace gl -{ -struct ImageIndex; -struct Box; -struct PixelUnpackState; -} - -namespace rx -{ -class SwapChain; -class RenderTarget; -class Image; - -class TextureStorage -{ - public: - TextureStorage(); - virtual ~TextureStorage() {}; - - virtual int getTopLevel() const = 0; - virtual bool isRenderTarget() const = 0; - virtual bool isManaged() const = 0; - virtual int getLevelCount() const = 0; - - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) = 0; - virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0; - - virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0; - virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0; - - unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const; - unsigned int getTextureSerial() const; - - protected: - void initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage); - - unsigned int mFirstRenderTargetSerial; - unsigned int mRenderTargetSerialsLayerStride; -}; - -} - -#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.cpp deleted file mode 100644 index 11596006d0..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright 2014 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. -// - -// TransformFeedbackD3D.cpp is a no-op implementation for both the D3D9 and D3D11 renderers. - -#include "libGLESv2/renderer/d3d/TransformFeedbackD3D.h" - -namespace rx -{ - -TransformFeedbackD3D::TransformFeedbackD3D() -{ -} - -TransformFeedbackD3D::~TransformFeedbackD3D() -{ -} - -void TransformFeedbackD3D::begin(GLenum primitiveMode) -{ -} - -void TransformFeedbackD3D::end() -{ -} - -void TransformFeedbackD3D::pause() -{ -} - -void TransformFeedbackD3D::resume() -{ -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.h deleted file mode 100644 index 7c367aba1d..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright 2014 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. -// - -// TransformFeedbackD3D.h: Implements the abstract rx::TransformFeedbackImpl class. - -#ifndef LIBGLESV2_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ -#define LIBGLESV2_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ - -#include "libGLESv2/renderer/TransformFeedbackImpl.h" -#include "libGLESv2/angletypes.h" - -namespace rx -{ - -class TransformFeedbackD3D : public TransformFeedbackImpl -{ - public: - TransformFeedbackD3D(); - virtual ~TransformFeedbackD3D(); - - virtual void begin(GLenum primitiveMode); - virtual void end(); - virtual void pause(); - virtual void resume(); -}; - -} - -#endif // LIBGLESV2_RENDERER_D3D_TRANSFORMFEEDBACKD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp deleted file mode 100644 index 73f0c79e19..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp +++ /dev/null @@ -1,307 +0,0 @@ -// -// 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. -// - -// VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface -// class with derivations, classes that perform graphics API agnostic vertex buffer operations. - -#include "libGLESv2/renderer/d3d/VertexBuffer.h" -#include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/VertexAttribute.h" - -#include "common/mathutil.h" - -namespace rx -{ - -unsigned int VertexBuffer::mNextSerial = 1; - -VertexBuffer::VertexBuffer() -{ - updateSerial(); -} - -VertexBuffer::~VertexBuffer() -{ -} - -void VertexBuffer::updateSerial() -{ - mSerial = mNextSerial++; -} - -unsigned int VertexBuffer::getSerial() const -{ - return mSerial; -} - -VertexBufferInterface::VertexBufferInterface(RendererD3D *renderer, bool dynamic) : mRenderer(renderer) -{ - mDynamic = dynamic; - mWritePosition = 0; - mReservedSpace = 0; - - mVertexBuffer = renderer->createVertexBuffer(); -} - -VertexBufferInterface::~VertexBufferInterface() -{ - delete mVertexBuffer; -} - -unsigned int VertexBufferInterface::getSerial() const -{ - return mVertexBuffer->getSerial(); -} - -unsigned int VertexBufferInterface::getBufferSize() const -{ - return mVertexBuffer->getBufferSize(); -} - -gl::Error VertexBufferInterface::setBufferSize(unsigned int size) -{ - if (mVertexBuffer->getBufferSize() == 0) - { - return mVertexBuffer->initialize(size, mDynamic); - } - else - { - return mVertexBuffer->setBufferSize(size); - } -} - -unsigned int VertexBufferInterface::getWritePosition() const -{ - return mWritePosition; -} - -void VertexBufferInterface::setWritePosition(unsigned int writePosition) -{ - mWritePosition = writePosition; -} - -gl::Error VertexBufferInterface::discard() -{ - return mVertexBuffer->discard(); -} - -gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) -{ - gl::Error error(GL_NO_ERROR); - - unsigned int spaceRequired; - error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &spaceRequired); - if (error.isError()) - { - return error; - } - - if (mWritePosition + spaceRequired < mWritePosition) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, new vertex buffer write position would overflow."); - } - - error = reserveSpace(mReservedSpace); - if (error.isError()) - { - return error; - } - mReservedSpace = 0; - - error = mVertexBuffer->storeVertexAttributes(attrib, currentValue, start, count, instances, mWritePosition); - if (error.isError()) - { - return error; - } - - if (outStreamOffset) - { - *outStreamOffset = mWritePosition; - } - - mWritePosition += spaceRequired; - - // Align to 16-byte boundary - mWritePosition = roundUp(mWritePosition, 16u); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances) -{ - gl::Error error(GL_NO_ERROR); - - unsigned int requiredSpace; - error = mVertexBuffer->getSpaceRequired(attrib, count, instances, &requiredSpace); - if (error.isError()) - { - return error; - } - - // Protect against integer overflow - if (mReservedSpace + requiredSpace < mReservedSpace) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to reserve %u extra bytes in internal vertex buffer, " - "it would result in an overflow.", requiredSpace); - } - - mReservedSpace += requiredSpace; - - // Align to 16-byte boundary - mReservedSpace = roundUp(mReservedSpace, 16u); - - return gl::Error(GL_NO_ERROR); -} - -VertexBuffer* VertexBufferInterface::getVertexBuffer() const -{ - return mVertexBuffer; -} - -bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue) const -{ - gl::Buffer *buffer = attrib.buffer.get(); - BufferD3D *storage = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; - - if (!storage || !storage->supportsDirectBinding()) - { - return false; - } - - // Alignment restrictions: In D3D, vertex data must be aligned to - // the format stride, or to a 4-byte boundary, whichever is smaller. - // (Undocumented, and experimentally confirmed) - size_t alignment = 4; - bool requiresConversion = false; - - if (attrib.type != GL_FLOAT) - { - gl::VertexFormat vertexFormat(attrib, currentValue.Type); - - unsigned int outputElementSize; - getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); - alignment = std::min(outputElementSize, 4); - - requiresConversion = (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_CPU) != 0; - } - - bool isAligned = (static_cast(ComputeVertexAttributeStride(attrib)) % alignment == 0) && - (static_cast(attrib.offset) % alignment == 0); - - return !requiresConversion && isAligned; -} - -StreamingVertexBufferInterface::StreamingVertexBufferInterface(RendererD3D *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true) -{ - setBufferSize(initialSize); -} - -StreamingVertexBufferInterface::~StreamingVertexBufferInterface() -{ -} - -gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size) -{ - unsigned int curBufferSize = getBufferSize(); - if (size > curBufferSize) - { - gl::Error error = setBufferSize(std::max(size, 3 * curBufferSize / 2)); - if (error.isError()) - { - return error; - } - setWritePosition(0); - } - else if (getWritePosition() + size > curBufferSize) - { - gl::Error error = discard(); - if (error.isError()) - { - return error; - } - setWritePosition(0); - } - - return gl::Error(GL_NO_ERROR); -} - -StaticVertexBufferInterface::StaticVertexBufferInterface(RendererD3D *renderer) : VertexBufferInterface(renderer, false) -{ -} - -StaticVertexBufferInterface::~StaticVertexBufferInterface() -{ -} - -bool StaticVertexBufferInterface::lookupAttribute(const gl::VertexAttribute &attrib, unsigned int *outStreamOffset) -{ - for (unsigned int element = 0; element < mCache.size(); element++) - { - if (mCache[element].type == attrib.type && - mCache[element].size == attrib.size && - mCache[element].stride == ComputeVertexAttributeStride(attrib) && - mCache[element].normalized == attrib.normalized && - mCache[element].pureInteger == attrib.pureInteger) - { - size_t offset = (static_cast(attrib.offset) % ComputeVertexAttributeStride(attrib)); - if (mCache[element].attributeOffset == offset) - { - if (outStreamOffset) - { - *outStreamOffset = mCache[element].streamOffset; - } - return true; - } - } - } - - return false; -} - -gl::Error StaticVertexBufferInterface::reserveSpace(unsigned int size) -{ - unsigned int curSize = getBufferSize(); - if (curSize == 0) - { - return setBufferSize(size); - } - else if (curSize >= size) - { - return gl::Error(GL_NO_ERROR); - } - else - { - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Internal error, Static vertex buffers can't be resized."); - } -} - -gl::Error StaticVertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset) -{ - unsigned int streamOffset; - gl::Error error = VertexBufferInterface::storeVertexAttributes(attrib, currentValue, start, count, instances, &streamOffset); - if (error.isError()) - { - return error; - } - - size_t attributeOffset = static_cast(attrib.offset) % ComputeVertexAttributeStride(attrib); - VertexElement element = { attrib.type, attrib.size, ComputeVertexAttributeStride(attrib), attrib.normalized, attrib.pureInteger, attributeOffset, streamOffset }; - mCache.push_back(element); - - if (outStreamOffset) - { - *outStreamOffset = streamOffset; - } - - return gl::Error(GL_NO_ERROR); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h deleted file mode 100644 index 4b40818f8e..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h +++ /dev/null @@ -1,144 +0,0 @@ -// -// 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. -// - -// VertexBuffer.h: Defines the abstract VertexBuffer class and VertexBufferInterface -// class with derivations, classes that perform graphics API agnostic vertex buffer operations. - -#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER_H_ -#define LIBGLESV2_RENDERER_VERTEXBUFFER_H_ - -#include "common/angleutils.h" -#include "libGLESv2/Error.h" - -#include - -#include -#include - -namespace gl -{ -struct VertexAttribute; -struct VertexAttribCurrentValueData; -} - -namespace rx -{ -class RendererD3D; - -class VertexBuffer -{ - public: - VertexBuffer(); - virtual ~VertexBuffer(); - - virtual gl::Error initialize(unsigned int size, bool dynamicUsage) = 0; - - virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int offset) = 0; - virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, - unsigned int *outSpaceRequired) const = 0; - - virtual unsigned int getBufferSize() const = 0; - virtual gl::Error setBufferSize(unsigned int size) = 0; - virtual gl::Error discard() = 0; - - unsigned int getSerial() const; - - protected: - void updateSerial(); - - private: - DISALLOW_COPY_AND_ASSIGN(VertexBuffer); - - unsigned int mSerial; - static unsigned int mNextSerial; -}; - -class VertexBufferInterface -{ - public: - VertexBufferInterface(RendererD3D *renderer, bool dynamic); - virtual ~VertexBufferInterface(); - - gl::Error reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances); - - unsigned int getBufferSize() const; - - unsigned int getSerial() const; - - virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset); - - bool directStoragePossible(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue) const; - - VertexBuffer* getVertexBuffer() const; - - protected: - virtual gl::Error reserveSpace(unsigned int size) = 0; - - unsigned int getWritePosition() const; - void setWritePosition(unsigned int writePosition); - - gl::Error discard(); - - gl::Error setBufferSize(unsigned int size); - - private: - DISALLOW_COPY_AND_ASSIGN(VertexBufferInterface); - - RendererD3D *const mRenderer; - - VertexBuffer* mVertexBuffer; - - unsigned int mWritePosition; - unsigned int mReservedSpace; - bool mDynamic; -}; - -class StreamingVertexBufferInterface : public VertexBufferInterface -{ - public: - StreamingVertexBufferInterface(RendererD3D *renderer, std::size_t initialSize); - ~StreamingVertexBufferInterface(); - - protected: - gl::Error reserveSpace(unsigned int size); -}; - -class StaticVertexBufferInterface : public VertexBufferInterface -{ - public: - explicit StaticVertexBufferInterface(RendererD3D *renderer); - ~StaticVertexBufferInterface(); - - gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int *outStreamOffset); - - bool lookupAttribute(const gl::VertexAttribute &attribute, unsigned int* outStreamFffset); - - protected: - gl::Error reserveSpace(unsigned int size); - - private: - struct VertexElement - { - GLenum type; - GLuint size; - GLuint stride; - bool normalized; - bool pureInteger; - size_t attributeOffset; - - unsigned int streamOffset; - }; - - std::vector mCache; -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXBUFFER_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp deleted file mode 100644 index 8d3df31c8b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp +++ /dev/null @@ -1,354 +0,0 @@ -// -// 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/renderer/d3d/VertexDataManager.h" -#include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/renderer/d3d/VertexBuffer.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/VertexAttribute.h" -#include "libGLESv2/State.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 rx -{ - -static int ElementsInBuffer(const gl::VertexAttribute &attrib, unsigned int size) -{ - // Size cannot be larger than a GLsizei - if (size > static_cast(std::numeric_limits::max())) - { - size = static_cast(std::numeric_limits::max()); - } - - GLsizei stride = ComputeVertexAttributeStride(attrib); - return (size - attrib.offset % stride + (stride - ComputeVertexAttributeTypeSize(attrib))) / stride; -} - -static int StreamingBufferElementCount(const gl::VertexAttribute &attrib, int vertexDrawCount, int instanceDrawCount) -{ - // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices. - // - // A vertex attribute with a positive divisor loads one instanced vertex for every set of - // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" instances. - if (instanceDrawCount > 0 && attrib.divisor > 0) - { - return instanceDrawCount / attrib.divisor; - } - - return vertexDrawCount; -} - -VertexDataManager::VertexDataManager(RendererD3D *renderer) : mRenderer(renderer) -{ - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - mCurrentValue[i].FloatValues[0] = std::numeric_limits::quiet_NaN(); - mCurrentValue[i].FloatValues[1] = std::numeric_limits::quiet_NaN(); - mCurrentValue[i].FloatValues[2] = std::numeric_limits::quiet_NaN(); - mCurrentValue[i].FloatValues[3] = std::numeric_limits::quiet_NaN(); - mCurrentValue[i].Type = GL_FLOAT; - mCurrentValueBuffer[i] = NULL; - mCurrentValueOffsets[i] = 0; - } - - mStreamingBuffer = new StreamingVertexBufferInterface(renderer, INITIAL_STREAM_BUFFER_SIZE); - - if (!mStreamingBuffer) - { - ERR("Failed to allocate the streaming vertex buffer."); - } -} - -VertexDataManager::~VertexDataManager() -{ - delete mStreamingBuffer; - - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - delete mCurrentValueBuffer[i]; - } -} - -gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count, - TranslatedAttribute *translated, GLsizei instances) -{ - if (!mStreamingBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal streaming vertex buffer is unexpectedly NULL."); - } - - // Invalidate static buffers that don't contain matching attributes - for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) - { - translated[attributeIndex].active = (state.getCurrentProgramBinary()->getSemanticIndex(attributeIndex) != -1); - const gl::VertexAttribute &curAttrib = state.getVertexAttribState(attributeIndex); - - if (translated[attributeIndex].active && curAttrib.enabled) - { - invalidateMatchingStaticData(curAttrib, state.getVertexAttribCurrentValue(attributeIndex)); - } - } - - // Reserve the required space in the buffers - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); - if (translated[i].active && curAttrib.enabled) - { - gl::Error error = reserveSpaceForAttrib(curAttrib, state.getVertexAttribCurrentValue(i), count, instances); - if (error.isError()) - { - return error; - } - } - } - - // Perform the vertex data translations - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); - if (translated[i].active) - { - if (curAttrib.enabled) - { - gl::Error error = storeAttribute(curAttrib, state.getVertexAttribCurrentValue(i), - &translated[i], start, count, instances); - - if (error.isError()) - { - return error; - } - } - else - { - if (!mCurrentValueBuffer[i]) - { - mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE); - } - - gl::Error error = storeCurrentValue(curAttrib, state.getVertexAttribCurrentValue(i), &translated[i], - &mCurrentValue[i], &mCurrentValueOffsets[i], - mCurrentValueBuffer[i]); - if (error.isError()) - { - return error; - } - } - } - } - - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); - if (translated[i].active && curAttrib.enabled) - { - gl::Buffer *buffer = curAttrib.buffer.get(); - - if (buffer) - { - BufferD3D *bufferImpl = BufferD3D::makeBufferD3D(buffer->getImplementation()); - bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(curAttrib)); - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -void VertexDataManager::invalidateMatchingStaticData(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue) const -{ - gl::Buffer *buffer = attrib.buffer.get(); - - if (buffer) - { - BufferD3D *bufferImpl = BufferD3D::makeBufferD3D(buffer->getImplementation()); - StaticVertexBufferInterface *staticBuffer = bufferImpl->getStaticVertexBuffer(); - - if (staticBuffer && - staticBuffer->getBufferSize() > 0 && - !staticBuffer->lookupAttribute(attrib, NULL) && - !staticBuffer->directStoragePossible(attrib, currentValue)) - { - bufferImpl->invalidateStaticData(); - } - } -} - -gl::Error VertexDataManager::reserveSpaceForAttrib(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, - GLsizei count, - GLsizei instances) const -{ - gl::Buffer *buffer = attrib.buffer.get(); - BufferD3D *bufferImpl = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; - StaticVertexBufferInterface *staticBuffer = bufferImpl ? bufferImpl->getStaticVertexBuffer() : NULL; - VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); - - if (!vertexBuffer->directStoragePossible(attrib, currentValue)) - { - if (staticBuffer) - { - if (staticBuffer->getBufferSize() == 0) - { - int totalCount = ElementsInBuffer(attrib, bufferImpl->getSize()); - gl::Error error = staticBuffer->reserveVertexSpace(attrib, totalCount, 0); - if (error.isError()) - { - return error; - } - } - } - else - { - int totalCount = StreamingBufferElementCount(attrib, count, instances); - ASSERT(!bufferImpl || ElementsInBuffer(attrib, bufferImpl->getSize()) >= totalCount); - - gl::Error error = mStreamingBuffer->reserveVertexSpace(attrib, totalCount, instances); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error VertexDataManager::storeAttribute(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, - TranslatedAttribute *translated, - GLint start, - GLsizei count, - GLsizei instances) -{ - gl::Buffer *buffer = attrib.buffer.get(); - ASSERT(buffer || attrib.pointer); - - BufferD3D *storage = buffer ? BufferD3D::makeBufferD3D(buffer->getImplementation()) : NULL; - StaticVertexBufferInterface *staticBuffer = storage ? storage->getStaticVertexBuffer() : NULL; - VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast(mStreamingBuffer); - bool directStorage = vertexBuffer->directStoragePossible(attrib, currentValue); - - unsigned int streamOffset = 0; - unsigned int outputElementSize = 0; - - if (directStorage) - { - outputElementSize = ComputeVertexAttributeStride(attrib); - streamOffset = attrib.offset + outputElementSize * start; - } - else if (staticBuffer) - { - gl::Error error = staticBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); - if (error.isError()) - { - return error; - } - - if (!staticBuffer->lookupAttribute(attrib, &streamOffset)) - { - // Convert the entire buffer - int totalCount = ElementsInBuffer(attrib, storage->getSize()); - int startIndex = attrib.offset / ComputeVertexAttributeStride(attrib); - - gl::Error error = staticBuffer->storeVertexAttributes(attrib, currentValue, -startIndex, totalCount, - 0, &streamOffset); - if (error.isError()) - { - return error; - } - } - - unsigned int firstElementOffset = (attrib.offset / ComputeVertexAttributeStride(attrib)) * outputElementSize; - unsigned int startOffset = (instances == 0 || attrib.divisor == 0) ? start * outputElementSize : 0; - if (streamOffset + firstElementOffset + startOffset < streamOffset) - { - return gl::Error(GL_OUT_OF_MEMORY); - } - - streamOffset += firstElementOffset + startOffset; - } - else - { - int totalCount = StreamingBufferElementCount(attrib, count, instances); - gl::Error error = mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attrib, 1, 0, &outputElementSize); - if (error.isError()) - { - return error; - } - - error = mStreamingBuffer->storeVertexAttributes(attrib, currentValue, start, totalCount, instances, &streamOffset); - if (error.isError()) - { - return error; - } - } - - translated->storage = directStorage ? storage : NULL; - translated->vertexBuffer = vertexBuffer->getVertexBuffer(); - translated->serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial(); - translated->divisor = attrib.divisor; - - translated->attribute = &attrib; - translated->currentValueType = currentValue.Type; - translated->stride = outputElementSize; - translated->offset = streamOffset; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error VertexDataManager::storeCurrentValue(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, - TranslatedAttribute *translated, - gl::VertexAttribCurrentValueData *cachedValue, - size_t *cachedOffset, - StreamingVertexBufferInterface *buffer) -{ - if (*cachedValue != currentValue) - { - gl::Error error = buffer->reserveVertexSpace(attrib, 1, 0); - if (error.isError()) - { - return error; - } - - unsigned int streamOffset; - error = buffer->storeVertexAttributes(attrib, currentValue, 0, 1, 0, &streamOffset); - if (error.isError()) - { - return error; - } - - *cachedValue = currentValue; - *cachedOffset = streamOffset; - } - - translated->storage = NULL; - translated->vertexBuffer = buffer->getVertexBuffer(); - translated->serial = buffer->getSerial(); - translated->divisor = 0; - - translated->attribute = &attrib; - translated->currentValueType = currentValue.Type; - translated->stride = 0; - translated->offset = *cachedOffset; - - return gl::Error(GL_NO_ERROR); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h deleted file mode 100644 index 64ef653221..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h +++ /dev/null @@ -1,96 +0,0 @@ -// -// 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_RENDERER_VERTEXDATAMANAGER_H_ -#define LIBGLESV2_RENDERER_VERTEXDATAMANAGER_H_ - -#include "libGLESv2/Constants.h" -#include "libGLESv2/VertexAttribute.h" -#include "common/angleutils.h" - -namespace gl -{ -class ProgramBinary; -class State; -struct VertexAttribute; -struct VertexAttribCurrentValueData; -} - -namespace rx -{ -class BufferD3D; -class StreamingVertexBufferInterface; -class VertexBuffer; -class RendererD3D; - -struct TranslatedAttribute -{ - TranslatedAttribute() : active(false), attribute(NULL), currentValueType(GL_NONE), - offset(0), stride(0), vertexBuffer(NULL), storage(NULL), - serial(0), divisor(0) {}; - bool active; - - const gl::VertexAttribute *attribute; - GLenum currentValueType; - unsigned int offset; - unsigned int stride; // 0 means not to advance the read pointer at all - - VertexBuffer *vertexBuffer; - BufferD3D *storage; - unsigned int serial; - unsigned int divisor; -}; - -class VertexDataManager -{ - public: - VertexDataManager(RendererD3D *renderer); - virtual ~VertexDataManager(); - - gl::Error prepareVertexData(const gl::State &state, GLint start, GLsizei count, - TranslatedAttribute *outAttribs, GLsizei instances); - - private: - DISALLOW_COPY_AND_ASSIGN(VertexDataManager); - - gl::Error reserveSpaceForAttrib(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, - GLsizei count, - GLsizei instances) const; - - void invalidateMatchingStaticData(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue) const; - - gl::Error storeAttribute(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, - TranslatedAttribute *translated, - GLint start, - GLsizei count, - GLsizei instances); - - gl::Error storeCurrentValue(const gl::VertexAttribute &attrib, - const gl::VertexAttribCurrentValueData ¤tValue, - TranslatedAttribute *translated, - gl::VertexAttribCurrentValueData *cachedValue, - size_t *cachedOffset, - StreamingVertexBufferInterface *buffer); - - RendererD3D *const mRenderer; - - StreamingVertexBufferInterface *mStreamingBuffer; - - gl::VertexAttribCurrentValueData mCurrentValue[gl::MAX_VERTEX_ATTRIBS]; - - StreamingVertexBufferInterface *mCurrentValueBuffer[gl::MAX_VERTEX_ATTRIBS]; - std::size_t mCurrentValueOffsets[gl::MAX_VERTEX_ATTRIBS]; -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXDATAMANAGER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp deleted file mode 100644 index 06aea9befe..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp +++ /dev/null @@ -1,1047 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Blit11.cpp: Texture copy utility class. - -#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/main.h" -#include "libGLESv2/formatutils.h" - -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2duips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2duips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2duips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2duips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2dps.h" - -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3dvs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3dgs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3duips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3duips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3duips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3duips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum3dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3dps.h" - -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui2dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef3dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei3dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef2darrayps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei2darrayps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzleui2darrayps.h" - -namespace rx -{ - -static DXGI_FORMAT GetTextureFormat(ID3D11Resource *resource) -{ - ID3D11Texture2D *texture = d3d11::DynamicCastComObject(resource); - if (!texture) - { - return DXGI_FORMAT_UNKNOWN; - } - - D3D11_TEXTURE2D_DESC desc; - texture->GetDesc(&desc); - - SafeRelease(texture); - - return desc.Format; -} - -static ID3D11Resource *CreateStagingTexture(ID3D11Device *device, ID3D11DeviceContext *context, - ID3D11Resource *source, unsigned int subresource, - const gl::Extents &size, unsigned int cpuAccessFlags) -{ - D3D11_TEXTURE2D_DESC stagingDesc; - stagingDesc.Width = size.width; - stagingDesc.Height = size.height; - stagingDesc.MipLevels = 1; - stagingDesc.ArraySize = 1; - stagingDesc.Format = GetTextureFormat(source); - stagingDesc.SampleDesc.Count = 1; - stagingDesc.SampleDesc.Quality = 0; - stagingDesc.Usage = D3D11_USAGE_STAGING; - stagingDesc.CPUAccessFlags = cpuAccessFlags; - stagingDesc.MiscFlags = 0; - stagingDesc.BindFlags = 0; - - ID3D11Texture2D *stagingTexture = NULL; - HRESULT result = device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture); - if (FAILED(result)) - { - ERR("Failed to create staging texture for depth stencil blit. HRESULT: 0x%X.", result); - return NULL; - } - - context->CopySubresourceRegion(stagingTexture, 0, 0, 0, 0, source, subresource, NULL); - - return stagingTexture; -} - -inline static void GenerateVertexCoords(const gl::Box &sourceArea, const gl::Extents &sourceSize, - const gl::Box &destArea, const gl::Extents &destSize, - float *x1, float *y1, float *x2, float *y2, - float *u1, float *v1, float *u2, float *v2) -{ - *x1 = (destArea.x / float(destSize.width)) * 2.0f - 1.0f; - *y1 = ((destSize.height - destArea.y - destArea.height) / float(destSize.height)) * 2.0f - 1.0f; - *x2 = ((destArea.x + destArea.width) / float(destSize.width)) * 2.0f - 1.0f; - *y2 = ((destSize.height - destArea.y) / float(destSize.height)) * 2.0f - 1.0f; - - *u1 = sourceArea.x / float(sourceSize.width); - *v1 = sourceArea.y / float(sourceSize.height); - *u2 = (sourceArea.x + sourceArea.width) / float(sourceSize.width); - *v2 = (sourceArea.y + sourceArea.height) / float(sourceSize.height); -} - -static void Write2DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, - const gl::Box &destArea, const gl::Extents &destSize, - void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, - D3D11_PRIMITIVE_TOPOLOGY *outTopology) -{ - float x1, y1, x2, y2, u1, v1, u2, v2; - GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); - - d3d11::PositionTexCoordVertex *vertices = static_cast(outVertices); - - d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v2); - d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v1); - d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v2); - d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v1); - - *outStride = sizeof(d3d11::PositionTexCoordVertex); - *outVertexCount = 4; - *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; -} - -static void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &sourceSize, - const gl::Box &destArea, const gl::Extents &destSize, - void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, - D3D11_PRIMITIVE_TOPOLOGY *outTopology) -{ - ASSERT(sourceSize.depth > 0 && destSize.depth > 0); - - float x1, y1, x2, y2, u1, v1, u2, v2; - GenerateVertexCoords(sourceArea, sourceSize, destArea, destSize, &x1, &y1, &x2, &y2, &u1, &v1, &u2, &v2); - - d3d11::PositionLayerTexCoord3DVertex *vertices = static_cast(outVertices); - - for (int i = 0; i < destSize.depth; i++) - { - float readDepth = (float)i / std::max(destSize.depth - 1, 1); - - d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 0], x1, y1, i, u1, v2, readDepth); - d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 1], x1, y2, i, u1, v1, readDepth); - d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 2], x2, y1, i, u2, v2, readDepth); - - d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 3], x1, y2, i, u1, v1, readDepth); - d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 4], x2, y2, i, u2, v1, readDepth); - d3d11::SetPositionLayerTexCoord3DVertex(&vertices[i * 6 + 5], x2, y1, i, u2, v2, readDepth); - } - - *outStride = sizeof(d3d11::PositionLayerTexCoord3DVertex); - *outVertexCount = destSize.depth * 6; - *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; -} - -Blit11::Blit11(Renderer11 *renderer) - : mRenderer(renderer), mBlitShaderMap(compareBlitParameters), mSwizzleShaderMap(compareSwizzleParameters), - mVertexBuffer(NULL), mPointSampler(NULL), mLinearSampler(NULL), mScissorEnabledRasterizerState(NULL), - mScissorDisabledRasterizerState(NULL), mDepthStencilState(NULL), - mQuad2DIL(NULL), mQuad2DVS(NULL), mDepthPS(NULL), - mQuad3DIL(NULL), mQuad3DVS(NULL), mQuad3DGS(NULL), - mSwizzleCB(NULL) -{ - HRESULT result; - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_BUFFER_DESC vbDesc; - vbDesc.ByteWidth = std::max(sizeof(d3d11::PositionLayerTexCoord3DVertex), sizeof(d3d11::PositionTexCoordVertex)) * - 6 * renderer->getRendererCaps().max3DTextureSize; - vbDesc.Usage = D3D11_USAGE_DYNAMIC; - vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - vbDesc.MiscFlags = 0; - vbDesc.StructureByteStride = 0; - - result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mVertexBuffer, "Blit11 vertex buffer"); - - D3D11_SAMPLER_DESC pointSamplerDesc; - pointSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; - pointSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - pointSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - pointSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - pointSamplerDesc.MipLODBias = 0.0f; - pointSamplerDesc.MaxAnisotropy = 0; - pointSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; - pointSamplerDesc.BorderColor[0] = 0.0f; - pointSamplerDesc.BorderColor[1] = 0.0f; - pointSamplerDesc.BorderColor[2] = 0.0f; - pointSamplerDesc.BorderColor[3] = 0.0f; - pointSamplerDesc.MinLOD = 0.0f; - pointSamplerDesc.MaxLOD = mRenderer->isLevel9() ? D3D11_FLOAT32_MAX : 0.0f; - - result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPointSampler, "Blit11 point sampler"); - - D3D11_SAMPLER_DESC linearSamplerDesc; - linearSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - linearSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - linearSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - linearSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - linearSamplerDesc.MipLODBias = 0.0f; - linearSamplerDesc.MaxAnisotropy = 0; - linearSamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; - linearSamplerDesc.BorderColor[0] = 0.0f; - linearSamplerDesc.BorderColor[1] = 0.0f; - linearSamplerDesc.BorderColor[2] = 0.0f; - linearSamplerDesc.BorderColor[3] = 0.0f; - linearSamplerDesc.MinLOD = 0.0f; - linearSamplerDesc.MaxLOD = mRenderer->isLevel9() ? D3D11_FLOAT32_MAX : 0.0f; - - result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mLinearSampler, "Blit11 linear sampler"); - - // Use a rasterizer state that will not cull so that inverted quads will not be culled - D3D11_RASTERIZER_DESC rasterDesc; - rasterDesc.FillMode = D3D11_FILL_SOLID; - rasterDesc.CullMode = D3D11_CULL_NONE; - rasterDesc.FrontCounterClockwise = FALSE; - rasterDesc.DepthBias = 0; - rasterDesc.SlopeScaledDepthBias = 0.0f; - rasterDesc.DepthBiasClamp = 0.0f; - rasterDesc.DepthClipEnable = TRUE; - rasterDesc.MultisampleEnable = FALSE; - rasterDesc.AntialiasedLineEnable = FALSE; - - rasterDesc.ScissorEnable = TRUE; - result = device->CreateRasterizerState(&rasterDesc, &mScissorEnabledRasterizerState); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mScissorEnabledRasterizerState, "Blit11 scissoring rasterizer state"); - - rasterDesc.ScissorEnable = FALSE; - result = device->CreateRasterizerState(&rasterDesc, &mScissorDisabledRasterizerState); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mScissorDisabledRasterizerState, "Blit11 no scissoring rasterizer state"); - - D3D11_DEPTH_STENCIL_DESC depthStencilDesc; - depthStencilDesc.DepthEnable = true; - depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - depthStencilDesc.StencilEnable = FALSE; - depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - - result = device->CreateDepthStencilState(&depthStencilDesc, &mDepthStencilState); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mDepthStencilState, "Blit11 depth stencil state"); - - D3D11_INPUT_ELEMENT_DESC quad2DLayout[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - result = device->CreateInputLayout(quad2DLayout, ArraySize(quad2DLayout), g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), &mQuad2DIL); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuad2DIL, "Blit11 2D input layout"); - - result = device->CreateVertexShader(g_VS_Passthrough2D, ArraySize(g_VS_Passthrough2D), NULL, &mQuad2DVS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuad2DVS, "Blit11 2D vertex shader"); - - if (!renderer->isLevel9()) - { - result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader"); - - D3D11_INPUT_ELEMENT_DESC quad3DLayout[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout"); - - result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); - - result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader"); - } - - buildShaderMap(); - - D3D11_BUFFER_DESC swizzleBufferDesc; - swizzleBufferDesc.ByteWidth = sizeof(unsigned int) * 4; - swizzleBufferDesc.Usage = D3D11_USAGE_DYNAMIC; - swizzleBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - swizzleBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - swizzleBufferDesc.MiscFlags = 0; - swizzleBufferDesc.StructureByteStride = 0; - - result = device->CreateBuffer(&swizzleBufferDesc, NULL, &mSwizzleCB); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mSwizzleCB, "Blit11 swizzle constant buffer"); -} - -Blit11::~Blit11() -{ - SafeRelease(mVertexBuffer); - SafeRelease(mPointSampler); - SafeRelease(mLinearSampler); - SafeRelease(mScissorEnabledRasterizerState); - SafeRelease(mScissorDisabledRasterizerState); - SafeRelease(mDepthStencilState); - - SafeRelease(mQuad2DIL); - SafeRelease(mQuad2DVS); - SafeRelease(mDepthPS); - - SafeRelease(mQuad3DIL); - SafeRelease(mQuad3DVS); - SafeRelease(mQuad3DGS); - - SafeRelease(mSwizzleCB); - - clearShaderMap(); -} - -static inline unsigned int GetSwizzleIndex(GLenum swizzle) -{ - unsigned int colorIndex = 0; - - switch (swizzle) - { - case GL_RED: colorIndex = 0; break; - case GL_GREEN: colorIndex = 1; break; - case GL_BLUE: colorIndex = 2; break; - case GL_ALPHA: colorIndex = 3; break; - case GL_ZERO: colorIndex = 4; break; - case GL_ONE: colorIndex = 5; break; - default: UNREACHABLE(); break; - } - - return colorIndex; -} - -gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, - GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) -{ - HRESULT result; - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; - source->GetDesc(&sourceSRVDesc); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); - const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); - - GLenum shaderType = GL_NONE; - switch (sourceFormatInfo.componentType) - { - case GL_UNSIGNED_NORMALIZED: - case GL_SIGNED_NORMALIZED: - case GL_FLOAT: - shaderType = GL_FLOAT; - break; - case GL_INT: - shaderType = GL_INT; - break; - case GL_UNSIGNED_INT: - shaderType = GL_UNSIGNED_INT; - break; - default: - UNREACHABLE(); - break; - } - - SwizzleParameters parameters = { 0 }; - parameters.mDestinationType = shaderType; - parameters.mViewDimension = sourceSRVDesc.ViewDimension; - - SwizzleShaderMap::const_iterator i = mSwizzleShaderMap.find(parameters); - if (i == mSwizzleShaderMap.end()) - { - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION, "Internal error, missing swizzle shader."); - } - - const Shader &shader = i->second; - - // Set vertices - D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for swizzle, HRESULT: 0x%X.", result); - } - - UINT stride = 0; - UINT startIdx = 0; - UINT drawCount = 0; - D3D11_PRIMITIVE_TOPOLOGY topology; - - gl::Box area(0, 0, 0, size.width, size.height, size.depth); - shader.mVertexWriteFunction(area, size, area, size, mappedResource.pData, &stride, &drawCount, &topology); - - deviceContext->Unmap(mVertexBuffer, 0); - - // Set constant buffer - result = deviceContext->Map(mSwizzleCB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal constant buffer for swizzle, HRESULT: 0x%X.", result); - } - - unsigned int *swizzleIndices = reinterpret_cast(mappedResource.pData); - swizzleIndices[0] = GetSwizzleIndex(swizzleRed); - swizzleIndices[1] = GetSwizzleIndex(swizzleGreen); - swizzleIndices[2] = GetSwizzleIndex(swizzleBlue); - swizzleIndices[3] = GetSwizzleIndex(swizzleAlpha); - - deviceContext->Unmap(mSwizzleCB, 0); - - // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); - - // Apply constant buffer - deviceContext->PSSetConstantBuffers(0, 1, &mSwizzleCB); - - // Apply state - deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); - deviceContext->RSSetState(mScissorDisabledRasterizerState); - - // Apply shaders - deviceContext->IASetInputLayout(shader.mInputLayout); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); - - deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); - deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); - - // Unset the currently bound shader resource to avoid conflicts - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - - // Apply render target - mRenderer->setOneTimeRenderTarget(dest); - - // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = size.width; - viewport.Height = size.height; - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); - - // Apply textures - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); - - // Apply samplers - deviceContext->PSSetSamplers(0, 1, &mPointSampler); - - // Draw the quad - deviceContext->Draw(drawCount, 0); - - // Unbind textures and render targets and vertex buffer - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = NULL; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor, GLenum destFormat, GLenum filter) -{ - HRESULT result; - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - // Determine if the source format is a signed integer format, the destFormat will already - // be GL_XXXX_INTEGER but it does not tell us if it is signed or unsigned. - D3D11_SHADER_RESOURCE_VIEW_DESC sourceSRVDesc; - source->GetDesc(&sourceSRVDesc); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(sourceSRVDesc.Format); - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); - - BlitParameters parameters = { 0 }; - parameters.mDestinationFormat = destFormat; - parameters.mSignedInteger = (internalFormatInfo.componentType == GL_INT); - parameters.m3DBlit = sourceArea.depth > 1; - - BlitShaderMap::const_iterator i = mBlitShaderMap.find(parameters); - if (i == mBlitShaderMap.end()) - { - UNREACHABLE(); - return gl::Error(GL_OUT_OF_MEMORY, "Could not find appropriate shader for internal texture blit."); - } - - const Shader& shader = i->second; - - // Set vertices - D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); - } - - UINT stride = 0; - UINT startIdx = 0; - UINT drawCount = 0; - D3D11_PRIMITIVE_TOPOLOGY topology; - - shader.mVertexWriteFunction(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, - &stride, &drawCount, &topology); - - deviceContext->Unmap(mVertexBuffer, 0); - - // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); - - // Apply state - deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); - - if (scissor) - { - D3D11_RECT scissorRect; - scissorRect.left = scissor->x; - scissorRect.right = scissor->x + scissor->width; - scissorRect.top = scissor->y; - scissorRect.bottom = scissor->y + scissor->height; - - deviceContext->RSSetScissorRects(1, &scissorRect); - deviceContext->RSSetState(mScissorEnabledRasterizerState); - } - else - { - deviceContext->RSSetState(mScissorDisabledRasterizerState); - } - - // Apply shaders - deviceContext->IASetInputLayout(shader.mInputLayout); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(shader.mVertexShader, NULL, 0); - - deviceContext->PSSetShader(shader.mPixelShader, NULL, 0); - deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); - - // Unset the currently bound shader resource to avoid conflicts - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - - // Apply render target - mRenderer->setOneTimeRenderTarget(dest); - - // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = destSize.width; - viewport.Height = destSize.height; - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); - - // Apply textures - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); - - // Apply samplers - ID3D11SamplerState *sampler = NULL; - switch (filter) - { - case GL_NEAREST: sampler = mPointSampler; break; - case GL_LINEAR: sampler = mLinearSampler; break; - - default: - UNREACHABLE(); - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, unknown blit filter mode."); - } - deviceContext->PSSetSamplers(0, 1, &sampler); - - // Draw the quad - deviceContext->Draw(drawCount, 0); - - // Unbind textures and render targets and vertex buffer - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = NULL; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Blit11::copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor) -{ - return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, - dest, destSubresource, destArea, destSize, - scissor, true); -} - -gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor) -{ - HRESULT result; - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - // Set vertices - D3D11_MAPPED_SUBRESOURCE mappedResource; - result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); - } - - UINT stride = 0; - UINT startIdx = 0; - UINT drawCount = 0; - D3D11_PRIMITIVE_TOPOLOGY topology; - - Write2DVertices(sourceArea, sourceSize, destArea, destSize, mappedResource.pData, - &stride, &drawCount, &topology); - - deviceContext->Unmap(mVertexBuffer, 0); - - // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &startIdx); - - // Apply state - deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(mDepthStencilState, 0xFFFFFFFF); - - if (scissor) - { - D3D11_RECT scissorRect; - scissorRect.left = scissor->x; - scissorRect.right = scissor->x + scissor->width; - scissorRect.top = scissor->y; - scissorRect.bottom = scissor->y + scissor->height; - - deviceContext->RSSetScissorRects(1, &scissorRect); - deviceContext->RSSetState(mScissorEnabledRasterizerState); - } - else - { - deviceContext->RSSetState(mScissorDisabledRasterizerState); - } - - // Apply shaders - deviceContext->IASetInputLayout(mQuad2DIL); - deviceContext->IASetPrimitiveTopology(topology); - deviceContext->VSSetShader(mQuad2DVS, NULL, 0); - - deviceContext->PSSetShader(mDepthPS, NULL, 0); - deviceContext->GSSetShader(NULL, NULL, 0); - - // Unset the currently bound shader resource to avoid conflicts - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - - // Apply render target - deviceContext->OMSetRenderTargets(0, NULL, dest); - - // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = destSize.width; - viewport.Height = destSize.height; - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); - - // Apply textures - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); - - // Apply samplers - deviceContext->PSSetSamplers(0, 1, &mPointSampler); - - // Draw the quad - deviceContext->Draw(drawCount, 0); - - // Unbind textures and render targets and vertex buffer - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - - mRenderer->unapplyRenderTargets(); - - UINT zero = 0; - ID3D11Buffer *const nullBuffer = NULL; - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor) -{ - return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, - dest, destSubresource, destArea, destSize, - scissor, false); -} - -gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor, bool stencilOnly) -{ - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - ID3D11Resource *sourceStaging = CreateStagingTexture(device, deviceContext, source, sourceSubresource, sourceSize, D3D11_CPU_ACCESS_READ); - // HACK: Create the destination staging buffer as a read/write texture so ID3D11DevicContext::UpdateSubresource can be called - // using it's mapped data as a source - ID3D11Resource *destStaging = CreateStagingTexture(device, deviceContext, dest, destSubresource, destSize, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); - - if (!sourceStaging || !destStaging) - { - SafeRelease(sourceStaging); - SafeRelease(destStaging); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging textures for depth stencil blit."); - } - - DXGI_FORMAT format = GetTextureFormat(source); - ASSERT(format == GetTextureFormat(dest)); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); - unsigned int pixelSize = dxgiFormatInfo.pixelBytes; - unsigned int copyOffset = 0; - unsigned int copySize = pixelSize; - if (stencilOnly) - { - copyOffset = dxgiFormatInfo.depthBits / 8; - copySize = dxgiFormatInfo.stencilBits / 8; - - // It would be expensive to have non-byte sized stencil sizes since it would - // require reading from the destination, currently there aren't any though. - ASSERT(dxgiFormatInfo.stencilBits % 8 == 0 && - dxgiFormatInfo.depthBits % 8 == 0); - } - - D3D11_MAPPED_SUBRESOURCE sourceMapping; - HRESULT result = deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); - if (FAILED(result)) - { - SafeRelease(sourceStaging); - SafeRelease(destStaging); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal source staging texture for depth stencil blit, HRESULT: 0x%X.", result); - } - - D3D11_MAPPED_SUBRESOURCE destMapping; - result = deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); - if (FAILED(result)) - { - deviceContext->Unmap(sourceStaging, 0); - SafeRelease(sourceStaging); - SafeRelease(destStaging); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal destination staging texture for depth stencil blit, HRESULT: 0x%X.", result); - } - - gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); - - // Clip dest area to the destination size - gl::ClipRectangle(clippedDestArea, gl::Rectangle(0, 0, destSize.width, destSize.height), &clippedDestArea); - - // Clip dest area to the scissor - if (scissor) - { - gl::ClipRectangle(clippedDestArea, *scissor, &clippedDestArea); - } - - // Determine if entire rows can be copied at once instead of each individual pixel, requires that there is - // no out of bounds lookups required, the entire pixel is copied and no stretching - bool wholeRowCopy = sourceArea.width == clippedDestArea.width && - sourceArea.x >= 0 && sourceArea.x + sourceArea.width <= sourceSize.width && - copySize == pixelSize; - - for (int y = clippedDestArea.y; y < clippedDestArea.y + clippedDestArea.height; y++) - { - float yPerc = static_cast(y - destArea.y) / (destArea.height - 1); - - // Interpolate using the original source rectangle to determine which row to sample from while clamping to the edges - unsigned int readRow = gl::clamp(sourceArea.y + floor(yPerc * (sourceArea.height - 1) + 0.5f), 0, sourceSize.height - 1); - unsigned int writeRow = y; - - if (wholeRowCopy) - { - void *sourceRow = reinterpret_cast(sourceMapping.pData) + - readRow * sourceMapping.RowPitch + - sourceArea.x * pixelSize; - - void *destRow = reinterpret_cast(destMapping.pData) + - writeRow * destMapping.RowPitch + - destArea.x * pixelSize; - - memcpy(destRow, sourceRow, pixelSize * destArea.width); - } - else - { - for (int x = clippedDestArea.x; x < clippedDestArea.x + clippedDestArea.width; x++) - { - float xPerc = static_cast(x - destArea.x) / (destArea.width - 1); - - // Interpolate the original source rectangle to determine which column to sample from while clamping to the edges - unsigned int readColumn = gl::clamp(sourceArea.x + floor(xPerc * (sourceArea.width - 1) + 0.5f), 0, sourceSize.width - 1); - unsigned int writeColumn = x; - - void *sourcePixel = reinterpret_cast(sourceMapping.pData) + - readRow * sourceMapping.RowPitch + - readColumn * pixelSize + - copyOffset; - - void *destPixel = reinterpret_cast(destMapping.pData) + - writeRow * destMapping.RowPitch + - writeColumn * pixelSize + - copyOffset; - - memcpy(destPixel, sourcePixel, copySize); - } - } - } - - // HACK: Use ID3D11DevicContext::UpdateSubresource which causes an extra copy compared to ID3D11DevicContext::CopySubresourceRegion - // according to MSDN. - deviceContext->UpdateSubresource(dest, destSubresource, NULL, destMapping.pData, destMapping.RowPitch, destMapping.DepthPitch); - - deviceContext->Unmap(sourceStaging, 0); - deviceContext->Unmap(destStaging, 0); - - // TODO: Determine why this call to ID3D11DevicContext::CopySubresourceRegion causes a TDR timeout on some - // systems when called repeatedly. - // deviceContext->CopySubresourceRegion(dest, destSubresource, 0, 0, 0, destStaging, 0, NULL); - - SafeRelease(sourceStaging); - SafeRelease(destStaging); - - return gl::Error(GL_NO_ERROR); -} - -bool Blit11::compareBlitParameters(const Blit11::BlitParameters &a, const Blit11::BlitParameters &b) -{ - return memcmp(&a, &b, sizeof(Blit11::BlitParameters)) < 0; -} - -bool Blit11::compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b) -{ - return memcmp(&a, &b, sizeof(Blit11::SwizzleParameters)) < 0; -} - -void Blit11::add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) -{ - BlitParameters params = { 0 }; - params.mDestinationFormat = destFormat; - params.mSignedInteger = signedInteger; - params.m3DBlit = false; - - ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); - ASSERT(ps); - - Shader shader; - shader.mVertexWriteFunction = Write2DVertices; - shader.mInputLayout = mQuad2DIL; - shader.mVertexShader = mQuad2DVS; - shader.mGeometryShader = NULL; - shader.mPixelShader = ps; - - mBlitShaderMap[params] = shader; -} - -void Blit11::add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps) -{ - BlitParameters params = { 0 }; - params.mDestinationFormat = destFormat; - params.mSignedInteger = signedInteger; - params.m3DBlit = true; - - ASSERT(mBlitShaderMap.find(params) == mBlitShaderMap.end()); - ASSERT(ps); - - Shader shader; - shader.mVertexWriteFunction = Write3DVertices; - shader.mInputLayout = mQuad3DIL; - shader.mVertexShader = mQuad3DVS; - shader.mGeometryShader = mQuad3DGS; - shader.mPixelShader = ps; - - mBlitShaderMap[params] = shader; -} - -void Blit11::addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps) -{ - SwizzleParameters params = { 0 }; - params.mDestinationType = destType; - params.mViewDimension = viewDimension; - - ASSERT(mSwizzleShaderMap.find(params) == mSwizzleShaderMap.end()); - ASSERT(ps); - - Shader shader; - switch (viewDimension) - { - case D3D_SRV_DIMENSION_TEXTURE2D: - shader.mVertexWriteFunction = Write2DVertices; - shader.mInputLayout = mQuad2DIL; - shader.mVertexShader = mQuad2DVS; - shader.mGeometryShader = NULL; - break; - - case D3D_SRV_DIMENSION_TEXTURE3D: - case D3D_SRV_DIMENSION_TEXTURE2DARRAY: - case D3D_SRV_DIMENSION_TEXTURECUBE: - shader.mVertexWriteFunction = Write3DVertices; - shader.mInputLayout = mQuad3DIL; - shader.mVertexShader = mQuad3DVS; - shader.mGeometryShader = mQuad3DGS; - break; - - default: - UNREACHABLE(); - break; - } - shader.mPixelShader = ps; - - mSwizzleShaderMap[params] = shader; -} - -void Blit11::buildShaderMap() -{ - ID3D11Device *device = mRenderer->getDevice(); - - add2DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader" )); - add2DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader" )); - add2DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader" )); - add2DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader" )); - add2DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader" )); - add2DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader" )); - add2DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader" )); - add2DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader")); - - addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader" )); - - if (mRenderer->isLevel9()) - return; - - add2DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader" )); - add2DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader" )); - add2DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader" )); - add2DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader" )); - add2DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader" )); - add2DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader" )); - add2DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader" )); - add2DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader" )); - add3DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader" )); - add3DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader" )); - add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" )); - add3DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader" )); - add3DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader" )); - add3DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader" )); - add3DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader" )); - add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); - add3DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader" )); - add3DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader" )); - add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); - add3DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader" )); - add3DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader" )); - add3DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader" )); - add3DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader" )); - add3DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader")); - - addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader")); - addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader" )); - - addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Cube F swizzle pixel shader" )); - addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Cube UI swizzle pixel shader")); - addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURECUBE, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Cube I swizzle pixel shader" )); - - addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleF3D, "Blit11 3D F swizzle pixel shader" )); - addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleUI3D, "Blit11 3D UI swizzle pixel shader")); - addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE3D, d3d11::CompilePS(device, g_PS_SwizzleI3D, "Blit11 3D I swizzle pixel shader" )); - - addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleF2DArray, "Blit11 2D Array F swizzle pixel shader" )); - addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleUI2DArray, "Blit11 2D Array UI swizzle pixel shader")); - addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2DARRAY, d3d11::CompilePS(device, g_PS_SwizzleI2DArray, "Blit11 2D Array I swizzle pixel shader" )); -} - -void Blit11::clearShaderMap() -{ - for (BlitShaderMap::iterator i = mBlitShaderMap.begin(); i != mBlitShaderMap.end(); ++i) - { - Shader &shader = i->second; - SafeRelease(shader.mPixelShader); - } - mBlitShaderMap.clear(); - - for (SwizzleShaderMap::iterator i = mSwizzleShaderMap.begin(); i != mSwizzleShaderMap.end(); ++i) - { - Shader &shader = i->second; - SafeRelease(shader.mPixelShader); - } - mSwizzleShaderMap.clear(); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h deleted file mode 100644 index 821fa9d0cc..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h +++ /dev/null @@ -1,123 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Blit11.cpp: Texture copy utility class. - -#ifndef LIBGLESV2_BLIT11_H_ -#define LIBGLESV2_BLIT11_H_ - -#include "common/angleutils.h" -#include "libGLESv2/angletypes.h" -#include "libGLESv2/Error.h" - -#include - -namespace rx -{ -class Renderer11; - -class Blit11 -{ - public: - explicit Blit11(Renderer11 *renderer); - ~Blit11(); - - gl::Error swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, - GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); - - gl::Error copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor, GLenum destFormat, GLenum filter); - - gl::Error copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor); - - gl::Error copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor); - - gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor); - - private: - Renderer11 *mRenderer; - - struct BlitParameters - { - GLenum mDestinationFormat; - bool mSignedInteger; - bool m3DBlit; - }; - - gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor, bool stencilOnly); - - static bool compareBlitParameters(const BlitParameters &a, const BlitParameters &b); - - typedef void (*WriteVertexFunction)(const gl::Box &sourceArea, const gl::Extents &sourceSize, - const gl::Box &destArea, const gl::Extents &destSize, - void *outVertices, unsigned int *outStride, unsigned int *outVertexCount, - D3D11_PRIMITIVE_TOPOLOGY *outTopology); - - struct Shader - { - WriteVertexFunction mVertexWriteFunction; - ID3D11InputLayout *mInputLayout; - ID3D11VertexShader *mVertexShader; - ID3D11GeometryShader *mGeometryShader; - ID3D11PixelShader *mPixelShader; - }; - - typedef bool (*BlitParametersComparisonFunction)(const BlitParameters&, const BlitParameters &); - typedef std::map BlitShaderMap; - BlitShaderMap mBlitShaderMap; - - void add2DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); - void add3DBlitShaderToMap(GLenum destFormat, bool signedInteger, ID3D11PixelShader *ps); - - struct SwizzleParameters - { - GLenum mDestinationType; - D3D11_SRV_DIMENSION mViewDimension; - }; - - static bool compareSwizzleParameters(const SwizzleParameters &a, const SwizzleParameters &b); - - typedef bool (*SwizzleParametersComparisonFunction)(const SwizzleParameters&, const SwizzleParameters &); - typedef std::map SwizzleShaderMap; - SwizzleShaderMap mSwizzleShaderMap; - - void addSwizzleShaderToMap(GLenum destType, D3D11_SRV_DIMENSION viewDimension, ID3D11PixelShader *ps); - - void buildShaderMap(); - void clearShaderMap(); - - ID3D11Buffer *mVertexBuffer; - ID3D11SamplerState *mPointSampler; - ID3D11SamplerState *mLinearSampler; - ID3D11RasterizerState *mScissorEnabledRasterizerState; - ID3D11RasterizerState *mScissorDisabledRasterizerState; - ID3D11DepthStencilState *mDepthStencilState; - - ID3D11InputLayout *mQuad2DIL; - ID3D11VertexShader *mQuad2DVS; - ID3D11PixelShader *mDepthPS; - - ID3D11InputLayout *mQuad3DIL; - ID3D11VertexShader *mQuad3DVS; - ID3D11GeometryShader *mQuad3DGS; - - ID3D11Buffer *mSwizzleCB; - - DISALLOW_COPY_AND_ASSIGN(Blit11); -}; - -} - -#endif // LIBGLESV2_BLIT11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp deleted file mode 100644 index 5aab37938f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp +++ /dev/null @@ -1,983 +0,0 @@ -// -// Copyright 2014 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. -// - -// Buffer11.cpp Defines the Buffer11 class. - -#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -PackPixelsParams::PackPixelsParams() - : format(GL_NONE), - type(GL_NONE), - outputPitch(0), - packBuffer(NULL), - offset(0) -{} - -PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, GLenum formatIn, GLenum typeIn, GLuint outputPitchIn, - const gl::PixelPackState &packIn, ptrdiff_t offsetIn) - : area(areaIn), - format(formatIn), - type(typeIn), - outputPitch(outputPitchIn), - packBuffer(packIn.pixelBuffer.get()), - pack(packIn.alignment, packIn.reverseRowOrder), - offset(offsetIn) -{} - -namespace gl_d3d11 -{ - -D3D11_MAP GetD3DMapTypeFromBits(GLbitfield access) -{ - bool readBit = ((access & GL_MAP_READ_BIT) != 0); - bool writeBit = ((access & GL_MAP_WRITE_BIT) != 0); - - ASSERT(readBit || writeBit); - - // Note : we ignore the discard bit, because in D3D11, staging buffers - // don't accept the map-discard flag (discard only works for DYNAMIC usage) - - if (readBit && !writeBit) - { - return D3D11_MAP_READ; - } - else if (writeBit && !readBit) - { - return D3D11_MAP_WRITE; - } - else if (writeBit && readBit) - { - return D3D11_MAP_READ_WRITE; - } - else - { - UNREACHABLE(); - return D3D11_MAP_READ; - } -} - -} - -// Each instance of Buffer11::BufferStorage11 is specialized for a class of D3D binding points -// - vertex/transform feedback buffers -// - index buffers -// - pixel unpack buffers -// - uniform buffers -class Buffer11::BufferStorage11 -{ - public: - virtual ~BufferStorage11() {} - - DataRevision getDataRevision() const { return mRevision; } - BufferUsage getUsage() const { return mUsage; } - size_t getSize() const { return mBufferSize; } - bool isMappable() const { return (mUsage == BUFFER_USAGE_STAGING || mUsage == BUFFER_USAGE_PIXEL_PACK); } - - void setDataRevision(DataRevision rev) { mRevision = rev; } - - virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, - size_t size, size_t destOffset) = 0; - virtual gl::Error resize(size_t size, bool preserveData) = 0; - - virtual void *map(size_t offset, size_t length, GLbitfield access) = 0; - virtual void unmap() = 0; - - protected: - BufferStorage11(Renderer11 *renderer, BufferUsage usage); - - Renderer11 *mRenderer; - DataRevision mRevision; - const BufferUsage mUsage; - size_t mBufferSize; -}; - -// A native buffer storage represents an underlying D3D11 buffer for a particular -// type of storage. -class Buffer11::NativeBuffer11 : public Buffer11::BufferStorage11 -{ - public: - NativeBuffer11(Renderer11 *renderer, BufferUsage usage); - ~NativeBuffer11(); - - ID3D11Buffer *getNativeBuffer() const { return mNativeBuffer; } - - virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, - size_t size, size_t destOffset); - virtual gl::Error resize(size_t size, bool preserveData); - - virtual void *map(size_t offset, size_t length, GLbitfield access); - virtual void unmap(); - - gl::Error setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset); - - private: - ID3D11Buffer *mNativeBuffer; - - static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize); -}; - -// Pack storage represents internal storage for pack buffers. We implement pack buffers -// as CPU memory, tied to a staging texture, for asynchronous texture readback. -class Buffer11::PackStorage11 : public Buffer11::BufferStorage11 -{ - public: - PackStorage11(Renderer11 *renderer); - ~PackStorage11(); - - virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, - size_t size, size_t destOffset); - virtual gl::Error resize(size_t size, bool preserveData); - - virtual void *map(size_t offset, size_t length, GLbitfield access); - virtual void unmap(); - - gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); - - private: - - gl::Error flushQueuedPackCommand(); - - ID3D11Texture2D *mStagingTexture; - DXGI_FORMAT mTextureFormat; - gl::Extents mTextureSize; - MemoryBuffer mMemoryBuffer; - PackPixelsParams *mQueuedPackCommand; - PackPixelsParams mPackParams; - bool mDataModified; -}; - - -Buffer11::Buffer11(Renderer11 *renderer) - : BufferD3D(), - mRenderer(renderer), - mSize(0), - mMappedStorage(NULL), - mResolvedDataRevision(0), - mReadUsageCount(0) -{} - -Buffer11::~Buffer11() -{ - for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) - { - SafeDelete(it->second); - } -} - -Buffer11 *Buffer11::makeBuffer11(BufferImpl *buffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(Buffer11*, buffer)); - return static_cast(buffer); -} - -gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage) -{ - gl::Error error = setSubData(data, size, 0); - if (error.isError()) - { - return error; - } - - if (usage == GL_STATIC_DRAW) - { - initializeStaticData(); - } - - return error; -} - -gl::Error Buffer11::getData(const uint8_t **outData) -{ - NativeBuffer11 *stagingBuffer = getStagingBuffer(); - - if (!stagingBuffer) - { - // Out-of-memory - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get internal staging buffer."); - } - - if (stagingBuffer->getDataRevision() > mResolvedDataRevision) - { - if (stagingBuffer->getSize() > mResolvedData.size()) - { - if (!mResolvedData.resize(stagingBuffer->getSize())) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize data resolve buffer."); - } - } - - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = context->Map(stagingBuffer->getNativeBuffer(), 0, D3D11_MAP_READ, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer, result: 0x%X.", result); - } - - memcpy(mResolvedData.data(), mappedResource.pData, stagingBuffer->getSize()); - - context->Unmap(stagingBuffer->getNativeBuffer(), 0); - - mResolvedDataRevision = stagingBuffer->getDataRevision(); - } - - mReadUsageCount = 0; - - // Only happens if we initialized the buffer with no data (NULL) - if (mResolvedData.empty()) - { - if (!mResolvedData.resize(mSize)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize data resolve buffer."); - } - } - - ASSERT(mResolvedData.size() >= mSize); - - *outData = mResolvedData.data(); - return gl::Error(GL_NO_ERROR); -} - -gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) -{ - size_t requiredSize = size + offset; - - if (data && size > 0) - { - NativeBuffer11 *stagingBuffer = getStagingBuffer(); - - if (!stagingBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); - } - - // Explicitly resize the staging buffer, preserving data if the new data will not - // completely fill the buffer - if (stagingBuffer->getSize() < requiredSize) - { - bool preserveData = (offset > 0); - gl::Error error = stagingBuffer->resize(requiredSize, preserveData); - if (error.isError()) - { - return error; - } - } - - gl::Error error = stagingBuffer->setData(D3D11_MAP_WRITE, reinterpret_cast(data), size, offset); - if (error.isError()) - { - return error; - } - - stagingBuffer->setDataRevision(stagingBuffer->getDataRevision() + 1); - } - - mSize = std::max(mSize, requiredSize); - invalidateStaticData(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Buffer11::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) -{ - Buffer11 *sourceBuffer = makeBuffer11(source); - ASSERT(sourceBuffer != NULL); - - BufferStorage11 *copyDest = getLatestBufferStorage(); - if (!copyDest) - { - copyDest = getStagingBuffer(); - } - - BufferStorage11 *copySource = sourceBuffer->getLatestBufferStorage(); - - if (!copySource || !copyDest) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging buffer."); - } - - // If copying to/from a pixel pack buffer, we must have a staging or - // pack buffer partner, because other native buffers can't be mapped - if (copyDest->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copySource->isMappable()) - { - copySource = sourceBuffer->getStagingBuffer(); - } - else if (copySource->getUsage() == BUFFER_USAGE_PIXEL_PACK && !copyDest->isMappable()) - { - copyDest = getStagingBuffer(); - } - - // D3D11 does not allow overlapped copies until 11.1, and only if the - // device supports D3D11_FEATURE_DATA_D3D11_OPTIONS::CopyWithOverlap - // Get around this via a different source buffer - if (copySource == copyDest) - { - if (copySource->getUsage() == BUFFER_USAGE_STAGING) - { - copySource = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - } - else - { - copySource = getStagingBuffer(); - } - } - - copyDest->copyFromStorage(copySource, sourceOffset, size, destOffset); - copyDest->setDataRevision(copyDest->getDataRevision() + 1); - - mSize = std::max(mSize, destOffset + size); - invalidateStaticData(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Buffer11::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) -{ - ASSERT(!mMappedStorage); - - BufferStorage11 *latestStorage = getLatestBufferStorage(); - if (latestStorage && - (latestStorage->getUsage() == BUFFER_USAGE_PIXEL_PACK || - latestStorage->getUsage() == BUFFER_USAGE_STAGING)) - { - // Latest storage is mappable. - mMappedStorage = latestStorage; - } - else - { - // Fall back to using the staging buffer if the latest storage does - // not exist or is not CPU-accessible. - mMappedStorage = getStagingBuffer(); - } - - if (!mMappedStorage) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate mappable internal buffer."); - } - - if ((access & GL_MAP_WRITE_BIT) > 0) - { - // Update the data revision immediately, since the data might be changed at any time - mMappedStorage->setDataRevision(mMappedStorage->getDataRevision() + 1); - } - - void *mappedBuffer = mMappedStorage->map(offset, length, access); - if (!mappedBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer."); - } - - *mapPtr = mappedBuffer; - return gl::Error(GL_NO_ERROR); -} - -gl::Error Buffer11::unmap() -{ - ASSERT(mMappedStorage); - mMappedStorage->unmap(); - mMappedStorage = NULL; - return gl::Error(GL_NO_ERROR); -} - -void Buffer11::markTransformFeedbackUsage() -{ - BufferStorage11 *transformFeedbackStorage = getBufferStorage(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - - if (transformFeedbackStorage) - { - transformFeedbackStorage->setDataRevision(transformFeedbackStorage->getDataRevision() + 1); - } - - invalidateStaticData(); -} - -void Buffer11::markBufferUsage() -{ - mReadUsageCount++; - - const unsigned int usageLimit = 5; - - if (mReadUsageCount > usageLimit && mResolvedData.size() > 0) - { - mResolvedData.resize(0); - mResolvedDataRevision = 0; - } -} - -RendererD3D* Buffer11::getRenderer() -{ - return mRenderer; -} - -ID3D11Buffer *Buffer11::getBuffer(BufferUsage usage) -{ - markBufferUsage(); - - BufferStorage11 *bufferStorage = getBufferStorage(usage); - - if (!bufferStorage) - { - // Storage out-of-memory - return NULL; - } - - ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, bufferStorage)); - - return static_cast(bufferStorage)->getNativeBuffer(); -} - -ID3D11ShaderResourceView *Buffer11::getSRV(DXGI_FORMAT srvFormat) -{ - BufferStorage11 *storage = getBufferStorage(BUFFER_USAGE_PIXEL_UNPACK); - - if (!storage) - { - // Storage out-of-memory - return NULL; - } - - ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, storage)); - ID3D11Buffer *buffer = static_cast(storage)->getNativeBuffer(); - - auto bufferSRVIt = mBufferResourceViews.find(srvFormat); - - if (bufferSRVIt != mBufferResourceViews.end()) - { - if (bufferSRVIt->second.first == buffer) - { - return bufferSRVIt->second.second; - } - else - { - // The underlying buffer has changed since the SRV was created: recreate the SRV. - SafeRelease(bufferSRVIt->second.second); - } - } - - ID3D11Device *device = mRenderer->getDevice(); - ID3D11ShaderResourceView *bufferSRV = NULL; - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(srvFormat); - - D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; - bufferSRVDesc.Buffer.ElementOffset = 0; - bufferSRVDesc.Buffer.ElementWidth = mSize / dxgiFormatInfo.pixelBytes; - bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - bufferSRVDesc.Format = srvFormat; - - HRESULT result = device->CreateShaderResourceView(buffer, &bufferSRVDesc, &bufferSRV); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - - mBufferResourceViews[srvFormat] = BufferSRVPair(buffer, bufferSRV); - - return bufferSRV; -} - -gl::Error Buffer11::packPixels(ID3D11Texture2D *srcTexture, UINT srcSubresource, const PackPixelsParams ¶ms) -{ - PackStorage11 *packStorage = getPackStorage(); - - BufferStorage11 *latestStorage = getLatestBufferStorage(); - - if (packStorage) - { - gl::Error error = packStorage->packPixels(srcTexture, srcSubresource, params); - if (error.isError()) - { - return error; - } - packStorage->setDataRevision(latestStorage ? latestStorage->getDataRevision() + 1 : 1); - } - - return gl::Error(GL_NO_ERROR); -} - -Buffer11::BufferStorage11 *Buffer11::getBufferStorage(BufferUsage usage) -{ - BufferStorage11 *directBuffer = NULL; - auto directBufferIt = mBufferStorages.find(usage); - if (directBufferIt != mBufferStorages.end()) - { - directBuffer = directBufferIt->second; - } - - if (!directBuffer) - { - if (usage == BUFFER_USAGE_PIXEL_PACK) - { - directBuffer = new PackStorage11(mRenderer); - } - else - { - // buffer is not allocated, create it - directBuffer = new NativeBuffer11(mRenderer, usage); - } - - mBufferStorages.insert(std::make_pair(usage, directBuffer)); - } - - // resize buffer - if (directBuffer->getSize() < mSize) - { - if (directBuffer->resize(mSize, true).isError()) - { - // Out of memory error - return NULL; - } - } - - BufferStorage11 *latestBuffer = getLatestBufferStorage(); - if (latestBuffer && latestBuffer->getDataRevision() > directBuffer->getDataRevision()) - { - // if copying from a pack buffer to a non-staging native buffer, we must first - // copy through the staging buffer, because other native buffers can't be mapped - if (latestBuffer->getUsage() == BUFFER_USAGE_PIXEL_PACK && !directBuffer->isMappable()) - { - NativeBuffer11 *stagingBuffer = getStagingBuffer(); - - stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); - directBuffer->setDataRevision(latestBuffer->getDataRevision()); - - latestBuffer = stagingBuffer; - } - - // if copyFromStorage returns true, the D3D buffer has been recreated - // and we should update our serial - if (directBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) - { - updateSerial(); - } - directBuffer->setDataRevision(latestBuffer->getDataRevision()); - } - - return directBuffer; -} - -Buffer11::BufferStorage11 *Buffer11::getLatestBufferStorage() const -{ - // Even though we iterate over all the direct buffers, it is expected that only - // 1 or 2 will be present. - BufferStorage11 *latestStorage = NULL; - DataRevision latestRevision = 0; - for (auto it = mBufferStorages.begin(); it != mBufferStorages.end(); it++) - { - BufferStorage11 *storage = it->second; - if (!latestStorage || storage->getDataRevision() > latestRevision) - { - latestStorage = storage; - latestRevision = storage->getDataRevision(); - } - } - - return latestStorage; -} - -Buffer11::NativeBuffer11 *Buffer11::getStagingBuffer() -{ - BufferStorage11 *stagingStorage = getBufferStorage(BUFFER_USAGE_STAGING); - - if (!stagingStorage) - { - // Out-of-memory - return NULL; - } - - ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, stagingStorage)); - return static_cast(stagingStorage); -} - -Buffer11::PackStorage11 *Buffer11::getPackStorage() -{ - BufferStorage11 *packStorage = getBufferStorage(BUFFER_USAGE_PIXEL_PACK); - - if (!packStorage) - { - // Out-of-memory - return NULL; - } - - ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, packStorage)); - return static_cast(packStorage); -} - -bool Buffer11::supportsDirectBinding() const -{ - // Do not support direct buffers for dynamic data. The streaming buffer - // offers better performance for data which changes every frame. - // Check for absence of static buffer interfaces to detect dynamic data. - return (mStaticVertexBuffer && mStaticIndexBuffer); -} - -Buffer11::BufferStorage11::BufferStorage11(Renderer11 *renderer, BufferUsage usage) - : mRenderer(renderer), - mUsage(usage), - mRevision(0), - mBufferSize(0) -{ -} - -Buffer11::NativeBuffer11::NativeBuffer11(Renderer11 *renderer, BufferUsage usage) - : BufferStorage11(renderer, usage), - mNativeBuffer(NULL) -{ -} - -Buffer11::NativeBuffer11::~NativeBuffer11() -{ - SafeRelease(mNativeBuffer); -} - -// Returns true if it recreates the direct buffer -bool Buffer11::NativeBuffer11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset, - size_t size, size_t destOffset) -{ - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - size_t requiredSize = sourceOffset + size; - bool createBuffer = !mNativeBuffer || mBufferSize < requiredSize; - - // (Re)initialize D3D buffer if needed - if (createBuffer) - { - bool preserveData = (destOffset > 0); - resize(source->getSize(), preserveData); - } - - if (source->getUsage() == BUFFER_USAGE_PIXEL_PACK) - { - ASSERT(HAS_DYNAMIC_TYPE(PackStorage11*, source)); - - void *sourcePointer = source->map(sourceOffset, size, GL_MAP_READ_BIT); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT hr = context->Map(mNativeBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); - UNUSED_ASSERTION_VARIABLE(hr); - ASSERT(SUCCEEDED(hr)); - - unsigned char *destPointer = static_cast(mappedResource.pData) + destOffset; - - // Offset bounds are validated at the API layer - ASSERT(sourceOffset + size <= destOffset + mBufferSize); - memcpy(destPointer, sourcePointer, size); - - context->Unmap(mNativeBuffer, 0); - source->unmap(); - } - else - { - ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source)); - - D3D11_BOX srcBox; - srcBox.left = sourceOffset; - srcBox.right = sourceOffset + size; - srcBox.top = 0; - srcBox.bottom = 1; - srcBox.front = 0; - srcBox.back = 1; - - ASSERT(HAS_DYNAMIC_TYPE(NativeBuffer11*, source)); - ID3D11Buffer *sourceBuffer = static_cast(source)->getNativeBuffer(); - - context->CopySubresourceRegion(mNativeBuffer, 0, destOffset, 0, 0, sourceBuffer, 0, &srcBox); - } - - return createBuffer; -} - -gl::Error Buffer11::NativeBuffer11::resize(size_t size, bool preserveData) -{ - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - D3D11_BUFFER_DESC bufferDesc; - fillBufferDesc(&bufferDesc, mRenderer, mUsage, size); - - ID3D11Buffer *newBuffer; - HRESULT result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); - - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", result); - } - - if (mNativeBuffer && preserveData) - { - // We don't call resize if the buffer is big enough already. - ASSERT(mBufferSize <= size); - - D3D11_BOX srcBox; - srcBox.left = 0; - srcBox.right = mBufferSize; - srcBox.top = 0; - srcBox.bottom = 1; - srcBox.front = 0; - srcBox.back = 1; - - context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mNativeBuffer, 0, &srcBox); - } - - // No longer need the old buffer - SafeRelease(mNativeBuffer); - mNativeBuffer = newBuffer; - - mBufferSize = bufferDesc.ByteWidth; - - return gl::Error(GL_NO_ERROR); -} - -void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, - BufferUsage usage, unsigned int bufferSize) -{ - bufferDesc->ByteWidth = bufferSize; - bufferDesc->MiscFlags = 0; - bufferDesc->StructureByteStride = 0; - - switch (usage) - { - case BUFFER_USAGE_STAGING: - bufferDesc->Usage = D3D11_USAGE_STAGING; - bufferDesc->BindFlags = 0; - bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - break; - - case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: - bufferDesc->Usage = D3D11_USAGE_DEFAULT; - bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; - if (!renderer->isLevel9()) - bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; - bufferDesc->CPUAccessFlags = 0; - break; - - case BUFFER_USAGE_INDEX: - bufferDesc->Usage = D3D11_USAGE_DEFAULT; - bufferDesc->BindFlags = D3D11_BIND_INDEX_BUFFER; - bufferDesc->CPUAccessFlags = 0; - break; - - case BUFFER_USAGE_PIXEL_UNPACK: - bufferDesc->Usage = D3D11_USAGE_DEFAULT; - bufferDesc->BindFlags = D3D11_BIND_SHADER_RESOURCE; - bufferDesc->CPUAccessFlags = 0; - break; - - case BUFFER_USAGE_UNIFORM: - bufferDesc->Usage = D3D11_USAGE_DYNAMIC; - bufferDesc->BindFlags = D3D11_BIND_CONSTANT_BUFFER; - bufferDesc->CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - - // Constant buffers must be of a limited size, and aligned to 16 byte boundaries - // For our purposes we ignore any buffer data past the maximum constant buffer size - bufferDesc->ByteWidth = roundUp(bufferDesc->ByteWidth, 16u); - bufferDesc->ByteWidth = std::min(bufferDesc->ByteWidth, renderer->getRendererCaps().maxUniformBlockSize); - break; - - default: - UNREACHABLE(); - } -} - -void *Buffer11::NativeBuffer11::map(size_t offset, size_t length, GLbitfield access) -{ - ASSERT(mUsage == BUFFER_USAGE_STAGING); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - D3D11_MAP d3dMapType = gl_d3d11::GetD3DMapTypeFromBits(access); - UINT d3dMapFlag = ((access & GL_MAP_UNSYNCHRONIZED_BIT) != 0 ? D3D11_MAP_FLAG_DO_NOT_WAIT : 0); - - HRESULT result = context->Map(mNativeBuffer, 0, d3dMapType, d3dMapFlag, &mappedResource); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - - return static_cast(mappedResource.pData) + offset; -} - -gl::Error Buffer11::NativeBuffer11::setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset) -{ - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = context->Map(mNativeBuffer, 0, mapMode, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer, result: 0x%X.", result); - } - - uint8_t *offsetBufferPointer = reinterpret_cast(mappedResource.pData) + offset; - memcpy(offsetBufferPointer, data, size); - - context->Unmap(mNativeBuffer, 0); - - return gl::Error(GL_NO_ERROR); -} - -void Buffer11::NativeBuffer11::unmap() -{ - ASSERT(mUsage == BUFFER_USAGE_STAGING); - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->Unmap(mNativeBuffer, 0); -} - -Buffer11::PackStorage11::PackStorage11(Renderer11 *renderer) - : BufferStorage11(renderer, BUFFER_USAGE_PIXEL_PACK), - mStagingTexture(NULL), - mTextureFormat(DXGI_FORMAT_UNKNOWN), - mQueuedPackCommand(NULL), - mDataModified(false) -{ -} - -Buffer11::PackStorage11::~PackStorage11() -{ - SafeRelease(mStagingTexture); - SafeDelete(mQueuedPackCommand); -} - -bool Buffer11::PackStorage11::copyFromStorage(BufferStorage11 *source, size_t sourceOffset, - size_t size, size_t destOffset) -{ - // We copy through a staging buffer when drawing with a pack buffer, - // or for other cases where we access the pack buffer - UNREACHABLE(); - return false; -} - -gl::Error Buffer11::PackStorage11::resize(size_t size, bool preserveData) -{ - if (size != mBufferSize) - { - if (!mMemoryBuffer.resize(size)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer storage."); - } - mBufferSize = size; - } - - return gl::Error(GL_NO_ERROR); -} - -void *Buffer11::PackStorage11::map(size_t offset, size_t length, GLbitfield access) -{ - ASSERT(offset + length <= getSize()); - // TODO: fast path - // We might be able to optimize out one or more memcpy calls by detecting when - // and if D3D packs the staging texture memory identically to how we would fill - // the pack buffer according to the current pack state. - - gl::Error error = flushQueuedPackCommand(); - if (error.isError()) - { - return NULL; - } - - mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); - - return mMemoryBuffer.data() + offset; -} - -void Buffer11::PackStorage11::unmap() -{ - // No-op -} - -gl::Error Buffer11::PackStorage11::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms) -{ - gl::Error error = flushQueuedPackCommand(); - if (error.isError()) - { - return error; - } - - mQueuedPackCommand = new PackPixelsParams(params); - - D3D11_TEXTURE2D_DESC textureDesc; - srcTexure->GetDesc(&textureDesc); - - if (mStagingTexture != NULL && - (mTextureFormat != textureDesc.Format || - mTextureSize.width != params.area.width || - mTextureSize.height != params.area.height)) - { - SafeRelease(mStagingTexture); - mTextureSize.width = 0; - mTextureSize.height = 0; - mTextureFormat = DXGI_FORMAT_UNKNOWN; - } - - if (mStagingTexture == NULL) - { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT hr; - - mTextureSize.width = params.area.width; - mTextureSize.height = params.area.height; - mTextureFormat = textureDesc.Format; - - D3D11_TEXTURE2D_DESC stagingDesc; - stagingDesc.Width = params.area.width; - stagingDesc.Height = params.area.height; - stagingDesc.MipLevels = 1; - stagingDesc.ArraySize = 1; - stagingDesc.Format = mTextureFormat; - stagingDesc.SampleDesc.Count = 1; - stagingDesc.SampleDesc.Quality = 0; - stagingDesc.Usage = D3D11_USAGE_STAGING; - stagingDesc.BindFlags = 0; - stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - stagingDesc.MiscFlags = 0; - - hr = device->CreateTexture2D(&stagingDesc, NULL, &mStagingTexture); - if (FAILED(hr)) - { - ASSERT(hr == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal staging texture."); - } - } - - // ReadPixels from multisampled FBOs isn't supported in current GL - ASSERT(textureDesc.SampleDesc.Count <= 1); - - ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - D3D11_BOX srcBox; - srcBox.left = params.area.x; - srcBox.right = params.area.x + params.area.width; - srcBox.top = params.area.y; - srcBox.bottom = params.area.y + params.area.height; - srcBox.front = 0; - srcBox.back = 1; - - // Asynchronous copy - immediateContext->CopySubresourceRegion(mStagingTexture, 0, 0, 0, 0, srcTexure, srcSubresource, &srcBox); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Buffer11::PackStorage11::flushQueuedPackCommand() -{ - ASSERT(mMemoryBuffer.size() > 0); - - if (mQueuedPackCommand) - { - gl::Error error = mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); - SafeDelete(mQueuedPackCommand); - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h deleted file mode 100644 index 1c06bbf88a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h +++ /dev/null @@ -1,105 +0,0 @@ -// -// Copyright 2014 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. -// - -// Buffer11.h: Defines the rx::Buffer11 class which implements rx::BufferImpl via rx::BufferD3D. - -#ifndef LIBGLESV2_RENDERER_BUFFER11_H_ -#define LIBGLESV2_RENDERER_BUFFER11_H_ - -#include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/renderer/d3d/MemoryBuffer.h" -#include "libGLESv2/angletypes.h" - -namespace rx -{ -class Renderer11; - -enum BufferUsage -{ - BUFFER_USAGE_STAGING, - BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK, - BUFFER_USAGE_INDEX, - BUFFER_USAGE_PIXEL_UNPACK, - BUFFER_USAGE_PIXEL_PACK, - BUFFER_USAGE_UNIFORM, -}; - -struct PackPixelsParams -{ - PackPixelsParams(); - PackPixelsParams(const gl::Rectangle &area, GLenum format, GLenum type, GLuint outputPitch, - const gl::PixelPackState &pack, ptrdiff_t offset); - - gl::Rectangle area; - GLenum format; - GLenum type; - GLuint outputPitch; - gl::Buffer *packBuffer; - gl::PixelPackState pack; - ptrdiff_t offset; -}; - -typedef size_t DataRevision; - -class Buffer11 : public BufferD3D -{ - public: - Buffer11(Renderer11 *renderer); - virtual ~Buffer11(); - - static Buffer11 *makeBuffer11(BufferImpl *buffer); - - ID3D11Buffer *getBuffer(BufferUsage usage); - ID3D11ShaderResourceView *getSRV(DXGI_FORMAT srvFormat); - bool isMapped() const { return mMappedStorage != NULL; } - gl::Error packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms); - - // BufferD3D implementation - virtual size_t getSize() const { return mSize; } - virtual bool supportsDirectBinding() const; - RendererD3D *getRenderer() override; - - // BufferImpl implementation - virtual gl::Error setData(const void* data, size_t size, GLenum usage); - gl::Error getData(const uint8_t **outData) override; - virtual gl::Error setSubData(const void* data, size_t size, size_t offset); - virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); - virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); - virtual gl::Error unmap(); - virtual void markTransformFeedbackUsage(); - - private: - DISALLOW_COPY_AND_ASSIGN(Buffer11); - - class BufferStorage11; - class NativeBuffer11; - class PackStorage11; - - Renderer11 *mRenderer; - size_t mSize; - - BufferStorage11 *mMappedStorage; - - std::map mBufferStorages; - - typedef std::pair BufferSRVPair; - std::map mBufferResourceViews; - - MemoryBuffer mResolvedData; - DataRevision mResolvedDataRevision; - unsigned int mReadUsageCount; - - void markBufferUsage(); - NativeBuffer11 *getStagingBuffer(); - PackStorage11 *getPackStorage(); - - BufferStorage11 *getBufferStorage(BufferUsage usage); - BufferStorage11 *getLatestBufferStorage() const; -}; - -} - -#endif // LIBGLESV2_RENDERER_BUFFER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp deleted file mode 100644 index 7185a05506..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp +++ /dev/null @@ -1,556 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Clear11.cpp: Framebuffer clear utility class. - -#include "libGLESv2/renderer/d3d/d3d11/Clear11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" - -// Precompiled shaders -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloatvs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloatps.h" - -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuintvs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuintps.h" - -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsintvs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsintps.h" - -namespace rx -{ - -template -static void ApplyVertices(const gl::Extents &framebufferSize, const gl::Rectangle *scissor, const gl::Color &color, float depth, void *buffer) -{ - d3d11::PositionDepthColorVertex *vertices = reinterpret_cast*>(buffer); - - float depthClear = gl::clamp01(depth); - float left = -1.0f; - float right = 1.0f; - float top = -1.0f; - float bottom = 1.0f; - - // Clip the quad coordinates to the scissor if needed - if (scissor != NULL) - { - left = std::max(left, (scissor->x / float(framebufferSize.width)) * 2.0f - 1.0f); - right = std::min(right, ((scissor->x + scissor->width) / float(framebufferSize.width)) * 2.0f - 1.0f); - top = std::max(top, ((framebufferSize.height - scissor->y - scissor->height) / float(framebufferSize.height)) * 2.0f - 1.0f); - bottom = std::min(bottom, ((framebufferSize.height - scissor->y) / float(framebufferSize.height)) * 2.0f - 1.0f); - } - - d3d11::SetPositionDepthColorVertex(vertices + 0, left, bottom, depthClear, color); - d3d11::SetPositionDepthColorVertex(vertices + 1, left, top, depthClear, color); - d3d11::SetPositionDepthColorVertex(vertices + 2, right, bottom, depthClear, color); - d3d11::SetPositionDepthColorVertex(vertices + 3, right, top, depthClear, color); -} - -template -Clear11::ClearShader Clear11::CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize]) -{ - HRESULT result; - - ClearShader shader = { 0 }; - - D3D11_INPUT_ELEMENT_DESC quadLayout[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, colorType, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - result = device->CreateInputLayout(quadLayout, ArraySize(quadLayout), vsByteCode, vsSize, &shader.inputLayout); - ASSERT(SUCCEEDED(result)); - - result = device->CreateVertexShader(vsByteCode, vsSize, NULL, &shader.vertexShader); - ASSERT(SUCCEEDED(result)); - - result = device->CreatePixelShader(psByteCode, psSize, NULL, &shader.pixelShader); - ASSERT(SUCCEEDED(result)); - - return shader; -} - -Clear11::Clear11(Renderer11 *renderer) - : mRenderer(renderer), mClearBlendStates(StructLessThan), mClearDepthStencilStates(StructLessThan), - mVertexBuffer(NULL), mRasterizerState(NULL) -{ - HRESULT result; - ID3D11Device *device = renderer->getDevice(); - - D3D11_BUFFER_DESC vbDesc; - vbDesc.ByteWidth = sizeof(d3d11::PositionDepthColorVertex) * 4; - vbDesc.Usage = D3D11_USAGE_DYNAMIC; - vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - vbDesc.MiscFlags = 0; - vbDesc.StructureByteStride = 0; - - result = device->CreateBuffer(&vbDesc, NULL, &mVertexBuffer); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mVertexBuffer, "Clear11 masked clear vertex buffer"); - - D3D11_RASTERIZER_DESC rsDesc; - rsDesc.FillMode = D3D11_FILL_SOLID; - rsDesc.CullMode = D3D11_CULL_NONE; - rsDesc.FrontCounterClockwise = FALSE; - rsDesc.DepthBias = 0; - rsDesc.DepthBiasClamp = 0.0f; - rsDesc.SlopeScaledDepthBias = 0.0f; - rsDesc.DepthClipEnable = renderer->isLevel9(); - rsDesc.ScissorEnable = FALSE; - rsDesc.MultisampleEnable = FALSE; - rsDesc.AntialiasedLineEnable = FALSE; - - result = device->CreateRasterizerState(&rsDesc, &mRasterizerState); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); - - mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat); - if (mRenderer->isLevel9()) { - memset(&mUintClearShader, 0, sizeof(ClearShader)); - memset(&mIntClearShader, 0, sizeof(ClearShader)); - return; - } - mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint ); - mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); -} - -Clear11::~Clear11() -{ - for (ClearBlendStateMap::iterator i = mClearBlendStates.begin(); i != mClearBlendStates.end(); i++) - { - SafeRelease(i->second); - } - mClearBlendStates.clear(); - - SafeRelease(mFloatClearShader.inputLayout); - SafeRelease(mFloatClearShader.vertexShader); - SafeRelease(mFloatClearShader.pixelShader); - - SafeRelease(mUintClearShader.inputLayout); - SafeRelease(mUintClearShader.vertexShader); - SafeRelease(mUintClearShader.pixelShader); - - SafeRelease(mIntClearShader.inputLayout); - SafeRelease(mIntClearShader.vertexShader); - SafeRelease(mIntClearShader.pixelShader); - - for (ClearDepthStencilStateMap::iterator i = mClearDepthStencilStates.begin(); i != mClearDepthStencilStates.end(); i++) - { - SafeRelease(i->second); - } - mClearDepthStencilStates.clear(); - - SafeRelease(mVertexBuffer); - SafeRelease(mRasterizerState); -} - -gl::Error Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) -{ - // First determine if a scissored clear is needed, this will always require drawing a quad. - // - // Otherwise, iterate over the color buffers which require clearing and determine if they can be - // cleared with ID3D11DeviceContext::ClearRenderTargetView... This requires: - // 1) The render target is being cleared to a float value (will be cast to integer when clearing integer - // render targets as expected but does not work the other way around) - // 2) The format of the render target has no color channels that are currently masked out. - // Clear the easy-to-clear buffers on the spot and accumulate the ones that require special work. - // - // Also determine if the depth stencil can be cleared with ID3D11DeviceContext::ClearDepthStencilView - // by checking if the stencil write mask covers the entire stencil. - // - // To clear the remaining buffers, quads must be drawn containing an int, uint or float vertex color - // attribute. - - gl::Extents framebufferSize; - if (frameBuffer->getFirstColorbuffer() != NULL) - { - gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer(); - framebufferSize.width = attachment->getWidth(); - framebufferSize.height = attachment->getHeight(); - framebufferSize.depth = 1; - } - else if (frameBuffer->getDepthOrStencilbuffer() != NULL) - { - gl::FramebufferAttachment *attachment = frameBuffer->getDepthOrStencilbuffer(); - framebufferSize.width = attachment->getWidth(); - framebufferSize.height = attachment->getHeight(); - framebufferSize.depth = 1; - } - else - { - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - - if (clearParams.scissorEnabled && (clearParams.scissor.x >= framebufferSize.width || - clearParams.scissor.y >= framebufferSize.height || - clearParams.scissor.x + clearParams.scissor.width <= 0 || - clearParams.scissor.y + clearParams.scissor.height <= 0)) - { - // Scissor is enabled and the scissor rectangle is outside the renderbuffer - return gl::Error(GL_NO_ERROR); - } - - bool needScissoredClear = clearParams.scissorEnabled && (clearParams.scissor.x > 0 || clearParams.scissor.y > 0 || - clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width || - clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height); - - std::vector maskedClearRenderTargets; - RenderTarget11* maskedClearDepthStencil = NULL; - - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (clearParams.clearColor[colorAttachment] && frameBuffer->isEnabledColorAttachment(colorAttachment)) - { - gl::FramebufferAttachment *attachment = frameBuffer->getColorbuffer(colorAttachment); - if (attachment) - { - RenderTarget11 *renderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); - if (error.isError()) - { - return error; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat()); - - if (clearParams.colorClearType == GL_FLOAT && - !(formatInfo.componentType == GL_FLOAT || formatInfo.componentType == GL_UNSIGNED_NORMALIZED || formatInfo.componentType == GL_SIGNED_NORMALIZED)) - { - ERR("It is undefined behaviour to clear a render buffer which is not normalized fixed point or floating-" - "point to floating point values (color attachment %u has internal format 0x%X).", colorAttachment, - attachment->getInternalFormat()); - } - - if ((formatInfo.redBits == 0 || !clearParams.colorMaskRed) && - (formatInfo.greenBits == 0 || !clearParams.colorMaskGreen) && - (formatInfo.blueBits == 0 || !clearParams.colorMaskBlue) && - (formatInfo.alphaBits == 0 || !clearParams.colorMaskAlpha)) - { - // Every channel either does not exist in the render target or is masked out - continue; - } - else if (needScissoredClear || clearParams.colorClearType != GL_FLOAT || - (formatInfo.redBits > 0 && !clearParams.colorMaskRed) || - (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || - (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || - (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) - { - // A scissored or masked clear is required - MaskedRenderTarget maskAndRt; - bool clearColor = clearParams.clearColor[colorAttachment]; - maskAndRt.colorMask[0] = (clearColor && clearParams.colorMaskRed); - maskAndRt.colorMask[1] = (clearColor && clearParams.colorMaskGreen); - maskAndRt.colorMask[2] = (clearColor && clearParams.colorMaskBlue); - maskAndRt.colorMask[3] = (clearColor && clearParams.colorMaskAlpha); - maskAndRt.renderTarget = renderTarget; - maskedClearRenderTargets.push_back(maskAndRt); - } - else - { - // ID3D11DeviceContext::ClearRenderTargetView is possible - - ID3D11RenderTargetView *framebufferRTV = renderTarget->getRenderTargetView(); - if (!framebufferRTV) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); - } - - const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(attachment->getActualFormat()); - - // Check if the actual format has a channel that the internal format does not and set them to the - // default values - const float clearValues[4] = - { - ((formatInfo.redBits == 0 && actualFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), - ((formatInfo.greenBits == 0 && actualFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), - ((formatInfo.blueBits == 0 && actualFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue), - ((formatInfo.alphaBits == 0 && actualFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), - }; - - deviceContext->ClearRenderTargetView(framebufferRTV, clearValues); - } - } - } - } - - if (clearParams.clearDepth || clearParams.clearStencil) - { - gl::FramebufferAttachment *attachment = frameBuffer->getDepthOrStencilbuffer(); - if (attachment) - { - RenderTarget11 *renderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); - if (error.isError()) - { - return error; - } - - const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(attachment->getActualFormat()); - - unsigned int stencilUnmasked = frameBuffer->hasStencil() ? (1 << actualFormatInfo.stencilBits) - 1 : 0; - bool needMaskedStencilClear = clearParams.clearStencil && (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; - - if (needScissoredClear || needMaskedStencilClear) - { - maskedClearDepthStencil = renderTarget; - } - else - { - ID3D11DepthStencilView *framebufferDSV = renderTarget->getDepthStencilView(); - if (!framebufferDSV) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null."); - } - - UINT clearFlags = (clearParams.clearDepth ? D3D11_CLEAR_DEPTH : 0) | - (clearParams.clearStencil ? D3D11_CLEAR_STENCIL : 0); - FLOAT depthClear = gl::clamp01(clearParams.depthClearValue); - UINT8 stencilClear = clearParams.stencilClearValue & 0xFF; - - deviceContext->ClearDepthStencilView(framebufferDSV, clearFlags, depthClear, stencilClear); - } - } - } - - if (maskedClearRenderTargets.size() > 0 || maskedClearDepthStencil) - { - // To clear the render targets and depth stencil in one pass: - // - // Render a quad clipped to the scissor rectangle which draws the clear color and a blend - // state that will perform the required color masking. - // - // The quad's depth is equal to the depth clear value with a depth stencil state that - // will enable or disable depth test/writes if the depth buffer should be cleared or not. - // - // The rasterizer state's stencil is set to always pass or fail based on if the stencil - // should be cleared or not with a stencil write mask of the stencil clear value. - // - // ====================================================================================== - // - // Luckily, the gl spec (ES 3.0.2 pg 183) states that the results of clearing a render- - // buffer that is not normalized fixed point or floating point with floating point values - // are undefined so we can just write floats to them and D3D11 will bit cast them to - // integers. - // - // Also, we don't have to worry about attempting to clear a normalized fixed/floating point - // buffer with integer values because there is no gl API call which would allow it, - // glClearBuffer* calls only clear a single renderbuffer at a time which is verified to - // be a compatible clear type. - - // Bind all the render targets which need clearing - ASSERT(maskedClearRenderTargets.size() <= mRenderer->getRendererCaps().maxDrawBuffers); - std::vector rtvs(maskedClearRenderTargets.size()); - for (unsigned int i = 0; i < maskedClearRenderTargets.size(); i++) - { - RenderTarget11 *renderTarget = maskedClearRenderTargets[i].renderTarget; - ID3D11RenderTargetView *rtv = renderTarget->getRenderTargetView(); - if (!rtv) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); - } - - rtvs[i] = rtv; - } - ID3D11DepthStencilView *dsv = maskedClearDepthStencil ? maskedClearDepthStencil->getDepthStencilView() : NULL; - - ID3D11BlendState *blendState = getBlendState(maskedClearRenderTargets); - const FLOAT blendFactors[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - const UINT sampleMask = 0xFFFFFFFF; - - ID3D11DepthStencilState *dsState = getDepthStencilState(clearParams); - const UINT stencilClear = clearParams.stencilClearValue & 0xFF; - - // Set the vertices - UINT vertexStride = 0; - const UINT startIdx = 0; - const ClearShader* shader = NULL; - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal masked clear vertex buffer, HRESULT: 0x%X.", result); - } - - const gl::Rectangle *scissorPtr = clearParams.scissorEnabled ? &clearParams.scissor : NULL; - switch (clearParams.colorClearType) - { - case GL_FLOAT: - ApplyVertices(framebufferSize, scissorPtr, clearParams.colorFClearValue, clearParams.depthClearValue, mappedResource.pData); - vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = &mFloatClearShader; - break; - - case GL_UNSIGNED_INT: - ApplyVertices(framebufferSize, scissorPtr, clearParams.colorUIClearValue, clearParams.depthClearValue, mappedResource.pData); - vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = &mUintClearShader; - break; - - case GL_INT: - ApplyVertices(framebufferSize, scissorPtr, clearParams.colorIClearValue, clearParams.depthClearValue, mappedResource.pData); - vertexStride = sizeof(d3d11::PositionDepthColorVertex); - shader = &mIntClearShader; - break; - - default: - UNREACHABLE(); - break; - } - - deviceContext->Unmap(mVertexBuffer, 0); - - // Set the viewport to be the same size as the framebuffer - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = framebufferSize.width; - viewport.Height = framebufferSize.height; - viewport.MinDepth = 0; - viewport.MaxDepth = 1; - deviceContext->RSSetViewports(1, &viewport); - - // Apply state - deviceContext->OMSetBlendState(blendState, blendFactors, sampleMask); - deviceContext->OMSetDepthStencilState(dsState, stencilClear); - deviceContext->RSSetState(mRasterizerState); - - // Apply shaders - deviceContext->IASetInputLayout(shader->inputLayout); - deviceContext->VSSetShader(shader->vertexShader, NULL, 0); - deviceContext->PSSetShader(shader->pixelShader, NULL, 0); - deviceContext->GSSetShader(NULL, NULL, 0); - - // Apply vertex buffer - deviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &vertexStride, &startIdx); - deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - - // Apply render targets - deviceContext->OMSetRenderTargets(rtvs.size(), (rtvs.empty() ? NULL : &rtvs[0]), dsv); - - // Draw the clear quad - deviceContext->Draw(4, 0); - - // Clean up - mRenderer->markAllStateDirty(); - } - - return gl::Error(GL_NO_ERROR); -} - -ID3D11BlendState *Clear11::getBlendState(const std::vector& rts) -{ - ClearBlendInfo blendKey = { 0 }; - for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) - { - if (i < rts.size()) - { - RenderTarget11 *rt = rts[i].renderTarget; - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(rt->getInternalFormat()); - - blendKey.maskChannels[i][0] = (rts[i].colorMask[0] && formatInfo.redBits > 0); - blendKey.maskChannels[i][1] = (rts[i].colorMask[1] && formatInfo.greenBits > 0); - blendKey.maskChannels[i][2] = (rts[i].colorMask[2] && formatInfo.blueBits > 0); - blendKey.maskChannels[i][3] = (rts[i].colorMask[3] && formatInfo.alphaBits > 0); - } - else - { - blendKey.maskChannels[i][0] = false; - blendKey.maskChannels[i][1] = false; - blendKey.maskChannels[i][2] = false; - blendKey.maskChannels[i][3] = false; - } - } - - ClearBlendStateMap::const_iterator i = mClearBlendStates.find(blendKey); - if (i != mClearBlendStates.end()) - { - return i->second; - } - else - { - D3D11_BLEND_DESC blendDesc = { 0 }; - blendDesc.AlphaToCoverageEnable = FALSE; - blendDesc.IndependentBlendEnable = (rts.size() > 1) ? TRUE : FALSE; - - for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) - { - blendDesc.RenderTarget[i].BlendEnable = FALSE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = gl_d3d11::ConvertColorMask(blendKey.maskChannels[i][0], - blendKey.maskChannels[i][1], - blendKey.maskChannels[i][2], - blendKey.maskChannels[i][3]); - } - - ID3D11Device *device = mRenderer->getDevice(); - ID3D11BlendState* blendState = NULL; - HRESULT result = device->CreateBlendState(&blendDesc, &blendState); - if (FAILED(result) || !blendState) - { - ERR("Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); - return NULL; - } - - mClearBlendStates[blendKey] = blendState; - - return blendState; - } -} - -ID3D11DepthStencilState *Clear11::getDepthStencilState(const gl::ClearParameters &clearParams) -{ - ClearDepthStencilInfo dsKey = { 0 }; - dsKey.clearDepth = clearParams.clearDepth; - dsKey.clearStencil = clearParams.clearStencil; - dsKey.stencilWriteMask = clearParams.stencilWriteMask & 0xFF; - - ClearDepthStencilStateMap::const_iterator i = mClearDepthStencilStates.find(dsKey); - if (i != mClearDepthStencilStates.end()) - { - return i->second; - } - else - { - D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; - dsDesc.DepthEnable = dsKey.clearDepth ? TRUE : FALSE; - dsDesc.DepthWriteMask = dsKey.clearDepth ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - dsDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.StencilEnable = dsKey.clearStencil ? TRUE : FALSE; - dsDesc.StencilReadMask = 0; - dsDesc.StencilWriteMask = dsKey.stencilWriteMask; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DepthStencilState* dsState = NULL; - HRESULT result = device->CreateDepthStencilState(&dsDesc, &dsState); - if (FAILED(result) || !dsState) - { - ERR("Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); - return NULL; - } - - mClearDepthStencilStates[dsKey] = dsState; - - return dsState; - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h deleted file mode 100644 index a7e8fea56a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h +++ /dev/null @@ -1,87 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Clear11.h: Framebuffer clear utility class. - -#ifndef LIBGLESV2_RENDERER_CLEAR11_H_ -#define LIBGLESV2_RENDERER_CLEAR11_H_ - -#include "libGLESv2/angletypes.h" -#include "libGLESv2/Error.h" - -#include -#include - -namespace gl -{ -class Framebuffer; -} - -namespace rx -{ -class Renderer11; -class RenderTarget11; - -class Clear11 -{ - public: - explicit Clear11(Renderer11 *renderer); - ~Clear11(); - - // Clears the framebuffer with the supplied clear parameters, assumes that the framebuffer is currently applied. - gl::Error clearFramebuffer(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer); - - private: - Renderer11 *mRenderer; - - struct ClearBlendInfo - { - bool maskChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; - }; - typedef bool (*ClearBlendInfoComparisonFunction)(const ClearBlendInfo&, const ClearBlendInfo &); - typedef std::map ClearBlendStateMap; - ClearBlendStateMap mClearBlendStates; - - struct MaskedRenderTarget - { - bool colorMask[4]; - RenderTarget11 *renderTarget; - }; - - ID3D11BlendState *getBlendState(const std::vector &rts); - - struct ClearShader - { - ID3D11InputLayout *inputLayout; - ID3D11VertexShader *vertexShader; - ID3D11PixelShader *pixelShader; - }; - ClearShader mFloatClearShader; - ClearShader mUintClearShader; - ClearShader mIntClearShader; - - template - static ClearShader CreateClearShader(ID3D11Device *device, DXGI_FORMAT colorType, const BYTE (&vsByteCode)[vsSize], const BYTE (&psByteCode)[psSize]); - - struct ClearDepthStencilInfo - { - bool clearDepth; - bool clearStencil; - UINT8 stencilWriteMask; - }; - typedef bool (*ClearDepthStencilInfoComparisonFunction)(const ClearDepthStencilInfo&, const ClearDepthStencilInfo &); - typedef std::map ClearDepthStencilStateMap; - ClearDepthStencilStateMap mClearDepthStencilStates; - - ID3D11DepthStencilState *getDepthStencilState(const gl::ClearParameters &clearParams); - - ID3D11Buffer *mVertexBuffer; - ID3D11RasterizerState *mRasterizerState; -}; - -} - -#endif // LIBGLESV2_RENDERER_CLEAR11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp deleted file mode 100644 index f44d934056..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp +++ /dev/null @@ -1,232 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. - -#include "libGLESv2/renderer/d3d/d3d11/Fence11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/main.h" - -#include "common/utilities.h" - -namespace rx -{ - -// -// Template helpers for set and test operations. -// - -template -gl::Error FenceSetHelper(FenceClass *fence) -{ - if (!fence->mQuery) - { - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_EVENT; - queryDesc.MiscFlags = 0; - - HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); - } - } - - fence->mRenderer->getDeviceContext()->End(fence->mQuery); - return gl::Error(GL_NO_ERROR); -} - -template -gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean *outFinished) -{ - ASSERT(fence->mQuery); - - UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); - HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags); - - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); - } - else if (fence->mRenderer->isDeviceLost()) - { - return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); - } - - ASSERT(result == S_OK || result == S_FALSE); - *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); - return gl::Error(GL_NO_ERROR); -} - -// -// FenceNV11 -// - -FenceNV11::FenceNV11(Renderer11 *renderer) - : FenceNVImpl(), - mRenderer(renderer), - mQuery(NULL) -{ -} - -FenceNV11::~FenceNV11() -{ - SafeRelease(mQuery); -} - -gl::Error FenceNV11::set() -{ - return FenceSetHelper(this); -} - -gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished) -{ - return FenceTestHelper(this, flushCommandBuffer, outFinished); -} - -gl::Error FenceNV11::finishFence(GLboolean *outFinished) -{ - ASSERT(outFinished); - - while (*outFinished != GL_TRUE) - { - gl::Error error = test(true, outFinished); - if (error.isError()) - { - return error; - } - - Sleep(0); - } - - return gl::Error(GL_NO_ERROR); -} - -// -// FenceSync11 -// - -// Important note on accurate timers in Windows: -// -// QueryPerformanceCounter has a few major issues, including being 10x as expensive to call -// as timeGetTime on laptops and "jumping" during certain hardware events. -// -// See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc" -// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc -// -// We still opt to use QPC. In the present and moving forward, most newer systems will not suffer -// from buggy implementations. - -FenceSync11::FenceSync11(Renderer11 *renderer) - : FenceSyncImpl(), - mRenderer(renderer), - mQuery(NULL) -{ - LARGE_INTEGER counterFreqency = { 0 }; - BOOL success = QueryPerformanceFrequency(&counterFreqency); - UNUSED_ASSERTION_VARIABLE(success); - ASSERT(success); - - mCounterFrequency = counterFreqency.QuadPart; -} - -FenceSync11::~FenceSync11() -{ - SafeRelease(mQuery); -} - -gl::Error FenceSync11::set() -{ - return FenceSetHelper(this); -} - -gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) -{ - ASSERT(outResult); - - bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); - - GLboolean result = GL_FALSE; - gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result); - if (error.isError()) - { - *outResult = GL_WAIT_FAILED; - return error; - } - - if (result == GL_TRUE) - { - *outResult = GL_ALREADY_SIGNALED; - return gl::Error(GL_NO_ERROR); - } - - if (timeout == 0) - { - *outResult = GL_TIMEOUT_EXPIRED; - return gl::Error(GL_NO_ERROR); - } - - LARGE_INTEGER currentCounter = { 0 }; - BOOL success = QueryPerformanceCounter(¤tCounter); - UNUSED_ASSERTION_VARIABLE(success); - ASSERT(success); - - LONGLONG timeoutInSeconds = static_cast(timeout) * static_cast(1000000ll); - LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; - - while (currentCounter.QuadPart < endCounter && !result) - { - Sleep(0); - BOOL success = QueryPerformanceCounter(¤tCounter); - UNUSED_ASSERTION_VARIABLE(success); - ASSERT(success); - - error = FenceTestHelper(this, flushCommandBuffer, &result); - if (error.isError()) - { - *outResult = GL_WAIT_FAILED; - return error; - } - } - - if (currentCounter.QuadPart >= endCounter) - { - *outResult = GL_TIMEOUT_EXPIRED; - } - else - { - *outResult = GL_CONDITION_SATISFIED; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout) -{ - // Because our API is currently designed to be called from a single thread, we don't need to do - // extra work for a server-side fence. GPU commands issued after the fence is created will always - // be processed after the fence is signaled. - return gl::Error(GL_NO_ERROR); -} - -gl::Error FenceSync11::getStatus(GLint *outResult) -{ - GLboolean result = GL_FALSE; - gl::Error error = FenceTestHelper(this, false, &result); - if (error.isError()) - { - // The spec does not specify any way to report errors during the status test (e.g. device lost) - // so we report the fence is unblocked in case of error or signaled. - *outResult = GL_SIGNALED; - - return error; - } - - *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED); - return gl::Error(GL_NO_ERROR); -} - -} // namespace rx diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h deleted file mode 100644 index 1223a53b90..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Fence11.h: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. - -#ifndef LIBGLESV2_RENDERER_FENCE11_H_ -#define LIBGLESV2_RENDERER_FENCE11_H_ - -#include "libGLESv2/renderer/FenceImpl.h" - -namespace rx -{ -class Renderer11; - -class FenceNV11 : public FenceNVImpl -{ - public: - explicit FenceNV11(Renderer11 *renderer); - virtual ~FenceNV11(); - - gl::Error set(); - gl::Error test(bool flushCommandBuffer, GLboolean *outFinished); - gl::Error finishFence(GLboolean *outFinished); - - private: - DISALLOW_COPY_AND_ASSIGN(FenceNV11); - - template friend gl::Error FenceSetHelper(T *fence); - template friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished); - - Renderer11 *mRenderer; - ID3D11Query *mQuery; -}; - -class FenceSync11 : public FenceSyncImpl -{ - public: - explicit FenceSync11(Renderer11 *renderer); - virtual ~FenceSync11(); - - gl::Error set(); - gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult); - gl::Error serverWait(GLbitfield flags, GLuint64 timeout); - gl::Error getStatus(GLint *outResult); - - private: - DISALLOW_COPY_AND_ASSIGN(FenceSync11); - - template friend gl::Error FenceSetHelper(T *fence); - template friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished); - - Renderer11 *mRenderer; - ID3D11Query *mQuery; - LONGLONG mCounterFrequency; -}; - -} - -#endif // LIBGLESV2_RENDERER_FENCE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp deleted file mode 100644 index e6f3e90683..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp +++ /dev/null @@ -1,634 +0,0 @@ -// -// 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. -// - -// Image11.h: Implements the rx::Image11 class, which acts as the interface to -// the actual underlying resources of a Texture - -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/Image11.h" -#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" -#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/main.h" - -#include "common/utilities.h" - -namespace rx -{ - -Image11::Image11() - : mRenderer(NULL), - mDXGIFormat(DXGI_FORMAT_UNKNOWN), - mStagingTexture(NULL), - mStagingSubresource(0), - mRecoverFromStorage(false), - mAssociatedStorage(NULL), - mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()), - mRecoveredFromStorageCount(0) - -{ -} - -Image11::~Image11() -{ - disassociateStorage(); - releaseStagingTexture(); -} - -Image11 *Image11::makeImage11(Image *img) -{ - ASSERT(HAS_DYNAMIC_TYPE(Image11*, img)); - return static_cast(img); -} - -gl::Error Image11::generateMipmap(Image11 *dest, Image11 *src) -{ - ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); - ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); - ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight()); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(src->getDXGIFormat()); - ASSERT(dxgiFormatInfo.mipGenerationFunction != NULL); - - D3D11_MAPPED_SUBRESOURCE destMapped; - gl::Error error = dest->map(D3D11_MAP_WRITE, &destMapped); - if (error.isError()) - { - return error; - } - - D3D11_MAPPED_SUBRESOURCE srcMapped; - error = src->map(D3D11_MAP_READ, &srcMapped); - if (error.isError()) - { - dest->unmap(); - return error; - } - - const uint8_t *sourceData = reinterpret_cast(srcMapped.pData); - uint8_t *destData = reinterpret_cast(destMapped.pData); - - dxgiFormatInfo.mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), - sourceData, srcMapped.RowPitch, srcMapped.DepthPitch, - destData, destMapped.RowPitch, destMapped.DepthPitch); - - dest->unmap(); - src->unmap(); - - dest->markDirty(); - - return gl::Error(GL_NO_ERROR); -} - -bool Image11::isDirty() const -{ - // If mDirty is true - // AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be recovered from TextureStorage - // AND the texture doesn't require init data (i.e. a blank new texture will suffice) - // then isDirty should still return false. - if (mDirty && !mStagingTexture && !mRecoverFromStorage && !(d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL)) - { - return false; - } - - return mDirty; -} - -gl::Error Image11::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) -{ - TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); - - // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times, - // then we should just keep the staging texture around to prevent the copying from impacting perf. - // We allow the Image11 to copy its data to/from TextureStorage once. - // This accounts for an app making a late call to glGenerateMipmap. - bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2); - - if (attemptToReleaseStagingTexture) - { - // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it. - gl::Error error = storage11->releaseAssociatedImage(index, this); - if (error.isError()) - { - return error; - } - } - - ID3D11Resource *stagingTexture = NULL; - unsigned int stagingSubresourceIndex = 0; - gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); - if (error.isError()) - { - return error; - } - - error = storage11->updateSubresourceLevel(stagingTexture, stagingSubresourceIndex, index, region); - if (error.isError()) - { - return error; - } - - // Once the image data has been copied into the Storage, we can release it locally. - if (attemptToReleaseStagingTexture) - { - storage11->associateImage(this, index); - releaseStagingTexture(); - mRecoverFromStorage = true; - mAssociatedStorage = storage11; - mAssociatedImageIndex = index; - } - - return gl::Error(GL_NO_ERROR); -} - -bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const -{ - return (mAssociatedStorage == textureStorage); -} - -gl::Error Image11::recoverFromAssociatedStorage() -{ - if (mRecoverFromStorage) - { - gl::Error error = createStagingTexture(); - if (error.isError()) - { - return error; - } - - bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedImageIndex, this); - - // This means that the cached TextureStorage has been modified after this Image11 released its copy of its data. - // This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten. - ASSERT(textureStorageCorrect); - - if (textureStorageCorrect) - { - // CopySubResource from the Storage to the Staging texture - gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); - error = mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region); - if (error.isError()) - { - return error; - } - - mRecoveredFromStorageCount += 1; - } - - // Reset all the recovery parameters, even if the texture storage association is broken. - disassociateStorage(); - } - - return gl::Error(GL_NO_ERROR); -} - -void Image11::disassociateStorage() -{ - if (mRecoverFromStorage) - { - // Make the texturestorage release the Image11 too - mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this); - - mRecoverFromStorage = false; - mAssociatedStorage = NULL; - mAssociatedImageIndex = gl::ImageIndex::MakeInvalid(); - } -} - -bool Image11::redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) -{ - if (mWidth != width || - mHeight != height || - mInternalFormat != internalformat || - forceRelease) - { - // End the association with the TextureStorage, since that data will be out of date. - // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined. - disassociateStorage(); - mRecoveredFromStorageCount = 0; - - mRenderer = Renderer11::makeRenderer11(renderer); - - mWidth = width; - mHeight = height; - mDepth = depth; - mInternalFormat = internalformat; - mTarget = target; - - // compute the d3d format that will be used - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(formatInfo.texFormat); - mDXGIFormat = formatInfo.texFormat; - mActualFormat = dxgiFormatInfo.internalFormat; - mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); - - releaseStagingTexture(); - mDirty = (formatInfo.dataInitializerFunction != NULL); - - return true; - } - - return false; -} - -DXGI_FORMAT Image11::getDXGIFormat() const -{ - // this should only happen if the image hasn't been redefined first - // which would be a bug by the caller - ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN); - - return mDXGIFormat; -} - -// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input -// into the target pixel rectangle. -gl::Error Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input) -{ - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); - GLsizei inputRowPitch = formatInfo.computeRowPitch(type, width, unpackAlignment); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpackAlignment); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); - GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; - - const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat); - LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type); - - D3D11_MAPPED_SUBRESOURCE mappedImage; - gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); - if (error.isError()) - { - return error; - } - - uint8_t* offsetMappedData = (reinterpret_cast(mappedImage.pData) + (yoffset * mappedImage.RowPitch + xoffset * outputPixelSize + zoffset * mappedImage.DepthPitch)); - loadFunction(width, height, depth, - reinterpret_cast(input), inputRowPitch, inputDepthPitch, - offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); - - unmap(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input) -{ - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); - GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, width, 1); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mDXGIFormat); - GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; - GLuint outputBlockWidth = dxgiFormatInfo.blockWidth; - GLuint outputBlockHeight = dxgiFormatInfo.blockHeight; - - ASSERT(xoffset % outputBlockWidth == 0); - ASSERT(yoffset % outputBlockHeight == 0); - - const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat); - LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE); - - D3D11_MAPPED_SUBRESOURCE mappedImage; - gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); - if (error.isError()) - { - return error; - } - - uint8_t* offsetMappedData = reinterpret_cast(mappedImage.pData) + ((yoffset / outputBlockHeight) * mappedImage.RowPitch + - (xoffset / outputBlockWidth) * outputPixelSize + - zoffset * mappedImage.DepthPitch); - - loadFunction(width, height, depth, - reinterpret_cast(input), inputRowPitch, inputDepthPitch, - offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); - - unmap(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) -{ - RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source); - ASSERT(sourceRenderTarget->getTexture()); - - UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex(); - ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject(sourceRenderTarget->getTexture()); - - if (!sourceTexture2D) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source RenderTarget."); - } - - gl::Error error = copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex); - - SafeRelease(sourceTexture2D); - - return error; -} - -gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source) -{ - TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source); - - UINT subresourceIndex = sourceStorage11->getSubresourceIndex(sourceIndex); - ID3D11Resource *resource = NULL; - gl::Error error = sourceStorage11->getResource(&resource); - if (error.isError()) - { - return error; - } - - ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject(resource); - - if (!sourceTexture2D) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source TextureStorage."); - } - - error = copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex); - - SafeRelease(sourceTexture2D); - - return error; -} - -gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource) -{ - D3D11_TEXTURE2D_DESC textureDesc; - source->GetDesc(&textureDesc); - - if (textureDesc.Format == mDXGIFormat) - { - // No conversion needed-- use copyback fastpath - ID3D11Resource *stagingTexture = NULL; - unsigned int stagingSubresourceIndex = 0; - gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - UINT subresourceAfterResolve = sourceSubResource; - - ID3D11Texture2D* srcTex = NULL; - if (textureDesc.SampleDesc.Count > 1) - { - D3D11_TEXTURE2D_DESC resolveDesc; - resolveDesc.Width = textureDesc.Width; - resolveDesc.Height = textureDesc.Height; - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; - resolveDesc.Format = textureDesc.Format; - resolveDesc.SampleDesc.Count = 1; - resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = D3D11_USAGE_DEFAULT; - resolveDesc.BindFlags = 0; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); - } - - deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format); - subresourceAfterResolve = 0; - } - else - { - srcTex = source; - } - - D3D11_BOX srcBox; - srcBox.left = sourceArea.x; - srcBox.right = sourceArea.x + sourceArea.width; - srcBox.top = sourceArea.y; - srcBox.bottom = sourceArea.y + sourceArea.height; - srcBox.front = 0; - srcBox.back = 1; - - deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, xoffset, yoffset, zoffset, srcTex, subresourceAfterResolve, &srcBox); - - if (textureDesc.SampleDesc.Count > 1) - { - SafeRelease(srcTex); - } - } - else - { - // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels - D3D11_MAPPED_SUBRESOURCE mappedImage; - gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); - if (error.isError()) - { - return error; - } - - // determine the offset coordinate into the destination buffer - GLsizei rowOffset = gl::GetInternalFormatInfo(mActualFormat).pixelBytes * xoffset; - uint8_t *dataOffset = static_cast(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch; - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); - - error = mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); - - unmap(); - - if (error.isError()) - { - return error; - } - } - - mDirty = true; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image11::getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex) -{ - gl::Error error = createStagingTexture(); - if (error.isError()) - { - return error; - } - - *outStagingTexture = mStagingTexture; - *outSubresourceIndex = mStagingSubresource; - return gl::Error(GL_NO_ERROR); -} - -void Image11::releaseStagingTexture() -{ - SafeRelease(mStagingTexture); -} - -gl::Error Image11::createStagingTexture() -{ - if (mStagingTexture) - { - return gl::Error(GL_NO_ERROR); - } - - ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0); - - const DXGI_FORMAT dxgiFormat = getDXGIFormat(); - - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - int lodOffset = 1; - GLsizei width = mWidth; - GLsizei height = mHeight; - - // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset); - - if (mTarget == GL_TEXTURE_3D) - { - ID3D11Texture3D *newTexture = NULL; - - D3D11_TEXTURE3D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.Depth = mDepth; - desc.MipLevels = lodOffset + 1; - desc.Format = dxgiFormat; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - - if (d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) - { - std::vector initialData; - std::vector< std::vector > textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, width, height, mDepth, - lodOffset + 1, &initialData, &textureData); - - result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); - } - else - { - result = device->CreateTexture3D(&desc, NULL, &newTexture); - } - - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); - } - - mStagingTexture = newTexture; - mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); - } - else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) - { - ID3D11Texture2D *newTexture = NULL; - - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = lodOffset + 1; - desc.ArraySize = 1; - desc.Format = dxgiFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - - if (d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) - { - std::vector initialData; - std::vector< std::vector > textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, width, height, 1, - lodOffset + 1, &initialData, &textureData); - - result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); - } - else - { - result = device->CreateTexture2D(&desc, NULL, &newTexture); - } - - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); - } - - mStagingTexture = newTexture; - mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); - } - else - { - UNREACHABLE(); - } - - mDirty = false; - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) -{ - // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE. - gl::Error error = recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - - ID3D11Resource *stagingTexture = NULL; - unsigned int subresourceIndex = 0; - error = getStagingTexture(&stagingTexture, &subresourceIndex); - if (error.isError()) - { - return error; - } - - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - ASSERT(mStagingTexture); - HRESULT result = deviceContext->Map(stagingTexture, subresourceIndex, mapType, 0, map); - - // this can fail if the device is removed (from TDR) - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - } - else if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map staging texture, result: 0x%X.", result); - } - - mDirty = true; - - return gl::Error(GL_NO_ERROR); -} - -void Image11::unmap() -{ - if (mStagingTexture) - { - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - deviceContext->Unmap(mStagingTexture, mStagingSubresource); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h deleted file mode 100644 index a936e6d7b2..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h +++ /dev/null @@ -1,87 +0,0 @@ -// -// 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. -// - -// Image11.h: Defines the rx::Image11 class, which acts as the interface to -// the actual underlying resources of a Texture - -#ifndef LIBGLESV2_RENDERER_IMAGE11_H_ -#define LIBGLESV2_RENDERER_IMAGE11_H_ - -#include "libGLESv2/renderer/d3d/ImageD3D.h" -#include "libGLESv2/ImageIndex.h" - -#include "common/debug.h" - -namespace gl -{ -class Framebuffer; -} - -namespace rx -{ -class Renderer11; -class TextureStorage11; - -class Image11 : public ImageD3D -{ - public: - Image11(); - virtual ~Image11(); - - static Image11 *makeImage11(Image *img); - - static gl::Error generateMipmap(Image11 *dest, Image11 *src); - - virtual bool isDirty() const; - - virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); - - bool redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) override; - - DXGI_FORMAT getDXGIFormat() const; - - virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input); - virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input); - - virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source); - virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, - const gl::ImageIndex &sourceIndex, TextureStorage *source); - - gl::Error recoverFromAssociatedStorage(); - bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; - void disassociateStorage(); - - protected: - gl::Error map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); - void unmap(); - - private: - DISALLOW_COPY_AND_ASSIGN(Image11); - - gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box ®ion); - gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource); - - gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex); - gl::Error createStagingTexture(); - void releaseStagingTexture(); - - Renderer11 *mRenderer; - - DXGI_FORMAT mDXGIFormat; - ID3D11Resource *mStagingTexture; - unsigned int mStagingSubresource; - - bool mRecoverFromStorage; - TextureStorage11 *mAssociatedStorage; - gl::ImageIndex mAssociatedImageIndex; - unsigned int mRecoveredFromStorageCount; -}; - -} - -#endif // LIBGLESV2_RENDERER_IMAGE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp deleted file mode 100644 index 9a61182ee9..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp +++ /dev/null @@ -1,162 +0,0 @@ -// -// 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. -// - -// IndexBuffer11.cpp: Defines the D3D11 IndexBuffer implementation. - -#include "libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" - -namespace rx -{ - -IndexBuffer11::IndexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) -{ - mBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; -} - -IndexBuffer11::~IndexBuffer11() -{ - SafeRelease(mBuffer); -} - -gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) -{ - SafeRelease(mBuffer); - - updateSerial(); - - if (bufferSize > 0) - { - ID3D11Device* dxDevice = mRenderer->getDevice(); - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = bufferSize; - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - - HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); - } - } - - mBufferSize = bufferSize; - mIndexType = indexType; - mDynamicUsage = dynamic; - - return gl::Error(GL_NO_ERROR); -} - -IndexBuffer11 *IndexBuffer11::makeIndexBuffer11(IndexBuffer *indexBuffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer11*, indexBuffer)); - return static_cast(indexBuffer); -} - -gl::Error IndexBuffer11::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) -{ - if (!mBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); - } - - // Check for integer overflows and out-out-bounds map requests - if (offset + size < offset || offset + size > mBufferSize) - { - return gl::Error(GL_OUT_OF_MEMORY, "Index buffer map range is not inside the buffer."); - } - - ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal index buffer, HRESULT: 0x%08x.", result); - } - - *outMappedMemory = reinterpret_cast(mappedResource.pData) + offset; - return gl::Error(GL_NO_ERROR); -} - -gl::Error IndexBuffer11::unmapBuffer() -{ - if (!mBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); - } - - ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - dxContext->Unmap(mBuffer, 0); - return gl::Error(GL_NO_ERROR); -} - -GLenum IndexBuffer11::getIndexType() const -{ - return mIndexType; -} - -unsigned int IndexBuffer11::getBufferSize() const -{ - return mBufferSize; -} - -gl::Error IndexBuffer11::setSize(unsigned int bufferSize, GLenum indexType) -{ - if (bufferSize > mBufferSize || indexType != mIndexType) - { - return initialize(bufferSize, indexType, mDynamicUsage); - } - else - { - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error IndexBuffer11::discard() -{ - if (!mBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); - } - - ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal index buffer, HRESULT: 0x%08x.", result); - } - - dxContext->Unmap(mBuffer, 0); - - return gl::Error(GL_NO_ERROR); -} - -DXGI_FORMAT IndexBuffer11::getIndexFormat() const -{ - switch (mIndexType) - { - case GL_UNSIGNED_BYTE: return DXGI_FORMAT_R16_UINT; - case GL_UNSIGNED_SHORT: return DXGI_FORMAT_R16_UINT; - case GL_UNSIGNED_INT: return DXGI_FORMAT_R32_UINT; - default: UNREACHABLE(); return DXGI_FORMAT_UNKNOWN; - } -} - -ID3D11Buffer *IndexBuffer11::getBuffer() const -{ - return mBuffer; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h deleted file mode 100644 index 3351df5ec1..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// 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. -// - -// IndexBuffer11.h: Defines the D3D11 IndexBuffer implementation. - -#ifndef LIBGLESV2_RENDERER_INDEXBUFFER11_H_ -#define LIBGLESV2_RENDERER_INDEXBUFFER11_H_ - -#include "libGLESv2/renderer/d3d/IndexBuffer.h" - -namespace rx -{ -class Renderer11; - -class IndexBuffer11 : public IndexBuffer -{ - public: - explicit IndexBuffer11(Renderer11 *const renderer); - virtual ~IndexBuffer11(); - - virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); - - static IndexBuffer11 *makeIndexBuffer11(IndexBuffer *indexBuffer); - - virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); - virtual gl::Error unmapBuffer(); - - virtual GLenum getIndexType() const; - virtual unsigned int getBufferSize() const; - virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); - - virtual gl::Error discard(); - - DXGI_FORMAT getIndexFormat() const; - ID3D11Buffer *getBuffer() const; - - private: - DISALLOW_COPY_AND_ASSIGN(IndexBuffer11); - - Renderer11 *const mRenderer; - - ID3D11Buffer *mBuffer; - unsigned int mBufferSize; - GLenum mIndexType; - bool mDynamicUsage; -}; - -} - -#endif // LIBGLESV2_RENDERER_INDEXBUFFER11_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp deleted file mode 100644 index ff90a6a69a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp +++ /dev/null @@ -1,255 +0,0 @@ -// -// 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. -// - -// InputLayoutCache.cpp: Defines InputLayoutCache, a class that builds and caches -// D3D11 input layouts. - -#include "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h" -#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/renderer/d3d/ProgramD3D.h" -#include "libGLESv2/renderer/d3d/VertexDataManager.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/VertexAttribute.h" - -#include "third_party/murmurhash/MurmurHash3.h" - -namespace rx -{ - -static void GetInputLayout(const TranslatedAttribute translatedAttributes[gl::MAX_VERTEX_ATTRIBS], - gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) -{ - for (unsigned int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) - { - const TranslatedAttribute &translatedAttribute = translatedAttributes[attributeIndex]; - - if (translatedAttributes[attributeIndex].active) - { - inputLayout[attributeIndex] = gl::VertexFormat(*translatedAttribute.attribute, - translatedAttribute.currentValueType); - } - } -} - -const unsigned int InputLayoutCache::kMaxInputLayouts = 1024; - -InputLayoutCache::InputLayoutCache() : mInputLayoutMap(kMaxInputLayouts, hashInputLayout, compareInputLayouts) -{ - mCounter = 0; - mDevice = NULL; - mDeviceContext = NULL; - mCurrentIL = NULL; - for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - mCurrentBuffers[i] = NULL; - mCurrentVertexStrides[i] = -1; - mCurrentVertexOffsets[i] = -1; - } -} - -InputLayoutCache::~InputLayoutCache() -{ - clear(); -} - -void InputLayoutCache::initialize(ID3D11Device *device, ID3D11DeviceContext *context) -{ - clear(); - mDevice = device; - mDeviceContext = context; -} - -void InputLayoutCache::clear() -{ - for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) - { - SafeRelease(i->second.inputLayout); - } - mInputLayoutMap.clear(); - markDirty(); -} - -void InputLayoutCache::markDirty() -{ - mCurrentIL = NULL; - for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - mCurrentBuffers[i] = NULL; - mCurrentVertexStrides[i] = -1; - mCurrentVertexOffsets[i] = -1; - } -} - -gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], - gl::ProgramBinary *programBinary) -{ - int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS]; - programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices); - - if (!mDevice || !mDeviceContext) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal input layout cache is not initialized."); - } - - InputLayoutKey ilKey = { 0 }; - - static const char* semanticName = "TEXCOORD"; - - for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - if (attributes[i].active) - { - D3D11_INPUT_CLASSIFICATION inputClass = attributes[i].divisor > 0 ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA; - - gl::VertexFormat vertexFormat(*attributes[i].attribute, attributes[i].currentValueType); - const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat); - - // Record the type of the associated vertex shader vector in our key - // This will prevent mismatched vertex shaders from using the same input layout - GLint attributeSize; - programBinary->getActiveAttribute(sortedSemanticIndices[i], 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL); - - ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName; - ilKey.elements[ilKey.elementCount].desc.SemanticIndex = i; - ilKey.elements[ilKey.elementCount].desc.Format = vertexFormatInfo.nativeFormat; - ilKey.elements[ilKey.elementCount].desc.InputSlot = i; - ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; - ilKey.elements[ilKey.elementCount].desc.InputSlotClass = inputClass; - ilKey.elements[ilKey.elementCount].desc.InstanceDataStepRate = attributes[i].divisor; - ilKey.elementCount++; - } - } - - ID3D11InputLayout *inputLayout = NULL; - - InputLayoutMap::iterator keyIter = mInputLayoutMap.find(ilKey); - if (keyIter != mInputLayoutMap.end()) - { - inputLayout = keyIter->second.inputLayout; - keyIter->second.lastUsedTime = mCounter++; - } - else - { - gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS]; - GetInputLayout(attributes, shaderInputLayout); - ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); - - ShaderExecutable *shader = NULL; - gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader); - if (error.isError()) - { - return error; - } - - ShaderExecutable *shader11 = ShaderExecutable11::makeShaderExecutable11(shader); - - D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS]; - for (unsigned int j = 0; j < ilKey.elementCount; ++j) - { - descs[j] = ilKey.elements[j].desc; - } - - HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader11->getFunction(), shader11->getLength(), &inputLayout); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result); - } - - if (mInputLayoutMap.size() >= kMaxInputLayouts) - { - TRACE("Overflowed the limit of %u input layouts, removing the least recently used " - "to make room.", kMaxInputLayouts); - - InputLayoutMap::iterator leastRecentlyUsed = mInputLayoutMap.begin(); - for (InputLayoutMap::iterator i = mInputLayoutMap.begin(); i != mInputLayoutMap.end(); i++) - { - if (i->second.lastUsedTime < leastRecentlyUsed->second.lastUsedTime) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.inputLayout); - mInputLayoutMap.erase(leastRecentlyUsed); - } - - InputLayoutCounterPair inputCounterPair; - inputCounterPair.inputLayout = inputLayout; - inputCounterPair.lastUsedTime = mCounter++; - - mInputLayoutMap.insert(std::make_pair(ilKey, inputCounterPair)); - } - - if (inputLayout != mCurrentIL) - { - mDeviceContext->IASetInputLayout(inputLayout); - mCurrentIL = inputLayout; - } - - bool dirtyBuffers = false; - size_t minDiff = gl::MAX_VERTEX_ATTRIBS; - size_t maxDiff = 0; - for (unsigned int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - ID3D11Buffer *buffer = NULL; - - if (attributes[i].active) - { - VertexBuffer11 *vertexBuffer = VertexBuffer11::makeVertexBuffer11(attributes[i].vertexBuffer); - Buffer11 *bufferStorage = attributes[i].storage ? Buffer11::makeBuffer11(attributes[i].storage) : NULL; - - buffer = bufferStorage ? bufferStorage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK) - : vertexBuffer->getBuffer(); - } - - UINT vertexStride = attributes[i].stride; - UINT vertexOffset = attributes[i].offset; - - if (buffer != mCurrentBuffers[i] || vertexStride != mCurrentVertexStrides[i] || - vertexOffset != mCurrentVertexOffsets[i]) - { - dirtyBuffers = true; - minDiff = std::min(minDiff, static_cast(i)); - maxDiff = std::max(maxDiff, static_cast(i)); - - mCurrentBuffers[i] = buffer; - mCurrentVertexStrides[i] = vertexStride; - mCurrentVertexOffsets[i] = vertexOffset; - } - } - - if (dirtyBuffers) - { - ASSERT(minDiff <= maxDiff && maxDiff < gl::MAX_VERTEX_ATTRIBS); - mDeviceContext->IASetVertexBuffers(minDiff, maxDiff - minDiff + 1, mCurrentBuffers + minDiff, - mCurrentVertexStrides + minDiff, mCurrentVertexOffsets + minDiff); - } - - return gl::Error(GL_NO_ERROR); -} - -std::size_t InputLayoutCache::hashInputLayout(const InputLayoutKey &inputLayout) -{ - static const unsigned int seed = 0xDEADBEEF; - - std::size_t hash = 0; - MurmurHash3_x86_32(inputLayout.begin(), inputLayout.end() - inputLayout.begin(), seed, &hash); - return hash; -} - -bool InputLayoutCache::compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b) -{ - if (a.elementCount != b.elementCount) - { - return false; - } - - return std::equal(a.begin(), a.end(), b.begin()); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h deleted file mode 100644 index cc71ac3f6f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h +++ /dev/null @@ -1,101 +0,0 @@ -// -// 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. -// - -// InputLayoutCache.h: Defines InputLayoutCache, a class that builds and caches -// D3D11 input layouts. - -#ifndef LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_ -#define LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_ - -#include "libGLESv2/Constants.h" -#include "libGLESv2/Error.h" -#include "common/angleutils.h" - -#include - -#include -#include - -namespace gl -{ -class ProgramBinary; -} - -namespace rx -{ -struct TranslatedAttribute; - -class InputLayoutCache -{ - public: - InputLayoutCache(); - virtual ~InputLayoutCache(); - - void initialize(ID3D11Device *device, ID3D11DeviceContext *context); - void clear(); - void markDirty(); - - gl::Error applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS], - gl::ProgramBinary *programBinary); - - private: - DISALLOW_COPY_AND_ASSIGN(InputLayoutCache); - - struct InputLayoutElement - { - D3D11_INPUT_ELEMENT_DESC desc; - GLenum glslElementType; - }; - - struct InputLayoutKey - { - unsigned int elementCount; - InputLayoutElement elements[gl::MAX_VERTEX_ATTRIBS]; - - const char *begin() const - { - return reinterpret_cast(&elementCount); - } - - const char *end() const - { - return reinterpret_cast(&elements[elementCount]); - } - }; - - struct InputLayoutCounterPair - { - ID3D11InputLayout *inputLayout; - unsigned long long lastUsedTime; - }; - - ID3D11InputLayout *mCurrentIL; - ID3D11Buffer *mCurrentBuffers[gl::MAX_VERTEX_ATTRIBS]; - UINT mCurrentVertexStrides[gl::MAX_VERTEX_ATTRIBS]; - UINT mCurrentVertexOffsets[gl::MAX_VERTEX_ATTRIBS]; - - static std::size_t hashInputLayout(const InputLayoutKey &inputLayout); - static bool compareInputLayouts(const InputLayoutKey &a, const InputLayoutKey &b); - - typedef std::size_t (*InputLayoutHashFunction)(const InputLayoutKey &); - typedef bool (*InputLayoutEqualityFunction)(const InputLayoutKey &, const InputLayoutKey &); - typedef std::unordered_map InputLayoutMap; - InputLayoutMap mInputLayoutMap; - - static const unsigned int kMaxInputLayouts; - - unsigned long long mCounter; - - ID3D11Device *mDevice; - ID3D11DeviceContext *mDeviceContext; -}; - -} - -#endif // LIBGLESV2_RENDERER_INPUTLAYOUTCACHE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp deleted file mode 100644 index 6a3d3475ee..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp +++ /dev/null @@ -1,304 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// PixelTransfer11.cpp: -// Implementation for buffer-to-texture and texture-to-buffer copies. -// Used to implement pixel transfers from unpack and to pack buffers. -// - -#include "libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" -#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/Context.h" - -// Precompiled shaders -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexturevs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexturegs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4fps.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4ips.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4uips.h" - -namespace rx -{ - -PixelTransfer11::PixelTransfer11(Renderer11 *renderer) - : mRenderer(renderer), - mResourcesLoaded(false), - mBufferToTextureVS(NULL), - mBufferToTextureGS(NULL), - mParamsConstantBuffer(NULL), - mCopyRasterizerState(NULL), - mCopyDepthStencilState(NULL) -{ -} - -PixelTransfer11::~PixelTransfer11() -{ - for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) - { - SafeRelease(shaderMapIt->second); - } - - mBufferToTexturePSMap.clear(); - - SafeRelease(mBufferToTextureVS); - SafeRelease(mBufferToTextureGS); - SafeRelease(mParamsConstantBuffer); - SafeRelease(mCopyRasterizerState); - SafeRelease(mCopyDepthStencilState); -} - -gl::Error PixelTransfer11::loadResources() -{ - if (mResourcesLoaded) - { - return gl::Error(GL_NO_ERROR); - } - - HRESULT result = S_OK; - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RASTERIZER_DESC rasterDesc; - rasterDesc.FillMode = D3D11_FILL_SOLID; - rasterDesc.CullMode = D3D11_CULL_NONE; - rasterDesc.FrontCounterClockwise = FALSE; - rasterDesc.DepthBias = 0; - rasterDesc.SlopeScaledDepthBias = 0.0f; - rasterDesc.DepthBiasClamp = 0.0f; - rasterDesc.DepthClipEnable = TRUE; - rasterDesc.ScissorEnable = FALSE; - rasterDesc.MultisampleEnable = FALSE; - rasterDesc.AntialiasedLineEnable = FALSE; - - result = device->CreateRasterizerState(&rasterDesc, &mCopyRasterizerState); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer rasterizer state, result: 0x%X.", result); - } - - D3D11_DEPTH_STENCIL_DESC depthStencilDesc; - depthStencilDesc.DepthEnable = true; - depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - depthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - depthStencilDesc.StencilEnable = FALSE; - depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - - result = device->CreateDepthStencilState(&depthStencilDesc, &mCopyDepthStencilState); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer depth stencil state, result: 0x%X.", result); - } - - D3D11_BUFFER_DESC constantBufferDesc = { 0 }; - constantBufferDesc.ByteWidth = roundUp(sizeof(CopyShaderParams), 32u); - constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; - constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - constantBufferDesc.MiscFlags = 0; - constantBufferDesc.StructureByteStride = 0; - - result = device->CreateBuffer(&constantBufferDesc, NULL, &mParamsConstantBuffer); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer constant buffer, result: 0x%X.", result); - } - d3d11::SetDebugName(mParamsConstantBuffer, "PixelTransfer11 constant buffer"); - - // init shaders - mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); - if (!mBufferToTextureVS) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture vertex shader."); - } - - if (!mRenderer->isLevel9()) - { - mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); - if (!mBufferToTextureGS) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); - } - } - - gl::Error error = buildShaderMap(); - if (error.isError()) - { - return error; - } - - StructZero(&mParamsData); - - mResourcesLoaded = true; - - return gl::Error(GL_NO_ERROR); -} - -void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, - const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut) -{ - StructZero(parametersOut); - - float texelCenterX = 0.5f / static_cast(destSize.width - 1); - float texelCenterY = 0.5f / static_cast(destSize.height - 1); - - unsigned int bytesPerPixel = gl::GetInternalFormatInfo(internalFormat).pixelBytes; - unsigned int alignmentBytes = static_cast(unpack.alignment); - unsigned int alignmentPixels = (alignmentBytes <= bytesPerPixel ? 1 : alignmentBytes / bytesPerPixel); - - parametersOut->FirstPixelOffset = offset; - parametersOut->PixelsPerRow = static_cast(destArea.width); - parametersOut->RowStride = roundUp(parametersOut->PixelsPerRow, alignmentPixels); - parametersOut->RowsPerSlice = static_cast(destArea.height); - parametersOut->PositionOffset[0] = texelCenterX + (destArea.x / float(destSize.width)) * 2.0f - 1.0f; - parametersOut->PositionOffset[1] = texelCenterY + ((destSize.height - destArea.y - 1) / float(destSize.height)) * 2.0f - 1.0f; - parametersOut->PositionScale[0] = 2.0f / static_cast(destSize.width); - parametersOut->PositionScale[1] = -2.0f / static_cast(destSize.height); -} - -gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) -{ - gl::Error error = loadResources(); - if (error.isError()) - { - return error; - } - - gl::Extents destSize = destRenderTarget->getExtents(); - - ASSERT(destArea.x >= 0 && destArea.x + destArea.width <= destSize.width && - destArea.y >= 0 && destArea.y + destArea.height <= destSize.height && - destArea.z >= 0 && destArea.z + destArea.depth <= destSize.depth ); - - const gl::Buffer &sourceBuffer = *unpack.pixelBuffer.get(); - - ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); - - ID3D11PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); - ASSERT(pixelShader); - - // The SRV must be in the proper read format, which may be different from the destination format - // EG: for half float data, we can load full precision floats with implicit conversion - GLenum unsizedFormat = gl::GetInternalFormatInfo(destinationFormat).format; - GLenum sourceFormat = gl::GetFormatTypeInfo(unsizedFormat, sourcePixelsType).internalFormat; - - const d3d11::TextureFormat &sourceFormatInfo = d3d11::GetTextureFormatInfo(sourceFormat); - DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat; - ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); - Buffer11 *bufferStorage11 = Buffer11::makeBuffer11(sourceBuffer.getImplementation()); - ID3D11ShaderResourceView *bufferSRV = bufferStorage11->getSRV(srvFormat); - ASSERT(bufferSRV != NULL); - - ID3D11RenderTargetView *textureRTV = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); - ASSERT(textureRTV != NULL); - - CopyShaderParams shaderParams; - setBufferToTextureCopyParams(destArea, destSize, sourceFormat, unpack, offset, &shaderParams); - - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - ID3D11Buffer *nullBuffer = NULL; - UINT zero = 0; - - // Are we doing a 2D or 3D copy? - ID3D11GeometryShader *geometryShader = ((destSize.depth > 1) ? mBufferToTextureGS : NULL); - - deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); - deviceContext->GSSetShader(geometryShader, NULL, 0); - deviceContext->PSSetShader(pixelShader, NULL, 0); - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV); - deviceContext->IASetInputLayout(NULL); - deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - - deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); - deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); - deviceContext->OMSetDepthStencilState(mCopyDepthStencilState, 0xFFFFFFFF); - deviceContext->RSSetState(mCopyRasterizerState); - - mRenderer->setOneTimeRenderTarget(textureRTV); - - if (!StructEquals(mParamsData, shaderParams)) - { - d3d11::SetBufferData(deviceContext, mParamsConstantBuffer, shaderParams); - mParamsData = shaderParams; - } - - deviceContext->VSSetConstantBuffers(0, 1, &mParamsConstantBuffer); - - // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = destSize.width; - viewport.Height = destSize.height; - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); - - UINT numPixels = (destArea.width * destArea.height * destArea.depth); - deviceContext->Draw(numPixels, 0); - - // Unbind textures and render targets and vertex buffer - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); - - mRenderer->markAllStateDirty(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error PixelTransfer11::buildShaderMap() -{ - ID3D11Device *device = mRenderer->getDevice(); - - mBufferToTexturePSMap[GL_FLOAT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4F, "BufferToTexture RGBA ps"); - mBufferToTexturePSMap[GL_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4I, "BufferToTexture RGBA-I ps"); - mBufferToTexturePSMap[GL_UNSIGNED_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4UI, "BufferToTexture RGBA-UI ps"); - - // Check that all the shaders were created successfully - for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) - { - if (shaderMapIt->second == NULL) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture pixel shader."); - } - } - - return gl::Error(GL_NO_ERROR); -} - -ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const -{ - GLenum componentType = gl::GetInternalFormatInfo(internalFormat).componentType; - if (componentType == GL_SIGNED_NORMALIZED || componentType == GL_UNSIGNED_NORMALIZED) - { - componentType = GL_FLOAT; - } - - auto shaderMapIt = mBufferToTexturePSMap.find(componentType); - return (shaderMapIt == mBufferToTexturePSMap.end() ? NULL : shaderMapIt->second); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h deleted file mode 100644 index 29552140bb..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// PixelTransfer11.h: -// Buffer-to-Texture and Texture-to-Buffer data transfers. -// Used to implement pixel unpack and pixel pack buffers in ES3. - -#ifndef LIBGLESV2_PIXELTRANSFER11_H_ -#define LIBGLESV2_PIXELTRANSFER11_H_ - -#include "libGLESv2/Error.h" - -#include "common/platform.h" - -#include - -#include - -namespace gl -{ - -class Buffer; -struct Box; -struct Extents; -struct PixelUnpackState; - -} - -namespace rx -{ -class Renderer11; -class RenderTarget; - -class PixelTransfer11 -{ - public: - explicit PixelTransfer11(Renderer11 *renderer); - ~PixelTransfer11(); - - // unpack: the source buffer is stored in the unpack state, and buffer strides - // offset: the start of the data within the unpack buffer - // destRenderTarget: individual slice/layer of a target texture - // destinationFormat/sourcePixelsType: determines shaders + shader parameters - // destArea: the sub-section of destRenderTarget to copy to - gl::Error copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); - - private: - - struct CopyShaderParams - { - unsigned int FirstPixelOffset; - unsigned int PixelsPerRow; - unsigned int RowStride; - unsigned int RowsPerSlice; - float PositionOffset[2]; - float PositionScale[2]; - int TexLocationOffset[2]; - int TexLocationScale[2]; - }; - - static void setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, - const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut); - - gl::Error loadResources(); - gl::Error buildShaderMap(); - ID3D11PixelShader *findBufferToTexturePS(GLenum internalFormat) const; - - Renderer11 *mRenderer; - - bool mResourcesLoaded; - std::map mBufferToTexturePSMap; - ID3D11VertexShader *mBufferToTextureVS; - ID3D11GeometryShader *mBufferToTextureGS; - ID3D11Buffer *mParamsConstantBuffer; - CopyShaderParams mParamsData; - - ID3D11RasterizerState *mCopyRasterizerState; - ID3D11DepthStencilState *mCopyDepthStencilState; - -}; - -} - -#endif // LIBGLESV2_PIXELTRANSFER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp deleted file mode 100644 index 17ab1f8ab3..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl. - -#include "libGLESv2/renderer/d3d/d3d11/Query11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/main.h" -#include "common/utilities.h" - -#include - -namespace rx -{ - -Query11::Query11(Renderer11 *renderer, GLenum type) - : QueryImpl(type), - mResult(0), - mQueryFinished(false), - mRenderer(renderer), - mQuery(NULL) -{ -} - -Query11::~Query11() -{ - SafeRelease(mQuery); -} - -gl::Error Query11::begin() -{ - if (mQuery == NULL) - { - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = gl_d3d11::ConvertQueryType(getType()); - queryDesc.MiscFlags = 0; - - HRESULT result = mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); - } - } - - mRenderer->getDeviceContext()->Begin(mQuery); - return gl::Error(GL_NO_ERROR); -} - -gl::Error Query11::end() -{ - ASSERT(mQuery); - mRenderer->getDeviceContext()->End(mQuery); - - mQueryFinished = false; - mResult = GL_FALSE; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Query11::getResult(GLuint *params) -{ - while (!mQueryFinished) - { - gl::Error error = testQuery(); - if (error.isError()) - { - return error; - } - - if (!mQueryFinished) - { - Sleep(0); - } - } - - ASSERT(mQueryFinished); - *params = mResult; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Query11::isResultAvailable(GLuint *available) -{ - gl::Error error = testQuery(); - if (error.isError()) - { - return error; - } - - *available = (mQueryFinished ? GL_TRUE : GL_FALSE); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Query11::testQuery() -{ - if (!mQueryFinished) - { - ASSERT(mQuery); - - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - switch (getType()) - { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - { - UINT64 numPixels = 0; - HRESULT result = context->GetData(mQuery, &numPixels, sizeof(numPixels), 0); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the data of an internal query, result: 0x%X.", result); - } - - if (result == S_OK) - { - mQueryFinished = true; - mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; - } - } - break; - - case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: - { - D3D11_QUERY_DATA_SO_STATISTICS soStats = { 0 }; - HRESULT result = context->GetData(mQuery, &soStats, sizeof(soStats), 0); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the data of an internal query, result: 0x%X.", result); - } - - if (result == S_OK) - { - mQueryFinished = true; - mResult = static_cast(soStats.NumPrimitivesWritten); - } - } - break; - - default: - UNREACHABLE(); - break; - } - - if (!mQueryFinished && mRenderer->testDeviceLost(true)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); - } - } - - return gl::Error(GL_NO_ERROR); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h deleted file mode 100644 index f9ff467873..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Query11.h: Defines the rx::Query11 class which implements rx::QueryImpl. - -#ifndef LIBGLESV2_RENDERER_QUERY11_H_ -#define LIBGLESV2_RENDERER_QUERY11_H_ - -#include "libGLESv2/renderer/QueryImpl.h" - -namespace rx -{ -class Renderer11; - -class Query11 : public QueryImpl -{ - public: - Query11(Renderer11 *renderer, GLenum type); - virtual ~Query11(); - - virtual gl::Error begin(); - virtual gl::Error end(); - virtual gl::Error getResult(GLuint *params); - virtual gl::Error isResultAvailable(GLuint *available); - - private: - DISALLOW_COPY_AND_ASSIGN(Query11); - - gl::Error testQuery(); - - GLuint mResult; - - bool mQueryFinished; - - Renderer11 *mRenderer; - ID3D11Query *mQuery; -}; - -} - -#endif // LIBGLESV2_RENDERER_QUERY11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp deleted file mode 100644 index ab4f60bd98..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp +++ /dev/null @@ -1,439 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// RenderStateCache.cpp: Defines rx::RenderStateCache, a cache of Direct3D render -// state objects. - -#include "libGLESv2/renderer/d3d/d3d11/RenderStateCache.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" - -#include "common/debug.h" - -#include "third_party/murmurhash/MurmurHash3.h" - -namespace rx -{ - -template -static void ClearStateMap(mapType &map) -{ - for (typename mapType::iterator i = map.begin(); i != map.end(); i++) - { - SafeRelease(i->second.first); - } - map.clear(); -} - -// MSDN's documentation of ID3D11Device::CreateBlendState, ID3D11Device::CreateRasterizerState, -// ID3D11Device::CreateDepthStencilState and ID3D11Device::CreateSamplerState claims the maximum -// number of unique states of each type an application can create is 4096 -const unsigned int RenderStateCache::kMaxBlendStates = 4096; -const unsigned int RenderStateCache::kMaxRasterizerStates = 4096; -const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096; -const unsigned int RenderStateCache::kMaxSamplerStates = 4096; - -RenderStateCache::RenderStateCache(Renderer11 *renderer) - : mRenderer(renderer), - mDevice(NULL), - mCounter(0), - mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), - mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), - mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), - mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates) -{ -} - -RenderStateCache::~RenderStateCache() -{ - clear(); -} - -void RenderStateCache::initialize(ID3D11Device *device) -{ - clear(); - mDevice = device; -} - -void RenderStateCache::clear() -{ - ClearStateMap(mBlendStateCache); - ClearStateMap(mRasterizerStateCache); - ClearStateMap(mDepthStencilStateCache); - ClearStateMap(mSamplerStateCache); -} - -std::size_t RenderStateCache::hashBlendState(const BlendStateKey &blendState) -{ - static const unsigned int seed = 0xABCDEF98; - - std::size_t hash = 0; - MurmurHash3_x86_32(&blendState, sizeof(gl::BlendState), seed, &hash); - return hash; -} - -bool RenderStateCache::compareBlendStates(const BlendStateKey &a, const BlendStateKey &b) -{ - return memcmp(&a, &b, sizeof(BlendStateKey)) == 0; -} - -gl::Error RenderStateCache::getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, - ID3D11BlendState **outBlendState) -{ - if (!mDevice) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); - } - - bool mrt = false; - - const gl::ColorbufferInfo &colorbuffers = framebuffer->getColorbuffersForRender(mRenderer->getWorkarounds()); - - BlendStateKey key = { 0 }; - key.blendState = blendState; - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) - { - const gl::FramebufferAttachment *attachment = colorbuffers[colorAttachment]; - - auto rtChannels = key.rtChannels[colorAttachment]; - - if (attachment) - { - if (colorAttachment > 0) - { - mrt = true; - } - - rtChannels[0] = attachment->getRedSize() > 0; - rtChannels[1] = attachment->getGreenSize() > 0; - rtChannels[2] = attachment->getBlueSize() > 0; - rtChannels[3] = attachment->getAlphaSize() > 0; - } - } - - BlendStateMap::iterator keyIter = mBlendStateCache.find(key); - if (keyIter != mBlendStateCache.end()) - { - BlendStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outBlendState = state.first; - return gl::Error(GL_NO_ERROR); - } - else - { - if (mBlendStateCache.size() >= kMaxBlendStates) - { - TRACE("Overflowed the limit of %u blend states, removing the least recently used " - "to make room.", kMaxBlendStates); - - BlendStateMap::iterator leastRecentlyUsed = mBlendStateCache.begin(); - for (BlendStateMap::iterator i = mBlendStateCache.begin(); i != mBlendStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mBlendStateCache.erase(leastRecentlyUsed); - } - - // Create a new blend state and insert it into the cache - D3D11_BLEND_DESC blendDesc = { 0 }; - blendDesc.AlphaToCoverageEnable = blendState.sampleAlphaToCoverage; - blendDesc.IndependentBlendEnable = mrt ? TRUE : FALSE; - - for (unsigned int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) - { - D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = blendDesc.RenderTarget[i]; - - rtBlend.BlendEnable = blendState.blend; - if (blendState.blend) - { - rtBlend.SrcBlend = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendRGB, false); - rtBlend.DestBlend = gl_d3d11::ConvertBlendFunc(blendState.destBlendRGB, false); - rtBlend.BlendOp = gl_d3d11::ConvertBlendOp(blendState.blendEquationRGB); - - rtBlend.SrcBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.sourceBlendAlpha, true); - rtBlend.DestBlendAlpha = gl_d3d11::ConvertBlendFunc(blendState.destBlendAlpha, true); - rtBlend.BlendOpAlpha = gl_d3d11::ConvertBlendOp(blendState.blendEquationAlpha); - } - - rtBlend.RenderTargetWriteMask = gl_d3d11::ConvertColorMask(key.rtChannels[i][0] && blendState.colorMaskRed, - key.rtChannels[i][1] && blendState.colorMaskGreen, - key.rtChannels[i][2] && blendState.colorMaskBlue, - key.rtChannels[i][3] && blendState.colorMaskAlpha); - } - - ID3D11BlendState *dx11BlendState = NULL; - HRESULT result = mDevice->CreateBlendState(&blendDesc, &dx11BlendState); - if (FAILED(result) || !dx11BlendState) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11BlendState, HRESULT: 0x%X.", result); - } - - mBlendStateCache.insert(std::make_pair(key, std::make_pair(dx11BlendState, mCounter++))); - - *outBlendState = dx11BlendState; - return gl::Error(GL_NO_ERROR); - } -} - -std::size_t RenderStateCache::hashRasterizerState(const RasterizerStateKey &rasterState) -{ - static const unsigned int seed = 0xABCDEF98; - - std::size_t hash = 0; - MurmurHash3_x86_32(&rasterState, sizeof(RasterizerStateKey), seed, &hash); - return hash; -} - -bool RenderStateCache::compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b) -{ - return memcmp(&a, &b, sizeof(RasterizerStateKey)) == 0; -} - -gl::Error RenderStateCache::getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, - ID3D11RasterizerState **outRasterizerState) -{ - if (!mDevice) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); - } - - RasterizerStateKey key = { 0 }; - key.rasterizerState = rasterState; - key.scissorEnabled = scissorEnabled; - - RasterizerStateMap::iterator keyIter = mRasterizerStateCache.find(key); - if (keyIter != mRasterizerStateCache.end()) - { - RasterizerStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outRasterizerState = state.first; - return gl::Error(GL_NO_ERROR); - } - else - { - if (mRasterizerStateCache.size() >= kMaxRasterizerStates) - { - TRACE("Overflowed the limit of %u rasterizer states, removing the least recently used " - "to make room.", kMaxRasterizerStates); - - RasterizerStateMap::iterator leastRecentlyUsed = mRasterizerStateCache.begin(); - for (RasterizerStateMap::iterator i = mRasterizerStateCache.begin(); i != mRasterizerStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mRasterizerStateCache.erase(leastRecentlyUsed); - } - - D3D11_CULL_MODE cullMode = gl_d3d11::ConvertCullMode(rasterState.cullFace, rasterState.cullMode); - - // Disable culling if drawing points - if (rasterState.pointDrawMode) - { - cullMode = D3D11_CULL_NONE; - } - - D3D11_RASTERIZER_DESC rasterDesc; - rasterDesc.FillMode = D3D11_FILL_SOLID; - rasterDesc.CullMode = cullMode; - rasterDesc.FrontCounterClockwise = (rasterState.frontFace == GL_CCW) ? FALSE: TRUE; - rasterDesc.DepthBiasClamp = 0.0f; // MSDN documentation of DepthBiasClamp implies a value of zero will preform no clamping, must be tested though. - rasterDesc.DepthClipEnable = TRUE; - rasterDesc.ScissorEnable = scissorEnabled ? TRUE : FALSE; - rasterDesc.MultisampleEnable = rasterState.multiSample; - rasterDesc.AntialiasedLineEnable = FALSE; - - if (rasterState.polygonOffsetFill) - { - rasterDesc.SlopeScaledDepthBias = rasterState.polygonOffsetFactor; - rasterDesc.DepthBias = (INT)rasterState.polygonOffsetUnits; - } - else - { - rasterDesc.SlopeScaledDepthBias = 0.0f; - rasterDesc.DepthBias = 0; - } - - ID3D11RasterizerState *dx11RasterizerState = NULL; - HRESULT result = mDevice->CreateRasterizerState(&rasterDesc, &dx11RasterizerState); - if (FAILED(result) || !dx11RasterizerState) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11RasterizerState, HRESULT: 0x%X.", result); - } - - mRasterizerStateCache.insert(std::make_pair(key, std::make_pair(dx11RasterizerState, mCounter++))); - - *outRasterizerState = dx11RasterizerState; - return gl::Error(GL_NO_ERROR); - } -} - -std::size_t RenderStateCache::hashDepthStencilState(const gl::DepthStencilState &dsState) -{ - static const unsigned int seed = 0xABCDEF98; - - std::size_t hash = 0; - MurmurHash3_x86_32(&dsState, sizeof(gl::DepthStencilState), seed, &hash); - return hash; -} - -bool RenderStateCache::compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b) -{ - return memcmp(&a, &b, sizeof(gl::DepthStencilState)) == 0; -} - -gl::Error RenderStateCache::getDepthStencilState(const gl::DepthStencilState &dsState, ID3D11DepthStencilState **outDSState) -{ - if (!mDevice) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); - } - - DepthStencilStateMap::iterator keyIter = mDepthStencilStateCache.find(dsState); - if (keyIter != mDepthStencilStateCache.end()) - { - DepthStencilStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outDSState = state.first; - return gl::Error(GL_NO_ERROR); - } - else - { - if (mDepthStencilStateCache.size() >= kMaxDepthStencilStates) - { - TRACE("Overflowed the limit of %u depth stencil states, removing the least recently used " - "to make room.", kMaxDepthStencilStates); - - DepthStencilStateMap::iterator leastRecentlyUsed = mDepthStencilStateCache.begin(); - for (DepthStencilStateMap::iterator i = mDepthStencilStateCache.begin(); i != mDepthStencilStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mDepthStencilStateCache.erase(leastRecentlyUsed); - } - - D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; - dsDesc.DepthEnable = dsState.depthTest ? TRUE : FALSE; - dsDesc.DepthWriteMask = gl_d3d11::ConvertDepthMask(dsState.depthMask); - dsDesc.DepthFunc = gl_d3d11::ConvertComparison(dsState.depthFunc); - dsDesc.StencilEnable = dsState.stencilTest ? TRUE : FALSE; - dsDesc.StencilReadMask = gl_d3d11::ConvertStencilMask(dsState.stencilMask); - dsDesc.StencilWriteMask = gl_d3d11::ConvertStencilMask(dsState.stencilWritemask); - dsDesc.FrontFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilFail); - dsDesc.FrontFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthFail); - dsDesc.FrontFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilPassDepthPass); - dsDesc.FrontFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilFunc); - dsDesc.BackFace.StencilFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackFail); - dsDesc.BackFace.StencilDepthFailOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthFail); - dsDesc.BackFace.StencilPassOp = gl_d3d11::ConvertStencilOp(dsState.stencilBackPassDepthPass); - dsDesc.BackFace.StencilFunc = gl_d3d11::ConvertComparison(dsState.stencilBackFunc); - - ID3D11DepthStencilState *dx11DepthStencilState = NULL; - HRESULT result = mDevice->CreateDepthStencilState(&dsDesc, &dx11DepthStencilState); - if (FAILED(result) || !dx11DepthStencilState) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11DepthStencilState, HRESULT: 0x%X.", result); - } - - mDepthStencilStateCache.insert(std::make_pair(dsState, std::make_pair(dx11DepthStencilState, mCounter++))); - - *outDSState = dx11DepthStencilState; - return gl::Error(GL_NO_ERROR); - } -} - -std::size_t RenderStateCache::hashSamplerState(const gl::SamplerState &samplerState) -{ - static const unsigned int seed = 0xABCDEF98; - - std::size_t hash = 0; - MurmurHash3_x86_32(&samplerState, sizeof(gl::SamplerState), seed, &hash); - return hash; -} - -bool RenderStateCache::compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b) -{ - return memcmp(&a, &b, sizeof(gl::SamplerState)) == 0; -} - -gl::Error RenderStateCache::getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState) -{ - if (!mDevice) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal error, RenderStateCache is not initialized."); - } - - SamplerStateMap::iterator keyIter = mSamplerStateCache.find(samplerState); - if (keyIter != mSamplerStateCache.end()) - { - SamplerStateCounterPair &state = keyIter->second; - state.second = mCounter++; - *outSamplerState = state.first; - return gl::Error(GL_NO_ERROR); - } - else - { - if (mSamplerStateCache.size() >= kMaxSamplerStates) - { - TRACE("Overflowed the limit of %u sampler states, removing the least recently used " - "to make room.", kMaxSamplerStates); - - SamplerStateMap::iterator leastRecentlyUsed = mSamplerStateCache.begin(); - for (SamplerStateMap::iterator i = mSamplerStateCache.begin(); i != mSamplerStateCache.end(); i++) - { - if (i->second.second < leastRecentlyUsed->second.second) - { - leastRecentlyUsed = i; - } - } - SafeRelease(leastRecentlyUsed->second.first); - mSamplerStateCache.erase(leastRecentlyUsed); - } - - D3D11_SAMPLER_DESC samplerDesc; - samplerDesc.Filter = gl_d3d11::ConvertFilter(samplerState.minFilter, samplerState.magFilter, - samplerState.maxAnisotropy, samplerState.compareMode); - samplerDesc.AddressU = gl_d3d11::ConvertTextureWrap(samplerState.wrapS); - samplerDesc.AddressV = gl_d3d11::ConvertTextureWrap(samplerState.wrapT); - samplerDesc.AddressW = gl_d3d11::ConvertTextureWrap(samplerState.wrapR); - samplerDesc.MipLODBias = 0; - samplerDesc.MaxAnisotropy = samplerState.maxAnisotropy; - samplerDesc.ComparisonFunc = gl_d3d11::ConvertComparison(samplerState.compareFunc); - samplerDesc.BorderColor[0] = 0.0f; - samplerDesc.BorderColor[1] = 0.0f; - samplerDesc.BorderColor[2] = 0.0f; - samplerDesc.BorderColor[3] = 0.0f; - samplerDesc.MinLOD = samplerState.minLod; - samplerDesc.MaxLOD = samplerState.maxLod; - - ID3D11SamplerState *dx11SamplerState = NULL; - HRESULT result = mDevice->CreateSamplerState(&samplerDesc, &dx11SamplerState); - if (FAILED(result) || !dx11SamplerState) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to create a ID3D11SamplerState, HRESULT: 0x%X.", result); - } - - mSamplerStateCache.insert(std::make_pair(samplerState, std::make_pair(dx11SamplerState, mCounter++))); - - *outSamplerState = dx11SamplerState; - return gl::Error(GL_NO_ERROR); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h deleted file mode 100644 index dfd1d84265..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h +++ /dev/null @@ -1,113 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// RenderStateCache.h: Defines rx::RenderStateCache, a cache of Direct3D render -// state objects. - -#ifndef LIBGLESV2_RENDERER_RENDERSTATECACHE_H_ -#define LIBGLESV2_RENDERER_RENDERSTATECACHE_H_ - -#include "libGLESv2/angletypes.h" -#include "libGLESv2/Error.h" -#include "common/angleutils.h" - -#include - -namespace gl -{ -class Framebuffer; -} - -namespace rx -{ -class Renderer11; - -class RenderStateCache -{ - public: - RenderStateCache(Renderer11 *renderer); - virtual ~RenderStateCache(); - - void initialize(ID3D11Device *device); - void clear(); - - gl::Error getBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, ID3D11BlendState **outBlendState); - gl::Error getRasterizerState(const gl::RasterizerState &rasterState, bool scissorEnabled, ID3D11RasterizerState **outRasterizerState); - gl::Error getDepthStencilState(const gl::DepthStencilState &dsState, ID3D11DepthStencilState **outDSState); - gl::Error getSamplerState(const gl::SamplerState &samplerState, ID3D11SamplerState **outSamplerState); - - private: - DISALLOW_COPY_AND_ASSIGN(RenderStateCache); - - Renderer11 *mRenderer; - unsigned long long mCounter; - - // Blend state cache - struct BlendStateKey - { - gl::BlendState blendState; - bool rtChannels[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT][4]; - }; - static std::size_t hashBlendState(const BlendStateKey &blendState); - static bool compareBlendStates(const BlendStateKey &a, const BlendStateKey &b); - static const unsigned int kMaxBlendStates; - - typedef std::size_t (*BlendStateHashFunction)(const BlendStateKey &); - typedef bool (*BlendStateEqualityFunction)(const BlendStateKey &, const BlendStateKey &); - typedef std::pair BlendStateCounterPair; - typedef std::unordered_map BlendStateMap; - BlendStateMap mBlendStateCache; - - // Rasterizer state cache - struct RasterizerStateKey - { - gl::RasterizerState rasterizerState; - bool scissorEnabled; - }; - static std::size_t hashRasterizerState(const RasterizerStateKey &rasterState); - static bool compareRasterizerStates(const RasterizerStateKey &a, const RasterizerStateKey &b); - static const unsigned int kMaxRasterizerStates; - - typedef std::size_t (*RasterizerStateHashFunction)(const RasterizerStateKey &); - typedef bool (*RasterizerStateEqualityFunction)(const RasterizerStateKey &, const RasterizerStateKey &); - typedef std::pair RasterizerStateCounterPair; - typedef std::unordered_map RasterizerStateMap; - RasterizerStateMap mRasterizerStateCache; - - // Depth stencil state cache - static std::size_t hashDepthStencilState(const gl::DepthStencilState &dsState); - static bool compareDepthStencilStates(const gl::DepthStencilState &a, const gl::DepthStencilState &b); - static const unsigned int kMaxDepthStencilStates; - - typedef std::size_t (*DepthStencilStateHashFunction)(const gl::DepthStencilState &); - typedef bool (*DepthStencilStateEqualityFunction)(const gl::DepthStencilState &, const gl::DepthStencilState &); - typedef std::pair DepthStencilStateCounterPair; - typedef std::unordered_map DepthStencilStateMap; - DepthStencilStateMap mDepthStencilStateCache; - - // Sample state cache - static std::size_t hashSamplerState(const gl::SamplerState &samplerState); - static bool compareSamplerStates(const gl::SamplerState &a, const gl::SamplerState &b); - static const unsigned int kMaxSamplerStates; - - typedef std::size_t (*SamplerStateHashFunction)(const gl::SamplerState &); - typedef bool (*SamplerStateEqualityFunction)(const gl::SamplerState &, const gl::SamplerState &); - typedef std::pair SamplerStateCounterPair; - typedef std::unordered_map SamplerStateMap; - SamplerStateMap mSamplerStateCache; - - ID3D11Device *mDevice; -}; - -} - -#endif // LIBGLESV2_RENDERER_RENDERSTATECACHE_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp deleted file mode 100644 index aff3453492..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp +++ /dev/null @@ -1,404 +0,0 @@ -// -// 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. -// - -// RenderTarget11.cpp: Implements a DX11-specific wrapper for ID3D11View pointers -// retained by Renderbuffers. - -#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -static bool getTextureProperties(ID3D11Resource *resource, unsigned int *mipLevels, unsigned int *samples) -{ - ID3D11Texture1D *texture1D = d3d11::DynamicCastComObject(resource); - if (texture1D) - { - D3D11_TEXTURE1D_DESC texDesc; - texture1D->GetDesc(&texDesc); - SafeRelease(texture1D); - - *mipLevels = texDesc.MipLevels; - *samples = 0; - - return true; - } - - ID3D11Texture2D *texture2D = d3d11::DynamicCastComObject(resource); - if (texture2D) - { - D3D11_TEXTURE2D_DESC texDesc; - texture2D->GetDesc(&texDesc); - SafeRelease(texture2D); - - *mipLevels = texDesc.MipLevels; - *samples = texDesc.SampleDesc.Count > 1 ? texDesc.SampleDesc.Count : 0; - - return true; - } - - ID3D11Texture3D *texture3D = d3d11::DynamicCastComObject(resource); - if (texture3D) - { - D3D11_TEXTURE3D_DESC texDesc; - texture3D->GetDesc(&texDesc); - SafeRelease(texture3D); - - *mipLevels = texDesc.MipLevels; - *samples = 0; - - return true; - } - - return false; -} - -static unsigned int getRTVSubresourceIndex(ID3D11Resource *resource, ID3D11RenderTargetView *view) -{ - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - view->GetDesc(&rtvDesc); - - unsigned int mipSlice = 0; - unsigned int arraySlice = 0; - - switch (rtvDesc.ViewDimension) - { - case D3D11_RTV_DIMENSION_TEXTURE1D: - mipSlice = rtvDesc.Texture1D.MipSlice; - arraySlice = 0; - break; - - case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: - mipSlice = rtvDesc.Texture1DArray.MipSlice; - arraySlice = rtvDesc.Texture1DArray.FirstArraySlice; - break; - - case D3D11_RTV_DIMENSION_TEXTURE2D: - mipSlice = rtvDesc.Texture2D.MipSlice; - arraySlice = 0; - break; - - case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: - mipSlice = rtvDesc.Texture2DArray.MipSlice; - arraySlice = rtvDesc.Texture2DArray.FirstArraySlice; - break; - - case D3D11_RTV_DIMENSION_TEXTURE2DMS: - mipSlice = 0; - arraySlice = 0; - break; - - case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY: - mipSlice = 0; - arraySlice = rtvDesc.Texture2DMSArray.FirstArraySlice; - break; - - case D3D11_RTV_DIMENSION_TEXTURE3D: - mipSlice = rtvDesc.Texture3D.MipSlice; - arraySlice = 0; - break; - - case D3D11_RTV_DIMENSION_UNKNOWN: - case D3D11_RTV_DIMENSION_BUFFER: - UNIMPLEMENTED(); - break; - - default: - UNREACHABLE(); - break; - } - - unsigned int mipLevels, samples; - getTextureProperties(resource, &mipLevels, &samples); - - return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); -} - -static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11DepthStencilView *view) -{ - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - view->GetDesc(&dsvDesc); - - unsigned int mipSlice = 0; - unsigned int arraySlice = 0; - - switch (dsvDesc.ViewDimension) - { - case D3D11_DSV_DIMENSION_TEXTURE1D: - mipSlice = dsvDesc.Texture1D.MipSlice; - arraySlice = 0; - break; - - case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: - mipSlice = dsvDesc.Texture1DArray.MipSlice; - arraySlice = dsvDesc.Texture1DArray.FirstArraySlice; - break; - - case D3D11_DSV_DIMENSION_TEXTURE2D: - mipSlice = dsvDesc.Texture2D.MipSlice; - arraySlice = 0; - break; - - case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: - mipSlice = dsvDesc.Texture2DArray.MipSlice; - arraySlice = dsvDesc.Texture2DArray.FirstArraySlice; - break; - - case D3D11_DSV_DIMENSION_TEXTURE2DMS: - mipSlice = 0; - arraySlice = 0; - break; - - case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: - mipSlice = 0; - arraySlice = dsvDesc.Texture2DMSArray.FirstArraySlice; - break; - - case D3D11_DSV_DIMENSION_UNKNOWN: - UNIMPLEMENTED(); - break; - - default: - UNREACHABLE(); - break; - } - - unsigned int mipLevels, samples; - getTextureProperties(resource, &mipLevels, &samples); - - return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); -} - -RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTarget *target) -{ - ASSERT(HAS_DYNAMIC_TYPE(RenderTarget11*, target)); - return static_cast(target); -} - -void RenderTarget11::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) -{ - // Currently a no-op -} - -TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) - : mWidth(width), - mHeight(height), - mDepth(depth), - mInternalFormat(internalFormat), - mActualFormat(internalFormat), - mSamples(samples), - mSubresourceIndex(0), - mTexture(resource), - mRenderTarget(rtv), - mDepthStencil(NULL), - mShaderResource(srv) -{ - if (mTexture) - { - mTexture->AddRef(); - } - - if (mRenderTarget) - { - mRenderTarget->AddRef(); - } - - if (mShaderResource) - { - mShaderResource->AddRef(); - } - - if (mRenderTarget && mTexture) - { - mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); - - D3D11_RENDER_TARGET_VIEW_DESC desc; - mRenderTarget->GetDesc(&desc); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format); - mActualFormat = dxgiFormatInfo.internalFormat; - } -} - -TextureRenderTarget11::TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) - : mWidth(width), - mHeight(height), - mDepth(depth), - mInternalFormat(internalFormat), - mActualFormat(internalFormat), - mSamples(samples), - mSubresourceIndex(0), - mTexture(resource), - mRenderTarget(NULL), - mDepthStencil(dsv), - mShaderResource(srv) -{ - if (mTexture) - { - mTexture->AddRef(); - } - - if (mDepthStencil) - { - mDepthStencil->AddRef(); - } - - if (mShaderResource) - { - mShaderResource->AddRef(); - } - - if (mDepthStencil && mTexture) - { - mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil); - - D3D11_DEPTH_STENCIL_VIEW_DESC desc; - mDepthStencil->GetDesc(&desc); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format); - mActualFormat = dxgiFormatInfo.internalFormat; - } -} - -TextureRenderTarget11::~TextureRenderTarget11() -{ - SafeRelease(mTexture); - SafeRelease(mRenderTarget); - SafeRelease(mDepthStencil); - SafeRelease(mShaderResource); -} - -ID3D11Resource *TextureRenderTarget11::getTexture() const -{ - return mTexture; -} - -ID3D11RenderTargetView *TextureRenderTarget11::getRenderTargetView() const -{ - return mRenderTarget; -} - -ID3D11DepthStencilView *TextureRenderTarget11::getDepthStencilView() const -{ - return mDepthStencil; -} - -ID3D11ShaderResourceView *TextureRenderTarget11::getShaderResourceView() const -{ - return mShaderResource; -} - -GLsizei TextureRenderTarget11::getWidth() const -{ - return mWidth; -} - -GLsizei TextureRenderTarget11::getHeight() const -{ - return mHeight; -} - -GLsizei TextureRenderTarget11::getDepth() const -{ - return mDepth; -} - -GLenum TextureRenderTarget11::getInternalFormat() const -{ - return mInternalFormat; -} - -GLenum TextureRenderTarget11::getActualFormat() const -{ - return mActualFormat; -} - -GLsizei TextureRenderTarget11::getSamples() const -{ - return mSamples; -} - -unsigned int TextureRenderTarget11::getSubresourceIndex() const -{ - return mSubresourceIndex; -} - - -SurfaceRenderTarget11::SurfaceRenderTarget11(SwapChain11 *swapChain, bool depth) - : mSwapChain(swapChain), - mDepth(depth) -{ - ASSERT(mSwapChain); -} - -SurfaceRenderTarget11::~SurfaceRenderTarget11() -{ -} - -GLsizei SurfaceRenderTarget11::getWidth() const -{ - return mSwapChain->getWidth(); -} - -GLsizei SurfaceRenderTarget11::getHeight() const -{ - return mSwapChain->getHeight(); -} - -GLsizei SurfaceRenderTarget11::getDepth() const -{ - return 1; -} - -GLenum SurfaceRenderTarget11::getInternalFormat() const -{ - return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat()); -} - -GLenum SurfaceRenderTarget11::getActualFormat() const -{ - return d3d11::GetDXGIFormatInfo(d3d11::GetTextureFormatInfo(getInternalFormat()).texFormat).internalFormat; -} - -GLsizei SurfaceRenderTarget11::getSamples() const -{ - // Our EGL surfaces do not support multisampling. - return 0; -} - -ID3D11Resource *SurfaceRenderTarget11::getTexture() const -{ - return (mDepth ? mSwapChain->getDepthStencilTexture() : mSwapChain->getOffscreenTexture()); -} - -ID3D11RenderTargetView *SurfaceRenderTarget11::getRenderTargetView() const -{ - return (mDepth ? NULL : mSwapChain->getRenderTarget()); -} - -ID3D11DepthStencilView *SurfaceRenderTarget11::getDepthStencilView() const -{ - return (mDepth ? mSwapChain->getDepthStencil() : NULL); -} - -ID3D11ShaderResourceView *SurfaceRenderTarget11::getShaderResourceView() const -{ - return (mDepth ? mSwapChain->getDepthStencilShaderResource() : mSwapChain->getRenderTargetShaderResource()); -} - -unsigned int SurfaceRenderTarget11::getSubresourceIndex() const -{ - return 0; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h deleted file mode 100644 index c7babdda3f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h +++ /dev/null @@ -1,110 +0,0 @@ -// -// 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. -// - -// RenderTarget11.h: Defines a DX11-specific wrapper for ID3D11View pointers -// retained by Renderbuffers. - -#ifndef LIBGLESV2_RENDERER_RENDERTARGET11_H_ -#define LIBGLESV2_RENDERER_RENDERTARGET11_H_ - -#include "libGLESv2/renderer/RenderTarget.h" - -namespace rx -{ -class SwapChain11; - -class RenderTarget11 : public RenderTarget -{ - public: - RenderTarget11() { } - virtual ~RenderTarget11() { } - - static RenderTarget11 *makeRenderTarget11(RenderTarget *renderTarget); - - void invalidate(GLint x, GLint y, GLsizei width, GLsizei height) override; - - virtual ID3D11Resource *getTexture() const = 0; - virtual ID3D11RenderTargetView *getRenderTargetView() const = 0; - virtual ID3D11DepthStencilView *getDepthStencilView() const = 0; - virtual ID3D11ShaderResourceView *getShaderResourceView() const = 0; - - virtual unsigned int getSubresourceIndex() const = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderTarget11); -}; - -class TextureRenderTarget11 : public RenderTarget11 -{ - public: - // TextureRenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them - TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); - TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); - virtual ~TextureRenderTarget11(); - - GLsizei getWidth() const override; - GLsizei getHeight() const override; - GLsizei getDepth() const override; - GLenum getInternalFormat() const override; - GLenum getActualFormat() const override; - GLsizei getSamples() const override; - - ID3D11Resource *getTexture() const override; - ID3D11RenderTargetView *getRenderTargetView() const override; - ID3D11DepthStencilView *getDepthStencilView() const override; - ID3D11ShaderResourceView *getShaderResourceView() const override; - - unsigned int getSubresourceIndex() const override; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureRenderTarget11); - - GLsizei mWidth; - GLsizei mHeight; - GLsizei mDepth; - GLenum mInternalFormat; - GLenum mActualFormat; - GLsizei mSamples; - - unsigned int mSubresourceIndex; - ID3D11Resource *mTexture; - ID3D11RenderTargetView *mRenderTarget; - ID3D11DepthStencilView *mDepthStencil; - ID3D11ShaderResourceView *mShaderResource; -}; - -class SurfaceRenderTarget11 : public RenderTarget11 -{ - public: - SurfaceRenderTarget11(SwapChain11 *swapChain, bool depth); - virtual ~SurfaceRenderTarget11(); - - GLsizei getWidth() const override; - GLsizei getHeight() const override; - GLsizei getDepth() const override; - GLenum getInternalFormat() const override; - GLenum getActualFormat() const override; - GLsizei getSamples() const override; - - ID3D11Resource *getTexture() const override; - ID3D11RenderTargetView *getRenderTargetView() const override; - ID3D11DepthStencilView *getDepthStencilView() const override; - ID3D11ShaderResourceView *getShaderResourceView() const override; - - unsigned int getSubresourceIndex() const override; - - private: - DISALLOW_COPY_AND_ASSIGN(SurfaceRenderTarget11); - - SwapChain11 *mSwapChain; - bool mDepth; -}; - -} - -#endif // LIBGLESV2_RENDERER_RENDERTARGET11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp deleted file mode 100644 index 777308e6cc..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp +++ /dev/null @@ -1,3422 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. - -#include "libGLESv2/main.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/State.h" -#include "libGLESv2/renderer/d3d/ProgramD3D.h" -#include "libGLESv2/renderer/d3d/ShaderD3D.h" -#include "libGLESv2/renderer/d3d/TextureD3D.h" -#include "libGLESv2/renderer/d3d/TransformFeedbackD3D.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" -#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" -#include "libGLESv2/renderer/d3d/d3d11/Image11.h" -#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" -#include "libGLESv2/renderer/d3d/VertexDataManager.h" -#include "libGLESv2/renderer/d3d/IndexDataManager.h" -#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" -#include "libGLESv2/renderer/d3d/d3d11/Query11.h" -#include "libGLESv2/renderer/d3d/d3d11/Fence11.h" -#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" -#include "libGLESv2/renderer/d3d/d3d11/Clear11.h" -#include "libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h" -#include "libGLESv2/renderer/d3d/d3d11/VertexArray11.h" -#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" -#include "libGLESv2/renderer/d3d/RenderbufferD3D.h" - -#include "libEGL/Display.h" - -#include "common/utilities.h" -#include "common/tls.h" - -#include - -#include - -// Enable ANGLE_SKIP_DXGI_1_2_CHECK if there is not a possibility of using cross-process -// HWNDs or the Windows 7 Platform Update (KB2670838) is expected to be installed. -#ifndef ANGLE_SKIP_DXGI_1_2_CHECK -#define ANGLE_SKIP_DXGI_1_2_CHECK 0 -#endif - -#ifdef _DEBUG -// this flag enables suppressing some spurious warnings that pop up in certain WebGL samples -// and conformance tests. to enable all warnings, remove this define. -#define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1 -#endif - -namespace rx -{ - -namespace -{ -static const DXGI_FORMAT RenderTargetFormats[] = - { - DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UNORM - }; - -static const DXGI_FORMAT DepthStencilFormats[] = - { - DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_D24_UNORM_S8_UINT, - DXGI_FORMAT_D16_UNORM - }; - -enum -{ - MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 -}; - -// Does *not* increment the resource ref count!! -ID3D11Resource *GetSRVResource(ID3D11ShaderResourceView *srv) -{ - ID3D11Resource *resource = NULL; - ASSERT(srv); - srv->GetResource(&resource); - resource->Release(); - return resource; -} - -} - -Renderer11::Renderer11(egl::Display *display, EGLNativeDisplayType hDc, const egl::AttributeMap &attributes) - : RendererD3D(display), - mDc(hDc), - mStateCache(this) -{ - mVertexDataManager = NULL; - mIndexDataManager = NULL; - - mLineLoopIB = NULL; - mTriangleFanIB = NULL; - - mBlit = NULL; - mPixelTransfer = NULL; - - mClear = NULL; - - mSyncQuery = NULL; - - mD3d11Module = NULL; - mDxgiModule = NULL; - - mDeviceLost = false; - - mDevice = NULL; - mDeviceContext = NULL; - mDxgiAdapter = NULL; - mDxgiFactory = NULL; - - mDriverConstantBufferVS = NULL; - mDriverConstantBufferPS = NULL; - - mAppliedVertexShader = NULL; - mAppliedGeometryShader = NULL; - mCurPointGeometryShader = NULL; - mAppliedPixelShader = NULL; - - EGLint requestedMajorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE); - EGLint requestedMinorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE); - - if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11) - { - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) - { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0); - } - } - - if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10) - { - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) - { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1); - } - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) - { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0); - } - } - -#if !defined(ANGLE_ENABLE_D3D9) - if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) - { - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3) - { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); - } - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 2) - { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_2); - } - if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) - { - mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_1); - } - } -#endif - - mDriverType = (attributes.get(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_FALSE) == EGL_TRUE) ? D3D_DRIVER_TYPE_WARP - : D3D_DRIVER_TYPE_HARDWARE; -} - -Renderer11::~Renderer11() -{ - release(); -} - -Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) -{ - ASSERT(HAS_DYNAMIC_TYPE(Renderer11*, renderer)); - return static_cast(renderer); -} - -#ifndef __d3d11_1_h__ -#define D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET ((D3D11_MESSAGE_ID)3146081) -#endif - -EGLint Renderer11::initialize() -{ - if (!mCompiler.initialize()) - { - return EGL_NOT_INITIALIZED; - } - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); - mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); - - if (mD3d11Module == NULL || mDxgiModule == NULL) - { - ERR("Could not load D3D11 or DXGI library - aborting!\n"); - return EGL_NOT_INITIALIZED; - } - - // create the D3D11 device - ASSERT(mDevice == NULL); - PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); - - if (D3D11CreateDevice == NULL) - { - ERR("Could not retrieve D3D11CreateDevice address - aborting!\n"); - return EGL_NOT_INITIALIZED; - } -#endif - - HRESULT result = S_OK; -#ifdef _DEBUG - result = D3D11CreateDevice(NULL, - mDriverType, - NULL, - D3D11_CREATE_DEVICE_DEBUG, - mAvailableFeatureLevels.data(), - mAvailableFeatureLevels.size(), - D3D11_SDK_VERSION, - &mDevice, - &mFeatureLevel, - &mDeviceContext); - - if (!mDevice || FAILED(result)) - { - ERR("Failed creating Debug D3D11 device - falling back to release runtime.\n"); - } - - if (!mDevice || FAILED(result)) -#endif - { - result = D3D11CreateDevice(NULL, - mDriverType, - NULL, - 0, - mAvailableFeatureLevels.data(), - mAvailableFeatureLevels.size(), - D3D11_SDK_VERSION, - &mDevice, - &mFeatureLevel, - &mDeviceContext); - - if (!mDevice || FAILED(result)) - { - ERR("Could not create D3D11 device - aborting!\n"); - return EGL_NOT_INITIALIZED; // Cleanup done by destructor through glDestroyRenderer - } - } - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); - if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) - { - ID3D10Multithread *multithread; - result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread)); - ASSERT(SUCCEEDED(result)); - result = multithread->SetMultithreadProtected(true); - ASSERT(SUCCEEDED(result)); - multithread->Release(); - } -#if !ANGLE_SKIP_DXGI_1_2_CHECK - // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. - // The easiest way to check is to query for a IDXGIDevice2. - bool requireDXGI1_2 = false; - HWND hwnd = WindowFromDC(mDc); - if (hwnd) - { - DWORD currentProcessId = GetCurrentProcessId(); - DWORD wndProcessId; - GetWindowThreadProcessId(hwnd, &wndProcessId); - requireDXGI1_2 = (currentProcessId != wndProcessId); - } - else - { - requireDXGI1_2 = true; - } - - if (requireDXGI1_2) - { - IDXGIDevice2 *dxgiDevice2 = NULL; - result = mDevice->QueryInterface(__uuidof(IDXGIDevice2), (void**)&dxgiDevice2); - if (FAILED(result)) - { - ERR("DXGI 1.2 required to present to HWNDs owned by another process.\n"); - return EGL_NOT_INITIALIZED; - } - SafeRelease(dxgiDevice2); - } -#endif -#endif - - IDXGIDevice *dxgiDevice = NULL; - result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); - - if (FAILED(result)) - { - ERR("Could not query DXGI device - aborting!\n"); - return EGL_NOT_INITIALIZED; - } - - result = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&mDxgiAdapter); - - if (FAILED(result)) - { - ERR("Could not retrieve DXGI adapter - aborting!\n"); - return EGL_NOT_INITIALIZED; - } - - SafeRelease(dxgiDevice); - - mDxgiAdapter->GetDesc(&mAdapterDescription); - memset(mDescription, 0, sizeof(mDescription)); - wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); - - result = mDxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&mDxgiFactory); - - if (!mDxgiFactory || FAILED(result)) - { - ERR("Could not create DXGI factory - aborting!\n"); - return EGL_NOT_INITIALIZED; - } - - // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log -#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) - ID3D11InfoQueue *infoQueue; - result = mDevice->QueryInterface(IID_ID3D11InfoQueue, (void **)&infoQueue); - - if (SUCCEEDED(result)) - { - D3D11_MESSAGE_ID hideMessages[] = - { - D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET - }; - - D3D11_INFO_QUEUE_FILTER filter = {0}; - filter.DenyList.NumIDs = ArraySize(hideMessages); - filter.DenyList.pIDList = hideMessages; - - infoQueue->AddStorageFilterEntries(&filter); - SafeRelease(infoQueue); - } -#endif - - initializeDevice(); - - return EGL_SUCCESS; -} - -// 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 Renderer11::initializeDevice() -{ - mStateCache.initialize(mDevice); - mInputLayoutCache.initialize(mDevice, mDeviceContext); - - ASSERT(!mVertexDataManager && !mIndexDataManager); - mVertexDataManager = new VertexDataManager(this); - mIndexDataManager = new IndexDataManager(this); - - ASSERT(!mBlit); - mBlit = new Blit11(this); - - ASSERT(!mClear); - mClear = new Clear11(this); - - ASSERT(!mPixelTransfer); - mPixelTransfer = new PixelTransfer11(this); - - const gl::Caps &rendererCaps = getRendererCaps(); - - mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); - mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); - - mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); - mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); - - mCurVertexSRVs.resize(rendererCaps.maxVertexTextureImageUnits); - mCurPixelSRVs.resize(rendererCaps.maxTextureImageUnits); - - markAllStateDirty(); -} - -int Renderer11::generateConfigs(ConfigDesc **configDescList) -{ - unsigned int numRenderFormats = ArraySize(RenderTargetFormats); - unsigned int numDepthFormats = ArraySize(DepthStencilFormats); - (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats]; - int numConfigs = 0; - - for (unsigned int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++) - { - const d3d11::DXGIFormat &renderTargetFormatInfo = d3d11::GetDXGIFormatInfo(RenderTargetFormats[formatIndex]); - const gl::TextureCaps &renderTargetFormatCaps = getRendererTextureCaps().get(renderTargetFormatInfo.internalFormat); - if (renderTargetFormatCaps.renderable) - { - for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++) - { - const d3d11::DXGIFormat &depthStencilFormatInfo = d3d11::GetDXGIFormatInfo(DepthStencilFormats[depthStencilIndex]); - const gl::TextureCaps &depthStencilFormatCaps = getRendererTextureCaps().get(depthStencilFormatInfo.internalFormat); - if (depthStencilFormatCaps.renderable || DepthStencilFormats[depthStencilIndex] == DXGI_FORMAT_UNKNOWN) - { - ConfigDesc newConfig; - newConfig.renderTargetFormat = renderTargetFormatInfo.internalFormat; - newConfig.depthStencilFormat = depthStencilFormatInfo.internalFormat; - newConfig.multiSample = 0; // FIXME: enumerate multi-sampling - newConfig.fastConfig = true; // Assume all DX11 format conversions to be fast - newConfig.es3Capable = true; - - (*configDescList)[numConfigs++] = newConfig; - } - } - } - } - - return numConfigs; -} - -void Renderer11::deleteConfigs(ConfigDesc *configDescList) -{ - delete [] (configDescList); -} - -gl::Error Renderer11::sync(bool block) -{ - if (block) - { - HRESULT result; - - if (!mSyncQuery) - { - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_EVENT; - queryDesc.MiscFlags = 0; - - result = mDevice->CreateQuery(&queryDesc, &mSyncQuery); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); - } - } - - mDeviceContext->End(mSyncQuery); - mDeviceContext->Flush(); - - do - { - result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); - } - - // Keep polling, but allow other threads to do something useful first - Sleep(0); - - if (testDeviceLost(true)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while waiting for sync."); - } - } - while (result == S_FALSE); - } - else - { - mDeviceContext->Flush(); - } - - return gl::Error(GL_NO_ERROR); -} - -SwapChain *Renderer11::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) -{ - return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); -} - -gl::Error Renderer11::generateSwizzle(gl::Texture *texture) -{ - if (texture) - { - TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); - ASSERT(textureD3D); - - TextureStorage *texStorage = textureD3D->getNativeTexture(); - if (texStorage) - { - TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); - gl::Error error = storage11->generateSwizzles(texture->getSamplerState().swizzleRed, - texture->getSamplerState().swizzleGreen, - texture->getSamplerState().swizzleBlue, - texture->getSamplerState().swizzleAlpha); - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerStateParam) -{ - // Make sure to add the level offset for our tiny compressed texture workaround - TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); - gl::SamplerState samplerStateInternal = samplerStateParam; - samplerStateInternal.baseLevel += textureD3D->getNativeTexture()->getTopLevel(); - - if (type == gl::SAMPLER_PIXEL) - { - ASSERT(static_cast(index) < getRendererCaps().maxTextureImageUnits); - - if (mForceSetPixelSamplerStates[index] || memcmp(&samplerStateInternal, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) - { - ID3D11SamplerState *dxSamplerState = NULL; - gl::Error error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); - if (error.isError()) - { - return error; - } - - ASSERT(dxSamplerState != NULL); - mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); - - mCurPixelSamplerStates[index] = samplerStateInternal; - } - - mForceSetPixelSamplerStates[index] = false; - } - else if (type == gl::SAMPLER_VERTEX) - { - ASSERT(static_cast(index) < getRendererCaps().maxVertexTextureImageUnits); - - if (mForceSetVertexSamplerStates[index] || memcmp(&samplerStateInternal, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) - { - ID3D11SamplerState *dxSamplerState = NULL; - gl::Error error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); - if (error.isError()) - { - return error; - } - - ASSERT(dxSamplerState != NULL); - mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); - - mCurVertexSamplerStates[index] = samplerStateInternal; - } - - mForceSetVertexSamplerStates[index] = false; - } - else UNREACHABLE(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) -{ - ID3D11ShaderResourceView *textureSRV = NULL; - - if (texture) - { - TextureD3D *textureImpl = TextureD3D::makeTextureD3D(texture->getImplementation()); - TextureStorage *texStorage = textureImpl->getNativeTexture(); - ASSERT(texStorage != NULL); - - TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); - - // Make sure to add the level offset for our tiny compressed texture workaround - gl::SamplerState samplerState = texture->getSamplerState(); - samplerState.baseLevel += storage11->getTopLevel(); - - gl::Error error = storage11->getSRV(samplerState, &textureSRV); - if (error.isError()) - { - return error; - } - - // If we get NULL back from getSRV here, something went wrong in the texture class and we're unexpectedly - // missing the shader resource view - ASSERT(textureSRV != NULL); - - textureImpl->resetDirty(); - } - - ASSERT((type == gl::SAMPLER_PIXEL && static_cast(index) < getRendererCaps().maxTextureImageUnits) || - (type == gl::SAMPLER_VERTEX && static_cast(index) < getRendererCaps().maxVertexTextureImageUnits)); - - setShaderResource(type, index, textureSRV); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) -{ - for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; uniformBufferIndex++) - { - const gl::Buffer *uniformBuffer = vertexUniformBuffers[uniformBufferIndex]; - if (uniformBuffer) - { - Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); - ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); - - if (!constantBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY); - } - - if (mCurrentConstantBufferVS[uniformBufferIndex] != bufferStorage->getSerial()) - { - mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex, - 1, &constantBuffer); - mCurrentConstantBufferVS[uniformBufferIndex] = bufferStorage->getSerial(); - } - } - } - - for (unsigned int uniformBufferIndex = 0; uniformBufferIndex < gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS; uniformBufferIndex++) - { - const gl::Buffer *uniformBuffer = fragmentUniformBuffers[uniformBufferIndex]; - if (uniformBuffer) - { - Buffer11 *bufferStorage = Buffer11::makeBuffer11(uniformBuffer->getImplementation()); - ID3D11Buffer *constantBuffer = bufferStorage->getBuffer(BUFFER_USAGE_UNIFORM); - - if (!constantBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY); - } - - if (mCurrentConstantBufferPS[uniformBufferIndex] != bufferStorage->getSerial()) - { - mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex, - 1, &constantBuffer); - mCurrentConstantBufferPS[uniformBufferIndex] = bufferStorage->getSerial(); - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) -{ - if (mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0) - { - ID3D11RasterizerState *dxRasterState = NULL; - gl::Error error = mStateCache.getRasterizerState(rasterState, mScissorEnabled, &dxRasterState); - if (error.isError()) - { - return error; - } - - mDeviceContext->RSSetState(dxRasterState); - - mCurRasterState = rasterState; - } - - mForceSetRasterState = false; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask) -{ - if (mForceSetBlendState || - memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0 || - memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0 || - sampleMask != mCurSampleMask) - { - ID3D11BlendState *dxBlendState = NULL; - gl::Error error = mStateCache.getBlendState(framebuffer, blendState, &dxBlendState); - if (error.isError()) - { - return error; - } - - ASSERT(dxBlendState != NULL); - - float blendColors[4] = {0.0f}; - if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && - blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) - { - blendColors[0] = blendColor.red; - blendColors[1] = blendColor.green; - blendColors[2] = blendColor.blue; - blendColors[3] = blendColor.alpha; - } - else - { - blendColors[0] = blendColor.alpha; - blendColors[1] = blendColor.alpha; - blendColors[2] = blendColor.alpha; - blendColors[3] = blendColor.alpha; - } - - mDeviceContext->OMSetBlendState(dxBlendState, blendColors, sampleMask); - - mCurBlendState = blendState; - mCurBlendColor = blendColor; - mCurSampleMask = sampleMask; - } - - mForceSetBlendState = false; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, - int stencilBackRef, bool frontFaceCCW) -{ - if (mForceSetDepthStencilState || - memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0 || - stencilRef != mCurStencilRef || stencilBackRef != mCurStencilBackRef) - { - ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); - ASSERT(stencilRef == stencilBackRef); - ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); - - ID3D11DepthStencilState *dxDepthStencilState = NULL; - gl::Error error = mStateCache.getDepthStencilState(depthStencilState, &dxDepthStencilState); - if (error.isError()) - { - return error; - } - - ASSERT(dxDepthStencilState); - - // Max D3D11 stencil reference value is 0xFF, corresponding to the max 8 bits in a stencil buffer - // GL specifies we should clamp the ref value to the nearest bit depth when doing stencil ops - META_ASSERT(D3D11_DEFAULT_STENCIL_READ_MASK == 0xFF); - META_ASSERT(D3D11_DEFAULT_STENCIL_WRITE_MASK == 0xFF); - UINT dxStencilRef = std::min(stencilRef, 0xFFu); - - mDeviceContext->OMSetDepthStencilState(dxDepthStencilState, dxStencilRef); - - mCurDepthStencilState = depthStencilState; - mCurStencilRef = stencilRef; - mCurStencilBackRef = stencilBackRef; - } - - mForceSetDepthStencilState = false; - - return gl::Error(GL_NO_ERROR); -} - -void Renderer11::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) -{ - if (mForceSetScissor || memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || - enabled != mScissorEnabled) - { - if (enabled) - { - D3D11_RECT rect; - rect.left = std::max(0, scissor.x); - rect.top = std::max(0, scissor.y); - rect.right = scissor.x + std::max(0, scissor.width); - rect.bottom = scissor.y + std::max(0, scissor.height); - - mDeviceContext->RSSetScissorRects(1, &rect); - } - - if (enabled != mScissorEnabled) - { - mForceSetRasterState = true; - } - - mCurScissor = scissor; - mScissorEnabled = enabled; - } - - mForceSetScissor = false; -} - -void Renderer11::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, - bool ignoreViewport) -{ - gl::Rectangle actualViewport = viewport; - float actualZNear = gl::clamp01(zNear); - float actualZFar = gl::clamp01(zFar); - if (ignoreViewport) - { - actualViewport.x = 0; - actualViewport.y = 0; - actualViewport.width = mRenderTargetDesc.width; - actualViewport.height = mRenderTargetDesc.height; - actualZNear = 0.0f; - actualZFar = 1.0f; - } - - const gl::Caps& caps = getRendererCaps(); - - // Clamp width and height first to the gl maximum, then clamp further if we extend past the D3D maximum bounds - D3D11_VIEWPORT dxViewport; - dxViewport.TopLeftX = gl::clamp(actualViewport.x, -static_cast(caps.maxViewportWidth), static_cast(caps.maxViewportWidth)); - dxViewport.TopLeftY = gl::clamp(actualViewport.y, -static_cast(caps.maxViewportHeight), static_cast(caps.maxViewportHeight)); - dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast(caps.maxViewportWidth - dxViewport.TopLeftX)); - dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast(caps.maxViewportHeight - dxViewport.TopLeftY)); - dxViewport.MinDepth = actualZNear; - dxViewport.MaxDepth = actualZFar; - - bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || - actualZNear != mCurNear || actualZFar != mCurFar; - - if (viewportChanged) - { - mDeviceContext->RSSetViewports(1, &dxViewport); - - mCurViewport = actualViewport; - mCurNear = actualZNear; - mCurFar = actualZFar; - - mPixelConstants.viewCoords[0] = actualViewport.width * 0.5f; - mPixelConstants.viewCoords[1] = actualViewport.height * 0.5f; - mPixelConstants.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); - mPixelConstants.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); - - mPixelConstants.depthFront[0] = (actualZFar - actualZNear) * 0.5f; - mPixelConstants.depthFront[1] = (actualZNear + actualZFar) * 0.5f; - - mVertexConstants.depthRange[0] = actualZNear; - mVertexConstants.depthRange[1] = actualZFar; - mVertexConstants.depthRange[2] = actualZFar - actualZNear; - - mPixelConstants.depthRange[0] = actualZNear; - mPixelConstants.depthRange[1] = actualZFar; - mPixelConstants.depthRange[2] = actualZFar - actualZNear; - } - - mForceSetViewport = false; -} - -bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count) -{ - D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - - GLsizei minCount = 0; - - switch (mode) - { - case GL_POINTS: primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; minCount = 1; break; - case GL_LINES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; minCount = 2; break; - case GL_LINE_LOOP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; - case GL_LINE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; minCount = 2; break; - case GL_TRIANGLES: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; - case GL_TRIANGLE_STRIP: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; minCount = 3; break; - // emulate fans via rewriting index buffer - case GL_TRIANGLE_FAN: primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; minCount = 3; break; - default: - UNREACHABLE(); - return false; - } - - if (primitiveTopology != mCurrentPrimitiveTopology) - { - mDeviceContext->IASetPrimitiveTopology(primitiveTopology); - mCurrentPrimitiveTopology = primitiveTopology; - } - - return count >= minCount; -} - -void Renderer11::unsetSRVsWithResource(gl::SamplerType samplerType, const ID3D11Resource *resource) -{ - std::vector ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); - - for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex) - { - ID3D11ShaderResourceView *srv = currentSRVs[resourceIndex]; - - if (srv && GetSRVResource(srv) == resource) - { - setShaderResource(samplerType, static_cast(resourceIndex), NULL); - } - } -} - -gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer) -{ - // Get the color render buffer and serial - // Also extract the render target dimensions and view - unsigned int renderTargetWidth = 0; - unsigned int renderTargetHeight = 0; - GLenum renderTargetFormat = 0; - unsigned int renderTargetSerials[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {0}; - ID3D11RenderTargetView* framebufferRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; - bool missingColorRenderTarget = true; - - const gl::ColorbufferInfo &colorbuffers = framebuffer->getColorbuffersForRender(getWorkarounds()); - - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) - { - gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - - if (colorbuffer) - { - // the draw buffer must be either "none", "back" for the default buffer or the same index as this color (in order) - - // check for zero-sized default framebuffer, which is a special case. - // in this case we do not wish to modify any state and just silently return false. - // this will not report any gl error but will cause the calling method to return. - if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) - { - return gl::Error(GL_NO_ERROR); - } - - renderTargetSerials[colorAttachment] = GetAttachmentSerial(colorbuffer); - - // Extract the render target dimensions and view - RenderTarget11 *renderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget); - if (error.isError()) - { - return error; - } - ASSERT(renderTarget); - - framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView(); - ASSERT(framebufferRTVs[colorAttachment]); - - if (missingColorRenderTarget) - { - renderTargetWidth = colorbuffer->getWidth(); - renderTargetHeight = colorbuffer->getHeight(); - renderTargetFormat = colorbuffer->getActualFormat(); - missingColorRenderTarget = false; - } - -#if !defined(NDEBUG) - // Unbind render target SRVs from the shader here to prevent D3D11 warnings. - ID3D11Resource *renderTargetResource = renderTarget->getTexture(); - unsetSRVsWithResource(gl::SAMPLER_VERTEX, renderTargetResource); - unsetSRVsWithResource(gl::SAMPLER_PIXEL, renderTargetResource); -#endif - } - } - - // Get the depth stencil render buffter and serials - gl::FramebufferAttachment *depthStencil = framebuffer->getDepthbuffer(); - unsigned int depthbufferSerial = 0; - unsigned int stencilbufferSerial = 0; - if (depthStencil) - { - depthbufferSerial = GetAttachmentSerial(depthStencil); - } - else if (framebuffer->getStencilbuffer()) - { - depthStencil = framebuffer->getStencilbuffer(); - stencilbufferSerial = GetAttachmentSerial(depthStencil); - } - - ID3D11DepthStencilView* framebufferDSV = NULL; - if (depthStencil) - { - RenderTarget11 *depthStencilRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(depthStencil, &depthStencilRenderTarget); - if (error.isError()) - { - SafeRelease(framebufferRTVs); - return error; - } - ASSERT(depthStencilRenderTarget); - - framebufferDSV = depthStencilRenderTarget->getDepthStencilView(); - ASSERT(framebufferDSV); - - // If there is no render buffer, the width, height and format values come from - // the depth stencil - if (missingColorRenderTarget) - { - renderTargetWidth = depthStencil->getWidth(); - renderTargetHeight = depthStencil->getHeight(); - renderTargetFormat = depthStencil->getActualFormat(); - } - } - - // Apply the render target and depth stencil - if (!mRenderTargetDescInitialized || !mDepthStencilInitialized || - memcmp(renderTargetSerials, mAppliedRenderTargetSerials, sizeof(renderTargetSerials)) != 0 || - depthbufferSerial != mAppliedDepthbufferSerial || - stencilbufferSerial != mAppliedStencilbufferSerial) - { - mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, framebufferRTVs, framebufferDSV); - - mRenderTargetDesc.width = renderTargetWidth; - mRenderTargetDesc.height = renderTargetHeight; - mRenderTargetDesc.format = renderTargetFormat; - mForceSetViewport = true; - mForceSetScissor = true; - mForceSetBlendState = true; - - if (!mDepthStencilInitialized) - { - mForceSetRasterState = true; - } - - for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) - { - mAppliedRenderTargetSerials[rtIndex] = renderTargetSerials[rtIndex]; - } - mAppliedDepthbufferSerial = depthbufferSerial; - mAppliedStencilbufferSerial = stencilbufferSerial; - mRenderTargetDescInitialized = true; - mDepthStencilInitialized = true; - } - - invalidateFramebufferSwizzles(framebuffer); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) -{ - TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); - if (error.isError()) - { - return error; - } - - return mInputLayoutCache.applyVertexBuffers(attributes, state.getCurrentProgramBinary()); -} - -gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) -{ - gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); - if (error.isError()) - { - return error; - } - - ID3D11Buffer *buffer = NULL; - DXGI_FORMAT bufferFormat = (indexInfo->indexType == GL_UNSIGNED_INT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; - - if (indexInfo->storage) - { - Buffer11 *storage = Buffer11::makeBuffer11(indexInfo->storage); - buffer = storage->getBuffer(BUFFER_USAGE_INDEX); - } - else - { - IndexBuffer11* indexBuffer = IndexBuffer11::makeIndexBuffer11(indexInfo->indexBuffer); - buffer = indexBuffer->getBuffer(); - } - - if (buffer != mAppliedIB || bufferFormat != mAppliedIBFormat || indexInfo->startOffset != mAppliedIBOffset) - { - mDeviceContext->IASetIndexBuffer(buffer, bufferFormat, indexInfo->startOffset); - - mAppliedIB = buffer; - mAppliedIBFormat = bufferFormat; - mAppliedIBOffset = indexInfo->startOffset; - } - - return gl::Error(GL_NO_ERROR); -} - -void Renderer11::applyTransformFeedbackBuffers(const gl::State& state) -{ - size_t numXFBBindings = state.getTransformFeedbackBufferIndexRange(); - ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); - - bool requiresUpdate = false; - for (size_t i = 0; i < numXFBBindings; i++) - { - gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); - GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); - ID3D11Buffer *d3dBuffer = NULL; - if (curXFBBuffer) - { - Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); - d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - } - - // TODO: mAppliedTFBuffers and friends should also be kept in a vector. - if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i]) - { - requiresUpdate = true; - } - } - - if (requiresUpdate) - { - for (size_t i = 0; i < numXFBBindings; ++i) - { - gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); - GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); - - if (curXFBBuffer) - { - Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); - ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - - mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer && mAppliedTFOffsets[i] != curXFBOffset) ? - static_cast(curXFBOffset) : -1; - mAppliedTFBuffers[i] = d3dBuffer; - } - else - { - mAppliedTFBuffers[i] = NULL; - mCurrentD3DOffsets[i] = 0; - } - mAppliedTFOffsets[i] = curXFBOffset; - } - - mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets); - } -} - -gl::Error Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) -{ - if (mode == GL_POINTS && transformFeedbackActive) - { - // Since point sprites are generated with a geometry shader, too many vertices will - // be written if transform feedback is active. To work around this, draw only the points - // with the stream out shader and no pixel shader to feed the stream out buffers and then - // draw again with the point sprite geometry shader to rasterize the point sprites. - - mDeviceContext->PSSetShader(NULL, NULL, 0); - - if (instances > 0) - { - mDeviceContext->DrawInstanced(count, instances, 0, 0); - } - else - { - mDeviceContext->Draw(count, 0); - } - - mDeviceContext->GSSetShader(mCurPointGeometryShader, NULL, 0); - mDeviceContext->PSSetShader(mAppliedPixelShader, NULL, 0); - - if (instances > 0) - { - mDeviceContext->DrawInstanced(count, instances, 0, 0); - } - else - { - mDeviceContext->Draw(count, 0); - } - - mDeviceContext->GSSetShader(mAppliedGeometryShader, NULL, 0); - - return gl::Error(GL_NO_ERROR); - } - else if (mode == GL_LINE_LOOP) - { - return drawLineLoop(count, GL_NONE, NULL, 0, NULL); - } - else if (mode == GL_TRIANGLE_FAN) - { - return drawTriangleFan(count, GL_NONE, NULL, 0, NULL, instances); - } - else if (instances > 0) - { - mDeviceContext->DrawInstanced(count, instances, 0, 0); - return gl::Error(GL_NO_ERROR); - } - else - { - mDeviceContext->Draw(count, 0); - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, - gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) -{ - int minIndex = static_cast(indexInfo.indexRange.start); - - if (mode == GL_LINE_LOOP) - { - return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); - } - else if (mode == GL_TRIANGLE_FAN) - { - return drawTriangleFan(count, type, indices, minIndex, elementArrayBuffer, instances); - } - else if (instances > 0) - { - mDeviceContext->DrawIndexedInstanced(count, instances, 0, -minIndex, 0); - return gl::Error(GL_NO_ERROR); - } - else - { - mDeviceContext->DrawIndexed(count, 0, -minIndex); - return gl::Error(GL_NO_ERROR); - } -} -template -static void fillLineLoopIndices(GLenum type, GLsizei count, const GLvoid *indices, T *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(); - } -} - -template -static void fillTriangleFanIndices(GLenum type, unsigned int numTris, const GLvoid *indices, T *data) -{ - switch (type) - { - case GL_NONE: // Non-indexed draw - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = 0; - data[i*3 + 1] = i + 1; - data[i*3 + 2] = i + 2; - } - break; - case GL_UNSIGNED_BYTE: - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = static_cast(indices)[0]; - data[i*3 + 1] = static_cast(indices)[i + 1]; - data[i*3 + 2] = static_cast(indices)[i + 2]; - } - break; - case GL_UNSIGNED_SHORT: - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = static_cast(indices)[0]; - data[i*3 + 1] = static_cast(indices)[i + 1]; - data[i*3 + 2] = static_cast(indices)[i + 2]; - } - break; - case GL_UNSIGNED_INT: - for (unsigned int i = 0; i < numTris; i++) - { - data[i*3 + 0] = static_cast(indices)[0]; - data[i*3 + 1] = static_cast(indices)[i + 1]; - data[i*3 + 2] = static_cast(indices)[i + 2]; - } - break; - default: UNREACHABLE(); - } -} - -gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) -{ - // Get the raw indices for an indexed draw - if (type != GL_NONE && elementArrayBuffer) - { - BufferD3D *storage = BufferD3D::makeFromBuffer(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); - - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); - if (error.isError()) - { - return error; - } - - indices = bufferData + offset; - } - - // TODO: some level 9 hardware supports 32-bit indices; test and store support instead - const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; - - if (!mLineLoopIB) - { - mLineLoopIB = new StreamingIndexBufferInterface(this); - gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, indexType); - if (error.isError()) - { - SafeDelete(mLineLoopIB); - return error; - } - } - - // Checked by Renderer11::applyPrimitiveType - ASSERT(count >= 0); - - int indexTypeSize = indexType == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int); - if (static_cast(count) + 1 > (std::numeric_limits::max() / indexTypeSize)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); - } - - const unsigned int spaceNeeded = (static_cast(count) + 1) * sizeof(unsigned int); - gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); - if (error.isError()) - { - return error; - } - - void* mappedMemory = NULL; - unsigned int offset; - error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; - } - - if (indexType == GL_UNSIGNED_SHORT) - fillLineLoopIndices(type, count, indices, reinterpret_cast(mappedMemory)); - else - fillLineLoopIndices(type, count, indices, reinterpret_cast(mappedMemory)); - unsigned int indexBufferOffset = offset; - - error = mLineLoopIB->unmapBuffer(); - if (error.isError()) - { - return error; - } - - IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mLineLoopIB->getIndexBuffer()); - ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); - DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - - if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) - { - mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); - mAppliedIB = d3dIndexBuffer; - mAppliedIBFormat = indexFormat; - mAppliedIBOffset = indexBufferOffset; - } - - mDeviceContext->DrawIndexed(count + 1, 0, -minIndex); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances) -{ - // Get the raw indices for an indexed draw - if (type != GL_NONE && elementArrayBuffer) - { - BufferD3D *storage = BufferD3D::makeFromBuffer(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); - - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); - if (error.isError()) - { - return error; - } - - indices = bufferData + offset; - } - - const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; - - if (!mTriangleFanIB) - { - mTriangleFanIB = new StreamingIndexBufferInterface(this); - gl::Error error = mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, indexType); - if (error.isError()) - { - SafeDelete(mTriangleFanIB); - return error; - } - } - - // Checked by Renderer11::applyPrimitiveType - ASSERT(count >= 3); - - const unsigned int numTris = count - 2; - - int indexTypeSize = indexType == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int); - if (numTris > (std::numeric_limits::max() / (indexTypeSize * 3))) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); - } - - const unsigned int spaceNeeded = (numTris * 3) * indexTypeSize; - gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, indexType); - if (error.isError()) - { - return error; - } - - void* mappedMemory = NULL; - unsigned int offset; - error = mTriangleFanIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; - } - - if (indexType == GL_UNSIGNED_SHORT) - fillTriangleFanIndices(type, numTris, indices, reinterpret_cast(mappedMemory)); - else - fillTriangleFanIndices(type, numTris, indices, reinterpret_cast(mappedMemory)); - - unsigned int indexBufferOffset = offset; - - error = mTriangleFanIB->unmapBuffer(); - if (error.isError()) - { - return error; - } - - IndexBuffer11 *indexBuffer = IndexBuffer11::makeIndexBuffer11(mTriangleFanIB->getIndexBuffer()); - ID3D11Buffer *d3dIndexBuffer = indexBuffer->getBuffer(); - DXGI_FORMAT indexFormat = indexBuffer->getIndexFormat(); - - if (mAppliedIB != d3dIndexBuffer || mAppliedIBFormat != indexFormat || mAppliedIBOffset != indexBufferOffset) - { - mDeviceContext->IASetIndexBuffer(d3dIndexBuffer, indexFormat, indexBufferOffset); - mAppliedIB = d3dIndexBuffer; - mAppliedIBFormat = indexFormat; - mAppliedIBOffset = indexBufferOffset; - } - - if (instances > 0) - { - mDeviceContext->DrawIndexedInstanced(numTris * 3, instances, 0, -minIndex, 0); - } - else - { - mDeviceContext->DrawIndexed(numTris * 3, 0, -minIndex); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, - bool rasterizerDiscard, bool transformFeedbackActive) -{ - ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); - - ShaderExecutable *vertexExe = NULL; - gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe); - if (error.isError()) - { - return error; - } - - ShaderExecutable *pixelExe = NULL; - error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); - if (error.isError()) - { - return error; - } - - ShaderExecutable *geometryExe = programD3D->getGeometryExecutable(); - - ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL); - - ID3D11PixelShader *pixelShader = NULL; - // Skip pixel shader if we're doing rasterizer discard. - if (!rasterizerDiscard) - { - pixelShader = (pixelExe ? ShaderExecutable11::makeShaderExecutable11(pixelExe)->getPixelShader() : NULL); - } - - ID3D11GeometryShader *geometryShader = NULL; - if (transformFeedbackActive) - { - geometryShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getStreamOutShader() : NULL); - } - else if (mCurRasterState.pointDrawMode) - { - geometryShader = (geometryExe ? ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader() : NULL); - } - - bool dirtyUniforms = false; - - if (vertexShader != mAppliedVertexShader) - { - mDeviceContext->VSSetShader(vertexShader, NULL, 0); - mAppliedVertexShader = vertexShader; - dirtyUniforms = true; - } - - if (geometryShader != mAppliedGeometryShader) - { - mDeviceContext->GSSetShader(geometryShader, NULL, 0); - mAppliedGeometryShader = geometryShader; - dirtyUniforms = true; - } - - if (geometryExe && mCurRasterState.pointDrawMode) - { - mCurPointGeometryShader = ShaderExecutable11::makeShaderExecutable11(geometryExe)->getGeometryShader(); - } - else - { - mCurPointGeometryShader = NULL; - } - - if (pixelShader != mAppliedPixelShader) - { - mDeviceContext->PSSetShader(pixelShader, NULL, 0); - mAppliedPixelShader = pixelShader; - dirtyUniforms = true; - } - - if (dirtyUniforms) - { - programD3D->dirtyAllUniforms(); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) -{ - unsigned int totalRegisterCountVS = 0; - unsigned int totalRegisterCountPS = 0; - - bool vertexUniformsDirty = false; - bool pixelUniformsDirty = false; - - for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) - { - const gl::LinkedUniform &uniform = *uniformArray[uniformIndex]; - - if (uniform.isReferencedByVertexShader() && !uniform.isSampler()) - { - totalRegisterCountVS += uniform.registerCount; - vertexUniformsDirty = (vertexUniformsDirty || uniform.dirty); - } - - if (uniform.isReferencedByFragmentShader() && !uniform.isSampler()) - { - totalRegisterCountPS += uniform.registerCount; - pixelUniformsDirty = (pixelUniformsDirty || uniform.dirty); - } - } - - const ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(&program); - const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getVertexUniformStorage()); - const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getFragmentUniformStorage()); - ASSERT(vertexUniformStorage); - ASSERT(fragmentUniformStorage); - - ID3D11Buffer *vertexConstantBuffer = vertexUniformStorage->getConstantBuffer(); - ID3D11Buffer *pixelConstantBuffer = fragmentUniformStorage->getConstantBuffer(); - - float (*mapVS)[4] = NULL; - float (*mapPS)[4] = NULL; - - if (totalRegisterCountVS > 0 && vertexUniformsDirty) - { - D3D11_MAPPED_SUBRESOURCE map = {0}; - HRESULT result = mDeviceContext->Map(vertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - mapVS = (float(*)[4])map.pData; - } - - if (totalRegisterCountPS > 0 && pixelUniformsDirty) - { - D3D11_MAPPED_SUBRESOURCE map = {0}; - HRESULT result = mDeviceContext->Map(pixelConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - mapPS = (float(*)[4])map.pData; - } - - for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) - { - gl::LinkedUniform *uniform = uniformArray[uniformIndex]; - - if (!uniform->isSampler()) - { - unsigned int componentCount = (4 - uniform->registerElement); - - // we assume that uniforms from structs are arranged in struct order in our uniforms list. otherwise we would - // overwrite previously written regions of memory. - - if (uniform->isReferencedByVertexShader() && mapVS) - { - memcpy(&mapVS[uniform->vsRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); - } - - if (uniform->isReferencedByFragmentShader() && mapPS) - { - memcpy(&mapPS[uniform->psRegisterIndex][uniform->registerElement], uniform->data, uniform->registerCount * sizeof(float) * componentCount); - } - } - } - - if (mapVS) - { - mDeviceContext->Unmap(vertexConstantBuffer, 0); - } - - if (mapPS) - { - mDeviceContext->Unmap(pixelConstantBuffer, 0); - } - - if (mCurrentVertexConstantBuffer != vertexConstantBuffer) - { - mDeviceContext->VSSetConstantBuffers(0, 1, &vertexConstantBuffer); - mCurrentVertexConstantBuffer = vertexConstantBuffer; - } - - if (mCurrentPixelConstantBuffer != pixelConstantBuffer) - { - mDeviceContext->PSSetConstantBuffers(0, 1, &pixelConstantBuffer); - mCurrentPixelConstantBuffer = pixelConstantBuffer; - } - - // Driver uniforms - if (!mDriverConstantBufferVS) - { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = sizeof(dx_VertexConstants); - constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; - constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constantBufferDescription.CPUAccessFlags = 0; - constantBufferDescription.MiscFlags = 0; - constantBufferDescription.StructureByteStride = 0; - - HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferVS); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - - mDeviceContext->VSSetConstantBuffers(1, 1, &mDriverConstantBufferVS); - } - - if (!mDriverConstantBufferPS) - { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = sizeof(dx_PixelConstants); - constantBufferDescription.Usage = D3D11_USAGE_DEFAULT; - constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constantBufferDescription.CPUAccessFlags = 0; - constantBufferDescription.MiscFlags = 0; - constantBufferDescription.StructureByteStride = 0; - - HRESULT result = mDevice->CreateBuffer(&constantBufferDescription, NULL, &mDriverConstantBufferPS); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - - mDeviceContext->PSSetConstantBuffers(1, 1, &mDriverConstantBufferPS); - } - - if (memcmp(&mVertexConstants, &mAppliedVertexConstants, sizeof(dx_VertexConstants)) != 0) - { - mDeviceContext->UpdateSubresource(mDriverConstantBufferVS, 0, NULL, &mVertexConstants, 16, 0); - memcpy(&mAppliedVertexConstants, &mVertexConstants, sizeof(dx_VertexConstants)); - } - - if (memcmp(&mPixelConstants, &mAppliedPixelConstants, sizeof(dx_PixelConstants)) != 0) - { - mDeviceContext->UpdateSubresource(mDriverConstantBufferPS, 0, NULL, &mPixelConstants, 16, 0); - memcpy(&mAppliedPixelConstants, &mPixelConstants, sizeof(dx_PixelConstants)); - } - - // needed for the point sprite geometry shader - if (mFeatureLevel >= D3D_FEATURE_LEVEL_10_0 && mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) - { - mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); - mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) -{ - gl::Error error = mClear->clearFramebuffer(clearParams, frameBuffer); - if (error.isError()) - { - return error; - } - - invalidateFramebufferSwizzles(frameBuffer); - - return gl::Error(GL_NO_ERROR); -} - -void Renderer11::markAllStateDirty() -{ - for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) - { - mAppliedRenderTargetSerials[rtIndex] = 0; - } - mAppliedDepthbufferSerial = 0; - mAppliedStencilbufferSerial = 0; - mDepthStencilInitialized = false; - mRenderTargetDescInitialized = false; - - ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexSRVs.size()); - for (size_t vsamplerId = 0; vsamplerId < mForceSetVertexSamplerStates.size(); ++vsamplerId) - { - mForceSetVertexSamplerStates[vsamplerId] = true; - } - - ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelSRVs.size()); - for (size_t fsamplerId = 0; fsamplerId < mForceSetPixelSamplerStates.size(); ++fsamplerId) - { - mForceSetPixelSamplerStates[fsamplerId] = true; - } - - mForceSetBlendState = true; - mForceSetRasterState = true; - mForceSetDepthStencilState = true; - mForceSetScissor = true; - mForceSetViewport = true; - - mAppliedIB = NULL; - mAppliedIBFormat = DXGI_FORMAT_UNKNOWN; - mAppliedIBOffset = 0; - - mAppliedVertexShader = NULL; - mAppliedGeometryShader = NULL; - mCurPointGeometryShader = NULL; - mAppliedPixelShader = NULL; - - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) - { - mAppliedTFBuffers[i] = NULL; - mAppliedTFOffsets[i] = 0; - } - - memset(&mAppliedVertexConstants, 0, sizeof(dx_VertexConstants)); - memset(&mAppliedPixelConstants, 0, sizeof(dx_PixelConstants)); - - mInputLayoutCache.markDirty(); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS; i++) - { - mCurrentConstantBufferVS[i] = -1; - mCurrentConstantBufferPS[i] = -1; - } - - mCurrentVertexConstantBuffer = NULL; - mCurrentPixelConstantBuffer = NULL; - mCurrentGeometryConstantBuffer = NULL; - - mCurrentPrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; -} - -void Renderer11::releaseDeviceResources() -{ - mStateCache.clear(); - mInputLayoutCache.clear(); - - SafeDelete(mVertexDataManager); - SafeDelete(mIndexDataManager); - SafeDelete(mLineLoopIB); - SafeDelete(mTriangleFanIB); - SafeDelete(mBlit); - SafeDelete(mClear); - SafeDelete(mPixelTransfer); - - SafeRelease(mDriverConstantBufferVS); - SafeRelease(mDriverConstantBufferPS); - SafeRelease(mSyncQuery); -} - -void Renderer11::notifyDeviceLost() -{ - mDeviceLost = true; - mDisplay->notifyDeviceLost(); -} - -bool Renderer11::isDeviceLost() -{ - return mDeviceLost; -} - -// set notify to true to broadcast a message to all contexts of the device loss -bool Renderer11::testDeviceLost(bool notify) -{ - bool isLost = false; - - // GetRemovedReason is used to test if the device is removed - HRESULT result = mDevice->GetDeviceRemovedReason(); - isLost = d3d11::isDeviceLostError(result); - - if (isLost) - { - // Log error if this is a new device lost event - if (mDeviceLost == false) - { - ERR("The D3D11 device was removed: 0x%08X", result); - } - - // ensure we note the device loss -- - // we'll probably get this done again by notifyDeviceLost - // but best to remember it! - // Note that we don't want to clear the device loss status here - // -- this needs to be done by resetDevice - mDeviceLost = true; - if (notify) - { - notifyDeviceLost(); - } - } - - return isLost; -} - -bool Renderer11::testDeviceResettable() -{ - // determine if the device is resettable by creating a dummy device - PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); - - if (D3D11CreateDevice == NULL) - { - return false; - } - - ID3D11Device* dummyDevice; - D3D_FEATURE_LEVEL dummyFeatureLevel; - ID3D11DeviceContext* dummyContext; - - HRESULT result = D3D11CreateDevice(NULL, - mDriverType, - NULL, - #if defined(_DEBUG) - D3D11_CREATE_DEVICE_DEBUG, - #else - 0, - #endif - mAvailableFeatureLevels.data(), - mAvailableFeatureLevels.size(), - D3D11_SDK_VERSION, - &dummyDevice, - &dummyFeatureLevel, - &dummyContext); - - if (!mDevice || FAILED(result)) - { - return false; - } - - SafeRelease(dummyContext); - SafeRelease(dummyDevice); - - return true; -} - -void Renderer11::release() -{ - RendererD3D::cleanup(); - - releaseShaderCompiler(); - releaseDeviceResources(); - - SafeRelease(mDxgiFactory); - SafeRelease(mDxgiAdapter); - - if (mDeviceContext) - { - mDeviceContext->ClearState(); - mDeviceContext->Flush(); - SafeRelease(mDeviceContext); - } - - SafeRelease(mDevice); - - if (mD3d11Module) - { - FreeLibrary(mD3d11Module); - mD3d11Module = NULL; - } - - if (mDxgiModule) - { - FreeLibrary(mDxgiModule); - mDxgiModule = NULL; - } - - mCompiler.release(); -} - -bool Renderer11::resetDevice() -{ - // recreate everything - release(); - EGLint result = initialize(); - - if (result != EGL_SUCCESS) - { - ERR("Could not reinitialize D3D11 device: %08X", result); - return false; - } - - mDeviceLost = false; - - return true; -} - -DWORD Renderer11::getAdapterVendor() const -{ - return mAdapterDescription.VendorId; -} - -std::string Renderer11::getRendererDescription() const -{ - std::ostringstream rendererString; - - rendererString << mDescription; - rendererString << " Direct3D11"; - - rendererString << " vs_" << getMajorShaderModel() << "_" << getMinorShaderModel(); - rendererString << " ps_" << getMajorShaderModel() << "_" << getMinorShaderModel(); - - return rendererString.str(); -} - -GUID Renderer11::getAdapterIdentifier() const -{ - // Use the adapter LUID as our adapter ID - // This number is local to a machine is only guaranteed to be unique between restarts - META_ASSERT(sizeof(LUID) <= sizeof(GUID)); - GUID adapterId = {0}; - memcpy(&adapterId, &mAdapterDescription.AdapterLuid, sizeof(LUID)); - return adapterId; -} - -unsigned int Renderer11::getReservedVertexUniformVectors() const -{ - return 0; // Driver uniforms are stored in a separate constant buffer -} - -unsigned int Renderer11::getReservedFragmentUniformVectors() const -{ - return 0; // Driver uniforms are stored in a separate constant buffer -} - -unsigned int Renderer11::getReservedVertexUniformBuffers() const -{ - // we reserve one buffer for the application uniforms, and one for driver uniforms - return 2; -} - -unsigned int Renderer11::getReservedFragmentUniformBuffers() const -{ - // we reserve one buffer for the application uniforms, and one for driver uniforms - return 2; -} - -bool Renderer11::getShareHandleSupport() const -{ - // We only currently support share handles with BGRA surfaces, because - // chrome needs BGRA. Once chrome fixes this, we should always support them. - // PIX doesn't seem to support using share handles, so disable them. - return getRendererExtensions().textureFormatBGRA8888 && !gl::perfActive(); -} - -bool Renderer11::getPostSubBufferSupport() const -{ - // D3D11 does not support present with dirty rectangles until D3D11.1 and DXGI 1.2. - return false; -} - -int Renderer11::getMajorShaderModel() const -{ - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 - case D3D_FEATURE_LEVEL_10_0: - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D10_SHADER_MAJOR_VERSION; // 4 - default: UNREACHABLE(); return 0; - } -} - -int Renderer11::getMinorShaderModel() const -{ - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 - case D3D_FEATURE_LEVEL_10_0: - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D10_SHADER_MINOR_VERSION; // 0 - default: UNREACHABLE(); return 0; - } -} - -int Renderer11::getMinSwapInterval() const -{ - return 0; -} - -int Renderer11::getMaxSwapInterval() const -{ - return 4; -} - -gl::Error Renderer11::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) -{ - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); - - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); - - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); - - TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage); - ASSERT(storage11); - - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - RenderTarget *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); - - ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); - - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - - gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); - - // Use nearest filtering because source and destination are the same size for the direct - // copy - mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); - if (error.isError()) - { - return error; - } - - storage11->invalidateSwizzleCacheLevel(level); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) -{ - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); - - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); - - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); - - TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage); - ASSERT(storage11); - - gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - RenderTarget *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); - - ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); - - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - - gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); - - // Use nearest filtering because source and destination are the same size for the direct - // copy - error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); - if (error.isError()) - { - return error; - } - - storage11->invalidateSwizzleCacheLevel(level); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) -{ - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); - - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); - - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); - - TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage); - ASSERT(storage11); - - gl::ImageIndex index = gl::ImageIndex::Make3D(level, zOffset); - RenderTarget *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); - - ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); - - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - - gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); - - // Use nearest filtering because source and destination are the same size for the direct - // copy - error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); - if (error.isError()) - { - return error; - } - - storage11->invalidateSwizzleCacheLevel(level); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) -{ - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); - - RenderTarget11 *sourceRenderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(sourceRenderTarget); - - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - ASSERT(source); - - TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage); - ASSERT(storage11); - - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zOffset); - RenderTarget *destRenderTarget = NULL; - error = storage11->getRenderTarget(index, &destRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(destRenderTarget); - - ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); - ASSERT(dest); - - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - - gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); - - // Use nearest filtering because source and destination are the same size for the direct - // copy - error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); - if (error.isError()) - { - return error; - } - - storage11->invalidateSwizzleCacheLevel(level); - - return gl::Error(GL_NO_ERROR); -} - -void Renderer11::unapplyRenderTargets() -{ - setOneTimeRenderTarget(NULL); -} - -void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView) -{ - ID3D11RenderTargetView *rtvArray[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; - - rtvArray[0] = renderTargetView; - - mDeviceContext->OMSetRenderTargets(getRendererCaps().maxDrawBuffers, rtvArray, NULL); - - // Do not preserve the serial for this one-time-use render target - for (unsigned int rtIndex = 0; rtIndex < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; rtIndex++) - { - mAppliedRenderTargetSerials[rtIndex] = 0; - } -} - -gl::Error Renderer11::createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT) -{ - SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); - *outRT = new SurfaceRenderTarget11(swapChain11, depth); - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT) -{ - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format); - - const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); - GLuint supportedSamples = textureCaps.getNearestSamples(samples); - - if (width > 0 && height > 0) - { - // Create texture resource - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = formatInfo.texFormat; - desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - // If a rendertarget or depthstencil format exists for this texture format, - // we'll flag it to allow binding that way. Shader resource views are a little - // more complicated. - bool bindRTV = false, bindDSV = false, bindSRV = false; - bindRTV = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); - bindDSV = (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); - if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) - { - // Multisample targets flagged for binding as depth stencil cannot also be - // flagged for binding as SRV, so make certain not to add the SRV flag for - // these targets. - bindSRV = !(formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1); - } - - desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | - (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | - (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0); - - // The format must be either an RTV or a DSV - ASSERT(bindRTV != bindDSV); - - ID3D11Texture2D *texture = NULL; - HRESULT result = mDevice->CreateTexture2D(&desc, NULL, &texture); - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target texture, result: 0x%X.", result); - } - - ID3D11ShaderResourceView *srv = NULL; - if (bindSRV) - { - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = formatInfo.srvFormat; - srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; - srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Texture2D.MipLevels = 1; - - result = mDevice->CreateShaderResourceView(texture, &srvDesc, &srv); - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - SafeRelease(texture); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target shader resource view, result: 0x%X.", result); - } - } - - if (bindDSV) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = formatInfo.dsvFormat; - dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; - dsvDesc.Texture2D.MipSlice = 0; - dsvDesc.Flags = 0; - - ID3D11DepthStencilView *dsv = NULL; - result = mDevice->CreateDepthStencilView(texture, &dsvDesc, &dsv); - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - SafeRelease(texture); - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target depth stencil view, result: 0x%X.", result); - } - - *outRT = new TextureRenderTarget11(dsv, texture, srv, format, width, height, 1, supportedSamples); - - SafeRelease(dsv); - } - else if (bindRTV) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = formatInfo.rtvFormat; - rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; - rtvDesc.Texture2D.MipSlice = 0; - - ID3D11RenderTargetView *rtv = NULL; - result = mDevice->CreateRenderTargetView(texture, &rtvDesc, &rtv); - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - SafeRelease(texture); - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target render target view, result: 0x%X.", result); - } - - if (formatInfo.dataInitializerFunction != NULL) - { - const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - mDeviceContext->ClearRenderTargetView(rtv, clearValues); - } - - *outRT = new TextureRenderTarget11(rtv, texture, srv, format, width, height, 1, supportedSamples); - - SafeRelease(rtv); - } - else - { - UNREACHABLE(); - } - - SafeRelease(texture); - SafeRelease(srv); - } - else - { - *outRT = new TextureRenderTarget11(reinterpret_cast(NULL), NULL, NULL, format, width, height, 1, supportedSamples); - } - - return gl::Error(GL_NO_ERROR); -} - -ShaderImpl *Renderer11::createShader(const gl::Data &data, GLenum type) -{ - return new ShaderD3D(data, type, this); -} - -ProgramImpl *Renderer11::createProgram() -{ - return new ProgramD3D(this); -} - -void Renderer11::releaseShaderCompiler() -{ - ShaderD3D::releaseCompiler(); -} - -gl::Error Renderer11::loadExecutable(const void *function, size_t length, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutable **outExecutable) -{ - switch (type) - { - case SHADER_VERTEX: - { - ID3D11VertexShader *vertexShader = NULL; - ID3D11GeometryShader *streamOutShader = NULL; - - HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result); - } - - if (transformFeedbackVaryings.size() > 0) - { - std::vector soDeclaration; - for (size_t i = 0; i < transformFeedbackVaryings.size(); i++) - { - const gl::LinkedVarying &varying = transformFeedbackVaryings[i]; - GLenum transposedType = gl::TransposeMatrixType(varying.type); - - for (size_t j = 0; j < varying.semanticIndexCount; j++) - { - D3D11_SO_DECLARATION_ENTRY entry = { 0 }; - entry.Stream = 0; - entry.SemanticName = varying.semanticName.c_str(); - entry.SemanticIndex = varying.semanticIndex + j; - entry.StartComponent = 0; - entry.ComponentCount = gl::VariableColumnCount(transposedType); - entry.OutputSlot = (separatedOutputBuffers ? i : 0); - soDeclaration.push_back(entry); - } - } - - result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(), - NULL, 0, 0, NULL, &streamOutShader); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create steam output shader, result: 0x%X.", result); - } - } - - *outExecutable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); - } - break; - case SHADER_PIXEL: - { - ID3D11PixelShader *pixelShader = NULL; - - HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.", result); - } - - *outExecutable = new ShaderExecutable11(function, length, pixelShader); - } - break; - case SHADER_GEOMETRY: - { - ID3D11GeometryShader *geometryShader = NULL; - - HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create geometry shader, result: 0x%X.", result); - } - - *outExecutable = new ShaderExecutable11(function, length, geometryShader); - } - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround, - ShaderExecutable **outExectuable) -{ - const char *profileType = NULL; - switch (type) - { - case SHADER_VERTEX: - profileType = "vs"; - break; - case SHADER_PIXEL: - profileType = "ps"; - break; - case SHADER_GEOMETRY: - profileType = "gs"; - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - - unsigned int profileMajorVersion = 0; - unsigned int profileMinorVersion = 0; - const char *profileSuffix = NULL; - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: - profileMajorVersion = 5; - profileMinorVersion = 0; - break; - case D3D_FEATURE_LEVEL_10_1: - profileMajorVersion = 4; - profileMinorVersion = 1; - break; - case D3D_FEATURE_LEVEL_10_0: - profileMajorVersion = 4; - profileMinorVersion = 0; - break; - case D3D_FEATURE_LEVEL_9_3: - profileMajorVersion = 4; - profileMinorVersion = 0; - profileSuffix = "_level_9_3"; - break; - case D3D_FEATURE_LEVEL_9_2: - profileMajorVersion = 4; - profileMinorVersion = 0; - profileSuffix = "_level_9_2"; - break; - case D3D_FEATURE_LEVEL_9_1: - profileMajorVersion = 4; - profileMinorVersion = 0; - profileSuffix = "_level_9_1"; - break; - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - - std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); - if (profileSuffix) - profile += profileSuffix; - - UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2; - - if (gl::perfActive()) - { -#ifndef NDEBUG - flags = D3DCOMPILE_SKIP_OPTIMIZATION; -#endif - - flags |= D3DCOMPILE_DEBUG; - } - - // 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. - std::vector configs; - configs.push_back(CompileConfig(flags, "default" )); - configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation" )); - configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization")); - - D3D_SHADER_MACRO loopMacros[] = { {"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0} }; - - ID3DBlob *binary = NULL; - std::string debugInfo; - gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary, &debugInfo); - if (error.isError()) - { - return error; - } - - // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL - // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. - if (!binary) - { - *outExectuable = NULL; - return gl::Error(GL_NO_ERROR); - } - - error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - transformFeedbackVaryings, separatedOutputBuffers, outExectuable); - - SafeRelease(binary); - if (error.isError()) - { - return error; - } - - if (!debugInfo.empty()) - { - (*outExectuable)->appendDebugInfo(debugInfo); - } - - return gl::Error(GL_NO_ERROR); -} - -UniformStorage *Renderer11::createUniformStorage(size_t storageSize) -{ - return new UniformStorage11(this, storageSize); -} - -VertexBuffer *Renderer11::createVertexBuffer() -{ - return new VertexBuffer11(this); -} - -IndexBuffer *Renderer11::createIndexBuffer() -{ - return new IndexBuffer11(this); -} - -BufferImpl *Renderer11::createBuffer() -{ - return new Buffer11(this); -} - -VertexArrayImpl *Renderer11::createVertexArray() -{ - return new VertexArray11(this); -} - -QueryImpl *Renderer11::createQuery(GLenum type) -{ - return new Query11(this, type); -} - -FenceNVImpl *Renderer11::createFenceNV() -{ - return new FenceNV11(this); -} - -FenceSyncImpl *Renderer11::createFenceSync() -{ - return new FenceSync11(this); -} - -TransformFeedbackImpl* Renderer11::createTransformFeedback() -{ - return new TransformFeedbackD3D(); -} - -bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const -{ - ASSERT(getRendererExtensions().pixelBufferObject); - - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); - const d3d11::TextureFormat &d3d11FormatInfo = d3d11::GetTextureFormatInfo(internalFormat); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11FormatInfo.texFormat); - - // sRGB formats do not work with D3D11 buffer SRVs - if (internalFormatInfo.colorEncoding == GL_SRGB) - { - return false; - } - - // We cannot support direct copies to non-color-renderable formats - if (d3d11FormatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN) - { - return false; - } - - // We skip all 3-channel formats since sometimes format support is missing - if (internalFormatInfo.componentCount == 3) - { - return false; - } - - // We don't support formats which we can't represent without conversion - if (dxgiFormatInfo.internalFormat != internalFormat) - { - return false; - } - - return true; -} - -gl::Error Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) -{ - ASSERT(supportsFastCopyBufferToTexture(destinationFormat)); - return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea); -} - -gl::Error Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, ID3D11Texture2D **texture2DOut) - -{ - ASSERT(colorbuffer); - - RenderTarget11 *renderTarget = NULL; - gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget); - if (error.isError()) - { - return error; - } - - ID3D11Resource *renderTargetResource = renderTarget->getTexture(); - ASSERT(renderTargetResource); - - *subresourceIndexOut = renderTarget->getSubresourceIndex(); - *texture2DOut = d3d11::DynamicCastComObject(renderTargetResource); - - if (!(*texture2DOut)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the ID3D11Texture2D from a RenderTarget"); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::blitRect(const gl::Framebuffer *readTarget, const gl::Rectangle &readRect, - const gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, - bool blitDepth, bool blitStencil, GLenum filter) -{ - if (blitRenderTarget) - { - gl::FramebufferAttachment *readBuffer = readTarget->getReadColorbuffer(); - ASSERT(readBuffer); - - RenderTarget *readRenderTarget = NULL; - gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(readRenderTarget); - - for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (drawTarget->isEnabledColorAttachment(colorAttachment)) - { - gl::FramebufferAttachment *drawBuffer = drawTarget->getColorbuffer(colorAttachment); - ASSERT(drawBuffer); - - RenderTarget *drawRenderTarget = NULL; - error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(drawRenderTarget); - - error = blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, blitRenderTarget, - false, false); - if (error.isError()) - { - return error; - } - } - } - } - - if (blitDepth || blitStencil) - { - gl::FramebufferAttachment *readBuffer = readTarget->getDepthOrStencilbuffer(); - ASSERT(readBuffer); - - RenderTarget *readRenderTarget = NULL; - gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(readRenderTarget); - - gl::FramebufferAttachment *drawBuffer = drawTarget->getDepthOrStencilbuffer(); - ASSERT(drawBuffer); - - RenderTarget *drawRenderTarget = NULL; - error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(drawRenderTarget); - - error = blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, false, - blitDepth, blitStencil); - if (error.isError()) - { - return error; - } - } - - invalidateFramebufferSwizzles(drawTarget); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) -{ - ID3D11Texture2D *colorBufferTexture = NULL; - unsigned int subresourceIndex = 0; - - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - ASSERT(colorbuffer); - - gl::Error error = getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture); - if (error.isError()) - { - return error; - } - - gl::Rectangle area; - area.x = x; - area.y = y; - area.width = width; - area.height = height; - - gl::Buffer *packBuffer = pack.pixelBuffer.get(); - if (packBuffer != NULL) - { - Buffer11 *packBufferStorage = Buffer11::makeBuffer11(packBuffer->getImplementation()); - PackPixelsParams packParams(area, format, type, outputPitch, pack, reinterpret_cast(pixels)); - - error = packBufferStorage->packPixels(colorBufferTexture, subresourceIndex, packParams); - if (error.isError()) - { - SafeRelease(colorBufferTexture); - return error; - } - - packBuffer->getIndexRangeCache()->clear(); - } - else - { - error = readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, pack, pixels); - if (error.isError()) - { - SafeRelease(colorBufferTexture); - return error; - } - } - - SafeRelease(colorBufferTexture); - - return gl::Error(GL_NO_ERROR); -} - -Image *Renderer11::createImage() -{ - return new Image11(); -} - -gl::Error Renderer11::generateMipmap(Image *dest, Image *src) -{ - Image11 *dest11 = Image11::makeImage11(dest); - Image11 *src11 = Image11::makeImage11(src); - return Image11::generateMipmap(dest11, src11); -} - -TextureStorage *Renderer11::createTextureStorage2D(SwapChain *swapChain) -{ - SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); - return new TextureStorage11_2D(this, swapChain11); -} - -TextureStorage *Renderer11::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) -{ - return new TextureStorage11_2D(this, internalformat, renderTarget, width, height, levels); -} - -TextureStorage *Renderer11::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) -{ - return new TextureStorage11_Cube(this, internalformat, renderTarget, size, levels); -} - -TextureStorage *Renderer11::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) -{ - return new TextureStorage11_3D(this, internalformat, renderTarget, width, height, depth, levels); -} - -TextureStorage *Renderer11::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) -{ - return new TextureStorage11_2DArray(this, internalformat, renderTarget, width, height, depth, levels); -} - -TextureImpl *Renderer11::createTexture(GLenum target) -{ - switch(target) - { - case GL_TEXTURE_2D: return new TextureD3D_2D(this); - case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); - case GL_TEXTURE_3D: return new TextureD3D_3D(this); - case GL_TEXTURE_2D_ARRAY: return new TextureD3D_2DArray(this); - default: - UNREACHABLE(); - } - - return NULL; -} - -RenderbufferImpl *Renderer11::createRenderbuffer() -{ - RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); - return renderbuffer; -} - -RenderbufferImpl *Renderer11::createRenderbuffer(SwapChain *swapChain, bool depth) -{ - RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); - renderbuffer->setStorage(swapChain, depth); - return renderbuffer; -} - -gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) -{ - ASSERT(area.width >= 0); - ASSERT(area.height >= 0); - - D3D11_TEXTURE2D_DESC textureDesc; - texture->GetDesc(&textureDesc); - - // Clamp read region to the defined texture boundaries, preventing out of bounds reads - // and reads of uninitialized data. - gl::Rectangle safeArea; - safeArea.x = gl::clamp(area.x, 0, static_cast(textureDesc.Width)); - safeArea.y = gl::clamp(area.y, 0, static_cast(textureDesc.Height)); - safeArea.width = gl::clamp(area.width + std::min(area.x, 0), 0, - static_cast(textureDesc.Width) - safeArea.x); - safeArea.height = gl::clamp(area.height + std::min(area.y, 0), 0, - static_cast(textureDesc.Height) - safeArea.y); - - ASSERT(safeArea.x >= 0 && safeArea.y >= 0); - ASSERT(safeArea.x + safeArea.width <= static_cast(textureDesc.Width)); - ASSERT(safeArea.y + safeArea.height <= static_cast(textureDesc.Height)); - - if (safeArea.width == 0 || safeArea.height == 0) - { - // no work to do - return gl::Error(GL_NO_ERROR); - } - - D3D11_TEXTURE2D_DESC stagingDesc; - stagingDesc.Width = safeArea.width; - stagingDesc.Height = safeArea.height; - stagingDesc.MipLevels = 1; - stagingDesc.ArraySize = 1; - stagingDesc.Format = textureDesc.Format; - stagingDesc.SampleDesc.Count = 1; - stagingDesc.SampleDesc.Quality = 0; - stagingDesc.Usage = D3D11_USAGE_STAGING; - stagingDesc.BindFlags = 0; - stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - stagingDesc.MiscFlags = 0; - - ID3D11Texture2D* stagingTex = NULL; - HRESULT result = mDevice->CreateTexture2D(&stagingDesc, NULL, &stagingTex); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging texture for ReadPixels, HRESULT: 0x%X.", result); - } - - ID3D11Texture2D* srcTex = NULL; - if (textureDesc.SampleDesc.Count > 1) - { - D3D11_TEXTURE2D_DESC resolveDesc; - resolveDesc.Width = textureDesc.Width; - resolveDesc.Height = textureDesc.Height; - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; - resolveDesc.Format = textureDesc.Format; - resolveDesc.SampleDesc.Count = 1; - resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = D3D11_USAGE_DEFAULT; - resolveDesc.BindFlags = 0; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; - - result = mDevice->CreateTexture2D(&resolveDesc, NULL, &srcTex); - if (FAILED(result)) - { - SafeRelease(stagingTex); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal resolve texture for ReadPixels, HRESULT: 0x%X.", result); - } - - mDeviceContext->ResolveSubresource(srcTex, 0, texture, subResource, textureDesc.Format); - subResource = 0; - } - else - { - srcTex = texture; - srcTex->AddRef(); - } - - D3D11_BOX srcBox; - srcBox.left = static_cast(safeArea.x); - srcBox.right = static_cast(safeArea.x + safeArea.width); - srcBox.top = static_cast(safeArea.y); - srcBox.bottom = static_cast(safeArea.y + safeArea.height); - srcBox.front = 0; - srcBox.back = 1; - - mDeviceContext->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, srcTex, subResource, &srcBox); - - SafeRelease(srcTex); - - PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); - gl::Error error = packPixels(stagingTex, packParams, pixels); - - SafeRelease(stagingTex); - - return error; -} - -gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut) -{ - D3D11_TEXTURE2D_DESC textureDesc; - readTexture->GetDesc(&textureDesc); - - D3D11_MAPPED_SUBRESOURCE mapping; - HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping); - if (FAILED(hr)) - { - ASSERT(hr == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal texture for reading, result: 0x%X.", hr); - } - - uint8_t *source; - int inputPitch; - if (params.pack.reverseRowOrder) - { - source = static_cast(mapping.pData) + mapping.RowPitch * (params.area.height - 1); - inputPitch = -static_cast(mapping.RowPitch); - } - else - { - source = static_cast(mapping.pData); - inputPitch = static_cast(mapping.RowPitch); - } - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format); - const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(dxgiFormatInfo.internalFormat); - if (sourceFormatInfo.format == params.format && sourceFormatInfo.type == params.type) - { - uint8_t *dest = pixelsOut + params.offset; - for (int y = 0; y < params.area.height; y++) - { - memcpy(dest + y * params.outputPitch, source + y * inputPitch, params.area.width * sourceFormatInfo.pixelBytes); - } - } - else - { - const d3d11::DXGIFormat &sourceDXGIFormatInfo = d3d11::GetDXGIFormatInfo(textureDesc.Format); - ColorCopyFunction fastCopyFunc = sourceDXGIFormatInfo.getFastCopyFunction(params.format, params.type); - - const gl::FormatType &destFormatTypeInfo = gl::GetFormatTypeInfo(params.format, params.type); - const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(destFormatTypeInfo.internalFormat); - - if (fastCopyFunc) - { - // Fast copy is possible through some special function - for (int y = 0; y < params.area.height; y++) - { - for (int x = 0; x < params.area.width; x++) - { - uint8_t *dest = pixelsOut + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes; - const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; - - fastCopyFunc(src, dest); - } - } - } - else - { - uint8_t temp[16]; // Maximum size of any Color type used. - META_ASSERT(sizeof(temp) >= sizeof(gl::ColorF) && - sizeof(temp) >= sizeof(gl::ColorUI) && - sizeof(temp) >= sizeof(gl::ColorI)); - - for (int y = 0; y < params.area.height; y++) - { - for (int x = 0; x < params.area.width; x++) - { - uint8_t *dest = pixelsOut + params.offset + y * params.outputPitch + x * destFormatInfo.pixelBytes; - const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; - - // readFunc and writeFunc will be using the same type of color, CopyTexImage - // will not allow the copy otherwise. - sourceDXGIFormatInfo.colorReadFunction(src, temp); - destFormatTypeInfo.colorWriteFunction(temp, dest); - } - } - } - } - - mDeviceContext->Unmap(readTexture, 0); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, - RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, - bool colorBlit, bool depthBlit, bool stencilBlit) -{ - // Since blitRenderbufferRect is called for each render buffer that needs to be blitted, - // it should never be the case that both color and depth/stencil need to be blitted at - // at the same time. - ASSERT(colorBlit != (depthBlit || stencilBlit)); - - RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget); - if (!drawRenderTarget) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal draw render target from the draw framebuffer."); - } - - ID3D11Resource *drawTexture = drawRenderTarget11->getTexture(); - unsigned int drawSubresource = drawRenderTarget11->getSubresourceIndex(); - ID3D11RenderTargetView *drawRTV = drawRenderTarget11->getRenderTargetView(); - ID3D11DepthStencilView *drawDSV = drawRenderTarget11->getDepthStencilView(); - - RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget); - if (!readRenderTarget) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target from the read framebuffer."); - } - - ID3D11Resource *readTexture = NULL; - ID3D11ShaderResourceView *readSRV = NULL; - unsigned int readSubresource = 0; - if (readRenderTarget->getSamples() > 0) - { - ID3D11Resource *unresolvedResource = readRenderTarget11->getTexture(); - ID3D11Texture2D *unresolvedTexture = d3d11::DynamicCastComObject(unresolvedResource); - - if (unresolvedTexture) - { - readTexture = resolveMultisampledTexture(unresolvedTexture, readRenderTarget11->getSubresourceIndex()); - readSubresource = 0; - - SafeRelease(unresolvedTexture); - - HRESULT hresult = mDevice->CreateShaderResourceView(readTexture, NULL, &readSRV); - if (FAILED(hresult)) - { - SafeRelease(readTexture); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader resource view to resolve multisampled framebuffer."); - } - } - } - else - { - readTexture = readRenderTarget11->getTexture(); - readTexture->AddRef(); - readSubresource = readRenderTarget11->getSubresourceIndex(); - readSRV = readRenderTarget11->getShaderResourceView(); - readSRV->AddRef(); - } - - if (!readTexture || !readSRV) - { - SafeRelease(readTexture); - SafeRelease(readSRV); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target view from the read render target."); - } - - gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); - gl::Extents drawSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); - - bool scissorNeeded = scissor && gl::ClipRectangle(drawRect, *scissor, NULL); - - bool wholeBufferCopy = !scissorNeeded && - readRect.x == 0 && readRect.width == readSize.width && - readRect.y == 0 && readRect.height == readSize.height && - drawRect.x == 0 && drawRect.width == drawSize.width && - drawRect.y == 0 && drawRect.height == drawSize.height; - - bool stretchRequired = readRect.width != drawRect.width || readRect.height != drawRect.height; - - bool flipRequired = readRect.width < 0 || readRect.height < 0 || drawRect.width < 0 || drawRect.height < 0; - - bool outOfBounds = readRect.x < 0 || readRect.x + readRect.width > readSize.width || - readRect.y < 0 || readRect.y + readRect.height > readSize.height || - drawRect.x < 0 || drawRect.x + drawRect.width > drawSize.width || - drawRect.y < 0 || drawRect.y + drawRect.height > drawSize.height; - - const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(drawRenderTarget->getActualFormat()); - bool partialDSBlit = (actualFormatInfo.depthBits > 0 && depthBlit) != (actualFormatInfo.stencilBits > 0 && stencilBlit); - - gl::Error result(GL_NO_ERROR); - - if (readRenderTarget11->getActualFormat() == drawRenderTarget->getActualFormat() && - !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit && - (!(depthBlit || stencilBlit) || wholeBufferCopy)) - { - UINT dstX = drawRect.x; - UINT dstY = drawRect.y; - - D3D11_BOX readBox; - readBox.left = readRect.x; - readBox.right = readRect.x + readRect.width; - readBox.top = readRect.y; - readBox.bottom = readRect.y + readRect.height; - readBox.front = 0; - readBox.back = 1; - - if (scissorNeeded) - { - // drawRect is guaranteed to have positive width and height because stretchRequired is false. - ASSERT(drawRect.width >= 0 || drawRect.height >= 0); - - if (drawRect.x < scissor->x) - { - dstX = scissor->x; - readBox.left += (scissor->x - drawRect.x); - } - if (drawRect.y < scissor->y) - { - dstY = scissor->y; - readBox.top += (scissor->y - drawRect.y); - } - if (drawRect.x + drawRect.width > scissor->x + scissor->width) - { - readBox.right -= ((drawRect.x + drawRect.width) - (scissor->x + scissor->width)); - } - if (drawRect.y + drawRect.height > scissor->y + scissor->height) - { - readBox.bottom -= ((drawRect.y + drawRect.height) - (scissor->y + scissor->height)); - } - } - - // D3D11 needs depth-stencil CopySubresourceRegions to have a NULL pSrcBox - // We also require complete framebuffer copies for depth-stencil blit. - D3D11_BOX *pSrcBox = wholeBufferCopy ? NULL : &readBox; - - mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0, - readTexture, readSubresource, pSrcBox); - result = gl::Error(GL_NO_ERROR); - } - else - { - gl::Box readArea(readRect.x, readRect.y, 0, readRect.width, readRect.height, 1); - gl::Box drawArea(drawRect.x, drawRect.y, 0, drawRect.width, drawRect.height, 1); - - if (depthBlit && stencilBlit) - { - result = mBlit->copyDepthStencil(readTexture, readSubresource, readArea, readSize, - drawTexture, drawSubresource, drawArea, drawSize, - scissor); - } - else if (depthBlit) - { - result = mBlit->copyDepth(readSRV, readArea, readSize, drawDSV, drawArea, drawSize, - scissor); - } - else if (stencilBlit) - { - result = mBlit->copyStencil(readTexture, readSubresource, readArea, readSize, - drawTexture, drawSubresource, drawArea, drawSize, - scissor); - } - else - { - GLenum format = gl::GetInternalFormatInfo(drawRenderTarget->getInternalFormat()).format; - result = mBlit->copyTexture(readSRV, readArea, readSize, drawRTV, drawArea, drawSize, - scissor, format, filter); - } - } - - SafeRelease(readTexture); - SafeRelease(readSRV); - - return result; -} - -ID3D11Texture2D *Renderer11::resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource) -{ - D3D11_TEXTURE2D_DESC textureDesc; - source->GetDesc(&textureDesc); - - if (textureDesc.SampleDesc.Count > 1) - { - D3D11_TEXTURE2D_DESC resolveDesc; - resolveDesc.Width = textureDesc.Width; - resolveDesc.Height = textureDesc.Height; - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; - resolveDesc.Format = textureDesc.Format; - resolveDesc.SampleDesc.Count = 1; - resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = textureDesc.Usage; - resolveDesc.BindFlags = textureDesc.BindFlags; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; - - ID3D11Texture2D *resolveTexture = NULL; - HRESULT result = mDevice->CreateTexture2D(&resolveDesc, NULL, &resolveTexture); - if (FAILED(result)) - { - ERR("Failed to create a multisample resolve texture, HRESULT: 0x%X.", result); - return NULL; - } - - mDeviceContext->ResolveSubresource(resolveTexture, 0, source, subresource, textureDesc.Format); - return resolveTexture; - } - else - { - source->AddRef(); - return source; - } -} - -void Renderer11::invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel) -{ - ASSERT(attachment->isTexture()); - gl::Texture *texture = attachment->getTexture(); - - TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); - TextureStorage *texStorage = textureD3D->getNativeTexture(); - if (texStorage) - { - TextureStorage11 *texStorage11 = TextureStorage11::makeTextureStorage11(texStorage); - if (!texStorage11) - { - ERR("texture storage pointer unexpectedly null."); - return; - } - - texStorage11->invalidateSwizzleCacheLevel(mipLevel); - } -} - -void Renderer11::invalidateFramebufferSwizzles(const gl::Framebuffer *framebuffer) -{ - for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(colorAttachment); - if (attachment && attachment->isTexture()) - { - invalidateFBOAttachmentSwizzles(attachment, attachment->mipLevel()); - } - } - - gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthbuffer(); - if (depthAttachment && depthAttachment->isTexture()) - { - invalidateFBOAttachmentSwizzles(depthAttachment, depthAttachment->mipLevel()); - } - - gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilbuffer(); - if (stencilAttachment && stencilAttachment->isTexture()) - { - invalidateFBOAttachmentSwizzles(stencilAttachment, stencilAttachment->mipLevel()); - } -} - -bool Renderer11::getLUID(LUID *adapterLuid) const -{ - adapterLuid->HighPart = 0; - adapterLuid->LowPart = 0; - - if (!mDxgiAdapter) - { - return false; - } - - DXGI_ADAPTER_DESC adapterDesc; - if (FAILED(mDxgiAdapter->GetDesc(&adapterDesc))) - { - return false; - } - - *adapterLuid = adapterDesc.AdapterLuid; - return true; -} - -VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const -{ - return d3d11::GetVertexFormatInfo(vertexFormat).conversionType; -} - -GLenum Renderer11::getVertexComponentType(const gl::VertexFormat &vertexFormat) const -{ - return d3d11::GetDXGIFormatInfo(d3d11::GetVertexFormatInfo(vertexFormat).nativeFormat).componentType; -} - -void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const -{ - d3d11_gl::GenerateCaps(mDevice, outCaps, outTextureCaps, outExtensions); -} - -Workarounds Renderer11::generateWorkarounds() const -{ - return d3d11::GenerateWorkarounds(); -} - -void Renderer11::setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv) -{ - std::vector ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); - - ASSERT(static_cast(resourceSlot) < currentSRVs.size()); - - if (currentSRVs[resourceSlot] != srv) - { - if (shaderType == gl::SAMPLER_VERTEX) - { - mDeviceContext->VSSetShaderResources(resourceSlot, 1, &srv); - } - else - { - mDeviceContext->PSSetShaderResources(resourceSlot, 1, &srv); - } - - currentSRVs[resourceSlot] = srv; - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h deleted file mode 100644 index d44bd2fd30..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h +++ /dev/null @@ -1,362 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// Renderer11.h: Defines a back-end specific class for the D3D11 renderer. - -#ifndef LIBGLESV2_RENDERER_RENDERER11_H_ -#define LIBGLESV2_RENDERER_RENDERER11_H_ - -#include "common/angleutils.h" -#include "libGLESv2/angletypes.h" -#include "common/mathutil.h" - -#include "libGLESv2/renderer/d3d/d3d11/RenderStateCache.h" -#include "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h" -#include "libGLESv2/renderer/d3d/HLSLCompiler.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/renderer/RenderTarget.h" - -#include "libEGL/AttributeMap.h" - -namespace gl -{ -class FramebufferAttachment; -} - -namespace rx -{ - -class VertexDataManager; -class IndexDataManager; -class StreamingIndexBufferInterface; -class Blit11; -class Clear11; -class PixelTransfer11; -class RenderTarget11; -struct PackPixelsParams; - -enum -{ - MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024, - MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024 -}; - -class Renderer11 : public RendererD3D -{ - public: - Renderer11(egl::Display *display, EGLNativeDisplayType hDc, const egl::AttributeMap &attributes); - virtual ~Renderer11(); - - static Renderer11 *makeRenderer11(Renderer *renderer); - - virtual EGLint initialize(); - virtual bool resetDevice(); - - virtual int generateConfigs(ConfigDesc **configDescList); - virtual void deleteConfigs(ConfigDesc *configDescList); - - virtual gl::Error sync(bool block); - - virtual SwapChain *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); - - virtual gl::Error generateSwizzle(gl::Texture *texture); - virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler); - virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); - - virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); - - virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); - gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask) override; - virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, - int stencilBackRef, bool frontFaceCCW); - - virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); - virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, - bool ignoreViewport); - - virtual bool applyPrimitiveType(GLenum mode, GLsizei count); - gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; - virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, - bool rasterizerDiscard, bool transformFeedbackActive); - - virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray); - virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances); - virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); - virtual void applyTransformFeedbackBuffers(const gl::State &state); - - virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); - virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, - gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); - - gl::Error clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) override; - - virtual void markAllStateDirty(); - - // lost device - void notifyDeviceLost() override; - bool isDeviceLost() override; - bool testDeviceLost(bool notify) override; - bool testDeviceResettable() override; - - DWORD getAdapterVendor() const override; - std::string getRendererDescription() const override; - GUID getAdapterIdentifier() const override; - - virtual unsigned int getReservedVertexUniformVectors() const; - virtual unsigned int getReservedFragmentUniformVectors() const; - virtual unsigned int getReservedVertexUniformBuffers() const; - virtual unsigned int getReservedFragmentUniformBuffers() const; - virtual bool getShareHandleSupport() const; - virtual bool getPostSubBufferSupport() const; - - virtual int getMajorShaderModel() const; - virtual int getMinSwapInterval() const; - virtual int getMaxSwapInterval() const; - - // Pixel operations - virtual gl::Error copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); - virtual gl::Error copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); - virtual gl::Error copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); - virtual gl::Error copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); - - gl::Error blitRect(const gl::Framebuffer *readTarget, const gl::Rectangle &readRect, const gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) override; - - virtual gl::Error readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); - - // RenderTarget creation - virtual gl::Error createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT); - virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT); - - // Shader creation - virtual ShaderImpl *createShader(const gl::Data &data, GLenum type); - virtual ProgramImpl *createProgram(); - - // Shader operations - void releaseShaderCompiler() override; - virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutable **outExecutable); - virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround, - ShaderExecutable **outExectuable); - virtual UniformStorage *createUniformStorage(size_t storageSize); - - // Image operations - virtual Image *createImage(); - gl::Error generateMipmap(Image *dest, Image *source) override; - virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); - virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); - virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); - virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); - virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); - - // Texture creation - virtual TextureImpl *createTexture(GLenum target); - - // Renderbuffer creation - virtual RenderbufferImpl *createRenderbuffer(); - virtual RenderbufferImpl *createRenderbuffer(SwapChain *swapChain, bool depth); - - // Buffer creation - virtual BufferImpl *createBuffer(); - virtual VertexBuffer *createVertexBuffer(); - virtual IndexBuffer *createIndexBuffer(); - - // Vertex Array creation - virtual VertexArrayImpl *createVertexArray(); - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type); - virtual FenceNVImpl *createFenceNV(); - virtual FenceSyncImpl *createFenceSync(); - - // Transform Feedback creation - virtual TransformFeedbackImpl* createTransformFeedback(); - - // D3D11-renderer specific methods - ID3D11Device *getDevice() { return mDevice; } - ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; - DXGIFactory *getDxgiFactory() { return mDxgiFactory; }; - bool isLevel9() { return mFeatureLevel <= D3D_FEATURE_LEVEL_9_3; } - - Blit11 *getBlitter() { return mBlit; } - - // Buffer-to-texture and Texture-to-buffer copies - virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; - virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); - - gl::Error getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, ID3D11Texture2D **texture2DOut); - - void unapplyRenderTargets(); - void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); - gl::Error packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut); - - virtual bool getLUID(LUID *adapterLuid) const; - virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; - virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; - - gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); - - void setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv); - - private: - DISALLOW_COPY_AND_ASSIGN(Renderer11); - - void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override; - Workarounds generateWorkarounds() const override; - - gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); - gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances); - - gl::Error blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, - RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, - bool colorBlit, bool depthBlit, bool stencilBlit); - ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); - void unsetSRVsWithResource(gl::SamplerType shaderType, const ID3D11Resource *resource); - - static void invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel); - static void invalidateFramebufferSwizzles(const gl::Framebuffer *framebuffer); - - HMODULE mD3d11Module; - HMODULE mDxgiModule; - EGLNativeDisplayType mDc; - std::vector mAvailableFeatureLevels; - D3D_DRIVER_TYPE mDriverType; - - HLSLCompiler mCompiler; - - bool mDeviceLost; - - void initializeDevice(); - void releaseDeviceResources(); - int getMinorShaderModel() const; - void release(); - - RenderStateCache mStateCache; - - // current render target states - unsigned int mAppliedRenderTargetSerials[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS]; - unsigned int mAppliedDepthbufferSerial; - unsigned int mAppliedStencilbufferSerial; - bool mDepthStencilInitialized; - bool mRenderTargetDescInitialized; - RenderTarget::Desc mRenderTargetDesc; - - // Currently applied sampler states - std::vector mForceSetVertexSamplerStates; - std::vector mCurVertexSamplerStates; - - std::vector mForceSetPixelSamplerStates; - std::vector mCurPixelSamplerStates; - - // Currently applied textures - std::vector mCurVertexSRVs; - std::vector mCurPixelSRVs; - - // Currently applied blend state - bool mForceSetBlendState; - gl::BlendState mCurBlendState; - gl::ColorF mCurBlendColor; - unsigned int mCurSampleMask; - - // Currently applied rasterizer state - bool mForceSetRasterState; - gl::RasterizerState mCurRasterState; - - // Currently applied depth stencil state - bool mForceSetDepthStencilState; - gl::DepthStencilState mCurDepthStencilState; - int mCurStencilRef; - int mCurStencilBackRef; - - // Currently applied scissor rectangle - bool mForceSetScissor; - bool mScissorEnabled; - gl::Rectangle mCurScissor; - - // Currently applied viewport - bool mForceSetViewport; - gl::Rectangle mCurViewport; - float mCurNear; - float mCurFar; - - // Currently applied primitive topology - D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; - - // Currently applied index buffer - ID3D11Buffer *mAppliedIB; - DXGI_FORMAT mAppliedIBFormat; - unsigned int mAppliedIBOffset; - - // Currently applied transform feedback buffers - ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers - // in use for streamout - GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified - // buffer offsets to transform feedback - // buffers - UINT mCurrentD3DOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the D3D buffer offsets, - // which may differ from GLs, due - // to different append behavior - - // Currently applied shaders - ID3D11VertexShader *mAppliedVertexShader; - ID3D11GeometryShader *mAppliedGeometryShader; - ID3D11GeometryShader *mCurPointGeometryShader; - ID3D11PixelShader *mAppliedPixelShader; - - dx_VertexConstants mVertexConstants; - dx_VertexConstants mAppliedVertexConstants; - ID3D11Buffer *mDriverConstantBufferVS; - ID3D11Buffer *mCurrentVertexConstantBuffer; - unsigned int mCurrentConstantBufferVS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; - - dx_PixelConstants mPixelConstants; - dx_PixelConstants mAppliedPixelConstants; - ID3D11Buffer *mDriverConstantBufferPS; - ID3D11Buffer *mCurrentPixelConstantBuffer; - unsigned int mCurrentConstantBufferPS[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS]; - - ID3D11Buffer *mCurrentGeometryConstantBuffer; - - // Vertex, index and input layouts - VertexDataManager *mVertexDataManager; - IndexDataManager *mIndexDataManager; - InputLayoutCache mInputLayoutCache; - - StreamingIndexBufferInterface *mLineLoopIB; - StreamingIndexBufferInterface *mTriangleFanIB; - - // Texture copy resources - Blit11 *mBlit; - PixelTransfer11 *mPixelTransfer; - - // Masked clear resources - Clear11 *mClear; - - // Sync query - ID3D11Query *mSyncQuery; - - ID3D11Device *mDevice; - D3D_FEATURE_LEVEL mFeatureLevel; - ID3D11DeviceContext *mDeviceContext; - IDXGIAdapter *mDxgiAdapter; - DXGI_ADAPTER_DESC mAdapterDescription; - char mDescription[128]; - DXGIFactory *mDxgiFactory; -}; - -} -#endif // LIBGLESV2_RENDERER_RENDERER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp deleted file mode 100644 index 52f34887fb..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// ShaderExecutable11.cpp: Implements a D3D11-specific class to contain shader -// executable implementation details. - -#include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" - -namespace rx -{ - -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable) - : ShaderExecutable(function, length) -{ - mPixelExecutable = executable; - mVertexExecutable = NULL; - mGeometryExecutable = NULL; - mStreamOutExecutable = NULL; -} - -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut) - : ShaderExecutable(function, length) -{ - mVertexExecutable = executable; - mPixelExecutable = NULL; - mGeometryExecutable = NULL; - mStreamOutExecutable = streamOut; -} - -ShaderExecutable11::ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable) - : ShaderExecutable(function, length) -{ - mGeometryExecutable = executable; - mVertexExecutable = NULL; - mPixelExecutable = NULL; - mStreamOutExecutable = NULL; -} - -ShaderExecutable11::~ShaderExecutable11() -{ - SafeRelease(mVertexExecutable); - SafeRelease(mPixelExecutable); - SafeRelease(mGeometryExecutable); - SafeRelease(mStreamOutExecutable); -} - -ShaderExecutable11 *ShaderExecutable11::makeShaderExecutable11(ShaderExecutable *executable) -{ - ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable11*, executable)); - return static_cast(executable); -} - -ID3D11VertexShader *ShaderExecutable11::getVertexShader() const -{ - return mVertexExecutable; -} - -ID3D11PixelShader *ShaderExecutable11::getPixelShader() const -{ - return mPixelExecutable; -} - -ID3D11GeometryShader *ShaderExecutable11::getGeometryShader() const -{ - return mGeometryExecutable; -} - -ID3D11GeometryShader *ShaderExecutable11::getStreamOutShader() const -{ - return mStreamOutExecutable; -} - -UniformStorage11::UniformStorage11(Renderer11 *renderer, size_t initialSize) - : UniformStorage(initialSize), - mConstantBuffer(NULL) -{ - ID3D11Device *d3d11Device = renderer->getDevice(); - - if (initialSize > 0) - { - D3D11_BUFFER_DESC constantBufferDescription = {0}; - constantBufferDescription.ByteWidth = initialSize; - constantBufferDescription.Usage = D3D11_USAGE_DYNAMIC; - constantBufferDescription.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - constantBufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - constantBufferDescription.MiscFlags = 0; - constantBufferDescription.StructureByteStride = 0; - - HRESULT result = d3d11Device->CreateBuffer(&constantBufferDescription, NULL, &mConstantBuffer); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - } -} - -UniformStorage11::~UniformStorage11() -{ - SafeRelease(mConstantBuffer); -} - -const UniformStorage11 *UniformStorage11::makeUniformStorage11(const UniformStorage *uniformStorage) -{ - ASSERT(HAS_DYNAMIC_TYPE(const UniformStorage11*, uniformStorage)); - return static_cast(uniformStorage); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h deleted file mode 100644 index 74a1e03915..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// ShaderExecutable11.h: Defines a D3D11-specific class to contain shader -// executable implementation details. - -#ifndef LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_ -#define LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_ - -#include "libGLESv2/renderer/ShaderExecutable.h" - -namespace rx -{ -class Renderer11; -class UniformStorage11; - -class ShaderExecutable11 : public ShaderExecutable -{ - public: - ShaderExecutable11(const void *function, size_t length, ID3D11PixelShader *executable); - ShaderExecutable11(const void *function, size_t length, ID3D11VertexShader *executable, ID3D11GeometryShader *streamOut); - ShaderExecutable11(const void *function, size_t length, ID3D11GeometryShader *executable); - - virtual ~ShaderExecutable11(); - - static ShaderExecutable11 *makeShaderExecutable11(ShaderExecutable *executable); - - ID3D11PixelShader *getPixelShader() const; - ID3D11VertexShader *getVertexShader() const; - ID3D11GeometryShader *getGeometryShader() const; - ID3D11GeometryShader *getStreamOutShader() const; - - private: - DISALLOW_COPY_AND_ASSIGN(ShaderExecutable11); - - ID3D11PixelShader *mPixelExecutable; - ID3D11VertexShader *mVertexExecutable; - ID3D11GeometryShader *mGeometryExecutable; - ID3D11GeometryShader *mStreamOutExecutable; -}; - -class UniformStorage11 : public UniformStorage -{ - public: - UniformStorage11(Renderer11 *renderer, size_t initialSize); - virtual ~UniformStorage11(); - - static const UniformStorage11 *makeUniformStorage11(const UniformStorage *uniformStorage); - - ID3D11Buffer *getConstantBuffer() const { return mConstantBuffer; } - - private: - ID3D11Buffer *mConstantBuffer; -}; - -} - -#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp deleted file mode 100644 index 52c8a81633..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp +++ /dev/null @@ -1,675 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain. - -#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" - -// Precompiled shaders -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" -#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" - -#include "common/features.h" -#include "common/NativeWindow.h" - -namespace rx -{ - -SwapChain11::SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, - GLenum backBufferFormat, GLenum depthBufferFormat) - : mRenderer(renderer), - SwapChain(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat) -{ - mSwapChain = NULL; - mBackBufferTexture = NULL; - mBackBufferRTView = NULL; - mOffscreenTexture = NULL; - mOffscreenRTView = NULL; - mOffscreenSRView = NULL; - mDepthStencilTexture = NULL; - mDepthStencilDSView = NULL; - mDepthStencilSRView = NULL; - mQuadVB = NULL; - mPassThroughSampler = NULL; - mPassThroughIL = NULL; - mPassThroughVS = NULL; - mPassThroughPS = NULL; - mWidth = -1; - mHeight = -1; - mRotateL = false; - mRotateR = false; - mSwapInterval = 0; - mAppCreatedShareHandle = mShareHandle != NULL; - mPassThroughResourcesInit = false; -} - -SwapChain11::~SwapChain11() -{ - release(); -} - -void SwapChain11::release() -{ - SafeRelease(mSwapChain); - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); - SafeRelease(mOffscreenTexture); - SafeRelease(mOffscreenRTView); - SafeRelease(mOffscreenSRView); - SafeRelease(mDepthStencilTexture); - SafeRelease(mDepthStencilDSView); - SafeRelease(mDepthStencilSRView); - SafeRelease(mQuadVB); - SafeRelease(mPassThroughSampler); - SafeRelease(mPassThroughIL); - SafeRelease(mPassThroughVS); - SafeRelease(mPassThroughPS); - - if (!mAppCreatedShareHandle) - { - mShareHandle = NULL; - } -} - -void SwapChain11::releaseOffscreenTexture() -{ - SafeRelease(mOffscreenTexture); - SafeRelease(mOffscreenRTView); - SafeRelease(mOffscreenSRView); - SafeRelease(mDepthStencilTexture); - SafeRelease(mDepthStencilDSView); - SafeRelease(mDepthStencilSRView); -} - -EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHeight) -{ - ID3D11Device *device = mRenderer->getDevice(); - - ASSERT(device != NULL); - - // D3D11 does not allow zero size textures - ASSERT(backbufferWidth != 0); - ASSERT(backbufferHeight != 0); - - // Preserve the render target content -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; - if (previousOffscreenTexture) - { - previousOffscreenTexture->AddRef(); - } - const int previousWidth = mWidth; - const int previousHeight = mHeight; -#endif - - releaseOffscreenTexture(); - - const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat); - - // If the app passed in a share handle, open the resource - // See EGL_ANGLE_d3d_share_handle_client_buffer - if (mAppCreatedShareHandle) - { - ID3D11Resource *tempResource11; - HRESULT result = device->OpenSharedResource(mShareHandle, __uuidof(ID3D11Resource), (void**)&tempResource11); - - if (FAILED(result)) - { - ERR("Failed to open the swap chain pbuffer share handle: %08lX", result); - release(); - return EGL_BAD_PARAMETER; - } - - result = tempResource11->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&mOffscreenTexture); - SafeRelease(tempResource11); - - if (FAILED(result)) - { - ERR("Failed to query texture2d interface in pbuffer share handle: %08lX", result); - release(); - return EGL_BAD_PARAMETER; - } - - // Validate offscreen texture parameters - D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; - mOffscreenTexture->GetDesc(&offscreenTextureDesc); - - if (offscreenTextureDesc.Width != UINT(abs(backbufferWidth)) || - offscreenTextureDesc.Height != UINT(abs(backbufferHeight)) || - offscreenTextureDesc.Format != backbufferFormatInfo.texFormat || - offscreenTextureDesc.MipLevels != 1 || - offscreenTextureDesc.ArraySize != 1) - { - ERR("Invalid texture parameters in the shared offscreen texture pbuffer"); - release(); - return EGL_BAD_PARAMETER; - } - } - else - { - const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); - - D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; - offscreenTextureDesc.Width = abs(backbufferWidth); - offscreenTextureDesc.Height = abs(backbufferHeight); - offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; - offscreenTextureDesc.MipLevels = 1; - offscreenTextureDesc.ArraySize = 1; - offscreenTextureDesc.SampleDesc.Count = 1; - offscreenTextureDesc.SampleDesc.Quality = 0; - offscreenTextureDesc.Usage = D3D11_USAGE_DEFAULT; - offscreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; - offscreenTextureDesc.CPUAccessFlags = 0; - offscreenTextureDesc.MiscFlags = useSharedResource ? D3D11_RESOURCE_MISC_SHARED : 0; - - HRESULT result = device->CreateTexture2D(&offscreenTextureDesc, NULL, &mOffscreenTexture); - - if (FAILED(result)) - { - ERR("Could not create offscreen texture: %08lX", result); - release(); - - if (d3d11::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } - } - - d3d11::SetDebugName(mOffscreenTexture, "Offscreen back buffer texture"); - - // EGL_ANGLE_surface_d3d_texture_2d_share_handle requires that we store a share handle for the client - if (useSharedResource) - { - IDXGIResource *offscreenTextureResource = NULL; - result = mOffscreenTexture->QueryInterface(__uuidof(IDXGIResource), (void**)&offscreenTextureResource); - - // Fall back to no share handle on failure - if (FAILED(result)) - { - ERR("Could not query offscreen texture resource: %08lX", result); - } - else - { - result = offscreenTextureResource->GetSharedHandle(&mShareHandle); - SafeRelease(offscreenTextureResource); - - if (FAILED(result)) - { - mShareHandle = NULL; - ERR("Could not get offscreen texture shared handle: %08lX", result); - } - } - } - } - - - D3D11_RENDER_TARGET_VIEW_DESC offscreenRTVDesc; - offscreenRTVDesc.Format = backbufferFormatInfo.rtvFormat; - offscreenRTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - offscreenRTVDesc.Texture2D.MipSlice = 0; - - HRESULT result = device->CreateRenderTargetView(mOffscreenTexture, &offscreenRTVDesc, &mOffscreenRTView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mOffscreenRTView, "Offscreen back buffer render target"); - - D3D11_SHADER_RESOURCE_VIEW_DESC offscreenSRVDesc; - offscreenSRVDesc.Format = backbufferFormatInfo.srvFormat; - offscreenSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - offscreenSRVDesc.Texture2D.MostDetailedMip = 0; - offscreenSRVDesc.Texture2D.MipLevels = -1; - - result = device->CreateShaderResourceView(mOffscreenTexture, &offscreenSRVDesc, &mOffscreenSRView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mOffscreenSRView, "Offscreen back buffer shader resource"); - - const d3d11::TextureFormat &depthBufferFormatInfo = d3d11::GetTextureFormatInfo(mDepthBufferFormat); - - if (mDepthBufferFormat != GL_NONE) - { - D3D11_TEXTURE2D_DESC depthStencilTextureDesc; - depthStencilTextureDesc.Width = abs(backbufferWidth); - depthStencilTextureDesc.Height = abs(backbufferHeight); - depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; - depthStencilTextureDesc.MipLevels = 1; - depthStencilTextureDesc.ArraySize = 1; - depthStencilTextureDesc.SampleDesc.Count = 1; - depthStencilTextureDesc.SampleDesc.Quality = 0; - depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT; - depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; - depthStencilTextureDesc.CPUAccessFlags = 0; - depthStencilTextureDesc.MiscFlags = 0; - - result = device->CreateTexture2D(&depthStencilTextureDesc, NULL, &mDepthStencilTexture); - if (FAILED(result)) - { - ERR("Could not create depthstencil surface for new swap chain: 0x%08X", result); - release(); - - if (d3d11::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } - } - d3d11::SetDebugName(mDepthStencilTexture, "Offscreen depth stencil texture"); - - D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilDesc; - depthStencilDesc.Format = depthBufferFormatInfo.dsvFormat; - depthStencilDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - depthStencilDesc.Flags = 0; - depthStencilDesc.Texture2D.MipSlice = 0; - - result = device->CreateDepthStencilView(mDepthStencilTexture, &depthStencilDesc, &mDepthStencilDSView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mDepthStencilDSView, "Offscreen depth stencil view"); - - D3D11_SHADER_RESOURCE_VIEW_DESC depthStencilSRVDesc; - depthStencilSRVDesc.Format = depthBufferFormatInfo.srvFormat; - depthStencilSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - depthStencilSRVDesc.Texture2D.MostDetailedMip = 0; - depthStencilSRVDesc.Texture2D.MipLevels = -1; - - result = device->CreateShaderResourceView(mDepthStencilTexture, &depthStencilSRVDesc, &mDepthStencilSRView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mDepthStencilSRView, "Offscreen depth stencil shader resource"); - } - - mWidth = backbufferWidth; - mHeight = backbufferHeight; - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - if (previousOffscreenTexture != NULL) - { - D3D11_BOX sourceBox = {0}; - sourceBox.left = 0; - sourceBox.right = std::min(previousWidth, mWidth); - sourceBox.top = std::max(previousHeight - mHeight, 0); - sourceBox.bottom = previousHeight; - sourceBox.front = 0; - sourceBox.back = 1; - - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - const int yoffset = std::max(mHeight - previousHeight, 0); - deviceContext->CopySubresourceRegion(mOffscreenTexture, 0, 0, yoffset, 0, previousOffscreenTexture, 0, &sourceBox); - - SafeRelease(previousOffscreenTexture); - - if (mSwapChain) - { - swapRect(0, 0, mWidth, mHeight); - } - } -#endif - - return EGL_SUCCESS; -} - -EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) -{ - ID3D11Device *device = mRenderer->getDevice(); - - if (device == NULL) - { - return EGL_BAD_ACCESS; - } - - // Windows Phone works around the rotation limitation by using negative values for the swap chain size -#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - mRotateL = backbufferWidth < 0; // Landscape/InvertedLandscape - mRotateR = backbufferHeight < 0; // InvertedPortrait/InvertedLandscape - backbufferWidth = abs(backbufferWidth); - backbufferHeight = abs(backbufferHeight); -#endif - - // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains - if (backbufferWidth == 0 || backbufferHeight == 0) - { - return EGL_SUCCESS; - } - - // Can only call resize if we have already created our swap buffer and resources - ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); - -#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // The swap chain is not directly resized on Windows Phone - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); - - // Resize swap chain - DXGI_SWAP_CHAIN_DESC desc; - mSwapChain->GetDesc(&desc); - const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat); - HRESULT result = mSwapChain->ResizeBuffers(desc.BufferCount, backbufferWidth, backbufferHeight, backbufferFormatInfo.texFormat, 0); - - if (FAILED(result)) - { - ERR("Error resizing swap chain buffers: 0x%08X", result); - release(); - - if (d3d11::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } - } - - result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) - { - d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture"); - } - - result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); - ASSERT(SUCCEEDED(result)); - if (SUCCEEDED(result)) - { - d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); - } -#endif - - return resetOffscreenTexture(backbufferWidth, backbufferHeight); -} - -EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) -{ - ID3D11Device *device = mRenderer->getDevice(); - - if (device == NULL) - { - return EGL_BAD_ACCESS; - } - - // 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. - SafeRelease(mSwapChain); - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); - - mSwapInterval = static_cast(swapInterval); - if (mSwapInterval > 4) - { - // IDXGISwapChain::Present documentation states that valid sync intervals are in the [0,4] range - return EGL_BAD_PARAMETER; - } - - // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains - if (backbufferWidth < 1 || backbufferHeight < 1) - { - releaseOffscreenTexture(); - return EGL_SUCCESS; - } - - if (mNativeWindow.getNativeWindow()) - { - const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat); - - HRESULT result = mNativeWindow.createSwapChain(device, mRenderer->getDxgiFactory(), - backbufferFormatInfo.texFormat, - backbufferWidth, backbufferHeight, &mSwapChain); - - if (FAILED(result)) - { - ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); - release(); - - if (d3d11::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } - } - - result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mBackBufferTexture, "Back buffer texture"); - - result = device->CreateRenderTargetView(mBackBufferTexture, NULL, &mBackBufferRTView); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); - } - - // If we are resizing the swap chain, we don't wish to recreate all the static resources - if (!mPassThroughResourcesInit) - { - mPassThroughResourcesInit = true; - initPassThroughResources(); - } - - return resetOffscreenTexture(backbufferWidth, backbufferHeight); -} - -void SwapChain11::initPassThroughResources() -{ - ID3D11Device *device = mRenderer->getDevice(); - - ASSERT(device != NULL); - - // Make sure our resources are all not allocated, when we create - ASSERT(mQuadVB == NULL && mPassThroughSampler == NULL); - ASSERT(mPassThroughIL == NULL && mPassThroughVS == NULL && mPassThroughPS == NULL); - - D3D11_BUFFER_DESC vbDesc; - vbDesc.ByteWidth = sizeof(d3d11::PositionTexCoordVertex) * 4; - vbDesc.Usage = D3D11_USAGE_DYNAMIC; - vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - vbDesc.MiscFlags = 0; - vbDesc.StructureByteStride = 0; - - HRESULT result = device->CreateBuffer(&vbDesc, NULL, &mQuadVB); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuadVB, "Swap chain quad vertex buffer"); - - D3D11_SAMPLER_DESC samplerDesc; - samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.MipLODBias = 0.0f; - samplerDesc.MaxAnisotropy = 0; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; - samplerDesc.BorderColor[0] = 0.0f; - samplerDesc.BorderColor[1] = 0.0f; - samplerDesc.BorderColor[2] = 0.0f; - samplerDesc.BorderColor[3] = 0.0f; - samplerDesc.MinLOD = 0; - samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; - - result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughSampler, "Swap chain pass through sampler"); - - D3D11_INPUT_ELEMENT_DESC quadLayout[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - result = device->CreateInputLayout(quadLayout, 2, g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), &mPassThroughIL); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughIL, "Swap chain pass through layout"); - - result = device->CreateVertexShader(g_VS_Passthrough2D, sizeof(g_VS_Passthrough2D), NULL, &mPassThroughVS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughVS, "Swap chain pass through vertex shader"); - - result = device->CreatePixelShader(g_PS_PassthroughRGBA2D, sizeof(g_PS_PassthroughRGBA2D), NULL, &mPassThroughPS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mPassThroughPS, "Swap chain pass through pixel shader"); -} - -// parameters should be validated/clamped by caller -EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) -{ - if (!mSwapChain) - { - return EGL_SUCCESS; - } - - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - - // Create a quad in homogeneous coordinates - float x1 = (x / float(mWidth)) * 2.0f - 1.0f; - float y1 = (y / float(mHeight)) * 2.0f - 1.0f; - float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; - float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; - - float u1 = x / float(mWidth); - float v1 = y / float(mHeight); - float u2 = (x + width) / float(mWidth); - float v2 = (y + height) / float(mHeight); - - const bool rotateL = mRotateL; - const bool rotateR = mRotateR; - - // Set vertices - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return EGL_BAD_ACCESS; - } - - d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); - - d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); - d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); - d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); - d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); - - deviceContext->Unmap(mQuadVB, 0); - - static UINT stride = sizeof(d3d11::PositionTexCoordVertex); - static UINT startIdx = 0; - deviceContext->IASetVertexBuffers(0, 1, &mQuadVB, &stride, &startIdx); - - // Apply state - deviceContext->OMSetDepthStencilState(NULL, 0xFFFFFFFF); - - static const float blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - deviceContext->OMSetBlendState(NULL, blendFactor, 0xFFFFFFF); - - deviceContext->RSSetState(NULL); - - // Apply shaders - deviceContext->IASetInputLayout(mPassThroughIL); - deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - deviceContext->VSSetShader(mPassThroughVS, NULL, 0); - deviceContext->PSSetShader(mPassThroughPS, NULL, 0); - deviceContext->GSSetShader(NULL, NULL, 0); - - // Apply render targets - mRenderer->setOneTimeRenderTarget(mBackBufferRTView); - - // Set the viewport - D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0.0f; - viewport.TopLeftY = 0.0f; - const bool invertViewport = (mRotateL || mRotateR) && !(mRotateL && mRotateR); - viewport.Width = FLOAT(invertViewport ? mHeight : mWidth); - viewport.Height = FLOAT(invertViewport ? mWidth : mHeight); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); - - // Apply textures - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, mOffscreenSRView); - deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler); - - // Draw - deviceContext->Draw(4, 0); - -#if ANGLE_VSYNC == ANGLE_DISABLED - result = mSwapChain->Present(0, 0); -#else - result = mSwapChain->Present(mSwapInterval, 0); -#endif - - if (result == DXGI_ERROR_DEVICE_REMOVED) - { - HRESULT removedReason = device->GetDeviceRemovedReason(); - UNUSED_TRACE_VARIABLE(removedReason); - ERR("Present failed: the D3D11 device was removed: 0x%08X", removedReason); - return EGL_CONTEXT_LOST; - } - else if (result == DXGI_ERROR_DEVICE_RESET) - { - ERR("Present failed: the D3D11 device was reset from a bad command."); - return EGL_CONTEXT_LOST; - } - else if (FAILED(result)) - { - ERR("Present failed with error code 0x%08X", result); - } - - // Unbind - mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); - - mRenderer->unapplyRenderTargets(); - mRenderer->markAllStateDirty(); - - return EGL_SUCCESS; -} - -ID3D11Texture2D *SwapChain11::getOffscreenTexture() -{ - return mOffscreenTexture; -} - -ID3D11RenderTargetView *SwapChain11::getRenderTarget() -{ - return mOffscreenRTView; -} - -ID3D11ShaderResourceView *SwapChain11::getRenderTargetShaderResource() -{ - return mOffscreenSRView; -} - -ID3D11DepthStencilView *SwapChain11::getDepthStencil() -{ - return mDepthStencilDSView; -} - -ID3D11ShaderResourceView * SwapChain11::getDepthStencilShaderResource() -{ - return mDepthStencilSRView; -} - -ID3D11Texture2D *SwapChain11::getDepthStencilTexture() -{ - return mDepthStencilTexture; -} - -SwapChain11 *SwapChain11::makeSwapChain11(SwapChain *swapChain) -{ - ASSERT(HAS_DYNAMIC_TYPE(SwapChain11*, swapChain)); - return static_cast(swapChain); -} - -void SwapChain11::recreate() -{ - // possibly should use this method instead of reset -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h deleted file mode 100644 index 77509edcd3..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h +++ /dev/null @@ -1,82 +0,0 @@ -// -// 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. -// - -// SwapChain11.h: Defines a back-end specific class for the D3D11 swap chain. - -#ifndef LIBGLESV2_RENDERER_SWAPCHAIN11_H_ -#define LIBGLESV2_RENDERER_SWAPCHAIN11_H_ - -#include "common/angleutils.h" -#include "libGLESv2/renderer/SwapChain.h" - -namespace rx -{ -class Renderer11; - -class SwapChain11 : public SwapChain -{ - public: - SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, - GLenum backBufferFormat, GLenum depthBufferFormat); - virtual ~SwapChain11(); - - EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); - virtual void recreate(); - - virtual ID3D11Texture2D *getOffscreenTexture(); - virtual ID3D11RenderTargetView *getRenderTarget(); - virtual ID3D11ShaderResourceView *getRenderTargetShaderResource(); - - virtual ID3D11Texture2D *getDepthStencilTexture(); - virtual ID3D11DepthStencilView *getDepthStencil(); - virtual ID3D11ShaderResourceView *getDepthStencilShaderResource(); - - EGLint getWidth() const { return mWidth; } - EGLint getHeight() const { return mHeight; } - - static SwapChain11 *makeSwapChain11(SwapChain *swapChain); - - private: - DISALLOW_COPY_AND_ASSIGN(SwapChain11); - - void release(); - void initPassThroughResources(); - void releaseOffscreenTexture(); - EGLint resetOffscreenTexture(int backbufferWidth, int backbufferHeight); - - Renderer11 *mRenderer; - EGLint mHeight; - EGLint mWidth; - bool mRotateL; - bool mRotateR; - bool mAppCreatedShareHandle; - unsigned int mSwapInterval; - bool mPassThroughResourcesInit; - - DXGISwapChain *mSwapChain; - - ID3D11Texture2D *mBackBufferTexture; - ID3D11RenderTargetView *mBackBufferRTView; - - ID3D11Texture2D *mOffscreenTexture; - ID3D11RenderTargetView *mOffscreenRTView; - ID3D11ShaderResourceView *mOffscreenSRView; - - ID3D11Texture2D *mDepthStencilTexture; - ID3D11DepthStencilView *mDepthStencilDSView; - ID3D11ShaderResourceView *mDepthStencilSRView; - - ID3D11Buffer *mQuadVB; - ID3D11SamplerState *mPassThroughSampler; - ID3D11InputLayout *mPassThroughIL; - ID3D11VertexShader *mPassThroughVS; - ID3D11PixelShader *mPassThroughPS; -}; - -} -#endif // LIBGLESV2_RENDERER_SWAPCHAIN11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp deleted file mode 100644 index 74af27e8b3..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp +++ /dev/null @@ -1,2112 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// TextureStorage11.cpp: Implements the abstract rx::TextureStorage11 class and its concrete derived -// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. - -#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" - -#include - -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" -#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/renderer/d3d/d3d11/Image11.h" -#include "libGLESv2/renderer/d3d/MemoryBuffer.h" -#include "libGLESv2/renderer/d3d/TextureD3D.h" -#include "libGLESv2/main.h" -#include "libGLESv2/ImageIndex.h" - -#include "common/utilities.h" - -namespace rx -{ - -TextureStorage11::SwizzleCacheValue::SwizzleCacheValue() - : swizzleRed(GL_NONE), swizzleGreen(GL_NONE), swizzleBlue(GL_NONE), swizzleAlpha(GL_NONE) -{ -} - -TextureStorage11::SwizzleCacheValue::SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha) - : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha) -{ -} - -bool TextureStorage11::SwizzleCacheValue::operator==(const SwizzleCacheValue &other) const -{ - return swizzleRed == other.swizzleRed && - swizzleGreen == other.swizzleGreen && - swizzleBlue == other.swizzleBlue && - swizzleAlpha == other.swizzleAlpha; -} - -bool TextureStorage11::SwizzleCacheValue::operator!=(const SwizzleCacheValue &other) const -{ - return !(*this == other); -} - -TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) - : baseLevel(baseLevel), mipLevels(mipLevels), swizzle(swizzle) -{ -} - -bool TextureStorage11::SRVKey::operator<(const SRVKey &rhs) const -{ - return std::tie(baseLevel, mipLevels, swizzle) < std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle); -} - -TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags) - : mBindFlags(bindFlags), - mTopLevel(0), - mMipLevels(0), - mInternalFormat(GL_NONE), - mTextureFormat(DXGI_FORMAT_UNKNOWN), - mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), - mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), - mDepthStencilFormat(DXGI_FORMAT_UNKNOWN), - mTextureWidth(0), - mTextureHeight(0), - mTextureDepth(0) -{ - mRenderer = Renderer11::makeRenderer11(renderer); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mLevelSRVs[i] = NULL; - } -} - -TextureStorage11::~TextureStorage11() -{ - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - SafeRelease(mLevelSRVs[level]); - } - - for (SRVCache::iterator i = mSrvCache.begin(); i != mSrvCache.end(); i++) - { - SafeRelease(i->second); - } - mSrvCache.clear(); -} - -TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11*, storage)); - return static_cast(storage); -} - -DWORD TextureStorage11::GetTextureBindFlags(GLenum internalFormat, bool renderTarget) -{ - UINT bindFlags = 0; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat); - if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) - { - bindFlags |= D3D11_BIND_SHADER_RESOURCE; - } - if (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN) - { - bindFlags |= D3D11_BIND_DEPTH_STENCIL; - } - if (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN && renderTarget) - { - bindFlags |= D3D11_BIND_RENDER_TARGET; - } - - return bindFlags; -} - -UINT TextureStorage11::getBindFlags() const -{ - return mBindFlags; -} - -int TextureStorage11::getTopLevel() const -{ - return mTopLevel; -} - -bool TextureStorage11::isRenderTarget() const -{ - return (mBindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL)) != 0; -} - -bool TextureStorage11::isManaged() const -{ - return false; -} - -int TextureStorage11::getLevelCount() const -{ - return mMipLevels - mTopLevel; -} - -int TextureStorage11::getLevelWidth(int mipLevel) const -{ - return std::max(static_cast(mTextureWidth) >> mipLevel, 1); -} - -int TextureStorage11::getLevelHeight(int mipLevel) const -{ - return std::max(static_cast(mTextureHeight) >> mipLevel, 1); -} - -int TextureStorage11::getLevelDepth(int mipLevel) const -{ - return std::max(static_cast(mTextureDepth) >> mipLevel, 1); -} - -UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const -{ - UINT mipSlice = static_cast(index.mipIndex + mTopLevel); - UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); - UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); - ASSERT(subresource != std::numeric_limits::max()); - return subresource; -} - -gl::Error TextureStorage11::getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV) -{ - bool swizzleRequired = samplerState.swizzleRequired(); - bool mipmapping = gl::IsMipmapFiltered(samplerState); - unsigned int mipLevels = mipmapping ? (samplerState.maxLevel - samplerState.baseLevel) : 1; - - // Make sure there's 'mipLevels' mipmap levels below the base level (offset by the top level, which corresponds to GL level 0) - mipLevels = std::min(mipLevels, mMipLevels - mTopLevel - samplerState.baseLevel); - - if (swizzleRequired) - { - verifySwizzleExists(samplerState.swizzleRed, samplerState.swizzleGreen, samplerState.swizzleBlue, samplerState.swizzleAlpha); - } - - SRVKey key(samplerState.baseLevel, mipLevels, swizzleRequired); - SRVCache::const_iterator iter = mSrvCache.find(key); - if (iter != mSrvCache.end()) - { - *outSRV = iter->second; - } - else - { - ID3D11Resource *texture = NULL; - if (swizzleRequired) - { - gl::Error error = getSwizzleTexture(&texture); - if (error.isError()) - { - return error; - } - } - else - { - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } - } - - ID3D11ShaderResourceView *srv = NULL; - DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); - gl::Error error = createSRV(samplerState.baseLevel, mipLevels, format, texture, &srv); - if (error.isError()) - { - return error; - } - - mSrvCache.insert(std::make_pair(key, srv)); - *outSRV = srv; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11::getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV) -{ - ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - - if (!mLevelSRVs[mipLevel]) - { - ID3D11Resource *resource = NULL; - gl::Error error = getResource(&resource); - if (error.isError()) - { - return error; - } - - error = createSRV(mipLevel, 1, mShaderResourceFormat, resource, &mLevelSRVs[mipLevel]); - if (error.isError()) - { - return error; - } - } - - *outSRV = mLevelSRVs[mipLevel]; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) -{ - SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); - for (int level = 0; level < getLevelCount(); level++) - { - // Check if the swizzle for this level is out of date - if (mSwizzleCache[level] != swizzleTarget) - { - // Need to re-render the swizzle for this level - ID3D11ShaderResourceView *sourceSRV = NULL; - gl::Error error = getSRVLevel(level, &sourceSRV); - if (error.isError()) - { - return error; - } - - ID3D11RenderTargetView *destRTV = NULL; - error = getSwizzleRenderTarget(level, &destRTV); - if (error.isError()) - { - return error; - } - - gl::Extents size(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); - - Blit11 *blitter = mRenderer->getBlitter(); - - error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); - if (error.isError()) - { - return error; - } - - mSwizzleCache[level] = swizzleTarget; - } - } - - return gl::Error(GL_NO_ERROR); -} - -void TextureStorage11::invalidateSwizzleCacheLevel(int mipLevel) -{ - if (mipLevel >= 0 && static_cast(mipLevel) < ArraySize(mSwizzleCache)) - { - // The default constructor of SwizzleCacheValue has GL_NONE for all channels which is not a - // valid swizzle combination - mSwizzleCache[mipLevel] = SwizzleCacheValue(); - } -} - -void TextureStorage11::invalidateSwizzleCache() -{ - for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++) - { - invalidateSwizzleCacheLevel(mipLevel); - } -} - -gl::Error TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, - const gl::ImageIndex &index, const gl::Box ©Area) -{ - ASSERT(srcTexture); - - GLint level = index.mipIndex; - - invalidateSwizzleCacheLevel(level); - - gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); - - bool fullCopy = copyArea.x == 0 && - copyArea.y == 0 && - copyArea.z == 0 && - copyArea.width == texSize.width && - copyArea.height == texSize.height && - copyArea.depth == texSize.depth; - - ID3D11Resource *dstTexture = NULL; - gl::Error error = getResource(&dstTexture); - if (error.isError()) - { - return error; - } - - unsigned int dstSubresource = getSubresourceIndex(index); - - ASSERT(dstTexture); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); - if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0)) - { - // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead - Blit11 *blitter = mRenderer->getBlitter(); - - return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, - dstTexture, dstSubresource, copyArea, texSize, - NULL); - } - else - { - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); - - D3D11_BOX srcBox; - srcBox.left = copyArea.x; - srcBox.top = copyArea.y; - srcBox.right = copyArea.x + roundUp(static_cast(copyArea.width), dxgiFormatInfo.blockWidth); - srcBox.bottom = copyArea.y + roundUp(static_cast(copyArea.height), dxgiFormatInfo.blockHeight); - srcBox.front = copyArea.z; - srcBox.back = copyArea.z + copyArea.depth; - - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, - srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, - const gl::ImageIndex &index, const gl::Box ®ion) -{ - ASSERT(dstTexture); - - ID3D11Resource *srcTexture = NULL; - gl::Error error = getResource(&srcTexture); - if (error.isError()) - { - return error; - } - - ASSERT(srcTexture); - - unsigned int srcSubresource = getSubresourceIndex(index); - - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->CopySubresourceRegion(dstTexture, dstSubresource, region.x, region.y, region.z, - srcTexture, srcSubresource, NULL); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) -{ - ASSERT(sourceIndex.layerIndex == destIndex.layerIndex); - - invalidateSwizzleCacheLevel(destIndex.mipIndex); - - RenderTarget *source = NULL; - gl::Error error = getRenderTarget(sourceIndex, &source); - if (error.isError()) - { - return error; - } - - RenderTarget *dest = NULL; - error = getRenderTarget(destIndex, &dest); - if (error.isError()) - { - return error; - } - - ID3D11ShaderResourceView *sourceSRV = RenderTarget11::makeRenderTarget11(source)->getShaderResourceView(); - ID3D11RenderTargetView *destRTV = RenderTarget11::makeRenderTarget11(dest)->getRenderTargetView(); - - gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); - gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); - - gl::Box destArea(0, 0, 0, dest->getWidth(), dest->getHeight(), dest->getDepth()); - gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth()); - - Blit11 *blitter = mRenderer->getBlitter(); - return blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL, - gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR); -} - -void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) -{ - SwizzleCacheValue swizzleTarget(swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); - for (unsigned int level = 0; level < mMipLevels; level++) - { - ASSERT(mSwizzleCache[level] == swizzleTarget); - } -} - -gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage) -{ - ASSERT(destStorage); - - ID3D11Resource *sourceResouce = NULL; - gl::Error error = getResource(&sourceResouce); - if (error.isError()) - { - return error; - } - - TextureStorage11 *dest11 = TextureStorage11::makeTextureStorage11(destStorage); - ID3D11Resource *destResource = NULL; - error = dest11->getResource(&destResource); - if (error.isError()) - { - return error; - } - - ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - immediateContext->CopyResource(destResource, sourceResouce); - - dest11->invalidateSwizzleCache(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11::setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData) -{ - ID3D11Resource *resource = NULL; - gl::Error error = getResource(&resource); - if (error.isError()) - { - return error; - } - ASSERT(resource); - - UINT destSubresource = getSubresourceIndex(index); - - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat()); - - bool fullUpdate = (destBox == NULL || *destBox == gl::Box(0, 0, 0, mTextureWidth, mTextureHeight, mTextureDepth)); - ASSERT(internalFormatInfo.depthBits == 0 || fullUpdate); - - // TODO(jmadill): Handle compressed formats - // Compressed formats have different load syntax, so we'll have to handle them with slightly - // different logic. Will implemnent this in a follow-up patch, and ensure we do not use SetData - // with compressed formats in the calling logic. - ASSERT(!internalFormatInfo.compressed); - - int width = destBox ? destBox->width : static_cast(image->getWidth()); - int height = destBox ? destBox->height : static_cast(image->getHeight()); - int depth = destBox ? destBox->depth : static_cast(image->getDepth()); - UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, width, unpack.alignment); - UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, width, height, unpack.alignment); - - const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat()); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat); - - size_t outputPixelSize = dxgiFormatInfo.pixelBytes; - - UINT bufferRowPitch = outputPixelSize * width; - UINT bufferDepthPitch = bufferRowPitch * height; - - MemoryBuffer conversionBuffer; - if (!conversionBuffer.resize(bufferDepthPitch * depth)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); - } - - // TODO: fast path - LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type); - loadFunction(width, height, depth, - pixelData, srcRowPitch, srcDepthPitch, - conversionBuffer.data(), bufferRowPitch, bufferDepthPitch); - - ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); - - if (!fullUpdate) - { - ASSERT(destBox); - - D3D11_BOX destD3DBox; - destD3DBox.left = destBox->x; - destD3DBox.right = destBox->x + destBox->width; - destD3DBox.top = destBox->y; - destD3DBox.bottom = destBox->y + destBox->height; - destD3DBox.front = 0; - destD3DBox.back = 1; - - immediateContext->UpdateSubresource(resource, destSubresource, - &destD3DBox, conversionBuffer.data(), - bufferRowPitch, bufferDepthPitch); - } - else - { - immediateContext->UpdateSubresource(resource, destSubresource, - NULL, conversionBuffer.data(), - bufferRowPitch, bufferDepthPitch); - } - - return gl::Error(GL_NO_ERROR); -} - -TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain) - : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), - mTexture(swapchain->getOffscreenTexture()), - mSwizzleTexture(NULL) -{ - mTexture->AddRef(); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mAssociatedImages[i] = NULL; - mRenderTarget[i] = NULL; - mSwizzleRenderTargets[i] = NULL; - } - - D3D11_TEXTURE2D_DESC texDesc; - mTexture->GetDesc(&texDesc); - mMipLevels = texDesc.MipLevels; - mTextureFormat = texDesc.Format; - mTextureWidth = texDesc.Width; - mTextureHeight = texDesc.Height; - mTextureDepth = 1; - - mInternalFormat = swapchain->GetBackBufferInternalFormat(); - - ID3D11ShaderResourceView *srv = swapchain->getRenderTargetShaderResource(); - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srv->GetDesc(&srvDesc); - mShaderResourceFormat = srvDesc.Format; - - ID3D11RenderTargetView* offscreenRTV = swapchain->getRenderTarget(); - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - offscreenRTV->GetDesc(&rtvDesc); - mRenderTargetFormat = rtvDesc.Format; - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(dxgiFormatInfo.internalFormat); - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - - mDepthStencilFormat = DXGI_FORMAT_UNKNOWN; - - initializeSerials(1, 1); -} - -TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) - : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)), - mTexture(NULL), - mSwizzleTexture(NULL) -{ - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mAssociatedImages[i] = NULL; - mRenderTarget[i] = NULL; - mSwizzleRenderTargets[i] = NULL; - } - - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); - mMipLevels = mTopLevel + levels; - mTextureWidth = width; - mTextureHeight = height; - mTextureDepth = 1; - - initializeSerials(getLevelCount(), 1); -} - -TextureStorage11_2D::~TextureStorage11_2D() -{ - for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - if (mAssociatedImages[i] != NULL) - { - bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - gl::Error error = mAssociatedImages[i]->recoverFromAssociatedStorage(); - if (error.isError()) - { - // TODO: Find a way to report this back to the context - } - } - } - } - - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - SafeDelete(mRenderTarget[i]); - SafeRelease(mSwizzleRenderTargets[i]); - } -} - -TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage)); - return static_cast(storage); -} - -void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &index) -{ - GLint level = index.mipIndex; - - ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - mAssociatedImages[level] = image; - } -} - -bool TextureStorage11_2D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) -{ - GLint level = index.mipIndex; - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - // This validation check should never return false. It means the Image/TextureStorage association is broken. - bool retValue = (mAssociatedImages[level] == expectedImage); - ASSERT(retValue); - return retValue; - } - - return false; -} - -// disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) -{ - GLint level = index.mipIndex; - - ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - ASSERT(mAssociatedImages[level] == expectedImage); - - if (mAssociatedImages[level] == expectedImage) - { - mAssociatedImages[level] = NULL; - } - } -} - -// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -gl::Error TextureStorage11_2D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) -{ - GLint level = index.mipIndex; - - ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - // No need to let the old Image recover its data, if it is also the incoming Image. - if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) - { - // Ensure that the Image is still associated with this TextureStorage. This should be true. - bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // Force the image to recover from storage before its data is overwritten. - // This will reset mAssociatedImages[level] to NULL too. - gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource) -{ - // 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 (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) - { - ASSERT(mMipLevels > 0); - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; // Compressed texture size constraints? - desc.Height = mTextureHeight; - desc.MipLevels = mRenderer->isLevel9() ? 1 : mMipLevels; - desc.ArraySize = 1; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); - } - } - - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - ASSERT(!index.hasLayer()); - - int level = index.mipIndex; - ASSERT(level >= 0 && level < getLevelCount()); - - if (!mRenderTarget[level]) - { - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } - - ID3D11ShaderResourceView *srv = NULL; - error = getSRVLevel(level, &srv); - if (error.isError()) - { - return error; - } - - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mTopLevel + level; - - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } - - mRenderTarget[level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mDepthStencilFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = mTopLevel + level; - dsvDesc.Flags = 0; - - ID3D11DepthStencilView *dsv; - HRESULT result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY,"Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); - } - - mRenderTarget[level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); - - // RenderTarget will take ownership of these resources - SafeRelease(dsv); - } - else - { - UNREACHABLE(); - } - } - - ASSERT(outRT); - *outRT = mRenderTarget[level]; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const -{ - ASSERT(outSRV); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; - srvDesc.Texture2D.MipLevels = mRenderer->isLevel9() ? -1 : mipLevels; - - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2D::getSwizzleTexture(ID3D11Resource **outTexture) -{ - ASSERT(outTexture); - - if (!mSwizzleTexture) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = 1; - desc.Format = mSwizzleTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); - } - } - - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) -{ - ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - ASSERT(outRTV); - - if (!mSwizzleRenderTargets[mipLevel]) - { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; - - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); - } - } - - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); -} - -TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels) - : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) -{ - mTexture = NULL; - mSwizzleTexture = NULL; - - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - mSwizzleRenderTargets[level] = NULL; - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) - { - mAssociatedImages[face][level] = NULL; - mRenderTarget[face][level] = NULL; - } - } - - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - - // adjust size if needed for compressed textures - int height = size; - d3d11::MakeValidSize(false, mTextureFormat, &size, &height, &mTopLevel); - - mMipLevels = mTopLevel + levels; - mTextureWidth = size; - mTextureHeight = size; - mTextureDepth = 1; - - initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT); -} - -TextureStorage11_Cube::~TextureStorage11_Cube() -{ - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) - { - if (mAssociatedImages[face][level] != NULL) - { - bool imageAssociationCorrect = mAssociatedImages[face][level]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - mAssociatedImages[face][level]->recoverFromAssociatedStorage(); - } - } - } - } - - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); - - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - SafeRelease(mSwizzleRenderTargets[level]); - for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) - { - SafeDelete(mRenderTarget[face][level]); - } - } -} - -TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage)); - return static_cast(storage); -} - -void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index) -{ - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; - - ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) - { - mAssociatedImages[layerTarget][level] = image; - } - } -} - -bool TextureStorage11_Cube::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) -{ - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) - { - // This validation check should never return false. It means the Image/TextureStorage association is broken. - bool retValue = (mAssociatedImages[layerTarget][level] == expectedImage); - ASSERT(retValue); - return retValue; - } - } - - return false; -} - -// disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) -{ - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; - - ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) - { - ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); - - if (mAssociatedImages[layerTarget][level] == expectedImage) - { - mAssociatedImages[layerTarget][level] = NULL; - } - } - } -} - -// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -gl::Error TextureStorage11_Cube::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) -{ - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; - - ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); - - if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)) - { - if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) - { - // No need to let the old Image recover its data, if it is also the incoming Image. - if (mAssociatedImages[layerTarget][level] != NULL && mAssociatedImages[layerTarget][level] != incomingImage) - { - // Ensure that the Image is still associated with this TextureStorage. This should be true. - bool imageAssociationCorrect = mAssociatedImages[layerTarget][level]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // Force the image to recover from storage before its data is overwritten. - // This will reset mAssociatedImages[level] to NULL too. - gl::Error error = mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - } - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_Cube::getResource(ID3D11Resource **outResource) -{ - // 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 (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) - { - ASSERT(mMipLevels > 0); - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = CUBE_FACE_COUNT; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); - } - } - - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - int faceIndex = index.layerIndex; - int level = index.mipIndex; - - ASSERT(level >= 0 && level < getLevelCount()); - ASSERT(faceIndex >= 0 && faceIndex < CUBE_FACE_COUNT); - - if (!mRenderTarget[faceIndex][level]) - { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube - srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.FirstArraySlice = faceIndex; - srvDesc.Texture2DArray.ArraySize = 1; - - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(texture, &srvDesc, &srv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); - } - - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; - rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; - rtvDesc.Texture2DArray.ArraySize = 1; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } - - mRenderTarget[faceIndex][level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - SafeRelease(srv); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mDepthStencilFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; - dsvDesc.Flags = 0; - dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; - dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; - dsvDesc.Texture2DArray.ArraySize = 1; - - ID3D11DepthStencilView *dsv; - result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); - } - - mRenderTarget[faceIndex][level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); - - // RenderTarget will take ownership of these resources - SafeRelease(dsv); - SafeRelease(srv); - } - else - { - UNREACHABLE(); - } - } - - ASSERT(outRT); - *outRT = mRenderTarget[faceIndex][level]; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const -{ - ASSERT(outSRV); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - - // Unnormalized integer cube maps are not supported by DX11; we emulate them as an array of six 2D textures - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); - if (dxgiFormatInfo.componentType == GL_INT || dxgiFormatInfo.componentType == GL_UNSIGNED_INT) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; - } - else - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - srvDesc.TextureCube.MipLevels = mipLevels; - srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; - } - - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_Cube::getSwizzleTexture(ID3D11Resource **outTexture) -{ - ASSERT(outTexture); - - if (!mSwizzleTexture) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = CUBE_FACE_COUNT; - desc.Format = mSwizzleTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - desc.CPUAccessFlags = 0; - desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); - } - } - - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) -{ - ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - ASSERT(outRTV); - - if (!mSwizzleRenderTargets[mipLevel]) - { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture2DArray.FirstArraySlice = 0; - rtvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; - - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); - } - } - - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); -} - -TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, - GLsizei width, GLsizei height, GLsizei depth, int levels) - : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) -{ - mTexture = NULL; - mSwizzleTexture = NULL; - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - mAssociatedImages[i] = NULL; - mLevelRenderTargets[i] = NULL; - mSwizzleRenderTargets[i] = NULL; - } - - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - - // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); - - mMipLevels = mTopLevel + levels; - mTextureWidth = width; - mTextureHeight = height; - mTextureDepth = depth; - - initializeSerials(getLevelCount() * depth, depth); -} - -TextureStorage11_3D::~TextureStorage11_3D() -{ - for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - if (mAssociatedImages[i] != NULL) - { - bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - mAssociatedImages[i]->recoverFromAssociatedStorage(); - } - } - } - - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); - - for (RenderTargetMap::iterator i = mLevelLayerRenderTargets.begin(); i != mLevelLayerRenderTargets.end(); i++) - { - SafeDelete(i->second); - } - mLevelLayerRenderTargets.clear(); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) - { - SafeDelete(mLevelRenderTargets[i]); - SafeRelease(mSwizzleRenderTargets[i]); - } -} - -TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_3D*, storage)); - return static_cast(storage); -} - -void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index) -{ - GLint level = index.mipIndex; - - ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - mAssociatedImages[level] = image; - } -} - -bool TextureStorage11_3D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) -{ - GLint level = index.mipIndex; - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - // This validation check should never return false. It means the Image/TextureStorage association is broken. - bool retValue = (mAssociatedImages[level] == expectedImage); - ASSERT(retValue); - return retValue; - } - - return false; -} - -// disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) -{ - GLint level = index.mipIndex; - - ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - ASSERT(mAssociatedImages[level] == expectedImage); - - if (mAssociatedImages[level] == expectedImage) - { - mAssociatedImages[level] = NULL; - } - } -} - -// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -gl::Error TextureStorage11_3D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) -{ - GLint level = index.mipIndex; - - ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)); - - if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) - { - // No need to let the old Image recover its data, if it is also the incoming Image. - if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage) - { - // Ensure that the Image is still associated with this TextureStorage. This should be true. - bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // Force the image to recover from storage before its data is overwritten. - // This will reset mAssociatedImages[level] to NULL too. - gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_3D::getResource(ID3D11Resource **outResource) -{ - // If the width, height or depth are not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) - { - ASSERT(mMipLevels > 0); - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE3D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.Depth = mTextureDepth; - desc.MipLevels = mMipLevels; - desc.Format = mTextureFormat; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); - } - } - - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const -{ - ASSERT(outSRV); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; - srvDesc.Texture3D.MostDetailedMip = baseLevel; - srvDesc.Texture3D.MipLevels = mipLevels; - - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - int mipLevel = index.mipIndex; - ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - - ASSERT(mRenderTargetFormat != DXGI_FORMAT_UNKNOWN); - - if (!index.hasLayer()) - { - if (!mLevelRenderTargets[mipLevel]) - { - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } - - ID3D11ShaderResourceView *srv = NULL; - error = getSRVLevel(mipLevel, &srv); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = -1; - - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } - - mLevelRenderTargets[mipLevel] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel), 0); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } - - ASSERT(outRT); - *outRT = mLevelRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); - } - else - { - int layer = index.layerIndex; - - LevelLayerKey key(mipLevel, layer); - if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) - { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } - - // TODO, what kind of SRV is expected here? - ID3D11ShaderResourceView *srv = NULL; - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture3D.FirstWSlice = layer; - rtvDesc.Texture3D.WSize = 1; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } - ASSERT(SUCCEEDED(result)); - - mLevelLayerRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } - - ASSERT(outRT); - *outRT = mLevelLayerRenderTargets[key]; - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error TextureStorage11_3D::getSwizzleTexture(ID3D11Resource **outTexture) -{ - ASSERT(outTexture); - - if (!mSwizzleTexture) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE3D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.Depth = mTextureDepth; - desc.MipLevels = mMipLevels; - desc.Format = mSwizzleTextureFormat; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture3D(&desc, NULL, &mSwizzleTexture); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); - } - } - - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) -{ - ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - ASSERT(outRTV); - - if (!mSwizzleRenderTargets[mipLevel]) - { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = -1; - - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); - } - } - - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); -} - -TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, - GLsizei width, GLsizei height, GLsizei depth, int levels) - : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) -{ - mTexture = NULL; - mSwizzleTexture = NULL; - - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - mSwizzleRenderTargets[level] = NULL; - } - - mInternalFormat = internalformat; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); - mTextureFormat = formatInfo.texFormat; - mShaderResourceFormat = formatInfo.srvFormat; - mDepthStencilFormat = formatInfo.dsvFormat; - mRenderTargetFormat = formatInfo.rtvFormat; - mSwizzleTextureFormat = formatInfo.swizzleTexFormat; - mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; - mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - - // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); - - mMipLevels = mTopLevel + levels; - mTextureWidth = width; - mTextureHeight = height; - mTextureDepth = depth; - - initializeSerials(getLevelCount() * depth, depth); -} - -TextureStorage11_2DArray::~TextureStorage11_2DArray() -{ - for (ImageMap::iterator i = mAssociatedImages.begin(); i != mAssociatedImages.end(); i++) - { - bool imageAssociationCorrect = i->second->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // We must let the Images recover their data before we delete it from the TextureStorage. - i->second->recoverFromAssociatedStorage(); - } - } - mAssociatedImages.clear(); - - SafeRelease(mTexture); - SafeRelease(mSwizzleTexture); - - for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) - { - SafeRelease(mSwizzleRenderTargets[level]); - } - - for (RenderTargetMap::iterator i = mRenderTargets.begin(); i != mRenderTargets.end(); i++) - { - SafeDelete(i->second); - } - mRenderTargets.clear(); -} - -TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2DArray*, storage)); - return static_cast(storage); -} - -void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index) -{ - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; - - ASSERT(0 <= level && level < getLevelCount()); - - if (0 <= level && level < getLevelCount()) - { - LevelLayerKey key(level, layerTarget); - mAssociatedImages[key] = image; - } -} - -bool TextureStorage11_2DArray::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) -{ - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; - - LevelLayerKey key(level, layerTarget); - - // This validation check should never return false. It means the Image/TextureStorage association is broken. - bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); - ASSERT(retValue); - return retValue; -} - -// disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) -{ - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; - - LevelLayerKey key(level, layerTarget); - - bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - mAssociatedImages[key] = NULL; - } -} - -// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -gl::Error TextureStorage11_2DArray::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) -{ - GLint level = index.mipIndex; - GLint layerTarget = index.layerIndex; - - LevelLayerKey key(level, layerTarget); - - ASSERT(mAssociatedImages.find(key) != mAssociatedImages.end()); - - if (mAssociatedImages.find(key) != mAssociatedImages.end()) - { - if (mAssociatedImages[key] != NULL && mAssociatedImages[key] != incomingImage) - { - // Ensure that the Image is still associated with this TextureStorage. This should be true. - bool imageAssociationCorrect = mAssociatedImages[key]->isAssociatedStorageValid(this); - ASSERT(imageAssociationCorrect); - - if (imageAssociationCorrect) - { - // Force the image to recover from storage before its data is overwritten. - // This will reset mAssociatedImages[level] to NULL too. - gl::Error error = mAssociatedImages[key]->recoverFromAssociatedStorage(); - if (error.isError()) - { - return error; - } - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2DArray::getResource(ID3D11Resource **outResource) -{ - // if the width, height or depth is not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) - { - ASSERT(mMipLevels > 0); - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = mTextureDepth; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); - } - } - - *outResource = mTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const -{ - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; - srvDesc.Texture2DArray.MipLevels = mipLevels; - srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.ArraySize = mTextureDepth; - - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - ASSERT(index.hasLayer()); - - int mipLevel = index.mipIndex; - int layer = index.layerIndex; - - ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - - LevelLayerKey key(mipLevel, layer); - if (mRenderTargets.find(key) == mRenderTargets.end()) - { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - ID3D11Resource *texture = NULL; - gl::Error error = getResource(&texture); - if (error.isError()) - { - return error; - } - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + mipLevel; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.FirstArraySlice = layer; - srvDesc.Texture2DArray.ArraySize = 1; - - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(texture, &srvDesc, &srv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); - } - - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture2DArray.FirstArraySlice = layer; - rtvDesc.Texture2DArray.ArraySize = 1; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - SafeRelease(srv); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); - } - - mRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - SafeRelease(srv); - } - else - { - UNREACHABLE(); - } - } - - ASSERT(outRT); - *outRT = mRenderTargets[key]; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2DArray::getSwizzleTexture(ID3D11Resource **outTexture) -{ - if (!mSwizzleTexture) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; - desc.Height = mTextureHeight; - desc.MipLevels = mMipLevels; - desc.ArraySize = mTextureDepth; - desc.Format = mSwizzleTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); - } - } - - *outTexture = mSwizzleTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) -{ - ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - ASSERT(outRTV); - - if (!mSwizzleRenderTargets[mipLevel]) - { - ID3D11Resource *swizzleTexture = NULL; - gl::Error error = getSwizzleTexture(&swizzleTexture); - if (error.isError()) - { - return error; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture2DArray.FirstArraySlice = 0; - rtvDesc.Texture2DArray.ArraySize = mTextureDepth; - - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); - - ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); - } - } - - *outRTV = mSwizzleRenderTargets[mipLevel]; - return gl::Error(GL_NO_ERROR); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h deleted file mode 100644 index 930300a63d..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h +++ /dev/null @@ -1,298 +0,0 @@ -// -// Copyright (c) 2012-2013 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. -// - -// TextureStorage11.h: Defines the abstract rx::TextureStorage11 class and its concrete derived -// classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. - -#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ -#define LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ - -#include "libGLESv2/Texture.h" -#include "libGLESv2/Error.h" -#include "libGLESv2/renderer/d3d/TextureStorage.h" - -#include - -namespace gl -{ -struct ImageIndex; -} - -namespace rx -{ -class RenderTarget; -class RenderTarget11; -class Renderer11; -class SwapChain11; -class Image11; - -class TextureStorage11 : public TextureStorage -{ - public: - virtual ~TextureStorage11(); - - static TextureStorage11 *makeTextureStorage11(TextureStorage *storage); - - static DWORD GetTextureBindFlags(GLenum internalFormat, bool renderTarget); - - UINT getBindFlags() const; - - virtual gl::Error getResource(ID3D11Resource **outResource) = 0; - virtual gl::Error getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) = 0; - - virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); - - virtual int getTopLevel() const; - virtual bool isRenderTarget() const; - virtual bool isManaged() const; - virtual int getLevelCount() const; - UINT getSubresourceIndex(const gl::ImageIndex &index) const; - - gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); - void invalidateSwizzleCacheLevel(int mipLevel); - void invalidateSwizzleCache(); - - gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, - const gl::ImageIndex &index, const gl::Box ©Area); - - gl::Error copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, - const gl::ImageIndex &index, const gl::Box ®ion); - - virtual void associateImage(Image11* image, const gl::ImageIndex &index) = 0; - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) = 0; - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) = 0; - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0; - - virtual gl::Error copyToStorage(TextureStorage *destStorage); - virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData); - - protected: - TextureStorage11(Renderer11 *renderer, UINT bindFlags); - int getLevelWidth(int mipLevel) const; - int getLevelHeight(int mipLevel) const; - int getLevelDepth(int mipLevel) const; - - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture) = 0; - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) = 0; - gl::Error getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV); - - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const = 0; - - void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); - - Renderer11 *mRenderer; - int mTopLevel; - unsigned int mMipLevels; - - GLenum mInternalFormat; - DXGI_FORMAT mTextureFormat; - DXGI_FORMAT mShaderResourceFormat; - DXGI_FORMAT mRenderTargetFormat; - DXGI_FORMAT mDepthStencilFormat; - DXGI_FORMAT mSwizzleTextureFormat; - DXGI_FORMAT mSwizzleShaderResourceFormat; - DXGI_FORMAT mSwizzleRenderTargetFormat; - unsigned int mTextureWidth; - unsigned int mTextureHeight; - unsigned int mTextureDepth; - - struct SwizzleCacheValue - { - GLenum swizzleRed; - GLenum swizzleGreen; - GLenum swizzleBlue; - GLenum swizzleAlpha; - - SwizzleCacheValue(); - SwizzleCacheValue(GLenum red, GLenum green, GLenum blue, GLenum alpha); - - bool operator ==(const SwizzleCacheValue &other) const; - bool operator !=(const SwizzleCacheValue &other) const; - }; - SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage11); - - const UINT mBindFlags; - - struct SRVKey - { - SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); - - bool operator<(const SRVKey &rhs) const; - - int baseLevel; - int mipLevels; - bool swizzle; - }; - typedef std::map SRVCache; - - SRVCache mSrvCache; - ID3D11ShaderResourceView *mLevelSRVs[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -class TextureStorage11_2D : public TextureStorage11 -{ - public: - TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain); - TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); - virtual ~TextureStorage11_2D(); - - static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage); - - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - - virtual void associateImage(Image11* image, const gl::ImageIndex &index); - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); - - protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2D); - - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; - - ID3D11Texture2D *mTexture; - RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -class TextureStorage11_Cube : public TextureStorage11 -{ - public: - TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels); - virtual ~TextureStorage11_Cube(); - - static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage); - - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - - virtual void associateImage(Image11* image, const gl::ImageIndex &index); - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); - - protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube); - - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; - - static const size_t CUBE_FACE_COUNT = 6; - - ID3D11Texture2D *mTexture; - RenderTarget11 *mRenderTarget[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - Image11 *mAssociatedImages[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -class TextureStorage11_3D : public TextureStorage11 -{ - public: - TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, - GLsizei width, GLsizei height, GLsizei depth, int levels); - virtual ~TextureStorage11_3D(); - - static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage); - - virtual gl::Error getResource(ID3D11Resource **outResource); - - // Handles both layer and non-layer RTs - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - - virtual void associateImage(Image11* image, const gl::ImageIndex &index); - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); - - protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage11_3D); - - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; - - typedef std::pair LevelLayerKey; - typedef std::map RenderTargetMap; - RenderTargetMap mLevelLayerRenderTargets; - - RenderTarget11 *mLevelRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - ID3D11Texture3D *mTexture; - ID3D11Texture3D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; -}; - -class TextureStorage11_2DArray : public TextureStorage11 -{ - public: - TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, - GLsizei width, GLsizei height, GLsizei depth, int levels); - virtual ~TextureStorage11_2DArray(); - - static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage); - - virtual gl::Error getResource(ID3D11Resource **outResource); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - - virtual void associateImage(Image11* image, const gl::ImageIndex &index); - virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); - virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); - virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); - - protected: - virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); - virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2DArray); - - virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, - ID3D11ShaderResourceView **outSRV) const; - - typedef std::pair LevelLayerKey; - typedef std::map RenderTargetMap; - RenderTargetMap mRenderTargets; - - ID3D11Texture2D *mTexture; - - ID3D11Texture2D *mSwizzleTexture; - ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - typedef std::map ImageMap; - ImageMap mAssociatedImages; -}; - -} - -#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h deleted file mode 100644 index 70bc3bb26f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2014 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. -// - -// VertexArray11.h: Defines the rx::VertexArray11 class which implements rx::VertexArrayImpl. - -#ifndef LIBGLESV2_RENDERER_VERTEXARRAY11_H_ -#define LIBGLESV2_RENDERER_VERTEXARRAY11_H_ - -#include "libGLESv2/renderer/VertexArrayImpl.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" - -namespace rx -{ -class Renderer11; - -class VertexArray11 : public VertexArrayImpl -{ - public: - VertexArray11(Renderer11 *renderer) - : VertexArrayImpl(), - mRenderer(renderer) - { - } - virtual ~VertexArray11() { } - - virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } - virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } - virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } - virtual void enableAttribute(size_t idx, bool enabledState) { } - - private: - DISALLOW_COPY_AND_ASSIGN(VertexArray11); - - Renderer11 *mRenderer; -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXARRAY11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp deleted file mode 100644 index a9d6fa2ca4..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// VertexBuffer11.cpp: Defines the D3D11 VertexBuffer implementation. - -#include "libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" -#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/VertexAttribute.h" - -namespace rx -{ - -VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) -{ - mBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; -} - -VertexBuffer11::~VertexBuffer11() -{ - SafeRelease(mBuffer); -} - -gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) -{ - SafeRelease(mBuffer); - - updateSerial(); - - if (size > 0) - { - ID3D11Device* dxDevice = mRenderer->getDevice(); - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = size; - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - - HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); - } - } - - mBufferSize = size; - mDynamicUsage = dynamicUsage; - - return gl::Error(GL_NO_ERROR); -} - -VertexBuffer11 *VertexBuffer11::makeVertexBuffer11(VertexBuffer *vetexBuffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer11*, vetexBuffer)); - return static_cast(vetexBuffer); -} - -gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int offset) -{ - if (!mBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); - } - - gl::Buffer *buffer = attrib.buffer.get(); - int inputStride = ComputeVertexAttributeStride(attrib); - ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer, HRESULT: 0x%08x.", result); - } - - uint8_t *output = reinterpret_cast(mappedResource.pData) + offset; - - const uint8_t *input = NULL; - if (attrib.enabled) - { - if (buffer) - { - BufferD3D *storage = BufferD3D::makeFromBuffer(buffer); - gl::Error error = storage->getData(&input); - if (error.isError()) - { - return error; - } - input += static_cast(attrib.offset); - } - else - { - input = static_cast(attrib.pointer); - } - } - else - { - input = reinterpret_cast(currentValue.FloatValues); - } - - if (instances == 0 || attrib.divisor == 0) - { - input += inputStride * start; - } - - gl::VertexFormat vertexFormat(attrib, currentValue.Type); - const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat); - ASSERT(vertexFormatInfo.copyFunction != NULL); - vertexFormatInfo.copyFunction(input, inputStride, count, output); - - dxContext->Unmap(mBuffer, 0); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, - GLsizei instances, unsigned int *outSpaceRequired) const -{ - unsigned int elementCount = 0; - if (attrib.enabled) - { - if (instances == 0 || attrib.divisor == 0) - { - elementCount = count; - } - else - { - // Round up to divisor, if possible - elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); - } - - gl::VertexFormat vertexFormat(attrib); - const d3d11::VertexFormat &vertexFormatInfo = d3d11::GetVertexFormatInfo(vertexFormat); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(vertexFormatInfo.nativeFormat); - unsigned int elementSize = dxgiFormatInfo.pixelBytes; - if (elementSize <= std::numeric_limits::max() / elementCount) - { - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * elementCount; - } - return gl::Error(GL_NO_ERROR); - } - else - { - return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); - } - } - else - { - const unsigned int elementSize = 4; - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * 4; - } - return gl::Error(GL_NO_ERROR); - } -} - -unsigned int VertexBuffer11::getBufferSize() const -{ - return mBufferSize; -} - -gl::Error VertexBuffer11::setBufferSize(unsigned int size) -{ - if (size > mBufferSize) - { - return initialize(size, mDynamicUsage); - } - else - { - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error VertexBuffer11::discard() -{ - if (!mBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); - } - - ID3D11DeviceContext *dxContext = mRenderer->getDeviceContext(); - - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = dxContext->Map(mBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer for discarding, HRESULT: 0x%08x", result); - } - - dxContext->Unmap(mBuffer, 0); - - return gl::Error(GL_NO_ERROR); -} - -ID3D11Buffer *VertexBuffer11::getBuffer() const -{ - return mBuffer; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h deleted file mode 100644 index a9bbac98fa..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// 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. -// - -// VertexBuffer11.h: Defines the D3D11 VertexBuffer implementation. - -#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ -#define LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ - -#include "libGLESv2/renderer/d3d/VertexBuffer.h" - -namespace rx -{ -class Renderer11; - -class VertexBuffer11 : public VertexBuffer -{ - public: - explicit VertexBuffer11(Renderer11 *const renderer); - virtual ~VertexBuffer11(); - - virtual gl::Error initialize(unsigned int size, bool dynamicUsage); - - static VertexBuffer11 *makeVertexBuffer11(VertexBuffer *vetexBuffer); - - virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int offset); - - virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, - unsigned int *outSpaceRequired) const; - - virtual unsigned int getBufferSize() const; - virtual gl::Error setBufferSize(unsigned int size); - virtual gl::Error discard(); - - ID3D11Buffer *getBuffer() const; - - private: - DISALLOW_COPY_AND_ASSIGN(VertexBuffer11); - - Renderer11 *const mRenderer; - - ID3D11Buffer *mBuffer; - unsigned int mBufferSize; - bool mDynamicUsage; -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXBUFFER11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp deleted file mode 100644 index 90a879e170..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp +++ /dev/null @@ -1,1075 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// formatutils11.cpp: Queries for GL image formats and their translations to D3D11 -// formats. - -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/renderer/generatemip.h" -#include "libGLESv2/renderer/loadimage.h" -#include "libGLESv2/renderer/copyimage.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/copyvertex.h" - -namespace rx -{ - -namespace d3d11 -{ - -typedef std::map DXGIToESFormatMap; - -inline void AddDXGIToESEntry(DXGIToESFormatMap *map, DXGI_FORMAT key, GLenum value) -{ - map->insert(std::make_pair(key, value)); -} - -static DXGIToESFormatMap BuildDXGIToESFormatMap() -{ - DXGIToESFormatMap map; - - AddDXGIToESEntry(&map, DXGI_FORMAT_UNKNOWN, GL_NONE); - - AddDXGIToESEntry(&map, DXGI_FORMAT_A8_UNORM, GL_ALPHA8_EXT); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UNORM, GL_R8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UNORM, GL_RG8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM, GL_RGBA8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, GL_SRGB8_ALPHA8); - AddDXGIToESEntry(&map, DXGI_FORMAT_B8G8R8A8_UNORM, GL_BGRA8_EXT); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SNORM, GL_R8_SNORM); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SNORM, GL_RG8_SNORM); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SNORM, GL_RGBA8_SNORM); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R8_UINT, GL_R8UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UINT, GL_R16UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_UINT, GL_R32UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_UINT, GL_RG8UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_UINT, GL_RG16UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_UINT, GL_RG32UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_UINT, GL_RGB32UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_UINT, GL_RGBA8UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_UINT, GL_RGBA16UI); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_UINT, GL_RGBA32UI); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R8_SINT, GL_R8I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_SINT, GL_R16I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_SINT, GL_R32I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8_SINT, GL_RG8I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_SINT, GL_RG16I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_SINT, GL_RG32I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_SINT, GL_RGB32I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R8G8B8A8_SINT, GL_RGBA8I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_SINT, GL_RGBA16I); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_SINT, GL_RGBA32I); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UNORM, GL_RGB10_A2); - AddDXGIToESEntry(&map, DXGI_FORMAT_R10G10B10A2_UINT, GL_RGB10_A2UI); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_FLOAT, GL_R16F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16_FLOAT, GL_RG16F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, GL_RGBA16F); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT, GL_R32F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32_FLOAT, GL_RG32F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32_FLOAT, GL_RGB32F); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, GL_RGBA32F); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, GL_RGB9_E5); - AddDXGIToESEntry(&map, DXGI_FORMAT_R11G11B10_FLOAT, GL_R11F_G11F_B10F); - - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_TYPELESS, GL_DEPTH_COMPONENT16); - AddDXGIToESEntry(&map, DXGI_FORMAT_R16_UNORM, GL_DEPTH_COMPONENT16); - AddDXGIToESEntry(&map, DXGI_FORMAT_D16_UNORM, GL_DEPTH_COMPONENT16); - AddDXGIToESEntry(&map, DXGI_FORMAT_R24G8_TYPELESS, GL_DEPTH24_STENCIL8_OES); - AddDXGIToESEntry(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, GL_DEPTH24_STENCIL8_OES); - AddDXGIToESEntry(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, GL_DEPTH24_STENCIL8_OES); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32G8X24_TYPELESS, GL_DEPTH32F_STENCIL8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, GL_DEPTH32F_STENCIL8); - AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, GL_DEPTH32F_STENCIL8); - AddDXGIToESEntry(&map, DXGI_FORMAT_R32_TYPELESS, GL_DEPTH_COMPONENT32F); - AddDXGIToESEntry(&map, DXGI_FORMAT_D32_FLOAT, GL_DEPTH_COMPONENT32F); - - AddDXGIToESEntry(&map, DXGI_FORMAT_BC1_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); - AddDXGIToESEntry(&map, DXGI_FORMAT_BC2_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE); - AddDXGIToESEntry(&map, DXGI_FORMAT_BC3_UNORM, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE); - - return map; -} - -struct D3D11FastCopyFormat -{ - GLenum destFormat; - GLenum destType; - ColorCopyFunction copyFunction; - - D3D11FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) - : destFormat(destFormat), destType(destType), copyFunction(copyFunction) - { } - - bool operator<(const D3D11FastCopyFormat& other) const - { - return memcmp(this, &other, sizeof(D3D11FastCopyFormat)) < 0; - } -}; - -typedef std::multimap D3D11FastCopyMap; - -static D3D11FastCopyMap BuildFastCopyMap() -{ - D3D11FastCopyMap map; - - map.insert(std::make_pair(DXGI_FORMAT_B8G8R8A8_UNORM, D3D11FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); - - return map; -} - -struct DXGIDepthStencilInfo -{ - unsigned int depthBits; - unsigned int depthOffset; - unsigned int stencilBits; - unsigned int stencilOffset; -}; - -typedef std::map DepthStencilInfoMap; -typedef std::pair DepthStencilInfoPair; - -static inline void InsertDXGIDepthStencilInfo(DepthStencilInfoMap *map, DXGI_FORMAT format, unsigned int depthBits, - unsigned int depthOffset, unsigned int stencilBits, unsigned int stencilOffset) -{ - DXGIDepthStencilInfo info; - info.depthBits = depthBits; - info.depthOffset = depthOffset; - info.stencilBits = stencilBits; - info.stencilOffset = stencilOffset; - - map->insert(std::make_pair(format, info)); -} - -static DepthStencilInfoMap BuildDepthStencilInfoMap() -{ - DepthStencilInfoMap map; - - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R16_TYPELESS, 16, 0, 0, 0); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R16_UNORM, 16, 0, 0, 0); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D16_UNORM, 16, 0, 0, 0); - - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R24G8_TYPELESS, 24, 0, 8, 24); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 24, 0, 8, 24); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 24, 0, 8, 24); - - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_TYPELESS, 32, 0, 0, 0); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_FLOAT, 32, 0, 0, 0); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D32_FLOAT, 32, 0, 0, 0); - - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 32, 0, 8, 32); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 32, 0, 8, 32); - InsertDXGIDepthStencilInfo(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 32, 0, 8, 32); - - return map; -} - -typedef std::map DXGIFormatInfoMap; - -DXGIFormat::DXGIFormat() - : pixelBytes(0), - blockWidth(0), - blockHeight(0), - depthBits(0), - depthOffset(0), - stencilBits(0), - stencilOffset(0), - internalFormat(GL_NONE), - componentType(GL_NONE), - mipGenerationFunction(NULL), - colorReadFunction(NULL), - fastCopyFunctions() -{ -} - -ColorCopyFunction DXGIFormat::getFastCopyFunction(GLenum format, GLenum type) const -{ - FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); - return (iter != fastCopyFunctions.end()) ? iter->second : NULL; -} - -void AddDXGIFormat(DXGIFormatInfoMap *map, DXGI_FORMAT dxgiFormat, GLuint pixelBits, GLuint blockWidth, GLuint blockHeight, - GLenum componentType, MipGenerationFunction mipFunc, ColorReadFunction readFunc) -{ - DXGIFormat info; - info.pixelBytes = pixelBits / 8; - info.blockWidth = blockWidth; - info.blockHeight = blockHeight; - - static const DepthStencilInfoMap dsInfoMap = BuildDepthStencilInfoMap(); - DepthStencilInfoMap::const_iterator dsInfoIter = dsInfoMap.find(dxgiFormat); - if (dsInfoIter != dsInfoMap.end()) - { - info.depthBits = dsInfoIter->second.depthBits; - info.depthOffset = dsInfoIter->second.depthOffset; - info.stencilBits = dsInfoIter->second.stencilBits; - info.stencilOffset = dsInfoIter->second.stencilOffset; - } - else - { - info.depthBits = 0; - info.depthOffset = 0; - info.stencilBits = 0; - info.stencilOffset = 0; - } - - static const DXGIToESFormatMap dxgiToESMap = BuildDXGIToESFormatMap(); - DXGIToESFormatMap::const_iterator dxgiToESIter = dxgiToESMap.find(dxgiFormat); - info.internalFormat = (dxgiToESIter != dxgiToESMap.end()) ? dxgiToESIter->second : GL_NONE; - - info.componentType = componentType; - - info.mipGenerationFunction = mipFunc; - info.colorReadFunction = readFunc; - - static const D3D11FastCopyMap fastCopyMap = BuildFastCopyMap(); - std::pair fastCopyIter = fastCopyMap.equal_range(dxgiFormat); - for (D3D11FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) - { - info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); - } - - map->insert(std::make_pair(dxgiFormat, info)); -} - -// A map to determine the pixel size and mipmap generation function of a given DXGI format -static DXGIFormatInfoMap BuildDXGIFormatInfoMap() -{ - DXGIFormatInfoMap map; - - // | DXGI format |S |W |H |Component Type | Mip generation function | Color read function - AddDXGIFormat(&map, DXGI_FORMAT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL); - - AddDXGIFormat(&map, DXGI_FORMAT_A8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8_UNORM, 8, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_B8G8R8A8_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R8_SNORM, 8, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R8_UINT, 8, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_UINT, 16, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_UINT, 96, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UINT, 64, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_UINT, 128, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R8_SINT, 8, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8_SINT, 16, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_SINT, 96, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R8G8B8A8_SINT, 32, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SINT, 64, 1, 1, GL_INT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_SINT, 128, 1, 1, GL_INT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R10G10B10A2_UINT, 32, 1, 1, GL_UNSIGNED_INT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R16_FLOAT, 16, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32_FLOAT, 64, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32_FLOAT, 96, 1, 1, GL_FLOAT, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R32G32B32A32_FLOAT, 128, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - AddDXGIFormat(&map, DXGI_FORMAT_R11G11B10_FLOAT, 32, 1, 1, GL_FLOAT, GenerateMip, ReadColor); - - AddDXGIFormat(&map, DXGI_FORMAT_R16_TYPELESS, 16, 1, 1, GL_NONE, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_D16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R24G8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_D24_UNORM_S8_UINT, 32, 1, 1, GL_UNSIGNED_INT, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R32G8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, 64, 1, 1, GL_NONE, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, 64, 1, 1, GL_UNSIGNED_INT, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R32_TYPELESS, 32, 1, 1, GL_NONE, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_D32_FLOAT, 32, 1, 1, GL_FLOAT, NULL, NULL); - - AddDXGIFormat(&map, DXGI_FORMAT_BC1_UNORM, 64, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_BC2_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_BC3_UNORM, 128, 4, 4, GL_UNSIGNED_NORMALIZED, NULL, NULL); - - // Useful formats for vertex buffers - AddDXGIFormat(&map, DXGI_FORMAT_R16_UNORM, 16, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R16_SNORM, 16, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_UNORM, 32, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16_SNORM, 32, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_UNORM, 64, 1, 1, GL_UNSIGNED_NORMALIZED, NULL, NULL); - AddDXGIFormat(&map, DXGI_FORMAT_R16G16B16A16_SNORM, 64, 1, 1, GL_SIGNED_NORMALIZED, NULL, NULL); - - return map; -} - -const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format) -{ - static const DXGIFormatInfoMap infoMap = BuildDXGIFormatInfoMap(); - DXGIFormatInfoMap::const_iterator iter = infoMap.find(format); - if (iter != infoMap.end()) - { - return iter->second; - } - else - { - static DXGIFormat defaultInfo; - return defaultInfo; - } -} - -struct SwizzleSizeType -{ - size_t maxComponentSize; - GLenum componentType; - - SwizzleSizeType() - : maxComponentSize(0), componentType(GL_NONE) - { } - - SwizzleSizeType(size_t maxComponentSize, GLenum componentType) - : maxComponentSize(maxComponentSize), componentType(componentType) - { } - - bool operator<(const SwizzleSizeType& other) const - { - return (maxComponentSize != other.maxComponentSize) ? (maxComponentSize < other.maxComponentSize) - : (componentType < other.componentType); - } -}; - -struct SwizzleFormatInfo -{ - DXGI_FORMAT mTexFormat; - DXGI_FORMAT mSRVFormat; - DXGI_FORMAT mRTVFormat; - - SwizzleFormatInfo() - : mTexFormat(DXGI_FORMAT_UNKNOWN), mSRVFormat(DXGI_FORMAT_UNKNOWN), mRTVFormat(DXGI_FORMAT_UNKNOWN) - { } - - SwizzleFormatInfo(DXGI_FORMAT texFormat, DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat) - : mTexFormat(texFormat), mSRVFormat(srvFormat), mRTVFormat(rtvFormat) - { } -}; - -typedef std::map SwizzleInfoMap; -typedef std::pair SwizzleInfoPair; - -static SwizzleInfoMap BuildSwizzleInfoMap() -{ - SwizzleInfoMap map; - - map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM ))); - map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM))); - map.insert(SwizzleInfoPair(SwizzleSizeType(24, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); - map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_NORMALIZED), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); - - map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_SIGNED_NORMALIZED ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM ))); - - map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT))); - map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_FLOAT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT))); - - map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT ))); - map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT ))); - map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_UNSIGNED_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT ))); - - map.insert(SwizzleInfoPair(SwizzleSizeType( 8, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT ))); - map.insert(SwizzleInfoPair(SwizzleSizeType(16, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT ))); - map.insert(SwizzleInfoPair(SwizzleSizeType(32, GL_INT ), SwizzleFormatInfo(DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT ))); - - return map; -} - -typedef std::pair InternalFormatInitializerPair; -typedef std::map InternalFormatInitializerMap; - -static InternalFormatInitializerMap BuildInternalFormatInitializerMap() -{ - InternalFormatInitializerMap map; - - map.insert(InternalFormatInitializerPair(GL_RGB8, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB565, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_SRGB8, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB16F, Initialize4ComponentData)); - map.insert(InternalFormatInitializerPair(GL_RGB32F, Initialize4ComponentData)); - map.insert(InternalFormatInitializerPair(GL_RGB8UI, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB8I, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB16UI, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB16I, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB32UI, Initialize4ComponentData )); - map.insert(InternalFormatInitializerPair(GL_RGB32I, Initialize4ComponentData )); - - return map; -} - -// ES3 image loading functions vary based on the internal format and data type given, -// this map type determines the loading function from the internal format and type supplied -// to glTex*Image*D and the destination DXGI_FORMAT. Source formats and types are taken from -// Tables 3.2 and 3.3 of the ES 3 spec. -typedef std::pair TypeLoadFunctionPair; -typedef std::map > D3D11LoadFunctionMap; - -static void UnimplementedLoadFunction(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - UNIMPLEMENTED(); -} - -static void UnreachableLoadFunction(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - UNREACHABLE(); -} - -// A helper function to insert data into the D3D11LoadFunctionMap with fewer characters. -static inline void InsertLoadFunction(D3D11LoadFunctionMap *map, GLenum internalFormat, GLenum type, - LoadImageFunction loadFunc) -{ - (*map)[internalFormat].push_back(TypeLoadFunctionPair(type, loadFunc)); -} - -D3D11LoadFunctionMap BuildD3D11LoadFunctionMap() -{ - D3D11LoadFunctionMap map; - - // | Internal format | Type | Load function | - InsertLoadFunction(&map, GL_RGBA8, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA8_SNORM, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4, LoadRGBA4ToRGBA8 ); - InsertLoadFunction(&map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative ); - InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1, LoadRGB5A1ToRGBA8 ); - InsertLoadFunction(&map, GL_RGB5_A1, GL_UNSIGNED_INT_2_10_10_10_REV, LoadRGB10A2ToRGBA8 ); - InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA16F, GL_HALF_FLOAT_OES, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA32F, GL_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA16F, GL_FLOAT, Load32FTo16F<4> ); - InsertLoadFunction(&map, GL_RGBA8UI, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA8I, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA16UI, GL_UNSIGNED_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA16I, GL_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA32UI, GL_UNSIGNED_INT, LoadToNative ); - InsertLoadFunction(&map, GL_RGBA32I, GL_INT, LoadToNative ); - InsertLoadFunction(&map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV, LoadToNative ); - InsertLoadFunction(&map, GL_RGB8, GL_UNSIGNED_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_SRGB8, GL_UNSIGNED_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB8_SNORM, GL_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, LoadR5G6B5ToRGBA8 ); - InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV, LoadToNative ); - InsertLoadFunction(&map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV, LoadToNative ); - InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT, LoadToNative3To4); - InsertLoadFunction(&map, GL_RGB16F, GL_HALF_FLOAT_OES, LoadToNative3To4); - InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT, LoadRGB16FToRG11B10F ); - InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_HALF_FLOAT_OES, LoadRGB16FToRG11B10F ); - InsertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT, LoadRGB16FToRGB9E5 ); - InsertLoadFunction(&map, GL_RGB9_E5, GL_HALF_FLOAT_OES, LoadRGB16FToRGB9E5 ); - InsertLoadFunction(&map, GL_RGB32F, GL_FLOAT, LoadToNative3To4); - InsertLoadFunction(&map, GL_RGB16F, GL_FLOAT, LoadRGB32FToRGBA16F ); - InsertLoadFunction(&map, GL_R11F_G11F_B10F, GL_FLOAT, LoadRGB32FToRG11B10F ); - InsertLoadFunction(&map, GL_RGB9_E5, GL_FLOAT, LoadRGB32FToRGB9E5 ); - InsertLoadFunction(&map, GL_RGB8UI, GL_UNSIGNED_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB8I, GL_BYTE, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB16UI, GL_UNSIGNED_SHORT, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB16I, GL_SHORT, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB32UI, GL_UNSIGNED_INT, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RGB32I, GL_INT, LoadToNative3To4 ); - InsertLoadFunction(&map, GL_RG8, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RG8_SNORM, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_RG16F, GL_HALF_FLOAT_OES, LoadToNative ); - InsertLoadFunction(&map, GL_RG32F, GL_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_RG16F, GL_FLOAT, Load32FTo16F<2> ); - InsertLoadFunction(&map, GL_RG8UI, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RG8I, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_RG16UI, GL_UNSIGNED_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_RG16I, GL_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_RG32UI, GL_UNSIGNED_INT, LoadToNative ); - InsertLoadFunction(&map, GL_RG32I, GL_INT, LoadToNative ); - InsertLoadFunction(&map, GL_R8, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_R8_SNORM, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_R16F, GL_HALF_FLOAT_OES, LoadToNative ); - InsertLoadFunction(&map, GL_R32F, GL_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_R16F, GL_FLOAT, Load32FTo16F<1> ); - InsertLoadFunction(&map, GL_R8UI, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_R8I, GL_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_R16UI, GL_UNSIGNED_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_R16I, GL_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_R32UI, GL_UNSIGNED_INT, LoadToNative ); - InsertLoadFunction(&map, GL_R32I, GL_INT, LoadToNative ); - InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, LoadToNative ); - InsertLoadFunction(&map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT, LoadR32ToR24G8 ); - InsertLoadFunction(&map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_INT, LoadR32ToR16 ); - InsertLoadFunction(&map, GL_DEPTH_COMPONENT32F, GL_FLOAT, LoadToNative ); - InsertLoadFunction(&map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8, LoadR32ToR24G8 ); - InsertLoadFunction(&map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, LoadToNative ); - - // Unsized formats - // Load functions are unreachable because they are converted to sized internal formats based on - // the format and type before loading takes place. - InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); - InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, UnreachableLoadFunction ); - InsertLoadFunction(&map, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, UnreachableLoadFunction ); - InsertLoadFunction(&map, GL_RGB, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); - InsertLoadFunction(&map, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, UnreachableLoadFunction ); - InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); - InsertLoadFunction(&map, GL_LUMINANCE, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); - InsertLoadFunction(&map, GL_ALPHA, GL_UNSIGNED_BYTE, UnreachableLoadFunction ); - - // From GL_OES_texture_float - InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_FLOAT, LoadLA32FToRGBA32F ); - InsertLoadFunction(&map, GL_LUMINANCE, GL_FLOAT, LoadL32FToRGBA32F ); - InsertLoadFunction(&map, GL_ALPHA, GL_FLOAT, LoadA32FToRGBA32F ); - - // From GL_OES_texture_half_float - InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); - InsertLoadFunction(&map, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); - InsertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT, LoadL16FToRGBA16F ); - InsertLoadFunction(&map, GL_LUMINANCE, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); - InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT, LoadA16FToRGBA16F ); - InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); - - // From GL_EXT_texture_storage - InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadA8ToRGBA8 ); - InsertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 ); - InsertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 ); - InsertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F ); - InsertLoadFunction(&map, GL_LUMINANCE32F_EXT, GL_FLOAT, LoadL32FToRGBA32F ); - InsertLoadFunction(&map, GL_LUMINANCE_ALPHA32F_EXT, GL_FLOAT, LoadLA32FToRGBA32F ); - InsertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT, LoadA16FToRGBA16F ); - InsertLoadFunction(&map, GL_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); - InsertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT, LoadL16FToRGBA16F ); - InsertLoadFunction(&map, GL_LUMINANCE16F_EXT, GL_HALF_FLOAT_OES, LoadL16FToRGBA16F ); - InsertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT, LoadLA16FToRGBA16F ); - InsertLoadFunction(&map, GL_LUMINANCE_ALPHA16F_EXT, GL_HALF_FLOAT_OES, LoadLA16FToRGBA16F ); - - // From GL_ANGLE_depth_texture - InsertLoadFunction(&map, GL_DEPTH_COMPONENT32_OES, GL_UNSIGNED_INT, LoadR32ToR24G8 ); - - // From GL_EXT_texture_format_BGRA8888 - InsertLoadFunction(&map, GL_BGRA8_EXT, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT, LoadRGBA4ToRGBA8 ); - InsertLoadFunction(&map, GL_BGRA4_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative ); - InsertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT, LoadRGB5A1ToRGBA8 ); - InsertLoadFunction(&map, GL_BGR5_A1_ANGLEX, GL_UNSIGNED_BYTE, LoadToNative ); - - // Compressed formats - // From ES 3.0.1 spec, table 3.16 - // | Internal format | Type | Load function | - InsertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - InsertLoadFunction(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE, UnimplementedLoadFunction ); - - // From GL_EXT_texture_compression_dxt1 - InsertLoadFunction(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); - InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 8>); - - // From GL_ANGLE_texture_compression_dxt3 - InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); - - // From GL_ANGLE_texture_compression_dxt5 - InsertLoadFunction(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE, LoadCompressedToNative<4, 4, 16>); - - return map; -} - -// For sized GL internal formats, there is only one corresponding D3D11 format. This map type allows -// querying for the DXGI texture formats to use for textures, SRVs, RTVs and DSVs given a GL internal -// format. -typedef std::map D3D11ES3FormatMap; - -TextureFormat::TextureFormat() - : texFormat(DXGI_FORMAT_UNKNOWN), - srvFormat(DXGI_FORMAT_UNKNOWN), - rtvFormat(DXGI_FORMAT_UNKNOWN), - dsvFormat(DXGI_FORMAT_UNKNOWN), - renderFormat(DXGI_FORMAT_UNKNOWN), - swizzleTexFormat(DXGI_FORMAT_UNKNOWN), - swizzleSRVFormat(DXGI_FORMAT_UNKNOWN), - swizzleRTVFormat(DXGI_FORMAT_UNKNOWN), - dataInitializerFunction(NULL), - loadFunctions() -{ -} - -static inline void InsertD3D11FormatInfo(D3D11ES3FormatMap *map, GLenum internalFormat, DXGI_FORMAT texFormat, - DXGI_FORMAT srvFormat, DXGI_FORMAT rtvFormat, DXGI_FORMAT dsvFormat) -{ - TextureFormat info; - info.texFormat = texFormat; - info.srvFormat = srvFormat; - info.rtvFormat = rtvFormat; - info.dsvFormat = dsvFormat; - - // Given a GL internal format, the renderFormat is the DSV format if it is depth- or stencil-renderable, - // the RTV format if it is color-renderable, and the (nonrenderable) texture format otherwise. - if (dsvFormat != DXGI_FORMAT_UNKNOWN) - { - info.renderFormat = dsvFormat; - } - else if (rtvFormat != DXGI_FORMAT_UNKNOWN) - { - info.renderFormat = rtvFormat; - } - else if (texFormat != DXGI_FORMAT_UNKNOWN) - { - info.renderFormat = texFormat; - } - else - { - info.renderFormat = DXGI_FORMAT_UNKNOWN; - } - - // Compute the swizzle formats - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (internalFormat != GL_NONE && formatInfo.pixelBytes > 0) - { - if (formatInfo.componentCount != 4 || texFormat == DXGI_FORMAT_UNKNOWN || - srvFormat == DXGI_FORMAT_UNKNOWN || rtvFormat == DXGI_FORMAT_UNKNOWN) - { - // Get the maximum sized component - unsigned int maxBits = 1; - if (formatInfo.compressed) - { - unsigned int compressedBitsPerBlock = formatInfo.pixelBytes * 8; - unsigned int blockSize = formatInfo.compressedBlockWidth * formatInfo.compressedBlockHeight; - maxBits = std::max(compressedBitsPerBlock / blockSize, maxBits); - } - else - { - maxBits = std::max(maxBits, formatInfo.alphaBits); - maxBits = std::max(maxBits, formatInfo.redBits); - maxBits = std::max(maxBits, formatInfo.greenBits); - maxBits = std::max(maxBits, formatInfo.blueBits); - maxBits = std::max(maxBits, formatInfo.luminanceBits); - maxBits = std::max(maxBits, formatInfo.depthBits); - } - - maxBits = roundUp(maxBits, 8U); - - static const SwizzleInfoMap swizzleMap = BuildSwizzleInfoMap(); - SwizzleInfoMap::const_iterator swizzleIter = swizzleMap.find(SwizzleSizeType(maxBits, formatInfo.componentType)); - ASSERT(swizzleIter != swizzleMap.end()); - - const SwizzleFormatInfo &swizzleInfo = swizzleIter->second; - info.swizzleTexFormat = swizzleInfo.mTexFormat; - info.swizzleSRVFormat = swizzleInfo.mSRVFormat; - info.swizzleRTVFormat = swizzleInfo.mRTVFormat; - } - else - { - // The original texture format is suitable for swizzle operations - info.swizzleTexFormat = texFormat; - info.swizzleSRVFormat = srvFormat; - info.swizzleRTVFormat = rtvFormat; - } - } - else - { - // Not possible to swizzle with this texture format since it is either unsized or GL_NONE - info.swizzleTexFormat = DXGI_FORMAT_UNKNOWN; - info.swizzleSRVFormat = DXGI_FORMAT_UNKNOWN; - info.swizzleRTVFormat = DXGI_FORMAT_UNKNOWN; - } - - // Check if there is an initialization function for this texture format - static const InternalFormatInitializerMap initializerMap = BuildInternalFormatInitializerMap(); - InternalFormatInitializerMap::const_iterator initializerIter = initializerMap.find(internalFormat); - info.dataInitializerFunction = (initializerIter != initializerMap.end()) ? initializerIter->second : NULL; - - // Gather all the load functions for this internal format - static const D3D11LoadFunctionMap loadFunctions = BuildD3D11LoadFunctionMap(); - D3D11LoadFunctionMap::const_iterator loadFunctionIter = loadFunctions.find(internalFormat); - if (loadFunctionIter != loadFunctions.end()) - { - const std::vector &loadFunctionVector = loadFunctionIter->second; - for (size_t i = 0; i < loadFunctionVector.size(); i++) - { - GLenum type = loadFunctionVector[i].first; - LoadImageFunction function = loadFunctionVector[i].second; - info.loadFunctions.insert(std::make_pair(type, function)); - } - } - - map->insert(std::make_pair(internalFormat, info)); -} - -static D3D11ES3FormatMap BuildD3D11FormatMap() -{ - D3D11ES3FormatMap map; - - // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | - InsertD3D11FormatInfo(&map, GL_NONE, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R8, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG8, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB8, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB565, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA4, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB5_A1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA8, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB10_A2, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB10_A2UI, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_R10G10B10A2_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_SRGB8, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_SRGB8_ALPHA8, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R16F, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG16F, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB16F, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA16F, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R32F, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG32F, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB32F, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA32F, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R11F_G11F_B10F, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB9_E5, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R8I, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R8UI, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R16I, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R16UI, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R32I, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_R32UI, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG8I, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG8UI, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG16I, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG16UI, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG32I, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RG32UI, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB8I, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB8UI, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB16I, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB16UI, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB32I, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB32UI, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA8I, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA8UI, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA16I, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA16UI, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA32I, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA32UI, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_UNKNOWN); - - // Unsized formats, TODO: Are types of float and half float allowed for the unsized types? Would it change the DXGI format? - InsertD3D11FormatInfo(&map, GL_ALPHA, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_LUMINANCE, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGB, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_BGRA_EXT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN); - - // From GL_EXT_texture_storage - // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | - InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_LUMINANCE8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_LUMINANCE32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_ALPHA16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_LUMINANCE16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_BGRA8_EXT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_BGRA4_ANGLEX, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_BGR5_A1_ANGLEX, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN ); - - // Depth stencil formats - InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT16, DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM ); - InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT24, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); - InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32F, DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT ); - InsertD3D11FormatInfo(&map, GL_DEPTH24_STENCIL8, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); - InsertD3D11FormatInfo(&map, GL_DEPTH32F_STENCIL8, DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT); - InsertD3D11FormatInfo(&map, GL_STENCIL_INDEX8, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_X24_TYPELESS_G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT ); - - // From GL_ANGLE_depth_texture - // Since D3D11 doesn't have a D32_UNORM format, use D24S8 which has comparable precision and matches the ES3 format. - InsertD3D11FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D24_UNORM_S8_UINT); - - // Compressed formats, From ES 3.0.1 spec, table 3.16 - // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | - InsertD3D11FormatInfo(&map, GL_COMPRESSED_R11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_SIGNED_R11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_RG11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_SIGNED_RG11_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB8_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA8_ETC2_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - - // From GL_EXT_texture_compression_dxt1 - InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - - // From GL_ANGLE_texture_compression_dxt3 - InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - - // From GL_ANGLE_texture_compression_dxt5 - InsertD3D11FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); - - return map; -} - -const TextureFormat &GetTextureFormatInfo(GLenum internalFormat) -{ - static const D3D11ES3FormatMap formatMap = BuildD3D11FormatMap(); - D3D11ES3FormatMap::const_iterator iter = formatMap.find(internalFormat); - if (iter != formatMap.end()) - { - return iter->second; - } - else - { - static const TextureFormat defaultInfo; - return defaultInfo; - } -} - -typedef std::map D3D11VertexFormatInfoMap; -typedef std::pair D3D11VertexFormatPair; - -VertexFormat::VertexFormat() - : conversionType(VERTEX_CONVERT_NONE), - nativeFormat(DXGI_FORMAT_UNKNOWN), - copyFunction(NULL) -{ -} - -static void AddVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLboolean normalized, GLuint componentCount, - VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) -{ - gl::VertexFormat inputFormat(inputType, normalized, componentCount, false); - - VertexFormat info; - info.conversionType = conversionType; - info.nativeFormat = nativeFormat; - info.copyFunction = copyFunction; - - map->insert(D3D11VertexFormatPair(inputFormat, info)); -} - -static void AddIntegerVertexFormatInfo(D3D11VertexFormatInfoMap *map, GLenum inputType, GLuint componentCount, - VertexConversionType conversionType, DXGI_FORMAT nativeFormat, VertexCopyFunction copyFunction) -{ - gl::VertexFormat inputFormat(inputType, GL_FALSE, componentCount, true); - - VertexFormat info; - info.conversionType = conversionType; - info.nativeFormat = nativeFormat; - info.copyFunction = copyFunction; - - map->insert(D3D11VertexFormatPair(inputFormat, info)); -} - -static D3D11VertexFormatInfoMap BuildD3D11VertexFormatInfoMap() -{ - D3D11VertexFormatInfoMap map; - - // TODO: column legend - - // - // Float formats - // - - // GL_BYTE -- un-normalized - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); - - // GL_BYTE -- normalized - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SNORM, &CopyNativeVertexData); - - // GL_UNSIGNED_BYTE -- un-normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - - // GL_UNSIGNED_BYTE -- normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_BYTE, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UNORM, &CopyNativeVertexData); - - // GL_SHORT -- un-normalized - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); - - // GL_SHORT -- normalized - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SNORM, &CopyNativeVertexData); - - // GL_UNSIGNED_SHORT -- un-normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 3, VERTEX_CONVERT_BOTH, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); - - // GL_UNSIGNED_SHORT -- normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_SHORT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UNORM, &CopyNativeVertexData); - - // GL_INT -- un-normalized - AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); - - // GL_INT -- normalized - AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_INT, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); - - // GL_UNSIGNED_INT -- un-normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 1, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 2, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 3, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32_UINT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_FALSE, 4, VERTEX_CONVERT_GPU, DXGI_FORMAT_R32G32B32A32_UINT, &CopyNativeVertexData); - - // GL_UNSIGNED_INT -- normalized - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &CopyTo32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyTo32FVertexData); - - // GL_FIXED - AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 1, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32_FLOAT, &Copy32FixedTo32FVertexData<1>); - AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 2, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32_FLOAT, &Copy32FixedTo32FVertexData<2>); - AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32_FLOAT, &Copy32FixedTo32FVertexData<3>); - AddVertexFormatInfo(&map, GL_FIXED, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &Copy32FixedTo32FVertexData<4>); - - // GL_HALF_FLOAT - AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_HALF_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_FLOAT, &CopyNativeVertexData); - - // GL_FLOAT - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_FLOAT, &CopyNativeVertexData); - AddVertexFormatInfo(&map, GL_FLOAT, GL_FALSE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyNativeVertexData); - - // GL_INT_2_10_10_10_REV - AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); - AddVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); - - // GL_UNSIGNED_INT_2_10_10_10_REV - AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_FALSE, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R32G32B32A32_FLOAT, &CopyXYZ10W2ToXYZW32FVertexData); - AddVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UNORM, &CopyNativeVertexData); - - // - // Integer Formats - // - - // GL_BYTE - AddIntegerVertexFormatInfo(&map, GL_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_SINT, &CopyNativeVertexData); - - // GL_UNSIGNED_BYTE - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_BYTE, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R8G8B8A8_UINT, &CopyNativeVertexData); - - // GL_SHORT - AddIntegerVertexFormatInfo(&map, GL_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_SINT, &CopyNativeVertexData); - - // GL_UNSIGNED_SHORT - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 3, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_SHORT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R16G16B16A16_UINT, &CopyNativeVertexData); - - // GL_INT - AddIntegerVertexFormatInfo(&map, GL_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); - - // GL_UNSIGNED_INT - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 1, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 2, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 3, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32_SINT, &CopyNativeVertexData); - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R32G32B32A32_SINT, &CopyNativeVertexData); - - // GL_INT_2_10_10_10_REV - AddIntegerVertexFormatInfo(&map, GL_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_CPU, DXGI_FORMAT_R16G16B16A16_SINT, &CopyXYZ10W2ToXYZW32FVertexData); - - // GL_UNSIGNED_INT_2_10_10_10_REV - AddIntegerVertexFormatInfo(&map, GL_UNSIGNED_INT_2_10_10_10_REV, 4, VERTEX_CONVERT_NONE, DXGI_FORMAT_R10G10B10A2_UINT, &CopyNativeVertexData); - - return map; -} - -const VertexFormat &GetVertexFormatInfo(const gl::VertexFormat &vertexFormat) -{ - static const D3D11VertexFormatInfoMap vertexFormatMap = BuildD3D11VertexFormatInfoMap(); - - D3D11VertexFormatInfoMap::const_iterator iter = vertexFormatMap.find(vertexFormat); - if (iter != vertexFormatMap.end()) - { - return iter->second; - } - else - { - static const VertexFormat defaultInfo; - return defaultInfo; - } -} - -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h deleted file mode 100644 index ea11aaa74c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h +++ /dev/null @@ -1,84 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// formatutils11.h: Queries for GL image formats and their translations to D3D11 -// formats. - -#ifndef LIBGLESV2_RENDERER_FORMATUTILS11_H_ -#define LIBGLESV2_RENDERER_FORMATUTILS11_H_ - -#include "libGLESv2/formatutils.h" - -#include - -namespace rx -{ - -namespace d3d11 -{ - -typedef std::map, ColorCopyFunction> FastCopyFunctionMap; - -struct DXGIFormat -{ - DXGIFormat(); - - GLuint pixelBytes; - GLuint blockWidth; - GLuint blockHeight; - - GLuint depthBits; - GLuint depthOffset; - GLuint stencilBits; - GLuint stencilOffset; - - GLenum internalFormat; - GLenum componentType; - - MipGenerationFunction mipGenerationFunction; - ColorReadFunction colorReadFunction; - - FastCopyFunctionMap fastCopyFunctions; - ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; -}; -const DXGIFormat &GetDXGIFormatInfo(DXGI_FORMAT format); - -struct TextureFormat -{ - TextureFormat(); - - DXGI_FORMAT texFormat; - DXGI_FORMAT srvFormat; - DXGI_FORMAT rtvFormat; - DXGI_FORMAT dsvFormat; - DXGI_FORMAT renderFormat; - - DXGI_FORMAT swizzleTexFormat; - DXGI_FORMAT swizzleSRVFormat; - DXGI_FORMAT swizzleRTVFormat; - - InitializeTextureDataFunction dataInitializerFunction; - - typedef std::map LoadFunctionMap; - LoadFunctionMap loadFunctions; -}; -const TextureFormat &GetTextureFormatInfo(GLenum internalFormat); - -struct VertexFormat -{ - VertexFormat(); - - VertexConversionType conversionType; - DXGI_FORMAT nativeFormat; - VertexCopyFunction copyFunction; -}; -const VertexFormat &GetVertexFormatInfo(const gl::VertexFormat &vertexFormat); - -} - -} - -#endif // LIBGLESV2_RENDERER_FORMATUTILS11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp deleted file mode 100644 index 121aa3bbad..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp +++ /dev/null @@ -1,1228 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// renderer11_utils.cpp: Conversion functions and other utility routines -// specific to the D3D11 renderer. - -#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" -#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" -#include "libGLESv2/renderer/Workarounds.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/Framebuffer.h" - -#include "common/debug.h" - -#include - -#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY -# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2 -#endif -#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT -# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1 -#endif -#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT -# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4 -#endif -#ifndef D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT -# define D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT 65535 -#endif -#ifndef D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT -# define D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT 1048575 -#endif -#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION -# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512 -#endif -#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION -# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096 -#endif -#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION -# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048 -#endif -#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION -# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256 -#endif -#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION -# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 -#endif -#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION -# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 -#endif -#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION -# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 -#endif -#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION -# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 -#endif -#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP -# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 -#endif -#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP -# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 -#endif -#ifndef D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT -# define D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT 32 -#endif -#ifndef D3D11_STANDARD_VERTEX_ELEMENT_COUNT -# define D3D11_STANDARD_VERTEX_ELEMENT_COUNT 32 -#endif -#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT -# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 -#endif -#ifndef D3D11_SO_BUFFER_SLOT_COUNT -# define D3D11_SO_BUFFER_SLOT_COUNT 4 -#endif -#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT -# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 -#endif -#ifndef D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT -# define D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT 16 -#endif -#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -8 -#endif -#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE -# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE 7 -#endif -#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT -# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 -#endif -#ifndef D3D11_PS_INPUT_REGISTER_COUNT -# define D3D11_PS_INPUT_REGISTER_COUNT 32 -#endif -#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT -# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 -#endif - -namespace rx -{ - -namespace gl_d3d11 -{ - -D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha) -{ - D3D11_BLEND d3dBlend = D3D11_BLEND_ZERO; - - switch (glBlend) - { - case GL_ZERO: d3dBlend = D3D11_BLEND_ZERO; break; - case GL_ONE: d3dBlend = D3D11_BLEND_ONE; break; - case GL_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_SRC_ALPHA : D3D11_BLEND_SRC_COLOR); break; - case GL_ONE_MINUS_SRC_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC_ALPHA : D3D11_BLEND_INV_SRC_COLOR); break; - case GL_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_DEST_COLOR); break; - case GL_ONE_MINUS_DST_COLOR: d3dBlend = (isAlpha ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_INV_DEST_COLOR); break; - case GL_SRC_ALPHA: d3dBlend = D3D11_BLEND_SRC_ALPHA; break; - case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3D11_BLEND_INV_SRC_ALPHA; break; - case GL_DST_ALPHA: d3dBlend = D3D11_BLEND_DEST_ALPHA; break; - case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3D11_BLEND_INV_DEST_ALPHA; break; - case GL_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; - case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; - case GL_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_BLEND_FACTOR; break; - case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3D11_BLEND_INV_BLEND_FACTOR; break; - case GL_SRC_ALPHA_SATURATE: d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT; break; - default: UNREACHABLE(); - } - - return d3dBlend; -} - -D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp) -{ - D3D11_BLEND_OP d3dBlendOp = D3D11_BLEND_OP_ADD; - - switch (glBlendOp) - { - case GL_FUNC_ADD: d3dBlendOp = D3D11_BLEND_OP_ADD; break; - case GL_FUNC_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_SUBTRACT; break; - case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3D11_BLEND_OP_REV_SUBTRACT; break; - case GL_MIN: d3dBlendOp = D3D11_BLEND_OP_MIN; break; - case GL_MAX: d3dBlendOp = D3D11_BLEND_OP_MAX; break; - default: UNREACHABLE(); - } - - return d3dBlendOp; -} - -UINT8 ConvertColorMask(bool red, bool green, bool blue, bool alpha) -{ - UINT8 mask = 0; - if (red) - { - mask |= D3D11_COLOR_WRITE_ENABLE_RED; - } - if (green) - { - mask |= D3D11_COLOR_WRITE_ENABLE_GREEN; - } - if (blue) - { - mask |= D3D11_COLOR_WRITE_ENABLE_BLUE; - } - if (alpha) - { - mask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; - } - return mask; -} - -D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode) -{ - D3D11_CULL_MODE cull = D3D11_CULL_NONE; - - if (cullEnabled) - { - switch (cullMode) - { - case GL_FRONT: cull = D3D11_CULL_FRONT; break; - case GL_BACK: cull = D3D11_CULL_BACK; break; - case GL_FRONT_AND_BACK: cull = D3D11_CULL_NONE; break; - default: UNREACHABLE(); - } - } - else - { - cull = D3D11_CULL_NONE; - } - - return cull; -} - -D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison) -{ - D3D11_COMPARISON_FUNC d3dComp = D3D11_COMPARISON_NEVER; - switch (comparison) - { - case GL_NEVER: d3dComp = D3D11_COMPARISON_NEVER; break; - case GL_ALWAYS: d3dComp = D3D11_COMPARISON_ALWAYS; break; - case GL_LESS: d3dComp = D3D11_COMPARISON_LESS; break; - case GL_LEQUAL: d3dComp = D3D11_COMPARISON_LESS_EQUAL; break; - case GL_EQUAL: d3dComp = D3D11_COMPARISON_EQUAL; break; - case GL_GREATER: d3dComp = D3D11_COMPARISON_GREATER; break; - case GL_GEQUAL: d3dComp = D3D11_COMPARISON_GREATER_EQUAL; break; - case GL_NOTEQUAL: d3dComp = D3D11_COMPARISON_NOT_EQUAL; break; - default: UNREACHABLE(); - } - - return d3dComp; -} - -D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled) -{ - return depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; -} - -UINT8 ConvertStencilMask(GLuint stencilmask) -{ - return static_cast(stencilmask); -} - -D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp) -{ - D3D11_STENCIL_OP d3dStencilOp = D3D11_STENCIL_OP_KEEP; - - switch (stencilOp) - { - case GL_ZERO: d3dStencilOp = D3D11_STENCIL_OP_ZERO; break; - case GL_KEEP: d3dStencilOp = D3D11_STENCIL_OP_KEEP; break; - case GL_REPLACE: d3dStencilOp = D3D11_STENCIL_OP_REPLACE; break; - case GL_INCR: d3dStencilOp = D3D11_STENCIL_OP_INCR_SAT; break; - case GL_DECR: d3dStencilOp = D3D11_STENCIL_OP_DECR_SAT; break; - case GL_INVERT: d3dStencilOp = D3D11_STENCIL_OP_INVERT; break; - case GL_INCR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_INCR; break; - case GL_DECR_WRAP: d3dStencilOp = D3D11_STENCIL_OP_DECR; break; - default: UNREACHABLE(); - } - - return d3dStencilOp; -} - -D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode) -{ - bool comparison = comparisonMode != GL_NONE; - - if (maxAnisotropy > 1.0f) - { - return D3D11_ENCODE_ANISOTROPIC_FILTER(static_cast(comparison)); - } - else - { - D3D11_FILTER_TYPE dxMin = D3D11_FILTER_TYPE_POINT; - D3D11_FILTER_TYPE dxMip = D3D11_FILTER_TYPE_POINT; - switch (minFilter) - { - case GL_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_NEAREST_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR_MIPMAP_NEAREST: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_POINT; break; - case GL_NEAREST_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_POINT; dxMip = D3D11_FILTER_TYPE_LINEAR; break; - case GL_LINEAR_MIPMAP_LINEAR: dxMin = D3D11_FILTER_TYPE_LINEAR; dxMip = D3D11_FILTER_TYPE_LINEAR; break; - default: UNREACHABLE(); - } - - D3D11_FILTER_TYPE dxMag = D3D11_FILTER_TYPE_POINT; - switch (magFilter) - { - case GL_NEAREST: dxMag = D3D11_FILTER_TYPE_POINT; break; - case GL_LINEAR: dxMag = D3D11_FILTER_TYPE_LINEAR; break; - default: UNREACHABLE(); - } - - return D3D11_ENCODE_BASIC_FILTER(dxMin, dxMag, dxMip, static_cast(comparison)); - } -} - -D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap) -{ - switch (wrap) - { - case GL_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP; - case GL_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP; - case GL_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR; - default: UNREACHABLE(); - } - - return D3D11_TEXTURE_ADDRESS_WRAP; -} - -D3D11_QUERY ConvertQueryType(GLenum queryType) -{ - switch (queryType) - { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: return D3D11_QUERY_OCCLUSION; - case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: return D3D11_QUERY_SO_STATISTICS; - default: UNREACHABLE(); return D3D11_QUERY_EVENT; - } -} - -} - - -namespace d3d11_gl -{ - -static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, ID3D11Device *device) -{ - gl::TextureCaps textureCaps; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat); - - UINT formatSupport; - if (SUCCEEDED(device->CheckFormatSupport(formatInfo.texFormat, &formatSupport))) - { - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0); - } - else - { - textureCaps.texturable = ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0) && - ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURECUBE) != 0) && - ((formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE3D) != 0); - } - } - - if (SUCCEEDED(device->CheckFormatSupport(formatInfo.renderFormat, &formatSupport)) && - ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) != 0)) - { - for (size_t sampleCount = 1; sampleCount <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sampleCount++) - { - UINT qualityCount = 0; - if (SUCCEEDED(device->CheckMultisampleQualityLevels(formatInfo.renderFormat, sampleCount, &qualityCount)) && - qualityCount > 0) - { - textureCaps.sampleCounts.insert(sampleCount); - } - } - } - - textureCaps.filterable = SUCCEEDED(device->CheckFormatSupport(formatInfo.srvFormat, &formatSupport)) && - ((formatSupport & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) != 0; - textureCaps.renderable = (SUCCEEDED(device->CheckFormatSupport(formatInfo.rtvFormat, &formatSupport)) && - ((formatSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)) != 0) || - (SUCCEEDED(device->CheckFormatSupport(formatInfo.dsvFormat, &formatSupport)) && - ((formatSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL) != 0)); - - return textureCaps; -} - -static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; - - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return true; // Provided that mipmaps & wrap modes are not used - - default: UNREACHABLE(); return false; - } -} - -static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_MAX_MAXANISOTROPY; - - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return 16; - - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_DEFAULT_MAX_ANISOTROPY; - - default: UNREACHABLE(); return 0; - } -} - -static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; - - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return true; - case D3D_FEATURE_LEVEL_9_1: return false; - - default: UNREACHABLE(); return false; - } -} - -static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) -{ - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateQuery - - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return true; - - default: UNREACHABLE(); return false; - } -} - -static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) -{ - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout - - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - case D3D_FEATURE_LEVEL_9_3: return true; - - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; - - default: UNREACHABLE(); return false; - } -} - -static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) -{ - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb509588.aspx states that shader model - // ps_2_x is required for the ddx (and other derivative functions). - - // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx states that feature level - // 9.3 supports shader model ps_2_x. - - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - case D3D_FEATURE_LEVEL_9_3: return true; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return false; - - default: UNREACHABLE(); return false; - } -} - -static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel) -{ - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476150.aspx ID3D11Device::CreateInputLayout - - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; - - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; - - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURECUBE_DIMENSION; - - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_VIEWPORT_BOUNDS_MAX; - - // No constants for D3D9 viewport size limits, use the maximum texture sizes - case D3D_FEATURE_LEVEL_9_3: return D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) -{ - // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since that's what's - // returned from glGetInteger - META_ASSERT(D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32); - META_ASSERT(D3D10_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP == 32); - - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) -{ - // D3D11 allows up to 2^32 elements, but we report max signed int for convenience since that's what's - // returned from glGetInteger - META_ASSERT(D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32); - META_ASSERT(D3D10_REQ_DRAW_VERTEX_COUNT_2_TO_EXP == 32); - - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: return D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT; - case D3D_FEATURE_LEVEL_9_1: return D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT; - case D3D_FEATURE_LEVEL_10_0: return D3D10_STANDARD_VERTEX_ELEMENT_COUNT; - - // From http://http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx "Max Input Slots" - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 16; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) -{ - // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::VSSetConstantBuffers - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 255; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetReservedVertexUniformBuffers() -{ - // Reserve one buffer for the application uniforms, and one for driver uniforms - return 2; -} - -static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); - - // Uniform blocks not supported in D3D9 feature levels - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetReservedVertexOutputVectors() -{ - // We potentially reserve varyings for gl_Position, dx_Position, gl_FragCoord and gl_PointSize - return 4; -} - -static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) -{ - META_ASSERT(gl::IMPLEMENTATION_MAX_VARYING_VECTORS == D3D11_VS_OUTPUT_REGISTER_COUNT); - - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); - - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); - case D3D_FEATURE_LEVEL_10_0: return D3D10_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); - - // Use D3D9 SM3 and SM2 limits - case D3D_FEATURE_LEVEL_9_3: return 10 - GetReservedVertexOutputVectors(); - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 8 - GetReservedVertexOutputVectors(); - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; - - // Vertex textures not supported in D3D9 feature levels according to - // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx - // ID3D11DeviceContext::VSSetSamplers and ID3D11DeviceContext::VSSetShaderResources - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) -{ - // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return 1024; // D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::PSSetConstantBuffers - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 32; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetReservedPixelUniformBuffers() -{ - // Reserve one buffer for the application uniforms, and one for driver uniforms - return 2; -} - -static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); - - // Uniform blocks not supported in D3D9 feature levels - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); - - // Use D3D9 SM3 and SM2 limits - case D3D_FEATURE_LEVEL_9_3: return 10 - GetReservedVertexOutputVectors(); - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 8 - GetReservedVertexOutputVectors(); - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT; - - // http://msdn.microsoft.com/en-us/library/windows/desktop/ff476149.aspx ID3D11DeviceContext::PSSetShaderResources - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 16; - - default: UNREACHABLE(); return 0; - } -} - -static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; - - // Sampling functions with offsets are not available below shader model 4.0. - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; - - // Sampling functions with offsets are not available below shader model 4.0. - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) -{ - // Returns a size_t despite the limit being a GLuint64 because size_t is the maximum size of - // any buffer that could be allocated. - - const size_t bytesPerComponent = 4 * sizeof(float); - - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; - - // Limits from http://msdn.microsoft.com/en-us/library/windows/desktop/ff476501.aspx remarks section - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 4096 * bytesPerComponent; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_SO_BUFFER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SO_BUFFER_SLOT_COUNT; - case D3D_FEATURE_LEVEL_10_0: return D3D10_SO_BUFFER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return GetMaximumVertexOutputVectors(featureLevel) * 4; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -#endif - case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / - GetMaximumStreamOutputBuffers(featureLevel); - - - // D3D 10 and 10.1 only allow one output per output slot if an output slot other than zero is used. - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return 4; - - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: return 0; - - default: UNREACHABLE(); return 0; - } -} - -void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) -{ - GLuint maxSamples = 0; - const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); - for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) - { - gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, device); - textureCapsMap->insert(*internalFormat, textureCaps); - - maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); - - if (gl::GetInternalFormatInfo(*internalFormat).compressed) - { - caps->compressedTextureFormats.push_back(*internalFormat); - } - } - - D3D_FEATURE_LEVEL featureLevel = device->GetFeatureLevel(); - - // GL core feature limits - caps->maxElementIndex = static_cast(std::numeric_limits::max()); - caps->max3DTextureSize = GetMaximum3DTextureSize(featureLevel); - caps->max2DTextureSize = GetMaximum2DTextureSize(featureLevel); - caps->maxCubeMapTextureSize = GetMaximumCubeMapTextureSize(featureLevel); - caps->maxArrayTextureLayers = GetMaximum2DTextureArraySize(featureLevel); - - // Unimplemented, set to minimum required - caps->maxLODBias = 2.0f; - - // No specific limits on render target size, maximum 2D texture size is equivalent - caps->maxRenderbufferSize = caps->max2DTextureSize; - - // Maximum draw buffers and color attachments are the same, max color attachments could eventually be - // increased to 16 - caps->maxDrawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel); - caps->maxColorAttachments = GetMaximumSimultaneousRenderTargets(featureLevel); - - // D3D11 has the same limit for viewport width and height - caps->maxViewportWidth = GetMaximumViewportSize(featureLevel); - caps->maxViewportHeight = caps->maxViewportWidth; - - // Choose a reasonable maximum, enforced in the shader. - caps->minAliasedPointSize = 1.0f; - caps->maxAliasedPointSize = 1024.0f; - - // Wide lines not supported - caps->minAliasedLineWidth = 1.0f; - caps->maxAliasedLineWidth = 1.0f; - - // Primitive count limits - caps->maxElementsIndices = GetMaximumDrawIndexedIndexCount(featureLevel); - caps->maxElementsVertices = GetMaximumDrawVertexCount(featureLevel); - - // Program and shader binary formats (no supported shader binary formats) - caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); - - // We do not wait for server fence objects internally, so report a max timeout of zero. - caps->maxServerWaitTimeout = 0; - - // Vertex shader limits - caps->maxVertexAttributes = GetMaximumVertexInputSlots(featureLevel); - caps->maxVertexUniformComponents = GetMaximumVertexUniformVectors(featureLevel) * 4; - caps->maxVertexUniformVectors = GetMaximumVertexUniformVectors(featureLevel); - caps->maxVertexUniformBlocks = GetMaximumVertexUniformBlocks(featureLevel); - caps->maxVertexOutputComponents = GetMaximumVertexOutputVectors(featureLevel) * 4; - caps->maxVertexTextureImageUnits = GetMaximumVertexTextureUnits(featureLevel); - - // Fragment shader limits - caps->maxFragmentUniformComponents = GetMaximumPixelUniformVectors(featureLevel) * 4; - caps->maxFragmentUniformVectors = GetMaximumPixelUniformVectors(featureLevel); - caps->maxFragmentUniformBlocks = GetMaximumPixelUniformBlocks(featureLevel); - caps->maxFragmentInputComponents = GetMaximumPixelInputVectors(featureLevel) * 4; - caps->maxTextureImageUnits = GetMaximumPixelTextureUnits(featureLevel); - caps->minProgramTexelOffset = GetMinimumTexelOffset(featureLevel); - caps->maxProgramTexelOffset = GetMaximumTexelOffset(featureLevel); - - // Aggregate shader limits - caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; - caps->maxUniformBlockSize = GetMaximumConstantBufferSize(featureLevel); - - // Setting a large alignment forces uniform buffers to bind with zero offset - caps->uniformBufferOffsetAlignment = static_cast(std::numeric_limits::max()); - - caps->maxCombinedUniformBlocks = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; - caps->maxCombinedVertexUniformComponents = (static_cast(caps->maxVertexUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + - static_cast(caps->maxVertexUniformComponents); - caps->maxCombinedFragmentUniformComponents = (static_cast(caps->maxFragmentUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + - static_cast(caps->maxFragmentUniformComponents); - caps->maxVaryingComponents = GetMaximumVertexOutputVectors(featureLevel) * 4; - caps->maxVaryingVectors = GetMaximumVertexOutputVectors(featureLevel); - caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; - - // Transform feedback limits - caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponents(featureLevel); - caps->maxTransformFeedbackSeparateAttributes = GetMaximumStreamOutputBuffers(featureLevel); - caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateComponents(featureLevel); - - // GL extension support - extensions->setTextureExtensionSupport(*textureCapsMap); - extensions->elementIndexUint = true; - extensions->packedDepthStencil = true; - extensions->getProgramBinary = true; - extensions->rgb8rgba8 = true; - extensions->readFormatBGRA = true; - extensions->pixelBufferObject = true; - extensions->mapBuffer = true; - extensions->mapBufferRange = true; - extensions->textureNPOT = GetNPOTTextureSupport(featureLevel); - extensions->drawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel) > 1; - extensions->textureStorage = true; - extensions->textureFilterAnisotropic = true; - extensions->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel); - extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel); - extensions->fence = GetEventQuerySupport(featureLevel); - extensions->timerQuery = false; // Unimplemented - extensions->robustness = true; - extensions->blendMinMax = true; - extensions->framebufferBlit = true; - extensions->framebufferMultisample = true; - extensions->maxSamples = maxSamples; - extensions->instancedArrays = GetInstancingSupport(featureLevel); - extensions->packReverseRowOrder = true; - extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel); - extensions->shaderTextureLOD = true; - extensions->fragDepth = true; - extensions->textureUsage = true; // This could be false since it has no effect in D3D11 - extensions->translatedShaderSource = true; -} - -} - -namespace d3d11 -{ - -void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) -{ - const DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(format); - - int upsampleCount = 0; - // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. - if (isImage || *requestWidth < static_cast(dxgiFormatInfo.blockWidth) || - *requestHeight < static_cast(dxgiFormatInfo.blockHeight)) - { - while (*requestWidth % dxgiFormatInfo.blockWidth != 0 || *requestHeight % dxgiFormatInfo.blockHeight != 0) - { - *requestWidth <<= 1; - *requestHeight <<= 1; - upsampleCount++; - } - } - *levelOffset = upsampleCount; -} - -void GenerateInitialTextureData(GLint internalFormat, GLuint width, GLuint height, GLuint depth, - GLuint mipLevels, std::vector *outSubresourceData, - std::vector< std::vector > *outData) -{ - const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(internalFormat); - ASSERT(d3dFormatInfo.dataInitializerFunction != NULL); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3dFormatInfo.texFormat); - - outSubresourceData->resize(mipLevels); - outData->resize(mipLevels); - - for (unsigned int i = 0; i < mipLevels; i++) - { - unsigned int mipWidth = std::max(width >> i, 1U); - unsigned int mipHeight = std::max(height >> i, 1U); - unsigned int mipDepth = std::max(depth >> i, 1U); - - unsigned int rowWidth = dxgiFormatInfo.pixelBytes * mipWidth; - unsigned int imageSize = rowWidth * height; - - outData->at(i).resize(rowWidth * mipHeight * mipDepth); - d3dFormatInfo.dataInitializerFunction(mipWidth, mipHeight, mipDepth, outData->at(i).data(), rowWidth, imageSize); - - outSubresourceData->at(i).pSysMem = outData->at(i).data(); - outSubresourceData->at(i).SysMemPitch = rowWidth; - outSubresourceData->at(i).SysMemSlicePitch = imageSize; - } -} - -void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v) -{ - vertex->x = x; - vertex->y = y; - vertex->u = u; - vertex->v = v; -} - -void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, - unsigned int layer, float u, float v, float s) -{ - vertex->x = x; - vertex->y = y; - vertex->l = layer; - vertex->u = u; - vertex->v = v; - vertex->s = s; -} - -HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) -{ -#if defined(_DEBUG) && !defined(__MINGW32__) - return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); -#else - return S_OK; -#endif -} - -gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget11 **outRT) -{ - RenderTarget *renderTarget = NULL; - gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); - if (error.isError()) - { - return error; - } - *outRT = RenderTarget11::makeRenderTarget11(renderTarget); - return gl::Error(GL_NO_ERROR); -} - -Workarounds GenerateWorkarounds() -{ - Workarounds workarounds; - workarounds.mrtPerfWorkaround = true; - workarounds.setDataFasterThanImageUpload = true; - return workarounds; -} - -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h deleted file mode 100644 index 9df9c95763..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h +++ /dev/null @@ -1,189 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// renderer11_utils.h: Conversion functions and other utility routines -// specific to the D3D11 renderer. - -#ifndef LIBGLESV2_RENDERER_RENDERER11_UTILS_H -#define LIBGLESV2_RENDERER_RENDERER11_UTILS_H - -#include "libGLESv2/angletypes.h" -#include "libGLESv2/Caps.h" -#include "libGLESv2/Error.h" - -#include - -namespace gl -{ -class FramebufferAttachment; -} - -namespace rx -{ -class RenderTarget11; -struct Workarounds; - -namespace gl_d3d11 -{ - -D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha); -D3D11_BLEND_OP ConvertBlendOp(GLenum glBlendOp); -UINT8 ConvertColorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha); - -D3D11_CULL_MODE ConvertCullMode(bool cullEnabled, GLenum cullMode); - -D3D11_COMPARISON_FUNC ConvertComparison(GLenum comparison); -D3D11_DEPTH_WRITE_MASK ConvertDepthMask(bool depthWriteEnabled); -UINT8 ConvertStencilMask(GLuint stencilmask); -D3D11_STENCIL_OP ConvertStencilOp(GLenum stencilOp); - -D3D11_FILTER ConvertFilter(GLenum minFilter, GLenum magFilter, float maxAnisotropy, GLenum comparisonMode); -D3D11_TEXTURE_ADDRESS_MODE ConvertTextureWrap(GLenum wrap); - -D3D11_QUERY ConvertQueryType(GLenum queryType); - -} - -namespace d3d11_gl -{ - -void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); - -} - -namespace d3d11 -{ - -void MakeValidSize(bool isImage, DXGI_FORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); - -void GenerateInitialTextureData(GLint internalFormat, GLuint width, GLuint height, GLuint depth, - GLuint mipLevels, std::vector *outSubresourceData, - std::vector< std::vector > *outData); - -struct PositionTexCoordVertex -{ - float x, y; - float u, v; -}; -void SetPositionTexCoordVertex(PositionTexCoordVertex* vertex, float x, float y, float u, float v); - -struct PositionLayerTexCoord3DVertex -{ - float x, y; - unsigned int l; - float u, v, s; -}; -void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, float x, float y, - unsigned int layer, float u, float v, float s); - -template -struct PositionDepthColorVertex -{ - float x, y, z; - T r, g, b, a; -}; - -template -void SetPositionDepthColorVertex(PositionDepthColorVertex* vertex, float x, float y, float z, - const gl::Color &color) -{ - vertex->x = x; - vertex->y = y; - vertex->z = z; - vertex->r = color.red; - vertex->g = color.green; - vertex->b = color.blue; - vertex->a = color.alpha; -} - -HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name); - -template -outType* DynamicCastComObject(IUnknown* object) -{ - outType *outObject = NULL; - HRESULT result = object->QueryInterface(__uuidof(outType), reinterpret_cast(&outObject)); - if (SUCCEEDED(result)) - { - return outObject; - } - else - { - SafeRelease(outObject); - return NULL; - } -} - -inline bool isDeviceLostError(HRESULT errorCode) -{ - switch (errorCode) - { - case DXGI_ERROR_DEVICE_HUNG: - case DXGI_ERROR_DEVICE_REMOVED: - case DXGI_ERROR_DEVICE_RESET: - case DXGI_ERROR_DRIVER_INTERNAL_ERROR: - case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: - return true; - default: - return false; - } -} - -template -inline ID3D11VertexShader *CompileVS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) -{ - ID3D11VertexShader *vs = NULL; - HRESULT result = device->CreateVertexShader(byteCode, N, NULL, &vs); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - SetDebugName(vs, name); - return vs; -} - -template -inline ID3D11GeometryShader *CompileGS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) -{ - ID3D11GeometryShader *gs = NULL; - HRESULT result = device->CreateGeometryShader(byteCode, N, NULL, &gs); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - SetDebugName(gs, name); - return gs; -} - -template -inline ID3D11PixelShader *CompilePS(ID3D11Device *device, const BYTE (&byteCode)[N], const char *name) -{ - ID3D11PixelShader *ps = NULL; - HRESULT result = device->CreatePixelShader(byteCode, N, NULL, &ps); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - SetDebugName(ps, name); - return ps; -} - -// Copy data to small D3D11 buffers, such as for small constant buffers, which use one struct to -// represent an entire buffer. -template -inline void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBuffer, const T &value) -{ - D3D11_MAPPED_SUBRESOURCE mappedResource; - context->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - - memcpy(mappedResource.pData, &value, sizeof(T)); - - context->Unmap(constantBuffer, 0); -} - -gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget11 **outRT); - -Workarounds GenerateWorkarounds(); - -} - -} - -#endif // LIBGLESV2_RENDERER_RENDERER11_UTILS_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl deleted file mode 100644 index 20e6623a30..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl +++ /dev/null @@ -1,76 +0,0 @@ -Buffer Buffer4F : register(t0); -Buffer Buffer4I : register(t0); -Buffer Buffer4UI : register(t0); - -struct VS_OUTPUT -{ - float4 position : SV_Position; - uint index : TEXCOORD0; - uint slice : LAYER; -}; - -struct GS_OUTPUT -{ - float4 position : SV_Position; - uint index : TEXCOORD0; - uint slice : SV_RenderTargetArrayIndex; -}; - -cbuffer BufferCopyParams : register(b0) -{ - uint FirstPixelOffset; - uint PixelsPerRow; - uint RowStride; - uint RowsPerSlice; - float2 PositionOffset; - float2 PositionScale; - int2 TexLocationOffset; - int2 TexLocationScale; -} - -void ComputePositionAndIndex(uint vertexID, out VS_OUTPUT outVertex) -{ - uint PixelsPerSlice = PixelsPerRow * RowsPerSlice; - uint SliceStride = RowStride * RowsPerSlice; - - uint slice = vertexID / PixelsPerSlice; - uint sliceOffset = slice * PixelsPerSlice; - uint row = (vertexID - sliceOffset) / PixelsPerRow; - uint col = vertexID - sliceOffset - (row * PixelsPerRow); - - float2 coords = float2(float(col), float(row)); - - outVertex.position = float4(PositionOffset + PositionScale * coords, 0.0f, 1.0f); - outVertex.index = FirstPixelOffset + slice * SliceStride + row * RowStride + col; - outVertex.slice = slice; -} - -void VS_BufferToTexture(in uint vertexID : SV_VertexID, out VS_OUTPUT outVertex) -{ - ComputePositionAndIndex(vertexID, outVertex); -} - -[maxvertexcount(1)] -void GS_BufferToTexture(point VS_OUTPUT inVertex[1], inout PointStream outStream) -{ - GS_OUTPUT outVertex; - outVertex.position = inVertex[0].position; - outVertex.index = inVertex[0].index; - outVertex.slice = inVertex[0].slice; - outStream.Append(outVertex); -} - -float4 PS_BufferToTexture_4F(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target -{ - return Buffer4F.Load(inIndex); -} - -int4 PS_BufferToTexture_4I(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target -{ - return Buffer4I.Load(inIndex); -} - -uint4 PS_BufferToTexture_4UI(in float4 inPosition : SV_Position, in uint inIndex : TEXCOORD0) : SV_Target -{ - return Buffer4UI.Load(inIndex); -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl deleted file mode 100644 index b4cf38076e..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl +++ /dev/null @@ -1,106 +0,0 @@ -// Assume we are in SM4+, which has 8 color outputs - -void VS_ClearFloat( in float3 inPosition : POSITION, in float4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out float4 outColor : COLOR) -{ - outPosition = float4(inPosition, 1.0f); - outColor = inColor; -} - -struct PS_OutputFloat -{ - float4 color0 : SV_TARGET0; - float4 color1 : SV_TARGET1; - float4 color2 : SV_TARGET2; - float4 color3 : SV_TARGET3; -#if SM4 - float4 color4 : SV_TARGET4; - float4 color5 : SV_TARGET5; - float4 color6 : SV_TARGET6; - float4 color7 : SV_TARGET7; -#endif -}; - -PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) -{ - PS_OutputFloat outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; -#if SM4 - outColor.color4 = inColor; - outColor.color5 = inColor; - outColor.color6 = inColor; - outColor.color7 = inColor; -#endif - return outColor; -} - - -void VS_ClearUint( in float3 inPosition : POSITION, in uint4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out uint4 outColor : COLOR) -{ - outPosition = float4(inPosition, 1.0f); - outColor = inColor; -} - -struct PS_OutputUint -{ - uint4 color0 : SV_TARGET0; - uint4 color1 : SV_TARGET1; - uint4 color2 : SV_TARGET2; - uint4 color3 : SV_TARGET3; - uint4 color4 : SV_TARGET4; - uint4 color5 : SV_TARGET5; - uint4 color6 : SV_TARGET6; - uint4 color7 : SV_TARGET7; -}; - -PS_OutputUint PS_ClearUint(in float4 inPosition : SV_POSITION, in uint4 inColor : COLOR) -{ - PS_OutputUint outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; - outColor.color4 = inColor; - outColor.color5 = inColor; - outColor.color6 = inColor; - outColor.color7 = inColor; - return outColor; -} - - -void VS_ClearSint( in float3 inPosition : POSITION, in int4 inColor : COLOR, - out float4 outPosition : SV_POSITION, out int4 outColor : COLOR) -{ - outPosition = float4(inPosition, 1.0f); - outColor = inColor; -} - -struct PS_OutputSint -{ - int4 color0 : SV_TARGET0; - int4 color1 : SV_TARGET1; - int4 color2 : SV_TARGET2; - int4 color3 : SV_TARGET3; - int4 color4 : SV_TARGET4; - int4 color5 : SV_TARGET5; - int4 color6 : SV_TARGET6; - int4 color7 : SV_TARGET7; -}; - -PS_OutputSint PS_ClearSint(in float4 inPosition : SV_POSITION, in int4 inColor : COLOR) -{ - PS_OutputSint outColor; - outColor.color0 = inColor; - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; - outColor.color4 = inColor; - outColor.color5 = inColor; - outColor.color6 = inColor; - outColor.color7 = inColor; - return outColor; -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl deleted file mode 100644 index 8671c39fb7..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl +++ /dev/null @@ -1,111 +0,0 @@ -Texture2D TextureF : register(t0); -Texture2D TextureUI : register(t0); -Texture2D TextureI : register(t0); - -SamplerState Sampler : register(s0); - -void VS_Passthrough2D( in float2 inPosition : POSITION, in float2 inTexCoord : TEXCOORD0, - out float4 outPosition : SV_POSITION, out float2 outTexCoord : TEXCOORD0) -{ - outPosition = float4(inPosition, 0.0f, 1.0f); - outTexCoord = inTexCoord; -} - -float PS_PassthroughDepth2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_DEPTH -{ - return TextureF.Sample(Sampler, inTexCoord).r; -} - -float4 PS_PassthroughRGBA2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return TextureF.Sample(Sampler, inTexCoord).rgba; -} - -uint4 PS_PassthroughRGBA2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureUI.GetDimensions(size.x, size.y); - - return TextureUI.Load(int3(size * inTexCoord, 0)).rgba; -} - -int4 PS_PassthroughRGBA2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureI.GetDimensions(size.x, size.y); - - return TextureI.Load(int3(size * inTexCoord, 0)).rgba; -} - -float4 PS_PassthroughRGB2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return float4(TextureF.Sample(Sampler, inTexCoord).rgb, 1.0f); -} - -uint4 PS_PassthroughRGB2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureUI.GetDimensions(size.x, size.y); - - return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rgb, 0); -} - -int4 PS_PassthroughRGB2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureI.GetDimensions(size.x, size.y); - - return int4(TextureI.Load(int3(size * inTexCoord, 0)).rgb, 0); -} - -float4 PS_PassthroughRG2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return float4(TextureF.Sample(Sampler, inTexCoord).rg, 0.0f, 1.0f); -} - -uint4 PS_PassthroughRG2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureUI.GetDimensions(size.x, size.y); - - return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); -} - -int4 PS_PassthroughRG2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureI.GetDimensions(size.x, size.y); - - return int4(TextureI.Load(int3(size * inTexCoord, 0)).rg, 0, 0); -} - -float4 PS_PassthroughR2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return float4(TextureF.Sample(Sampler, inTexCoord).r, 0.0f, 0.0f, 1.0f); -} - -uint4 PS_PassthroughR2DUI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureUI.GetDimensions(size.x, size.y); - - return uint4(TextureUI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); -} - -int4 PS_PassthroughR2DI(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureI.GetDimensions(size.x, size.y); - - return int4(TextureI.Load(int3(size * inTexCoord, 0)).r, 0, 0, 0); -} - -float4 PS_PassthroughLum2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return float4(TextureF.Sample(Sampler, inTexCoord).rrr, 1.0f); -} - -float4 PS_PassthroughLumAlpha2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return TextureF.Sample(Sampler, inTexCoord).rrra; -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl deleted file mode 100644 index c23c9032ec..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl +++ /dev/null @@ -1,146 +0,0 @@ -Texture3D TextureF : register(t0); -Texture3D TextureUI : register(t0); -Texture3D TextureI : register(t0); - -SamplerState Sampler : register(s0); - -struct VS_INPUT -{ - float2 Position : POSITION; - uint Layer : LAYER; - float3 TexCoord : TEXCOORD; -}; - -struct VS_OUTPUT -{ - float4 Position : SV_POSITION; - uint Layer : LAYER; - float3 TexCoord : TEXCOORD; -}; - -struct GS_OUTPUT -{ - float4 Position : SV_POSITION; - uint Layer : SV_RENDERTARGETARRAYINDEX; - float3 TexCoord : TEXCOORD; -}; - -VS_OUTPUT VS_Passthrough3D(VS_INPUT input) -{ - VS_OUTPUT output; - - output.Position = float4(input.Position, 0.0f, 1.0f); - output.Layer = input.Layer; - output.TexCoord = input.TexCoord; - - return output; -} - -[maxvertexcount(3)] -void GS_Passthrough3D(triangle VS_OUTPUT input[3], inout TriangleStream outputStream) -{ - GS_OUTPUT output; - - for (int i = 0; i < 3; i++) - { - output.Position = input[i].Position; - output.Layer = input[i].Layer; - output.TexCoord = input[i].TexCoord; - - outputStream.Append(output); - } -} - -float4 PS_PassthroughRGBA3D(GS_OUTPUT input) : SV_TARGET0 -{ - return TextureF.Sample(Sampler, input.TexCoord).rgba; -} - -uint4 PS_PassthroughRGBA3DUI(GS_OUTPUT input) : SV_TARGET0 -{ - uint3 size; - TextureUI.GetDimensions(size.x, size.y, size.z); - - return TextureUI.Load(int4(size * input.TexCoord, 0)).rgba; -} - -int4 PS_PassthroughRGBA3DI(GS_OUTPUT input) : SV_TARGET0 -{ - uint3 size; - TextureI.GetDimensions(size.x, size.y, size.z); - - return TextureI.Load(int4(size * input.TexCoord, 0)).rgba; -} - -float4 PS_PassthroughRGB3D(GS_OUTPUT input) : SV_TARGET0 -{ - return float4(TextureF.Sample(Sampler, input.TexCoord).rgb, 1.0f); -} - -uint4 PS_PassthroughRGB3DUI(GS_OUTPUT input) : SV_TARGET0 -{ - uint3 size; - TextureUI.GetDimensions(size.x, size.y, size.z); - - return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rgb, 0); -} - -int4 PS_PassthroughRGB3DI(GS_OUTPUT input) : SV_TARGET0 -{ - uint3 size; - TextureI.GetDimensions(size.x, size.y, size.z); - - return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rgb, 0); -} - -float4 PS_PassthroughRG3D(GS_OUTPUT input) : SV_TARGET0 -{ - return float4(TextureF.Sample(Sampler, input.TexCoord).rg, 0.0f, 1.0f); -} - -uint4 PS_PassthroughRG3DUI(GS_OUTPUT input) : SV_TARGET0 -{ - uint3 size; - TextureUI.GetDimensions(size.x, size.y, size.z); - - return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); -} - -int4 PS_PassthroughRG3DI(GS_OUTPUT input) : SV_TARGET0 -{ - uint3 size; - TextureI.GetDimensions(size.x, size.y, size.z); - - return int4(TextureI.Load(int4(size * input.TexCoord, 0)).rg, 0, 0); -} - -float4 PS_PassthroughR3D(GS_OUTPUT input) : SV_TARGET0 -{ - return float4(TextureF.Sample(Sampler, input.TexCoord).r, 0.0f, 0.0f, 1.0f); -} - -uint4 PS_PassthroughR3DUI(GS_OUTPUT input) : SV_TARGET0 -{ - uint3 size; - TextureUI.GetDimensions(size.x, size.y, size.z); - - return uint4(TextureUI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); -} - -int4 PS_PassthroughR3DI(GS_OUTPUT input) : SV_TARGET0 -{ - uint3 size; - TextureI.GetDimensions(size.x, size.y, size.z); - - return int4(TextureI.Load(int4(size * input.TexCoord, 0)).r, 0, 0, 0); -} - -float4 PS_PassthroughLum3D(GS_OUTPUT input) : SV_TARGET0 -{ - return float4(TextureF.Sample(Sampler, input.TexCoord).rrr, 1.0f); -} - -float4 PS_PassthroughLumAlpha3D(GS_OUTPUT input) : SV_TARGET0 -{ - return TextureF.Sample(Sampler, input.TexCoord).rrra; -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl deleted file mode 100644 index 505e222137..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Swizzle11.hlsl +++ /dev/null @@ -1,99 +0,0 @@ -Texture2D TextureF2D : register(t0); -Texture2D TextureUI2D : register(t0); -Texture2D TextureI2D : register(t0); - -Texture3D TextureF3D : register(t0); -Texture3D TextureUI3D : register(t0); -Texture3D TextureI3D : register(t0); - -Texture2DArray TextureF2DArray : register(t0); -Texture2DArray TextureUI2DArray : register(t0); -Texture2DArray TextureI2DArray : register(t0); - -SamplerState Sampler : register(s0); - -cbuffer SwizzleProperties : register(b0) -{ - uint4 SwizzleIndices : packoffset(c0); -} - -float4 SwizzleLookup(in float4 sample) -{ - float lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; - return float4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); -} - -int4 SwizzleLookup(in int4 sample) -{ - int lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; - return int4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); -} - -uint4 SwizzleLookup(in uint4 sample) -{ - uint lookup[6] = { sample[0], sample[1], sample[2], sample[3], 0.0f, 1.0f }; - return uint4(lookup[SwizzleIndices[0]], lookup[SwizzleIndices[1]], lookup[SwizzleIndices[2]], lookup[SwizzleIndices[3]]); -} - -float4 PS_SwizzleF2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return SwizzleLookup(TextureF2D.Sample(Sampler, inTexCoord)); -} - -int4 PS_SwizzleI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureI2D.GetDimensions(size.x, size.y); - - return SwizzleLookup(TextureI2D.Load(int3(size * inTexCoord, 0))); -} - -uint4 PS_SwizzleUI2D(in float4 inPosition : SV_POSITION, in float2 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint2 size; - TextureUI2D.GetDimensions(size.x, size.y); - - return SwizzleLookup(TextureUI2D.Load(int3(size * inTexCoord, 0))); -} - -float4 PS_SwizzleF3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return SwizzleLookup(TextureF3D.Sample(Sampler, inTexCoord)); -} - -int4 PS_SwizzleI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint3 size; - TextureI3D.GetDimensions(size.x, size.y, size.z); - - return SwizzleLookup(TextureI3D.Load(int4(size * inTexCoord, 0))); -} - -uint4 PS_SwizzleUI3D(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint3 size; - TextureUI3D.GetDimensions(size.x, size.y, size.z); - - return SwizzleLookup(TextureUI3D.Load(int4(size * inTexCoord, 0))); -} - -float4 PS_SwizzleF2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - return SwizzleLookup(TextureF2DArray.Sample(Sampler, float3(inTexCoord.xy, inLayer))); -} - -int4 PS_SwizzleI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint3 size; - TextureI2DArray.GetDimensions(size.x, size.y, size.z); - - return SwizzleLookup(TextureI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); -} - -uint4 PS_SwizzleUI2DArray(in float4 inPosition : SV_POSITION, in uint inLayer : SV_RENDERTARGETARRAYINDEX, in float3 inTexCoord : TEXCOORD0) : SV_TARGET0 -{ - uint3 size; - TextureUI2DArray.GetDimensions(size.x, size.y, size.z); - - return SwizzleLookup(TextureUI2DArray.Load(int4(size.xy * inTexCoord.xy, inLayer, 0))); -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp deleted file mode 100644 index 2ca7a9cf8a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp +++ /dev/null @@ -1,679 +0,0 @@ -// -// 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. -// - -// Blit9.cpp: Surface copy utility class. - -#include "libGLESv2/renderer/d3d/d3d9/Blit9.h" -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" -#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/main.h" - -namespace -{ -// Precompiled shaders -#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/standardvs.h" -#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/flipyvs.h" -#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/passthroughps.h" -#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/luminanceps.h" -#include "libGLESv2/renderer/d3d/d3d9/shaders/compiled/componentmaskps.h" - -const BYTE* const g_shaderCode[] = -{ - g_vs20_VS_standard, - g_vs20_VS_flipy, - g_ps20_PS_passthrough, - g_ps20_PS_luminance, - g_ps20_PS_componentmask -}; - -const size_t g_shaderSize[] = -{ - sizeof(g_vs20_VS_standard), - sizeof(g_vs20_VS_flipy), - sizeof(g_ps20_PS_passthrough), - sizeof(g_ps20_PS_luminance), - sizeof(g_ps20_PS_componentmask) -}; -} - -namespace rx -{ - -Blit9::Blit9(Renderer9 *renderer) - : mRenderer(renderer), - mGeometryLoaded(false), - mQuadVertexBuffer(NULL), - mQuadVertexDeclaration(NULL), - mSavedStateBlock(NULL), - mSavedRenderTarget(NULL), - mSavedDepthStencil(NULL) -{ - memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); -} - -Blit9::~Blit9() -{ - SafeRelease(mSavedStateBlock); - SafeRelease(mQuadVertexBuffer); - SafeRelease(mQuadVertexDeclaration); - - for (int i = 0; i < SHADER_COUNT; i++) - { - SafeRelease(mCompiledShaders[i]); - } -} - -gl::Error Blit9::initialize() -{ - if (mGeometryLoaded) - { - return gl::Error(GL_NO_ERROR); - } - - static const float quad[] = - { - -1, -1, - -1, 1, - 1, -1, - 1, 1 - }; - - IDirect3DDevice9 *device = mRenderer->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 gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal blit vertex shader, result: 0x%X.", result); - } - - void *lockPtr = NULL; - result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0); - - if (FAILED(result) || lockPtr == NULL) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - SafeRelease(mQuadVertexBuffer); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex shader, result: 0x%X.", result); - } - - 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); - SafeRelease(mQuadVertexBuffer); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex declaration, result: 0x%X.", result); - } - - mGeometryLoaded = true; - return gl::Error(GL_NO_ERROR); -} - -template -gl::Error Blit9::setShader(ShaderId source, const char *profile, - gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), - HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) -{ - IDirect3DDevice9 *device = mRenderer->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]; - - gl::Error error = (mRenderer->*createShader)(reinterpret_cast(shaderCode), shaderSize, &shader); - if (error.isError()) - { - return error; - } - - mCompiledShaders[source] = shader; - } - - HRESULT hr = (device->*setShader)(shader); - if (FAILED(hr)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to set shader for blit operation, result: 0x%X.", hr); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Blit9::setVertexShader(ShaderId shader) -{ - return setShader(shader, "vs_2_0", &Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader); -} - -gl::Error Blit9::setPixelShader(ShaderId shader) -{ - return setShader(shader, "ps_2_0", &Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader); -} - -RECT Blit9::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; -} - -gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) -{ - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } - - IDirect3DTexture9 *texture = NULL; - error = copySurfaceToTexture(source, getSurfaceRect(source), &texture); - if (error.isError()) - { - return error; - } - - IDirect3DDevice9 *device = mRenderer->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(); - - SafeRelease(texture); - - restoreState(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Blit9::copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) -{ - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } - - gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); - ASSERT(colorbuffer); - - RenderTarget9 *renderTarget9 = NULL; - error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9); - if (error.isError()) - { - return error; - } - ASSERT(renderTarget9); - - IDirect3DSurface9 *source = renderTarget9->getSurface(); - ASSERT(source); - - IDirect3DSurface9 *destSurface = NULL; - TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); - error = storage9->getSurfaceLevel(level, true, &destSurface); - if (error.isError()) - { - return error; - } - ASSERT(destSurface); - - gl::Error result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); - - SafeRelease(destSurface); - SafeRelease(source); - - return result; -} - -gl::Error Blit9::copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) -{ - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } - - gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); - ASSERT(colorbuffer); - - RenderTarget9 *renderTarget9 = NULL; - error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9); - if (error.isError()) - { - return error; - } - ASSERT(renderTarget9); - - IDirect3DSurface9 *source = renderTarget9->getSurface(); - ASSERT(source); - - IDirect3DSurface9 *destSurface = NULL; - TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); - error = storage9->getCubeMapSurface(target, level, true, &destSurface); - if (error.isError()) - { - return error; - } - ASSERT(destSurface); - - gl::Error result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); - - SafeRelease(destSurface); - SafeRelease(source); - - return result; -} - -gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) -{ - ASSERT(source != NULL && dest != NULL); - - IDirect3DDevice9 *device = mRenderer->getDevice(); - - D3DSURFACE_DESC sourceDesc; - D3DSURFACE_DESC destDesc; - source->GetDesc(&sourceDesc); - dest->GetDesc(&destDesc); - - if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET && - d3d9_gl::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 gl::Error(GL_OUT_OF_MEMORY, "Failed to blit between textures, StretchRect result: 0x%X.", result); - } - - return gl::Error(GL_NO_ERROR); - } - else - { - return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest); - } -} - -gl::Error Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) -{ - gl::Error error = initialize(); - if (error.isError()) - { - return error; - } - - IDirect3DTexture9 *texture = NULL; - error = copySurfaceToTexture(source, sourceRect, &texture); - if (error.isError()) - { - return error; - } - - IDirect3DDevice9 *device = mRenderer->getDevice(); - - saveState(); - - device->SetTexture(0, texture); - device->SetRenderTarget(0, dest); - - setViewport(sourceRect, xoffset, yoffset); - - setCommonBlitState(); - - error = setFormatConvertShaders(destFormat); - if (!error.isError()) - { - render(); - } - - SafeRelease(texture); - - restoreState(); - - return error; -} - -gl::Error Blit9::setFormatConvertShaders(GLenum destFormat) -{ - gl::Error error = setVertexShader(SHADER_VS_STANDARD); - if (error.isError()) - { - return error; - } - - switch (destFormat) - { - default: UNREACHABLE(); - case GL_RGBA: - case GL_BGRA_EXT: - case GL_RGB: - case GL_RG_EXT: - case GL_RED_EXT: - case GL_ALPHA: - error = setPixelShader(SHADER_PS_COMPONENTMASK); - break; - - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - error = setPixelShader(SHADER_PS_LUMINANCE); - break; - } - - if (error.isError()) - { - return error; - } - - 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. - // Allocate one array for both registers and split it into two float4's. - float psConst[8] = { 0 }; - float *multConst = &psConst[0]; - float *addConst = &psConst[4]; - - switch (destFormat) - { - default: UNREACHABLE(); - case GL_RGBA: - case GL_BGRA_EXT: - multConst[X] = 1; - multConst[Y] = 1; - multConst[Z] = 1; - multConst[W] = 1; - addConst[X] = 0; - addConst[Y] = 0; - addConst[Z] = 0; - addConst[W] = 0; - break; - - case GL_RGB: - multConst[X] = 1; - multConst[Y] = 1; - multConst[Z] = 1; - multConst[W] = 0; - addConst[X] = 0; - addConst[Y] = 0; - addConst[Z] = 0; - addConst[W] = 1; - break; - - case GL_RG_EXT: - multConst[X] = 1; - multConst[Y] = 1; - multConst[Z] = 0; - multConst[W] = 0; - addConst[X] = 0; - addConst[Y] = 0; - addConst[Z] = 0; - addConst[W] = 1; - break; - - case GL_RED_EXT: - multConst[X] = 1; - multConst[Y] = 0; - multConst[Z] = 0; - multConst[W] = 0; - addConst[X] = 0; - addConst[Y] = 0; - addConst[Z] = 0; - addConst[W] = 1; - break; - - case GL_ALPHA: - multConst[X] = 0; - multConst[Y] = 0; - multConst[Z] = 0; - multConst[W] = 1; - addConst[X] = 0; - addConst[Y] = 0; - addConst[Z] = 0; - addConst[W] = 0; - break; - - case GL_LUMINANCE: - multConst[X] = 1; - multConst[Y] = 0; - multConst[Z] = 0; - multConst[W] = 0; - addConst[X] = 0; - addConst[Y] = 0; - addConst[Z] = 0; - addConst[W] = 1; - break; - - case GL_LUMINANCE_ALPHA: - multConst[X] = 1; - multConst[Y] = 0; - multConst[Z] = 0; - multConst[W] = 1; - addConst[X] = 0; - addConst[Y] = 0; - addConst[Z] = 0; - addConst[W] = 0; - break; - } - - mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture) -{ - ASSERT(surface); - - IDirect3DDevice9 *device = mRenderer->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 gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for blit, result: 0x%X.", result); - } - - IDirect3DSurface9 *textureSurface; - result = texture->GetSurfaceLevel(0, &textureSurface); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - SafeRelease(texture); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to query surface of internal blit texture, result: 0x%X.", result); - } - - mRenderer->endScene(); - result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE); - - SafeRelease(textureSurface); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - SafeRelease(texture); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy between internal blit textures, result: 0x%X.", result); - } - - *outTexture = texture; - return gl::Error(GL_NO_ERROR); -} - -void Blit9::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) -{ - IDirect3DDevice9 *device = mRenderer->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 Blit9::setCommonBlitState() -{ - IDirect3DDevice9 *device = mRenderer->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 < gl::MAX_VERTEX_ATTRIBS; i++) - { - device->SetStreamSourceFreq(i, 1); - } -} - -void Blit9::render() -{ - IDirect3DDevice9 *device = mRenderer->getDevice(); - - HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float)); - hr = device->SetVertexDeclaration(mQuadVertexDeclaration); - - mRenderer->startScene(); - hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); -} - -void Blit9::saveState() -{ - IDirect3DDevice9 *device = mRenderer->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[8] = { 0 }; - - device->SetVertexShader(NULL); - device->SetVertexShaderConstantF(0, dummyConst, 2); - device->SetPixelShader(NULL); - device->SetPixelShaderConstantF(0, dummyConst, 2); - - 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 Blit9::restoreState() -{ - IDirect3DDevice9 *device = mRenderer->getDevice(); - - device->SetDepthStencilSurface(mSavedDepthStencil); - SafeRelease(mSavedDepthStencil); - - device->SetRenderTarget(0, mSavedRenderTarget); - SafeRelease(mSavedRenderTarget); - - ASSERT(mSavedStateBlock != NULL); - - if (mSavedStateBlock != NULL) - { - mSavedStateBlock->Apply(); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h deleted file mode 100644 index 5c7a76ce05..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// 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. -// - -// Blit9.cpp: Surface copy utility class. - -#ifndef LIBGLESV2_BLIT9_H_ -#define LIBGLESV2_BLIT9_H_ - -#include "common/angleutils.h" -#include "libGLESv2/Error.h" - -#include - -namespace gl -{ -class Framebuffer; -} - -namespace rx -{ -class Renderer9; -class TextureStorage; - -class Blit9 -{ - public: - explicit Blit9(Renderer9 *renderer); - ~Blit9(); - - gl::Error initialize(); - - // Copy from source surface to dest surface. - // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) - gl::Error copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); - gl::Error copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); - - // 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. - gl::Error 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. - gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); - - private: - Renderer9 *mRenderer; - - bool mGeometryLoaded; - IDirect3DVertexBuffer9 *mQuadVertexBuffer; - IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; - - gl::Error setFormatConvertShaders(GLenum destFormat); - - gl::Error copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); - gl::Error copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture); - 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 - gl::Error setShader(ShaderId source, const char *profile, - gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), - HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); - - gl::Error setVertexShader(ShaderId shader); - gl::Error setPixelShader(ShaderId shader); - void render(); - - void saveState(); - void restoreState(); - IDirect3DStateBlock9 *mSavedStateBlock; - IDirect3DSurface9 *mSavedRenderTarget; - IDirect3DSurface9 *mSavedDepthStencil; - - DISALLOW_COPY_AND_ASSIGN(Blit9); -}; -} - -#endif // LIBGLESV2_BLIT9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp deleted file mode 100644 index 430fe81e50..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright 2014 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. -// - -// Buffer9.cpp Defines the Buffer9 class. - -#include "libGLESv2/renderer/d3d/d3d9/Buffer9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -Buffer9::Buffer9(Renderer9 *renderer) - : BufferD3D(), - mRenderer(renderer), - mSize(0) -{} - -Buffer9::~Buffer9() -{ - mSize = 0; -} - -Buffer9 *Buffer9::makeBuffer9(BufferImpl *buffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(Buffer9*, buffer)); - return static_cast(buffer); -} - -gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) -{ - if (size > mMemory.size()) - { - if (!mMemory.resize(size)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); - } - } - - mSize = size; - if (data && size > 0) - { - memcpy(mMemory.data(), data, size); - } - - invalidateStaticData(); - - if (usage == GL_STATIC_DRAW) - { - initializeStaticData(); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Buffer9::getData(const uint8_t **outData) -{ - *outData = mMemory.data(); - return gl::Error(GL_NO_ERROR); -} - -gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) -{ - if (offset + size > mMemory.size()) - { - if (!mMemory.resize(offset + size)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer."); - } - } - - mSize = std::max(mSize, offset + size); - if (data && size > 0) - { - memcpy(mMemory.data() + offset, data, size); - } - - invalidateStaticData(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Buffer9::copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) -{ - // Note: this method is currently unreachable - Buffer9* sourceBuffer = makeBuffer9(source); - ASSERT(sourceBuffer); - - memcpy(mMemory.data() + destOffset, sourceBuffer->mMemory.data() + sourceOffset, size); - - invalidateStaticData(); - - return gl::Error(GL_NO_ERROR); -} - -// We do not support buffer mapping in D3D9 -gl::Error Buffer9::map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) -{ - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); -} - -gl::Error Buffer9::unmap() -{ - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); -} - -void Buffer9::markTransformFeedbackUsage() -{ - UNREACHABLE(); -} - -RendererD3D *Buffer9::getRenderer() -{ - return mRenderer; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h deleted file mode 100644 index c80b009738..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright 2014 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. -// - -// Buffer9.h: Defines the rx::Buffer9 class which implements rx::BufferImpl via rx::BufferD3D. - -#ifndef LIBGLESV2_RENDERER_BUFFER9_H_ -#define LIBGLESV2_RENDERER_BUFFER9_H_ - -#include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/renderer/d3d/MemoryBuffer.h" -#include "libGLESv2/angletypes.h" - -namespace rx -{ -class Renderer9; - -class Buffer9 : public BufferD3D -{ - public: - Buffer9(Renderer9 *renderer); - virtual ~Buffer9(); - - static Buffer9 *makeBuffer9(BufferImpl *buffer); - - // BufferD3D implementation - virtual size_t getSize() const { return mSize; } - virtual bool supportsDirectBinding() const { return false; } - RendererD3D *getRenderer() override; - - // BufferImpl implementation - virtual gl::Error setData(const void* data, size_t size, GLenum usage); - gl::Error getData(const uint8_t **outData) override; - virtual gl::Error setSubData(const void* data, size_t size, size_t offset); - virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); - virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); - virtual gl::Error unmap(); - virtual void markTransformFeedbackUsage(); - - private: - DISALLOW_COPY_AND_ASSIGN(Buffer9); - - Renderer9 *mRenderer; - MemoryBuffer mMemory; - size_t mSize; -}; - -} - -#endif // LIBGLESV2_RENDERER_BUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp deleted file mode 100644 index 66263fe110..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Fence9.cpp: Defines the rx::FenceNV9 class. - -#include "libGLESv2/renderer/d3d/d3d9/Fence9.h" -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -FenceNV9::FenceNV9(Renderer9 *renderer) - : FenceNVImpl(), - mRenderer(renderer), - mQuery(NULL) -{ -} - -FenceNV9::~FenceNV9() -{ - SafeRelease(mQuery); -} - -gl::Error FenceNV9::set() -{ - if (!mQuery) - { - gl::Error error = mRenderer->allocateEventQuery(&mQuery); - if (error.isError()) - { - return error; - } - } - - HRESULT result = mQuery->Issue(D3DISSUE_END); - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - SafeRelease(mQuery); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to end event query, result: 0x%X.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error FenceNV9::test(bool flushCommandBuffer, GLboolean *outFinished) -{ - ASSERT(mQuery); - - DWORD getDataFlags = (flushCommandBuffer ? D3DGETDATA_FLUSH : 0); - HRESULT result = mQuery->GetData(NULL, 0, getDataFlags); - - if (d3d9::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); - } - else if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); - } - - ASSERT(result == S_OK || result == S_FALSE); - *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); - return gl::Error(GL_NO_ERROR); -} - -gl::Error FenceNV9::finishFence(GLboolean *outFinished) -{ - ASSERT(outFinished); - - while (*outFinished != GL_TRUE) - { - gl::Error error = test(true, outFinished); - if (error.isError()) - { - return error; - } - - Sleep(0); - } - - return gl::Error(GL_NO_ERROR); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h deleted file mode 100644 index d7873d5264..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Fence9.h: Defines the rx::FenceNV9 class which implements rx::FenceNVImpl. - -#ifndef LIBGLESV2_RENDERER_FENCE9_H_ -#define LIBGLESV2_RENDERER_FENCE9_H_ - -#include "libGLESv2/renderer/FenceImpl.h" - -namespace rx -{ -class Renderer9; - -class FenceNV9 : public FenceNVImpl -{ - public: - explicit FenceNV9(Renderer9 *renderer); - virtual ~FenceNV9(); - - gl::Error set(); - gl::Error test(bool flushCommandBuffer, GLboolean *outFinished); - gl::Error finishFence(GLboolean *outFinished); - - private: - DISALLOW_COPY_AND_ASSIGN(FenceNV9); - - Renderer9 *mRenderer; - IDirect3DQuery9 *mQuery; -}; - -} - -#endif // LIBGLESV2_RENDERER_FENCE9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp deleted file mode 100644 index 2a06d12942..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp +++ /dev/null @@ -1,792 +0,0 @@ -// -// 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. -// - -// Image9.cpp: Implements the rx::Image9 class, which acts as the interface to -// the actual underlying surfaces of a Texture. - -#include "libGLESv2/renderer/d3d/d3d9/Image9.h" -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" -#include "libGLESv2/main.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/Renderbuffer.h" -#include "common/utilities.h" - -namespace rx -{ - -Image9::Image9() -{ - mSurface = NULL; - mRenderer = NULL; - - mD3DPool = D3DPOOL_SYSTEMMEM; - mD3DFormat = D3DFMT_UNKNOWN; -} - -Image9::~Image9() -{ - SafeRelease(mSurface); -} - -gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) -{ - D3DSURFACE_DESC destDesc; - HRESULT result = destSurface->GetDesc(&destDesc); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the source surface description for mipmap generation, result: 0x%X.", result); - } - - D3DSURFACE_DESC sourceDesc; - result = sourceSurface->GetDesc(&sourceDesc); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the destination surface description for mipmap generation, result: 0x%X.", result); - } - - ASSERT(sourceDesc.Format == destDesc.Format); - ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); - ASSERT(sourceDesc.Height == 1 || sourceDesc.Height / 2 == destDesc.Height); - - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(sourceDesc.Format); - ASSERT(d3dFormatInfo.mipGenerationFunction != NULL); - - D3DLOCKED_RECT sourceLocked = {0}; - result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface for mipmap generation, result: 0x%X.", result); - } - - D3DLOCKED_RECT destLocked = {0}; - result = destSurface->LockRect(&destLocked, NULL, 0); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - sourceSurface->UnlockRect(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the destination surface for mipmap generation, result: 0x%X.", result); - } - - const uint8_t *sourceData = reinterpret_cast(sourceLocked.pBits); - uint8_t *destData = reinterpret_cast(destLocked.pBits); - - ASSERT(sourceData && destData); - - d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, - destData, destLocked.Pitch, 0); - - destSurface->UnlockRect(); - sourceSurface->UnlockRect(); - - return gl::Error(GL_NO_ERROR); -} - -Image9 *Image9::makeImage9(Image *img) -{ - ASSERT(HAS_DYNAMIC_TYPE(Image9*, img)); - return static_cast(img); -} - -gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source) -{ - IDirect3DSurface9 *sourceSurface = NULL; - gl::Error error = source->getSurface(&sourceSurface); - if (error.isError()) - { - return error; - } - - IDirect3DSurface9 *destSurface = NULL; - error = dest->getSurface(&destSurface); - if (error.isError()) - { - return error; - } - - error = generateMip(destSurface, sourceSurface); - if (error.isError()) - { - return error; - } - - dest->markDirty(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) -{ - D3DLOCKED_RECT sourceLock = {0}; - D3DLOCKED_RECT destLock = {0}; - - HRESULT result; - - result = source->LockRect(&sourceLock, NULL, 0); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); - } - - result = dest->LockRect(&destLock, NULL, 0); - if (FAILED(result)) - { - source->UnlockRect(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); - } - - ASSERT(sourceLock.pBits && destLock.pBits); - - D3DSURFACE_DESC desc; - source->GetDesc(&desc); - - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); - unsigned int rows = desc.Height / d3dFormatInfo.blockHeight; - - unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight); - ASSERT(bytes <= static_cast(sourceLock.Pitch) && - bytes <= static_cast(destLock.Pitch)); - - for(unsigned int i = 0; i < rows; i++) - { - memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); - } - - source->UnlockRect(); - dest->UnlockRect(); - - return gl::Error(GL_NO_ERROR); -} - -bool Image9::redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) -{ - // 3D textures are not supported by the D3D9 backend. - ASSERT(depth <= 1); - - // Only 2D and cube texture are supported by the D3D9 backend. - ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP); - - if (mWidth != width || - mHeight != height || - mDepth != depth || - mInternalFormat != internalformat || - forceRelease) - { - mRenderer = Renderer9::makeRenderer9(renderer); - - mWidth = width; - mHeight = height; - mDepth = depth; - mInternalFormat = internalformat; - - // compute the d3d format that will be used - const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalformat); - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat); - mD3DFormat = d3d9FormatInfo.texFormat; - mActualFormat = d3dFormatInfo.internalFormat; - mRenderable = (d3d9FormatInfo.renderFormat != D3DFMT_UNKNOWN); - - SafeRelease(mSurface); - mDirty = (d3d9FormatInfo.dataInitializerFunction != NULL); - - return true; - } - - return false; -} - -gl::Error Image9::createSurface() -{ - if (mSurface) - { - return gl::Error(GL_NO_ERROR); - } - - IDirect3DTexture9 *newTexture = NULL; - IDirect3DSurface9 *newSurface = NULL; - const D3DPOOL poolToUse = D3DPOOL_SYSTEMMEM; - const D3DFORMAT d3dFormat = getD3DFormat(); - - if (mWidth != 0 && mHeight != 0) - { - int levelToFetch = 0; - GLsizei requestWidth = mWidth; - GLsizei requestHeight = mHeight; - d3d9::MakeValidSize(true, d3dFormat, &requestWidth, &requestHeight, &levelToFetch); - - IDirect3DDevice9 *device = mRenderer->getDevice(); - - HRESULT result = device->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, 0, d3dFormat, - poolToUse, &newTexture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create image surface, result: 0x%X.", result); - } - - newTexture->GetSurfaceLevel(levelToFetch, &newSurface); - SafeRelease(newTexture); - - const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); - if (d3dFormatInfo.dataInitializerFunction != NULL) - { - RECT entireRect; - entireRect.left = 0; - entireRect.right = mWidth; - entireRect.top = 0; - entireRect.bottom = mHeight; - - D3DLOCKED_RECT lockedRect; - result = newSurface->LockRect(&lockedRect, &entireRect, 0); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); - } - - d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast(lockedRect.pBits), - lockedRect.Pitch, 0); - - result = newSurface->UnlockRect(); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock image surface, result: 0x%X.", result); - } - } - } - - mSurface = newSurface; - mDirty = false; - mD3DPool = poolToUse; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect) -{ - gl::Error error = createSurface(); - if (error.isError()) - { - return error; - } - - if (mSurface) - { - HRESULT result = mSurface->LockRect(lockedRect, &rect, 0); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); - } - - mDirty = true; - } - - return gl::Error(GL_NO_ERROR); -} - -void Image9::unlock() -{ - if (mSurface) - { - HRESULT result = mSurface->UnlockRect(); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - } -} - -D3DFORMAT Image9::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; -} - -bool Image9::isDirty() const -{ - // Make sure to that this image is marked as dirty even if the staging texture hasn't been created yet - // if initialization is required before use. - return (mSurface || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty; -} - -gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface) -{ - gl::Error error = createSurface(); - if (error.isError()) - { - return error; - } - - *outSurface = mSurface; - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level) -{ - IDirect3DSurface9 *surface = NULL; - TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); - gl::Error error = storage9->getSurfaceLevel(level, false, &surface); - if (error.isError()) - { - return error; - } - return setManagedSurface(surface); -} - -gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level) -{ - IDirect3DSurface9 *surface = NULL; - TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); - gl::Error error = storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface); - if (error.isError()) - { - return error; - } - return setManagedSurface(surface); -} - -gl::Error Image9::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) - { - gl::Error error = copyLockableSurfaces(surface, mSurface); - SafeRelease(mSurface); - if (error.isError()) - { - return error; - } - } - - mSurface = surface; - mD3DPool = desc.Pool; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) -{ - gl::Error error = createSurface(); - if (error.isError()) - { - return error; - } - - IDirect3DSurface9 *destSurface = NULL; - - if (index.type == GL_TEXTURE_2D) - { - TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); - gl::Error error = storage9->getSurfaceLevel(index.mipIndex, true, &destSurface); - if (error.isError()) - { - return error; - } - } - else - { - ASSERT(gl::IsCubemapTextureTarget(index.type)); - TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); - gl::Error error = storage9->getCubeMapSurface(index.type, index.mipIndex, true, &destSurface); - if (error.isError()) - { - return error; - } - } - - error = copyToSurface(destSurface, region.x, region.y, region.width, region.height); - SafeRelease(destSurface); - return error; -} - -gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) -{ - ASSERT(width > 0 && height > 0); - ASSERT(destSurface); - - IDirect3DSurface9 *sourceSurface = NULL; - gl::Error error = getSurface(&sourceSurface); - if (error.isError()) - { - return error; - } - - ASSERT(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}; - - IDirect3DDevice9 *device = mRenderer->getDevice(); - - if (mD3DPool == D3DPOOL_MANAGED) - { - D3DSURFACE_DESC desc; - sourceSurface->GetDesc(&desc); - - IDirect3DSurface9 *surf = 0; - HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal CreateOffscreenPlainSurface call failed, result: 0x%X.", result); - } - - copyLockableSurfaces(surf, sourceSurface); - result = device->UpdateSurface(surf, &rect, destSurface, &point); - SafeRelease(surf); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); - } - } - else - { - // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools - HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); - } - } - - return gl::Error(GL_NO_ERROR); -} - -// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input -// into the target pixel rectangle. -gl::Error Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input) -{ - // 3D textures are not supported by the D3D9 backend. - ASSERT(zoffset == 0 && depth == 1); - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); - GLsizei inputRowPitch = formatInfo.computeRowPitch(type, width, unpackAlignment); - - const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); - ASSERT(d3dFormatInfo.loadFunction != NULL); - - RECT lockRect = - { - xoffset, yoffset, - xoffset + width, yoffset + height - }; - - D3DLOCKED_RECT locked; - gl::Error error = lock(&locked, lockRect); - if (error.isError()) - { - return error; - } - - d3dFormatInfo.loadFunction(width, height, depth, - reinterpret_cast(input), inputRowPitch, 0, - reinterpret_cast(locked.pBits), locked.Pitch, 0); - - unlock(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input) -{ - // 3D textures are not supported by the D3D9 backend. - ASSERT(zoffset == 0 && depth == 1); - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); - GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, width, 1); - GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1); - - const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(mInternalFormat); - - ASSERT(xoffset % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockWidth == 0); - ASSERT(yoffset % d3d9::GetD3DFormatInfo(d3d9FormatInfo.texFormat).blockHeight == 0); - - ASSERT(d3d9FormatInfo.loadFunction != NULL); - - RECT lockRect = - { - xoffset, yoffset, - xoffset + width, yoffset + height - }; - - D3DLOCKED_RECT locked; - gl::Error error = lock(&locked, lockRect); - if (error.isError()) - { - return error; - } - - d3d9FormatInfo.loadFunction(width, height, depth, - reinterpret_cast(input), inputRowPitch, inputDepthPitch, - reinterpret_cast(locked.pBits), locked.Pitch, 0); - - unlock(); - - return gl::Error(GL_NO_ERROR); -} - -// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures -gl::Error Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) -{ - ASSERT(source); - - // ES3.0 only behaviour to copy into a 3d texture - ASSERT(zoffset == 0); - - RenderTarget9 *renderTarget = RenderTarget9::makeRenderTarget9(source); - - IDirect3DSurface9 *surface = renderTarget->getSurface(); - ASSERT(surface); - - IDirect3DDevice9 *device = mRenderer->getDevice(); - - IDirect3DSurface9 *renderTargetData = NULL; - D3DSURFACE_DESC description; - surface->GetDesc(&description); - - HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL); - - if (FAILED(result)) - { - SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "Could not create matching destination surface, result: 0x%X.", result); - } - - result = device->GetRenderTargetData(surface, renderTargetData); - - if (FAILED(result)) - { - SafeRelease(renderTargetData); - SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "GetRenderTargetData unexpectedly failed, result: 0x%X.", result); - } - - int width = sourceArea.width; - int height = sourceArea.height; - - RECT sourceRect = { sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height }; - RECT destRect = { xoffset, yoffset, xoffset + width, yoffset + height }; - - D3DLOCKED_RECT sourceLock = {0}; - result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); - - if (FAILED(result)) - { - SafeRelease(renderTargetData); - SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface (rectangle might be invalid), result: 0x%X.", result); - } - - D3DLOCKED_RECT destLock = {0}; - gl::Error error = lock(&destLock, destRect); - if (error.isError()) - { - renderTargetData->UnlockRect(); - SafeRelease(renderTargetData); - SafeRelease(surface); - return error; - } - - ASSERT(destLock.pBits && sourceLock.pBits); - - unsigned char *sourcePixels = (unsigned char*)sourceLock.pBits; - unsigned char *destPixels = (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(destPixels, sourcePixels, 4 * width); - sourcePixels += sourceLock.Pitch; - destPixels += destLock.Pitch; - } - break; - case D3DFMT_L8: - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - destPixels[x] = sourcePixels[x * 4 + 2]; - } - sourcePixels += sourceLock.Pitch; - destPixels += destLock.Pitch; - } - break; - case D3DFMT_A8L8: - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2]; - destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3]; - } - sourcePixels += sourceLock.Pitch; - destPixels += 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*)sourcePixels)[x]; - unsigned char red = (rgb & 0xF800) >> 8; - unsigned char green = (rgb & 0x07E0) >> 3; - unsigned char blue = (rgb & 0x001F) << 3; - destPixels[x + 0] = blue | (blue >> 5); - destPixels[x + 1] = green | (green >> 6); - destPixels[x + 2] = red | (red >> 5); - destPixels[x + 3] = 0xFF; - } - sourcePixels += sourceLock.Pitch; - destPixels += destLock.Pitch; - } - break; - case D3DFMT_L8: - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - unsigned char red = sourcePixels[x * 2 + 1] & 0xF8; - destPixels[x] = red | (red >> 5); - } - sourcePixels += sourceLock.Pitch; - destPixels += 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*)sourcePixels)[x]; - unsigned char red = (argb & 0x7C00) >> 7; - unsigned char green = (argb & 0x03E0) >> 2; - unsigned char blue = (argb & 0x001F) << 3; - destPixels[x + 0] = blue | (blue >> 5); - destPixels[x + 1] = green | (green >> 5); - destPixels[x + 2] = red | (red >> 5); - destPixels[x + 3] = 0xFF; - } - sourcePixels += sourceLock.Pitch; - destPixels += 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*)sourcePixels)[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; - destPixels[x + 0] = blue | (blue >> 5); - destPixels[x + 1] = green | (green >> 5); - destPixels[x + 2] = red | (red >> 5); - destPixels[x + 3] = alpha; - } - sourcePixels += sourceLock.Pitch; - destPixels += destLock.Pitch; - } - break; - case D3DFMT_L8: - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; - destPixels[x] = (red << 1) | (red >> 4); - } - sourcePixels += sourceLock.Pitch; - destPixels += destLock.Pitch; - } - break; - case D3DFMT_A8L8: - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x++) - { - unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; - destPixels[x * 2 + 0] = (red << 1) | (red >> 4); - destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7; - } - sourcePixels += sourceLock.Pitch; - destPixels += destLock.Pitch; - } - break; - default: - UNREACHABLE(); - } - break; - default: - UNREACHABLE(); - } - - unlock(); - renderTargetData->UnlockRect(); - - SafeRelease(renderTargetData); - SafeRelease(surface); - - mDirty = true; - return gl::Error(GL_NO_ERROR); -} - -gl::Error Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage) -{ - // Currently unreachable, due to only being used in a D3D11-only workaround - UNIMPLEMENTED(); - return gl::Error(GL_INVALID_OPERATION); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h deleted file mode 100644 index 8cc2258859..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (c) 2002-2014 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. -// - -// Image9.h: Defines the rx::Image9 class, which acts as the interface to -// the actual underlying surfaces of a Texture. - -#ifndef LIBGLESV2_RENDERER_IMAGE9_H_ -#define LIBGLESV2_RENDERER_IMAGE9_H_ - -#include "libGLESv2/renderer/d3d/ImageD3D.h" -#include "common/debug.h" - -namespace gl -{ -class Framebuffer; -} - -namespace rx -{ -class Renderer9; - -class Image9 : public ImageD3D -{ - public: - Image9(); - ~Image9(); - - static Image9 *makeImage9(Image *img); - - static gl::Error generateMipmap(Image9 *dest, Image9 *source); - static gl::Error generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); - static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); - - bool redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) override; - - D3DFORMAT getD3DFormat() const; - - virtual bool isDirty() const; - - virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level); - virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level); - virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); - - virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input); - virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input); - - virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source); - virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, - const gl::ImageIndex &sourceIndex, TextureStorage *source); - - private: - DISALLOW_COPY_AND_ASSIGN(Image9); - - gl::Error getSurface(IDirect3DSurface9 **outSurface); - - gl::Error createSurface(); - gl::Error setManagedSurface(IDirect3DSurface9 *surface); - gl::Error copyToSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - - gl::Error lock(D3DLOCKED_RECT *lockedRect, const RECT &rect); - void unlock(); - - Renderer9 *mRenderer; - - D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable. - D3DFORMAT mD3DFormat; - - IDirect3DSurface9 *mSurface; -}; -} - -#endif // LIBGLESV2_RENDERER_IMAGE9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp deleted file mode 100644 index 1c51b9e985..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// -// Copyright (c) 2002-2014 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. -// - -// Indexffer9.cpp: Defines the D3D9 IndexBuffer implementation. - -#include "libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" - -namespace rx -{ - -IndexBuffer9::IndexBuffer9(Renderer9 *const renderer) : mRenderer(renderer) -{ - mIndexBuffer = NULL; - mBufferSize = 0; - mIndexType = 0; - mDynamic = false; -} - -IndexBuffer9::~IndexBuffer9() -{ - SafeRelease(mIndexBuffer); -} - -gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) -{ - SafeRelease(mIndexBuffer); - - updateSerial(); - - if (bufferSize > 0) - { - D3DFORMAT format = D3DFMT_UNKNOWN; - if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE) - { - format = D3DFMT_INDEX16; - } - else if (indexType == GL_UNSIGNED_INT) - { - ASSERT(mRenderer->getRendererExtensions().elementIndexUint); - format = D3DFMT_INDEX32; - } - else UNREACHABLE(); - - DWORD usageFlags = D3DUSAGE_WRITEONLY; - if (dynamic) - { - usageFlags |= D3DUSAGE_DYNAMIC; - } - - HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); - } - } - - mBufferSize = bufferSize; - mIndexType = indexType; - mDynamic = dynamic; - - return gl::Error(GL_NO_ERROR); -} - -IndexBuffer9 *IndexBuffer9::makeIndexBuffer9(IndexBuffer *indexBuffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(IndexBuffer9*, indexBuffer)); - return static_cast(indexBuffer); -} - -gl::Error IndexBuffer9::mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory) -{ - if (!mIndexBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); - } - - DWORD lockFlags = mDynamic ? D3DLOCK_NOOVERWRITE : 0; - - void *mapPtr = NULL; - HRESULT result = mIndexBuffer->Lock(offset, size, &mapPtr, lockFlags); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); - } - - *outMappedMemory = mapPtr; - return gl::Error(GL_NO_ERROR); -} - -gl::Error IndexBuffer9::unmapBuffer() -{ - if (!mIndexBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); - } - - HRESULT result = mIndexBuffer->Unlock(); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -GLenum IndexBuffer9::getIndexType() const -{ - return mIndexType; -} - -unsigned int IndexBuffer9::getBufferSize() const -{ - return mBufferSize; -} - -gl::Error IndexBuffer9::setSize(unsigned int bufferSize, GLenum indexType) -{ - if (bufferSize > mBufferSize || indexType != mIndexType) - { - return initialize(bufferSize, indexType, mDynamic); - } - else - { - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error IndexBuffer9::discard() -{ - if (!mIndexBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal index buffer is not initialized."); - } - - void *dummy; - HRESULT result; - - result = mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal index buffer, HRESULT: 0x%08x.", result); - } - - result = mIndexBuffer->Unlock(); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal index buffer, HRESULT: 0x%08x.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -D3DFORMAT IndexBuffer9::getIndexFormat() const -{ - switch (mIndexType) - { - case GL_UNSIGNED_BYTE: return D3DFMT_INDEX16; - case GL_UNSIGNED_SHORT: return D3DFMT_INDEX16; - case GL_UNSIGNED_INT: return D3DFMT_INDEX32; - default: UNREACHABLE(); return D3DFMT_UNKNOWN; - } -} - -IDirect3DIndexBuffer9 * IndexBuffer9::getBuffer() const -{ - return mIndexBuffer; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h deleted file mode 100644 index 2375fcf4b0..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// 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. -// - -// Indexffer9.h: Defines the D3D9 IndexBuffer implementation. - -#ifndef LIBGLESV2_RENDERER_INDEXBUFFER9_H_ -#define LIBGLESV2_RENDERER_INDEXBUFFER9_H_ - -#include "libGLESv2/renderer/d3d/IndexBuffer.h" - -namespace rx -{ -class Renderer9; - -class IndexBuffer9 : public IndexBuffer -{ - public: - explicit IndexBuffer9(Renderer9 *const renderer); - virtual ~IndexBuffer9(); - - virtual gl::Error initialize(unsigned int bufferSize, GLenum indexType, bool dynamic); - - static IndexBuffer9 *makeIndexBuffer9(IndexBuffer *indexBuffer); - - virtual gl::Error mapBuffer(unsigned int offset, unsigned int size, void** outMappedMemory); - virtual gl::Error unmapBuffer(); - - virtual GLenum getIndexType() const; - virtual unsigned int getBufferSize() const; - virtual gl::Error setSize(unsigned int bufferSize, GLenum indexType); - - virtual gl::Error discard(); - - D3DFORMAT getIndexFormat() const; - IDirect3DIndexBuffer9 *getBuffer() const; - - private: - DISALLOW_COPY_AND_ASSIGN(IndexBuffer9); - - Renderer9 *const mRenderer; - - IDirect3DIndexBuffer9 *mIndexBuffer; - unsigned int mBufferSize; - GLenum mIndexType; - bool mDynamic; -}; - -} - -#endif // LIBGLESV2_RENDERER_INDEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp deleted file mode 100644 index a3cab578be..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp +++ /dev/null @@ -1,144 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Query9.cpp: Defines the rx::Query9 class which implements rx::QueryImpl. - -#include "libGLESv2/renderer/d3d/d3d9/Query9.h" -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/main.h" - -#include - -namespace rx -{ -Query9::Query9(Renderer9 *renderer, GLenum type) - : QueryImpl(type), - mResult(GL_FALSE), - mQueryFinished(false), - mRenderer(renderer), - mQuery(NULL) -{ -} - -Query9::~Query9() -{ - SafeRelease(mQuery); -} - -gl::Error Query9::begin() -{ - if (mQuery == NULL) - { - HRESULT result = mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result); - } - } - - HRESULT result = mQuery->Issue(D3DISSUE_BEGIN); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Query9::end() -{ - ASSERT(mQuery); - - HRESULT result = mQuery->Issue(D3DISSUE_END); - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to end internal query, result: 0x%X.", result); - } - - mQueryFinished = false; - mResult = GL_FALSE; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Query9::getResult(GLuint *params) -{ - while (!mQueryFinished) - { - gl::Error error = testQuery(); - if (error.isError()) - { - return error; - } - - if (!mQueryFinished) - { - Sleep(0); - } - } - - ASSERT(mQueryFinished); - *params = mResult; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Query9::isResultAvailable(GLuint *available) -{ - gl::Error error = testQuery(); - if (error.isError()) - { - return error; - } - - *available = (mQueryFinished ? GL_TRUE : GL_FALSE); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Query9::testQuery() -{ - if (!mQueryFinished) - { - ASSERT(mQuery); - - DWORD numPixels = 0; - - HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH); - if (hres == S_OK) - { - mQueryFinished = true; - - switch (getType()) - { - case GL_ANY_SAMPLES_PASSED_EXT: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: - mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE; - break; - - default: - UNREACHABLE(); - break; - } - } - else if (d3d9::isDeviceLostError(hres)) - { - mRenderer->notifyDeviceLost(); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); - } - else if (mRenderer->testDeviceLost(true)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost."); - } - } - - return gl::Error(GL_NO_ERROR); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h deleted file mode 100644 index 36851c6c6c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// Query9.h: Defines the rx::Query9 class which implements rx::QueryImpl. - -#ifndef LIBGLESV2_RENDERER_QUERY9_H_ -#define LIBGLESV2_RENDERER_QUERY9_H_ - -#include "libGLESv2/renderer/QueryImpl.h" - -namespace rx -{ -class Renderer9; - -class Query9 : public QueryImpl -{ - public: - Query9(Renderer9 *renderer, GLenum type); - virtual ~Query9(); - - virtual gl::Error begin(); - virtual gl::Error end(); - virtual gl::Error getResult(GLuint *params); - virtual gl::Error isResultAvailable(GLuint *available); - - private: - DISALLOW_COPY_AND_ASSIGN(Query9); - - gl::Error testQuery(); - - GLuint mResult; - bool mQueryFinished; - - Renderer9 *mRenderer; - IDirect3DQuery9 *mQuery; -}; - -} - -#endif // LIBGLESV2_RENDERER_QUERY9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp deleted file mode 100644 index 53d1f752fa..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// RenderTarget9.cpp: Implements a D3D9-specific wrapper for IDirect3DSurface9 -// pointers retained by renderbuffers. - -#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/main.h" - -namespace rx -{ - -RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTarget *target) -{ - ASSERT(HAS_DYNAMIC_TYPE(RenderTarget9*, target)); - return static_cast(target); -} - -void RenderTarget9::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) -{ - // Currently a no-op -} - -// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given. -TextureRenderTarget9::TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, - GLsizei samples) - : mWidth(width), - mHeight(height), - mDepth(depth), - mInternalFormat(internalFormat), - mActualFormat(internalFormat), - mSamples(samples), - mRenderTarget(surface) -{ - ASSERT(mDepth == 1); - - if (mRenderTarget) - { - D3DSURFACE_DESC description; - mRenderTarget->GetDesc(&description); - - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(description.Format); - mActualFormat = d3dFormatInfo.internalFormat; - } -} - -TextureRenderTarget9::~TextureRenderTarget9() -{ - SafeRelease(mRenderTarget); -} - -GLsizei TextureRenderTarget9::getWidth() const -{ - return mWidth; -} - -GLsizei TextureRenderTarget9::getHeight() const -{ - return mHeight; -} - -GLsizei TextureRenderTarget9::getDepth() const -{ - return mDepth; -} - -GLenum TextureRenderTarget9::getInternalFormat() const -{ - return mInternalFormat; -} - -GLenum TextureRenderTarget9::getActualFormat() const -{ - return mActualFormat; -} - -GLsizei TextureRenderTarget9::getSamples() const -{ - return mSamples; -} - -IDirect3DSurface9 *TextureRenderTarget9::getSurface() -{ - // Caller is responsible for releasing the returned surface reference. - // TODO: remove the AddRef to match RenderTarget11 - if (mRenderTarget) - { - mRenderTarget->AddRef(); - } - - return mRenderTarget; -} - - -SurfaceRenderTarget9::SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth) - : mSwapChain(swapChain), - mDepth(depth) -{ -} - -SurfaceRenderTarget9::~SurfaceRenderTarget9() -{ -} - -GLsizei SurfaceRenderTarget9::getWidth() const -{ - return mSwapChain->getWidth(); -} - -GLsizei SurfaceRenderTarget9::getHeight() const -{ - return mSwapChain->getHeight(); -} - -GLsizei SurfaceRenderTarget9::getDepth() const -{ - return 1; -} - -GLenum SurfaceRenderTarget9::getInternalFormat() const -{ - return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat()); -} - -GLenum SurfaceRenderTarget9::getActualFormat() const -{ - return d3d9::GetD3DFormatInfo(d3d9::GetTextureFormatInfo(getInternalFormat()).texFormat).internalFormat; -} - -GLsizei SurfaceRenderTarget9::getSamples() const -{ - // Our EGL surfaces do not support multisampling. - return 0; -} - -IDirect3DSurface9 *SurfaceRenderTarget9::getSurface() -{ - return (mDepth ? mSwapChain->getDepthStencil() : mSwapChain->getRenderTarget()); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h deleted file mode 100644 index 4585697f4c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h +++ /dev/null @@ -1,89 +0,0 @@ -// -// 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. -// - -// RenderTarget9.h: Defines a D3D9-specific wrapper for IDirect3DSurface9 pointers -// retained by Renderbuffers. - -#ifndef LIBGLESV2_RENDERER_RENDERTARGET9_H_ -#define LIBGLESV2_RENDERER_RENDERTARGET9_H_ - -#include "libGLESv2/renderer/RenderTarget.h" - -namespace rx -{ -class Renderer9; -class SwapChain9; - -class RenderTarget9 : public RenderTarget -{ - public: - RenderTarget9() { } - virtual ~RenderTarget9() { } - - static RenderTarget9 *makeRenderTarget9(RenderTarget *renderTarget); - - void invalidate(GLint x, GLint y, GLsizei width, GLsizei height) override; - - virtual IDirect3DSurface9 *getSurface() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderTarget9); -}; - -class TextureRenderTarget9 : public RenderTarget9 -{ - public: - TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, - GLsizei samples); - virtual ~TextureRenderTarget9(); - - GLsizei getWidth() const override; - GLsizei getHeight() const override; - GLsizei getDepth() const override; - GLenum getInternalFormat() const override; - GLenum getActualFormat() const override; - GLsizei getSamples() const override; - - IDirect3DSurface9 *getSurface() override; - - private: - DISALLOW_COPY_AND_ASSIGN(TextureRenderTarget9); - - GLsizei mWidth; - GLsizei mHeight; - GLsizei mDepth; - GLenum mInternalFormat; - GLenum mActualFormat; - GLsizei mSamples; - - IDirect3DSurface9 *mRenderTarget; -}; - -class SurfaceRenderTarget9 : public RenderTarget9 -{ - public: - SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth); - virtual ~SurfaceRenderTarget9(); - - GLsizei getWidth() const override; - GLsizei getHeight() const override; - GLsizei getDepth() const override; - GLenum getInternalFormat() const override; - GLenum getActualFormat() const override; - GLsizei getSamples() const override; - - IDirect3DSurface9 *getSurface() override; - - private: - DISALLOW_COPY_AND_ASSIGN(SurfaceRenderTarget9); - - SwapChain9 *mSwapChain; - bool mDepth; -}; - -} - -#endif // LIBGLESV2_RENDERER_RENDERTARGET9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp deleted file mode 100644 index 18e6e2d7f0..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp +++ /dev/null @@ -1,3171 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer. - -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h" -#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" -#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" -#include "libGLESv2/renderer/d3d/d3d9/Image9.h" -#include "libGLESv2/renderer/d3d/d3d9/Blit9.h" -#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" -#include "libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h" -#include "libGLESv2/renderer/d3d/d3d9/Buffer9.h" -#include "libGLESv2/renderer/d3d/d3d9/Query9.h" -#include "libGLESv2/renderer/d3d/d3d9/Fence9.h" -#include "libGLESv2/renderer/d3d/d3d9/VertexArray9.h" -#include "libGLESv2/renderer/d3d/IndexDataManager.h" -#include "libGLESv2/renderer/d3d/ProgramD3D.h" -#include "libGLESv2/renderer/d3d/ShaderD3D.h" -#include "libGLESv2/renderer/d3d/TextureD3D.h" -#include "libGLESv2/renderer/d3d/TransformFeedbackD3D.h" -#include "libGLESv2/renderer/d3d/RenderbufferD3D.h" -#include "libGLESv2/main.h" -#include "libGLESv2/Buffer.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/State.h" -#include "libGLESv2/angletypes.h" - -#include "libEGL/Display.h" - -#include "common/features.h" -#include "common/utilities.h" - -#include - -// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros -#define REF_RAST 0 - -#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) -#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 -#endif - -const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I','N','T','Z'))); -const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N','U','L','L'))); - -namespace rx -{ -static 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 - }; - -static 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 - }; - -enum -{ - MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256, - MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32, - MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224, - MAX_VARYING_VECTORS_SM2 = 8, - MAX_VARYING_VECTORS_SM3 = 10, - - MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4 -}; - -Renderer9::Renderer9(egl::Display *display, EGLNativeDisplayType hDc, const egl::AttributeMap &attributes) - : RendererD3D(display), - mDc(hDc) -{ - mD3d9Module = NULL; - - mD3d9 = NULL; - mD3d9Ex = NULL; - mDevice = NULL; - mDeviceEx = NULL; - mDeviceWindow = NULL; - mBlit = NULL; - - mAdapter = D3DADAPTER_DEFAULT; - - #if REF_RAST == 1 || defined(FORCE_REF_RAST) - mDeviceType = D3DDEVTYPE_REF; - #else - mDeviceType = D3DDEVTYPE_HAL; - #endif - - mDeviceLost = false; - - mMaskedClearSavedState = NULL; - - mVertexDataManager = NULL; - mIndexDataManager = NULL; - mLineLoopIB = NULL; - mCountingIB = NULL; - - mMaxNullColorbufferLRU = 0; - for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) - { - mNullColorbufferCache[i].lruCount = 0; - mNullColorbufferCache[i].width = 0; - mNullColorbufferCache[i].height = 0; - mNullColorbufferCache[i].buffer = NULL; - } - - mAppliedVertexShader = NULL; - mAppliedPixelShader = NULL; - mAppliedProgramSerial = 0; -} - -Renderer9::~Renderer9() -{ - if (mDevice) - { - // If the device is lost, reset it first to prevent leaving the driver in an unstable state - if (testDeviceLost(false)) - { - resetDevice(); - } - } - - release(); -} - -void Renderer9::release() -{ - RendererD3D::cleanup(); - - releaseShaderCompiler(); - releaseDeviceResources(); - - SafeRelease(mDevice); - SafeRelease(mDeviceEx); - SafeRelease(mD3d9); - SafeRelease(mD3d9Ex); - - mCompiler.release(); - - if (mDeviceWindow) - { - DestroyWindow(mDeviceWindow); - mDeviceWindow = NULL; - } - - mD3d9Module = NULL; -} - -Renderer9 *Renderer9::makeRenderer9(Renderer *renderer) -{ - ASSERT(HAS_DYNAMIC_TYPE(Renderer9*, renderer)); - return static_cast(renderer); -} - -EGLint Renderer9::initialize() -{ - if (!mCompiler.initialize()) - { - return EGL_NOT_INITIALIZED; - } - - mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); - - if (mD3d9Module == NULL) - { - ERR("No D3D9 module found - aborting!\n"); - return EGL_NOT_INITIALIZED; - } - - 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_D3D9EX == ANGLE_ENABLED && 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) - { - ERR("Could not create D3D9 device - aborting!\n"); - return EGL_NOT_INITIALIZED; - } - - 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 - { - ERR("failed to get device caps (0x%x)\n", result); - return EGL_NOT_INITIALIZED; - } - } - } - - if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0)) - { - ERR("Renderer does not support PS 2.0. aborting!\n"); - return EGL_NOT_INITIALIZED; - } - - // 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::ensureRenderTarget. - if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0) - { - ERR("Renderer does not support stretctrect from textures!\n"); - return EGL_NOT_INITIALIZED; - } - - { - mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); - } - - 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); - } - - 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); - } - - D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; - - static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); - if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) - behaviorFlags |= D3DCREATE_MULTITHREADED; - - { - 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 EGL_BAD_ALLOC; - } - - 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 EGL_BAD_ALLOC; - } - } - - if (mD3d9Ex) - { - result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); - ASSERT(SUCCEEDED(result)); - } - - { - mVertexShaderCache.initialize(mDevice); - mPixelShaderCache.initialize(mDevice); - } - - D3DDISPLAYMODE currentDisplayMode; - mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); - - // Check vertex texture support - // Only Direct3D 10 ready devices support all the necessary vertex texture formats. - // We test this using D3D9 by checking support for the R16F format. - mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) && - SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, - D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)); - - initializeDevice(); - - return EGL_SUCCESS; -} - -// 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 Renderer9::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 - } - - const gl::Caps &rendererCaps = getRendererCaps(); - - mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); - mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); - - mForceSetPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); - mCurPixelSamplerStates.resize(rendererCaps.maxTextureImageUnits); - - mCurVertexTextureSerials.resize(rendererCaps.maxVertexTextureImageUnits); - mCurPixelTextureSerials.resize(rendererCaps.maxTextureImageUnits); - - markAllStateDirty(); - - mSceneStarted = false; - - ASSERT(!mBlit); - mBlit = new Blit9(this); - mBlit->initialize(); - - ASSERT(!mVertexDataManager && !mIndexDataManager); - mVertexDataManager = new VertexDataManager(this); - mIndexDataManager = new IndexDataManager(this); -} - -D3DPRESENT_PARAMETERS Renderer9::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; -} - -int Renderer9::generateConfigs(ConfigDesc **configDescList) -{ - D3DDISPLAYMODE currentDisplayMode; - mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); - - unsigned int numRenderFormats = ArraySize(RenderTargetFormats); - unsigned int numDepthFormats = ArraySize(DepthStencilFormats); - (*configDescList) = new ConfigDesc[numRenderFormats * numDepthFormats]; - int numConfigs = 0; - - for (unsigned int formatIndex = 0; formatIndex < numRenderFormats; formatIndex++) - { - const d3d9::D3DFormat &renderTargetFormatInfo = d3d9::GetD3DFormatInfo(RenderTargetFormats[formatIndex]); - const gl::TextureCaps &renderTargetFormatCaps = getRendererTextureCaps().get(renderTargetFormatInfo.internalFormat); - if (renderTargetFormatCaps.renderable) - { - for (unsigned int depthStencilIndex = 0; depthStencilIndex < numDepthFormats; depthStencilIndex++) - { - const d3d9::D3DFormat &depthStencilFormatInfo = d3d9::GetD3DFormatInfo(DepthStencilFormats[depthStencilIndex]); - const gl::TextureCaps &depthStencilFormatCaps = getRendererTextureCaps().get(depthStencilFormatInfo.internalFormat); - if (depthStencilFormatCaps.renderable || DepthStencilFormats[depthStencilIndex] == D3DFMT_UNKNOWN) - { - ConfigDesc newConfig; - newConfig.renderTargetFormat = renderTargetFormatInfo.internalFormat; - newConfig.depthStencilFormat = depthStencilFormatInfo.internalFormat; - newConfig.multiSample = 0; // FIXME: enumerate multi-sampling - newConfig.fastConfig = (currentDisplayMode.Format == RenderTargetFormats[formatIndex]); - newConfig.es3Capable = false; - - (*configDescList)[numConfigs++] = newConfig; - } - } - } - } - - return numConfigs; -} - -void Renderer9::deleteConfigs(ConfigDesc *configDescList) -{ - delete [] (configDescList); -} - -void Renderer9::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 Renderer9::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; - } -} - -gl::Error Renderer9::sync(bool block) -{ - IDirect3DQuery9* query = NULL; - gl::Error error = allocateEventQuery(&query); - if (error.isError()) - { - return error; - } - - HRESULT result = query->Issue(D3DISSUE_END); - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result); - } - - // Grab the query data once in blocking and non-blocking case - result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); - if (FAILED(result)) - { - if (d3d9::isDeviceLostError(result)) - { - notifyDeviceLost(); - } - - freeEventQuery(query); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); - } - - // If blocking, loop until the query completes - while (block && result == S_FALSE) - { - // Keep polling, but allow other threads to do something useful first - Sleep(0); - - result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); - - // 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 (result == S_FALSE && testDeviceLost(false)) - { - result = D3DERR_DEVICELOST; - } - - if (FAILED(result)) - { - if (d3d9::isDeviceLostError(result)) - { - notifyDeviceLost(); - } - - freeEventQuery(query); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); - } - - } - - freeEventQuery(query); - - return gl::Error(GL_NO_ERROR); -} - -SwapChain *Renderer9::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) -{ - return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); -} - -gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) -{ - if (mEventQueryPool.empty()) - { - HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, outQuery); - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate event query, result: 0x%X.", result); - } - } - else - { - *outQuery = mEventQueryPool.back(); - mEventQueryPool.pop_back(); - } - - return gl::Error(GL_NO_ERROR); -} - -void Renderer9::freeEventQuery(IDirect3DQuery9* query) -{ - if (mEventQueryPool.size() > 1000) - { - SafeRelease(query); - } - else - { - mEventQueryPool.push_back(query); - } -} - -gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader) -{ - return mVertexShaderCache.create(function, length, outShader); -} - -gl::Error Renderer9::createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader) -{ - return mPixelShaderCache.create(function, length, outShader); -} - -HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer) -{ - D3DPOOL Pool = getBufferPool(Usage); - return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL); -} - -VertexBuffer *Renderer9::createVertexBuffer() -{ - return new VertexBuffer9(this); -} - -HRESULT Renderer9::createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer) -{ - D3DPOOL Pool = getBufferPool(Usage); - return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, NULL); -} - -IndexBuffer *Renderer9::createIndexBuffer() -{ - return new IndexBuffer9(this); -} - -BufferImpl *Renderer9::createBuffer() -{ - return new Buffer9(this); -} - -VertexArrayImpl *Renderer9::createVertexArray() -{ - return new VertexArray9(this); -} - -QueryImpl *Renderer9::createQuery(GLenum type) -{ - return new Query9(this, type); -} - -FenceNVImpl *Renderer9::createFenceNV() -{ - return new FenceNV9(this); -} - -FenceSyncImpl *Renderer9::createFenceSync() -{ - // Renderer9 doesn't support ES 3.0 and its sync objects. - UNREACHABLE(); - return NULL; -} - -TransformFeedbackImpl* Renderer9::createTransformFeedback() -{ - return new TransformFeedbackD3D(); -} - -bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const -{ - // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. - return false; -} - -gl::Error Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) -{ - // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); -} - -gl::Error Renderer9::generateSwizzle(gl::Texture *texture) -{ - // Swizzled textures are not available in ES2 or D3D9 - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); -} - -gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerState) -{ - std::vector &forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; - std::vector &appliedSamplers = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates: mCurVertexSamplerStates; - - if (forceSetSamplers[index] || memcmp(&samplerState, &appliedSamplers[index], sizeof(gl::SamplerState)) != 0) - { - int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; - int d3dSampler = index + d3dSamplerOffset; - - // Make sure to add the level offset for our tiny compressed texture workaround - TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); - DWORD baseLevel = samplerState.baseLevel + textureD3D->getNativeTexture()->getTopLevel(); - - mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS)); - mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT)); - - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, gl_d3d9::ConvertMagFilter(samplerState.magFilter, samplerState.maxAnisotropy)); - D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; - gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy); - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel); - if (getRendererExtensions().textureFilterAnisotropic) - { - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); - } - } - - forceSetSamplers[index] = false; - appliedSamplers[index] = samplerState; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *texture) -{ - int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; - int d3dSampler = index + d3dSamplerOffset; - IDirect3DBaseTexture9 *d3dTexture = NULL; - unsigned int serial = 0; - bool forceSetTexture = false; - - std::vector &appliedSerials = (type == gl::SAMPLER_PIXEL) ? mCurPixelTextureSerials : mCurVertexTextureSerials; - - if (texture) - { - TextureD3D* textureImpl = TextureD3D::makeTextureD3D(texture->getImplementation()); - - TextureStorage *texStorage = textureImpl->getNativeTexture(); - if (texStorage) - { - TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage); - - gl::Error error = storage9->getBaseTexture(&d3dTexture); - if (error.isError()) - { - return error; - } - } - // If we get NULL back from getBaseTexture here, something went wrong - // in the texture class and we're unexpectedly missing the d3d texture - ASSERT(d3dTexture != NULL); - - serial = texture->getTextureSerial(); - forceSetTexture = textureImpl->hasDirtyImages(); - textureImpl->resetDirty(); - } - - if (forceSetTexture || appliedSerials[index] != serial) - { - mDevice->SetTexture(d3dSampler, d3dTexture); - } - - appliedSerials[index] = serial; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::setUniformBuffers(const gl::Buffer* /*vertexUniformBuffers*/[], const gl::Buffer* /*fragmentUniformBuffers*/[]) -{ - // No effect in ES2/D3D9 - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::setRasterizerState(const gl::RasterizerState &rasterState) -{ - bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0; - - if (rasterStateChanged) - { - // Set the cull mode - if (rasterState.cullFace) - { - mDevice->SetRenderState(D3DRS_CULLMODE, gl_d3d9::ConvertCullMode(rasterState.cullMode, rasterState.frontFace)); - } - else - { - mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - } - - if (rasterState.polygonOffsetFill) - { - if (mCurDepthSize > 0) - { - mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&rasterState.polygonOffsetFactor); - - float depthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast(mCurDepthSize)); - mDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&depthBias); - } - } - else - { - mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0); - mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0); - } - - mCurRasterState = rasterState; - } - - mForceSetRasterState = false; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask) -{ - bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0; - bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::ColorF)) != 0; - bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask; - - if (blendStateChanged || blendColorChanged) - { - if (blendState.blend) - { - mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - - if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && - blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) - { - mDevice->SetRenderState(D3DRS_BLENDFACTOR, gl_d3d9::ConvertColor(blendColor)); - } - else - { - mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha), - gl::unorm<8>(blendColor.alpha), - gl::unorm<8>(blendColor.alpha), - gl::unorm<8>(blendColor.alpha))); - } - - mDevice->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB)); - mDevice->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB)); - mDevice->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB)); - - if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha || - blendState.destBlendRGB != blendState.destBlendAlpha || - blendState.blendEquationRGB != blendState.blendEquationAlpha) - { - mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); - - mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha)); - mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha)); - mDevice->SetRenderState(D3DRS_BLENDOPALPHA, gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha)); - } - else - { - mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); - } - } - else - { - mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - } - - if (blendState.sampleAlphaToCoverage) - { - FIXME("Sample alpha to coverage is unimplemented."); - } - - gl::FramebufferAttachment *attachment = framebuffer->getFirstColorbuffer(); - GLenum internalFormat = attachment ? attachment->getInternalFormat() : GL_NONE; - - // Set the color mask - bool zeroColorMaskAllowed = getAdapterVendor() != VENDOR_ID_AMD; - // 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 - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - DWORD colorMask = gl_d3d9::ConvertColorMask(formatInfo.redBits > 0 && blendState.colorMaskRed, - formatInfo.greenBits > 0 && blendState.colorMaskGreen, - formatInfo.blueBits > 0 && blendState.colorMaskBlue, - formatInfo.alphaBits > 0 && blendState.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_DITHERENABLE, blendState.dither ? TRUE : FALSE); - - mCurBlendState = blendState; - mCurBlendColor = blendColor; - } - - if (sampleMaskChanged) - { - // Set the multisample mask - mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); - mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast(sampleMask)); - - mCurSampleMask = sampleMask; - } - - mForceSetBlendState = false; - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, - int stencilBackRef, bool frontFaceCCW) -{ - bool depthStencilStateChanged = mForceSetDepthStencilState || - memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0; - bool stencilRefChanged = mForceSetDepthStencilState || stencilRef != mCurStencilRef || - stencilBackRef != mCurStencilBackRef; - bool frontFaceCCWChanged = mForceSetDepthStencilState || frontFaceCCW != mCurFrontFaceCCW; - - if (depthStencilStateChanged) - { - if (depthStencilState.depthTest) - { - mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); - mDevice->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthStencilState.depthFunc)); - } - else - { - mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); - } - - mCurDepthStencilState = depthStencilState; - } - - if (depthStencilStateChanged || stencilRefChanged || frontFaceCCWChanged) - { - if (depthStencilState.stencilTest && mCurStencilSize > 0) - { - 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; - - ASSERT(depthStencilState.stencilWritemask == depthStencilState.stencilBackWritemask); - ASSERT(stencilRef == stencilBackRef); - ASSERT(depthStencilState.stencilMask == depthStencilState.stencilBackMask); - - // get the maximum size of the stencil ref - unsigned int maxStencil = (1 << mCurStencilSize) - 1; - - mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, - depthStencilState.stencilWritemask); - mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, - gl_d3d9::ConvertComparison(depthStencilState.stencilFunc)); - - mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, - (stencilRef < (int)maxStencil) ? stencilRef : maxStencil); - mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, - depthStencilState.stencilMask); - - mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, - gl_d3d9::ConvertStencilOp(depthStencilState.stencilFail)); - mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, - gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthFail)); - mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, - gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthPass)); - - mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, - depthStencilState.stencilBackWritemask); - mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, - gl_d3d9::ConvertComparison(depthStencilState.stencilBackFunc)); - - mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, - (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil); - mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, - depthStencilState.stencilBackMask); - - mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, - gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackFail)); - mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, - gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthFail)); - mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, - gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthPass)); - } - else - { - mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); - } - - mDevice->SetRenderState(D3DRS_ZWRITEENABLE, depthStencilState.depthMask ? TRUE : FALSE); - - mCurStencilRef = stencilRef; - mCurStencilBackRef = stencilBackRef; - mCurFrontFaceCCW = frontFaceCCW; - } - - mForceSetDepthStencilState = false; - - return gl::Error(GL_NO_ERROR); -} - -void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled) -{ - bool scissorChanged = mForceSetScissor || - memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0 || - enabled != mScissorEnabled; - - if (scissorChanged) - { - if (enabled) - { - RECT rect; - rect.left = gl::clamp(scissor.x, 0, static_cast(mRenderTargetDesc.width)); - rect.top = gl::clamp(scissor.y, 0, static_cast(mRenderTargetDesc.height)); - rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast(mRenderTargetDesc.width)); - rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast(mRenderTargetDesc.height)); - mDevice->SetScissorRect(&rect); - } - - mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, enabled ? TRUE : FALSE); - - mScissorEnabled = enabled; - mCurScissor = scissor; - } - - mForceSetScissor = false; -} - -void Renderer9::setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, - bool ignoreViewport) -{ - gl::Rectangle actualViewport = viewport; - float actualZNear = gl::clamp01(zNear); - float actualZFar = gl::clamp01(zFar); - if (ignoreViewport) - { - actualViewport.x = 0; - actualViewport.y = 0; - actualViewport.width = mRenderTargetDesc.width; - actualViewport.height = mRenderTargetDesc.height; - actualZNear = 0.0f; - actualZFar = 1.0f; - } - - D3DVIEWPORT9 dxViewport; - dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast(mRenderTargetDesc.width)); - dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast(mRenderTargetDesc.height)); - dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast(mRenderTargetDesc.width) - static_cast(dxViewport.X)); - dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast(mRenderTargetDesc.height) - static_cast(dxViewport.Y)); - dxViewport.MinZ = actualZNear; - dxViewport.MaxZ = actualZFar; - - float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f); - - bool viewportChanged = mForceSetViewport || memcmp(&actualViewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 || - actualZNear != mCurNear || actualZFar != mCurFar || mCurDepthFront != depthFront; - if (viewportChanged) - { - mDevice->SetViewport(&dxViewport); - - mCurViewport = actualViewport; - mCurNear = actualZNear; - mCurFar = actualZFar; - mCurDepthFront = depthFront; - - dx_VertexConstants vc = {0}; - dx_PixelConstants pc = {0}; - - vc.viewAdjust[0] = (float)((actualViewport.width - (int)dxViewport.Width) + 2 * (actualViewport.x - (int)dxViewport.X) - 1) / dxViewport.Width; - vc.viewAdjust[1] = (float)((actualViewport.height - (int)dxViewport.Height) + 2 * (actualViewport.y - (int)dxViewport.Y) - 1) / dxViewport.Height; - vc.viewAdjust[2] = (float)actualViewport.width / dxViewport.Width; - vc.viewAdjust[3] = (float)actualViewport.height / dxViewport.Height; - - pc.viewCoords[0] = actualViewport.width * 0.5f; - pc.viewCoords[1] = actualViewport.height * 0.5f; - pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f); - pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f); - - pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f; - pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f; - pc.depthFront[2] = depthFront; - - vc.depthRange[0] = actualZNear; - vc.depthRange[1] = actualZFar; - vc.depthRange[2] = actualZFar - actualZNear; - - pc.depthRange[0] = actualZNear; - pc.depthRange[1] = actualZFar; - pc.depthRange[2] = actualZFar - actualZNear; - - if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants)) != 0) - { - mVertexConstants = vc; - mDxUniformsDirty = true; - } - - if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants)) != 0) - { - mPixelConstants = pc; - mDxUniformsDirty = true; - } - } - - mForceSetViewport = false; -} - -bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count) -{ - switch (mode) - { - case GL_POINTS: - mPrimitiveType = D3DPT_POINTLIST; - mPrimitiveCount = count; - break; - case GL_LINES: - mPrimitiveType = D3DPT_LINELIST; - mPrimitiveCount = count / 2; - break; - case GL_LINE_LOOP: - mPrimitiveType = D3DPT_LINESTRIP; - mPrimitiveCount = count - 1; // D3D doesn't support line loops, so we draw the last line separately - break; - case GL_LINE_STRIP: - mPrimitiveType = D3DPT_LINESTRIP; - mPrimitiveCount = count - 1; - break; - case GL_TRIANGLES: - mPrimitiveType = D3DPT_TRIANGLELIST; - mPrimitiveCount = count / 3; - break; - case GL_TRIANGLE_STRIP: - mPrimitiveType = D3DPT_TRIANGLESTRIP; - mPrimitiveCount = count - 2; - break; - case GL_TRIANGLE_FAN: - mPrimitiveType = D3DPT_TRIANGLEFAN; - mPrimitiveCount = count - 2; - break; - default: - UNREACHABLE(); - return false; - } - - return mPrimitiveCount > 0; -} - - -gl::Error Renderer9::getNullColorbuffer(gl::FramebufferAttachment *depthbuffer, gl::FramebufferAttachment **outColorBuffer) -{ - ASSERT(depthbuffer); - - GLsizei width = depthbuffer->getWidth(); - GLsizei height = depthbuffer->getHeight(); - - // search cached nullcolorbuffers - for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) - { - if (mNullColorbufferCache[i].buffer != NULL && - mNullColorbufferCache[i].width == width && - mNullColorbufferCache[i].height == height) - { - mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU; - *outColorBuffer = mNullColorbufferCache[i].buffer; - return gl::Error(GL_NO_ERROR); - } - } - - gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(createRenderbuffer(), 0); - gl::Error error = nullRenderbuffer->setStorage(width, height, GL_NONE, 0); - if (error.isError()) - { - SafeDelete(nullRenderbuffer); - return error; - } - - gl::RenderbufferAttachment *nullbuffer = new gl::RenderbufferAttachment(GL_NONE, nullRenderbuffer); - - // add nullbuffer to the cache - NullColorbufferCacheEntry *oldest = &mNullColorbufferCache[0]; - for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) - { - if (mNullColorbufferCache[i].lruCount < oldest->lruCount) - { - oldest = &mNullColorbufferCache[i]; - } - } - - delete oldest->buffer; - oldest->buffer = nullbuffer; - oldest->lruCount = ++mMaxNullColorbufferLRU; - oldest->width = width; - oldest->height = height; - - *outColorBuffer = nullbuffer; - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::applyRenderTarget(const gl::Framebuffer *framebuffer) -{ - // 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. - gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(0); - if (!attachment) - { - gl::Error error = getNullColorbuffer(framebuffer->getDepthbuffer(), &attachment); - if (error.isError()) - { - return error; - } - } - ASSERT(attachment); - - bool renderTargetChanged = false; - unsigned int renderTargetSerial = GetAttachmentSerial(attachment); - if (renderTargetSerial != mAppliedRenderTargetSerial) - { - // Apply the render target on the device - RenderTarget9 *renderTarget = NULL; - gl::Error error = d3d9::GetAttachmentRenderTarget(attachment, &renderTarget); - if (error.isError()) - { - return error; - } - ASSERT(renderTarget); - - IDirect3DSurface9 *renderTargetSurface = renderTarget->getSurface(); - ASSERT(renderTargetSurface); - - mDevice->SetRenderTarget(0, renderTargetSurface); - SafeRelease(renderTargetSurface); - - mAppliedRenderTargetSerial = renderTargetSerial; - renderTargetChanged = true; - } - - gl::FramebufferAttachment *depthStencil = framebuffer->getDepthbuffer(); - unsigned int depthbufferSerial = 0; - unsigned int stencilbufferSerial = 0; - if (depthStencil) - { - depthbufferSerial = GetAttachmentSerial(depthStencil); - } - else if (framebuffer->getStencilbuffer()) - { - depthStencil = framebuffer->getStencilbuffer(); - stencilbufferSerial = GetAttachmentSerial(depthStencil); - } - - if (depthbufferSerial != mAppliedDepthbufferSerial || - stencilbufferSerial != mAppliedStencilbufferSerial || - !mDepthStencilInitialized) - { - unsigned int depthSize = 0; - unsigned int stencilSize = 0; - - // Apply the depth stencil on the device - if (depthStencil) - { - RenderTarget9 *depthStencilRenderTarget = NULL; - gl::Error error = d3d9::GetAttachmentRenderTarget(depthStencil, &depthStencilRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(depthStencilRenderTarget); - - IDirect3DSurface9 *depthStencilSurface = depthStencilRenderTarget->getSurface(); - ASSERT(depthStencilSurface); - - mDevice->SetDepthStencilSurface(depthStencilSurface); - SafeRelease(depthStencilSurface); - - depthSize = depthStencil->getDepthSize(); - stencilSize = depthStencil->getStencilSize(); - } - else - { - mDevice->SetDepthStencilSurface(NULL); - } - - if (!mDepthStencilInitialized || depthSize != mCurDepthSize) - { - mCurDepthSize = depthSize; - mForceSetRasterState = true; - } - - if (!mDepthStencilInitialized || stencilSize != mCurStencilSize) - { - mCurStencilSize = stencilSize; - mForceSetDepthStencilState = true; - } - - mAppliedDepthbufferSerial = depthbufferSerial; - mAppliedStencilbufferSerial = stencilbufferSerial; - mDepthStencilInitialized = true; - } - - if (renderTargetChanged || !mRenderTargetDescInitialized) - { - mForceSetScissor = true; - mForceSetViewport = true; - mForceSetBlendState = true; - - mRenderTargetDesc.width = attachment->getWidth(); - mRenderTargetDesc.height = attachment->getHeight(); - mRenderTargetDesc.format = attachment->getActualFormat(); - mRenderTargetDescInitialized = true; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) -{ - TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); - if (error.isError()) - { - return error; - } - - return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getCurrentProgramBinary(), instances, &mRepeatDraw); -} - -// Applies the indices and element array bindings to the Direct3D 9 device -gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) -{ - gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo); - if (error.isError()) - { - return error; - } - - // Directly binding the storage buffer is not supported for d3d9 - ASSERT(indexInfo->storage == NULL); - - if (indexInfo->serial != mAppliedIBSerial) - { - IndexBuffer9* indexBuffer = IndexBuffer9::makeIndexBuffer9(indexInfo->indexBuffer); - - mDevice->SetIndices(indexBuffer->getBuffer()); - mAppliedIBSerial = indexInfo->serial; - } - - return gl::Error(GL_NO_ERROR); -} - -void Renderer9::applyTransformFeedbackBuffers(const gl::State& state) -{ - UNREACHABLE(); -} - -gl::Error Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) -{ - ASSERT(!transformFeedbackActive); - - startScene(); - - if (mode == GL_LINE_LOOP) - { - return drawLineLoop(count, GL_NONE, NULL, 0, NULL); - } - else if (instances > 0) - { - StaticIndexBufferInterface *countingIB = NULL; - gl::Error error = getCountingIB(count, &countingIB); - if (error.isError()) - { - return error; - } - - if (mAppliedIBSerial != countingIB->getSerial()) - { - IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(countingIB->getIndexBuffer()); - - mDevice->SetIndices(indexBuffer->getBuffer()); - mAppliedIBSerial = countingIB->getSerial(); - } - - for (int i = 0; i < mRepeatDraw; i++) - { - mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount); - } - - return gl::Error(GL_NO_ERROR); - } - else // Regular case - { - mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount); - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error Renderer9::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, - gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei /*instances*/) -{ - startScene(); - - int minIndex = static_cast(indexInfo.indexRange.start); - - if (mode == GL_POINTS) - { - return drawIndexedPoints(count, type, indices, minIndex, elementArrayBuffer); - } - else if (mode == GL_LINE_LOOP) - { - return drawLineLoop(count, type, indices, minIndex, elementArrayBuffer); - } - else - { - for (int i = 0; i < mRepeatDraw; i++) - { - GLsizei vertexCount = static_cast(indexInfo.indexRange.length()) + 1; - mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex, vertexCount, indexInfo.startIndex, mPrimitiveCount); - } - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) -{ - // Get the raw indices for an indexed draw - if (type != GL_NONE && elementArrayBuffer) - { - BufferD3D *storage = BufferD3D::makeFromBuffer(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); - if (error.isError()) - { - return error; - } - indices = bufferData + offset; - } - - unsigned int startIndex = 0; - - if (getRendererExtensions().elementIndexUint) - { - if (!mLineLoopIB) - { - mLineLoopIB = new StreamingIndexBufferInterface(this); - gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); - if (error.isError()) - { - SafeDelete(mLineLoopIB); - return error; - } - } - - // Checked by Renderer9::applyPrimitiveType - ASSERT(count >= 0); - - if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); - } - - const unsigned int spaceNeeded = (static_cast(count)+1) * sizeof(unsigned int); - gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); - if (error.isError()) - { - return error; - } - - void* mappedMemory = NULL; - unsigned int offset = 0; - error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; - } - - startIndex = static_cast(offset) / 4; - unsigned int *data = reinterpret_cast(mappedMemory); - - 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(); - } - - error = mLineLoopIB->unmapBuffer(); - if (error.isError()) - { - return error; - } - } - else - { - if (!mLineLoopIB) - { - mLineLoopIB = new StreamingIndexBufferInterface(this); - gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); - if (error.isError()) - { - SafeDelete(mLineLoopIB); - return error; - } - } - - // Checked by Renderer9::applyPrimitiveType - ASSERT(count >= 0); - - if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned short))) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 16-bit looping index buffer for GL_LINE_LOOP, too many indices required."); - } - - const unsigned int spaceNeeded = (static_cast(count) + 1) * sizeof(unsigned short); - gl::Error error = mLineLoopIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); - if (error.isError()) - { - return error; - } - - void* mappedMemory = NULL; - unsigned int offset; - error = mLineLoopIB->mapBuffer(spaceNeeded, &mappedMemory, &offset); - if (error.isError()) - { - return error; - } - - startIndex = static_cast(offset) / 2; - unsigned short *data = reinterpret_cast(mappedMemory); - - 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(); - } - - error = mLineLoopIB->unmapBuffer(); - if (error.isError()) - { - return error; - } - } - - if (mAppliedIBSerial != mLineLoopIB->getSerial()) - { - IndexBuffer9 *indexBuffer = IndexBuffer9::makeIndexBuffer9(mLineLoopIB->getIndexBuffer()); - - mDevice->SetIndices(indexBuffer->getBuffer()); - mAppliedIBSerial = mLineLoopIB->getSerial(); - } - - mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count); - - return gl::Error(GL_NO_ERROR); -} - -template -static gl::Error drawPoints(IDirect3DDevice9* device, GLsizei count, const GLvoid *indices, int minIndex) -{ - for (int i = 0; i < count; i++) - { - unsigned int indexValue = static_cast(static_cast(indices)[i]) - minIndex; - device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) -{ - // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call - // for each individual point. This call is not expected to happen often. - - if (elementArrayBuffer) - { - BufferD3D *storage = BufferD3D::makeFromBuffer(elementArrayBuffer); - intptr_t offset = reinterpret_cast(indices); - - const uint8_t *bufferData = NULL; - gl::Error error = storage->getData(&bufferData); - if (error.isError()) - { - return error; - } - - indices = bufferData + offset; - } - - switch (type) - { - case GL_UNSIGNED_BYTE: return drawPoints(mDevice, count, indices, minIndex); - case GL_UNSIGNED_SHORT: return drawPoints(mDevice, count, indices, minIndex); - case GL_UNSIGNED_INT: return drawPoints(mDevice, count, indices, minIndex); - default: UNREACHABLE(); return gl::Error(GL_INVALID_OPERATION); - } -} - -gl::Error Renderer9::getCountingIB(size_t count, StaticIndexBufferInterface **outIB) -{ - // Update the counting index buffer if it is not large enough or has not been created yet. - if (count <= 65536) // 16-bit indices - { - const unsigned int spaceNeeded = count * sizeof(unsigned short); - - if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) - { - SafeDelete(mCountingIB); - mCountingIB = new StaticIndexBufferInterface(this); - mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); - - void *mappedMemory = NULL; - gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); - if (error.isError()) - { - return error; - } - - unsigned short *data = reinterpret_cast(mappedMemory); - for (size_t i = 0; i < count; i++) - { - data[i] = i; - } - - error = mCountingIB->unmapBuffer(); - if (error.isError()) - { - return error; - } - } - } - else if (getRendererExtensions().elementIndexUint) - { - const unsigned int spaceNeeded = count * sizeof(unsigned int); - - if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded) - { - SafeDelete(mCountingIB); - mCountingIB = new StaticIndexBufferInterface(this); - mCountingIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); - - void *mappedMemory = NULL; - gl::Error error = mCountingIB->mapBuffer(spaceNeeded, &mappedMemory, NULL); - if (error.isError()) - { - return error; - } - - unsigned int *data = reinterpret_cast(mappedMemory); - for (size_t i = 0; i < count; i++) - { - data[i] = i; - } - - error = mCountingIB->unmapBuffer(); - if (error.isError()) - { - return error; - } - } - } - else - { - return gl::Error(GL_OUT_OF_MEMORY, "Could not create a counting index buffer for glDrawArraysInstanced."); - } - - *outIB = mCountingIB; - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, - bool rasterizerDiscard, bool transformFeedbackActive) -{ - ASSERT(!transformFeedbackActive); - ASSERT(!rasterizerDiscard); - - ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); - - ShaderExecutable *vertexExe = NULL; - gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe); - if (error.isError()) - { - return error; - } - - ShaderExecutable *pixelExe = NULL; - error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); - if (error.isError()) - { - return error; - } - - IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL); - IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL); - - if (vertexShader != mAppliedVertexShader) - { - mDevice->SetVertexShader(vertexShader); - mAppliedVertexShader = vertexShader; - } - - if (pixelShader != mAppliedPixelShader) - { - mDevice->SetPixelShader(pixelShader); - mAppliedPixelShader = pixelShader; - } - - // D3D9 has a quirk where creating multiple shaders with the same content - // can return the same shader pointer. Because GL programs store different data - // per-program, checking the program serial guarantees we upload fresh - // uniform data even if our shader pointers are the same. - // https://code.google.com/p/angleproject/issues/detail?id=661 - unsigned int programSerial = programBinary->getSerial(); - if (programSerial != mAppliedProgramSerial) - { - programD3D->dirtyAllUniforms(); - mDxUniformsDirty = true; - mAppliedProgramSerial = programSerial; - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) -{ - for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) - { - gl::LinkedUniform *targetUniform = uniformArray[uniformIndex]; - - if (targetUniform->dirty) - { - GLfloat *f = (GLfloat*)targetUniform->data; - GLint *i = (GLint*)targetUniform->data; - - switch (targetUniform->type) - { - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: - break; - case GL_BOOL: - case GL_BOOL_VEC2: - case GL_BOOL_VEC3: - case GL_BOOL_VEC4: - applyUniformnbv(targetUniform, i); - 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_INT: - case GL_INT_VEC2: - case GL_INT_VEC3: - case GL_INT_VEC4: - applyUniformniv(targetUniform, i); - break; - default: - UNREACHABLE(); - } - } - } - - // Driver uniforms - if (mDxUniformsDirty) - { - mDevice->SetVertexShaderConstantF(0, (float*)&mVertexConstants, sizeof(dx_VertexConstants) / sizeof(float[4])); - mDevice->SetPixelShaderConstantF(0, (float*)&mPixelConstants, sizeof(dx_PixelConstants) / sizeof(float[4])); - mDxUniformsDirty = false; - } - - return gl::Error(GL_NO_ERROR); -} - -void Renderer9::applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v) -{ - if (targetUniform->isReferencedByFragmentShader()) - { - mDevice->SetPixelShaderConstantF(targetUniform->psRegisterIndex, v, targetUniform->registerCount); - } - - if (targetUniform->isReferencedByVertexShader()) - { - mDevice->SetVertexShaderConstantF(targetUniform->vsRegisterIndex, v, targetUniform->registerCount); - } -} - -void Renderer9::applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v) -{ - ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); - GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; - - for (unsigned int i = 0; i < targetUniform->registerCount; i++) - { - vector[i][0] = (GLfloat)v[4 * i + 0]; - vector[i][1] = (GLfloat)v[4 * i + 1]; - vector[i][2] = (GLfloat)v[4 * i + 2]; - vector[i][3] = (GLfloat)v[4 * i + 3]; - } - - applyUniformnfv(targetUniform, (GLfloat*)vector); -} - -void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v) -{ - ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9); - GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4]; - - for (unsigned int i = 0; i < targetUniform->registerCount; i++) - { - vector[i][0] = (v[4 * i + 0] == GL_FALSE) ? 0.0f : 1.0f; - vector[i][1] = (v[4 * i + 1] == GL_FALSE) ? 0.0f : 1.0f; - vector[i][2] = (v[4 * i + 2] == GL_FALSE) ? 0.0f : 1.0f; - vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f; - } - - applyUniformnfv(targetUniform, (GLfloat*)vector); -} - -gl::Error Renderer9::clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) -{ - if (clearParams.colorClearType != GL_FLOAT) - { - // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0 - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - - bool clearColor = clearParams.clearColor[0]; - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - if (clearParams.clearColor[i] != clearColor) - { - // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0 - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - } - - float depth = gl::clamp01(clearParams.depthClearValue); - DWORD stencil = clearParams.stencilClearValue & 0x000000FF; - - unsigned int stencilUnmasked = 0x0; - if (clearParams.clearStencil && frameBuffer->hasStencil()) - { - unsigned int stencilSize = gl::GetInternalFormatInfo((frameBuffer->getStencilbuffer()->getActualFormat())).stencilBits; - stencilUnmasked = (0x1 << stencilSize) - 1; - } - - const bool needMaskedStencilClear = clearParams.clearStencil && - (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked; - - bool needMaskedColorClear = false; - D3DCOLOR color = D3DCOLOR_ARGB(255, 0, 0, 0); - if (clearColor) - { - const gl::FramebufferAttachment *attachment = frameBuffer->getFirstColorbuffer(); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat()); - const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(attachment->getActualFormat()); - - color = D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && actualFormatInfo.alphaBits > 0) ? 1.0f : clearParams.colorFClearValue.alpha), - gl::unorm<8>((formatInfo.redBits == 0 && actualFormatInfo.redBits > 0) ? 0.0f : clearParams.colorFClearValue.red), - gl::unorm<8>((formatInfo.greenBits == 0 && actualFormatInfo.greenBits > 0) ? 0.0f : clearParams.colorFClearValue.green), - gl::unorm<8>((formatInfo.blueBits == 0 && actualFormatInfo.blueBits > 0) ? 0.0f : clearParams.colorFClearValue.blue)); - - if ((formatInfo.redBits > 0 && !clearParams.colorMaskRed) || - (formatInfo.greenBits > 0 && !clearParams.colorMaskGreen) || - (formatInfo.blueBits > 0 && !clearParams.colorMaskBlue) || - (formatInfo.alphaBits > 0 && !clearParams.colorMaskAlpha)) - { - needMaskedColorClear = true; - } - } - - 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 < gl::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 (clearColor) - { - mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, - gl_d3d9::ConvertColorMask(clearParams.colorMaskRed, - clearParams.colorMaskGreen, - clearParams.colorMaskBlue, - clearParams.colorMaskAlpha)); - } - else - { - mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); - } - - if (stencilUnmasked != 0x0 && clearParams.clearStencil) - { - 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, clearParams.stencilWriteMask); - mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); - mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); - mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); - } - 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 < gl::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; - - startScene(); - mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4])); - - if (clearParams.clearDepth) - { - 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 (clearColor || clearParams.clearDepth || clearParams.clearStencil) - { - DWORD dxClearFlags = 0; - if (clearColor) - { - dxClearFlags |= D3DCLEAR_TARGET; - } - if (clearParams.clearDepth) - { - dxClearFlags |= D3DCLEAR_ZBUFFER; - } - if (clearParams.clearStencil) - { - dxClearFlags |= D3DCLEAR_STENCIL; - } - - mDevice->Clear(0, NULL, dxClearFlags, color, depth, stencil); - } - - return gl::Error(GL_NO_ERROR); -} - -void Renderer9::markAllStateDirty() -{ - mAppliedRenderTargetSerial = 0; - mAppliedDepthbufferSerial = 0; - mAppliedStencilbufferSerial = 0; - mDepthStencilInitialized = false; - mRenderTargetDescInitialized = false; - - mForceSetDepthStencilState = true; - mForceSetRasterState = true; - mForceSetScissor = true; - mForceSetViewport = true; - mForceSetBlendState = true; - - ASSERT(mForceSetVertexSamplerStates.size() == mCurVertexTextureSerials.size()); - for (unsigned int i = 0; i < mForceSetVertexSamplerStates.size(); i++) - { - mForceSetVertexSamplerStates[i] = true; - mCurVertexTextureSerials[i] = 0; - } - - ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelTextureSerials.size()); - for (unsigned int i = 0; i < mForceSetPixelSamplerStates.size(); i++) - { - mForceSetPixelSamplerStates[i] = true; - mCurPixelTextureSerials[i] = 0; - } - - mAppliedIBSerial = 0; - mAppliedVertexShader = NULL; - mAppliedPixelShader = NULL; - mAppliedProgramSerial = 0; - mDxUniformsDirty = true; - - mVertexDeclarationCache.markStateDirty(); -} - -void Renderer9::releaseDeviceResources() -{ - for (size_t i = 0; i < mEventQueryPool.size(); i++) - { - SafeRelease(mEventQueryPool[i]); - } - mEventQueryPool.clear(); - - SafeRelease(mMaskedClearSavedState); - - mVertexShaderCache.clear(); - mPixelShaderCache.clear(); - - SafeDelete(mBlit); - SafeDelete(mVertexDataManager); - SafeDelete(mIndexDataManager); - SafeDelete(mLineLoopIB); - SafeDelete(mCountingIB); - - for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++) - { - SafeDelete(mNullColorbufferCache[i].buffer); - } -} - -void Renderer9::notifyDeviceLost() -{ - mDeviceLost = true; - mDisplay->notifyDeviceLost(); -} - -bool Renderer9::isDeviceLost() -{ - return mDeviceLost; -} - -// set notify to true to broadcast a message to all contexts of the device loss -bool Renderer9::testDeviceLost(bool notify) -{ - HRESULT status = getDeviceStatusCode(); - bool isLost = FAILED(status); - - if (isLost) - { - // ensure we note the device loss -- - // we'll probably get this done again by notifyDeviceLost - // but best to remember it! - // Note that we don't want to clear the device loss status here - // -- this needs to be done by resetDevice - mDeviceLost = true; - if (notify) - { - notifyDeviceLost(); - } - } - - return isLost; -} - -HRESULT Renderer9::getDeviceStatusCode() -{ - HRESULT status = D3D_OK; - - if (mDeviceEx) - { - status = mDeviceEx->CheckDeviceState(NULL); - } - else if (mDevice) - { - status = mDevice->TestCooperativeLevel(); - } - - return status; -} - -bool Renderer9::testDeviceResettable() -{ - // On D3D9Ex, DEVICELOST represents a hung device that needs to be restarted - // DEVICEREMOVED indicates the device has been stopped and must be recreated - switch (getDeviceStatusCode()) - { - case D3DERR_DEVICENOTRESET: - case D3DERR_DEVICEHUNG: - return true; - case D3DERR_DEVICELOST: - return (mDeviceEx != NULL); - case D3DERR_DEVICEREMOVED: - ASSERT(mDeviceEx != NULL); - return isRemovedDeviceResettable(); - default: - return false; - } -} - -bool Renderer9::resetDevice() -{ - releaseDeviceResources(); - - D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - - HRESULT result = D3D_OK; - bool lost = testDeviceLost(false); - bool removedDevice = (getDeviceStatusCode() == D3DERR_DEVICEREMOVED); - - // Device Removed is a feature which is only present with D3D9Ex - ASSERT(mDeviceEx != NULL || !removedDevice); - - for (int attempts = 3; lost && attempts > 0; attempts--) - { - if (removedDevice) - { - // Device removed, which may trigger on driver reinstallation, - // may cause a longer wait other reset attempts before the - // system is ready to handle creating a new device. - Sleep(800); - lost = !resetRemovedDevice(); - } - else if (mDeviceEx) - { - Sleep(500); // Give the graphics driver some CPU time - result = mDeviceEx->ResetEx(&presentParameters, NULL); - lost = testDeviceLost(false); - } - 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(false); - } - } - - if (FAILED(result)) - { - ERR("Reset/ResetEx failed multiple times: 0x%08X", result); - return false; - } - - if (removedDevice && lost) - { - ERR("Device lost reset failed multiple times"); - return false; - } - - // If the device was removed, we already finished re-initialization in resetRemovedDevice - if (!removedDevice) - { - // reset device defaults - initializeDevice(); - } - - mDeviceLost = false; - - return true; -} - -bool Renderer9::isRemovedDeviceResettable() const -{ - bool success = false; - -#if ANGLE_D3D9EX == ANGLE_ENABLED - IDirect3D9Ex *d3d9Ex = NULL; - typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); - Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); - - if (Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &d3d9Ex))) - { - D3DCAPS9 deviceCaps; - HRESULT result = d3d9Ex->GetDeviceCaps(mAdapter, mDeviceType, &deviceCaps); - success = SUCCEEDED(result); - } - - SafeRelease(d3d9Ex); -#else - ASSERT(UNREACHABLE()); -#endif - - return success; -} - -bool Renderer9::resetRemovedDevice() -{ - // From http://msdn.microsoft.com/en-us/library/windows/desktop/bb172554(v=vs.85).aspx: - // The hardware adapter has been removed. Application must destroy the device, do enumeration of - // adapters and create another Direct3D device. If application continues rendering without - // calling Reset, the rendering calls will succeed. Applies to Direct3D 9Ex only. - release(); - return (initialize() == EGL_SUCCESS); -} - -DWORD Renderer9::getAdapterVendor() const -{ - return mAdapterIdentifier.VendorId; -} - -std::string Renderer9::getRendererDescription() const -{ - std::ostringstream rendererString; - - rendererString << mAdapterIdentifier.Description; - if (getShareHandleSupport()) - { - rendererString << " Direct3D9Ex"; - } - else - { - rendererString << " Direct3D9"; - } - - rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion); - rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_" << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion); - - return rendererString.str(); -} - -GUID Renderer9::getAdapterIdentifier() const -{ - return mAdapterIdentifier.DeviceIdentifier; -} - -unsigned int Renderer9::getReservedVertexUniformVectors() const -{ - return 2; // dx_ViewAdjust and dx_DepthRange. -} - -unsigned int Renderer9::getReservedFragmentUniformVectors() const -{ - return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. -} - -unsigned int Renderer9::getReservedVertexUniformBuffers() const -{ - return 0; -} - -unsigned int Renderer9::getReservedFragmentUniformBuffers() const -{ - return 0; -} - -bool Renderer9::getShareHandleSupport() const -{ - // PIX doesn't seem to support using share handles, so disable them. - return (mD3d9Ex != NULL) && !gl::perfActive(); -} - -bool Renderer9::getPostSubBufferSupport() const -{ - return true; -} - -int Renderer9::getMajorShaderModel() const -{ - return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion); -} - -DWORD Renderer9::getCapsDeclTypes() const -{ - return mDeviceCaps.DeclTypes; -} - -int Renderer9::getMinSwapInterval() const -{ - return mMinSwapInterval; -} - -int Renderer9::getMaxSwapInterval() const -{ - return mMaxSwapInterval; -} - -D3DPOOL Renderer9::getBufferPool(DWORD usage) const -{ - if (mD3d9Ex != NULL) - { - return D3DPOOL_DEFAULT; - } - else - { - if (!(usage & D3DUSAGE_DYNAMIC)) - { - return D3DPOOL_MANAGED; - } - } - - return D3DPOOL_DEFAULT; -} - -gl::Error Renderer9::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) -{ - RECT rect; - rect.left = sourceRect.x; - rect.top = sourceRect.y; - rect.right = sourceRect.x + sourceRect.width; - rect.bottom = sourceRect.y + sourceRect.height; - - return mBlit->copy2D(framebuffer, rect, destFormat, xoffset, yoffset, storage, level); -} - -gl::Error Renderer9::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) -{ - RECT rect; - rect.left = sourceRect.x; - rect.top = sourceRect.y; - rect.right = sourceRect.x + sourceRect.width; - rect.bottom = sourceRect.y + sourceRect.height; - - return mBlit->copyCube(framebuffer, rect, destFormat, xoffset, yoffset, storage, target, level); -} - -gl::Error Renderer9::copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) -{ - // 3D textures are not available in the D3D9 backend. - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); -} - -gl::Error Renderer9::copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) -{ - // 2D array textures are not available in the D3D9 backend. - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); -} - -gl::Error Renderer9::blitRect(const gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, - const gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, - bool blitDepth, bool blitStencil, GLenum filter) -{ - ASSERT(filter == GL_NEAREST); - - endScene(); - - if (blitRenderTarget) - { - gl::FramebufferAttachment *readBuffer = readFramebuffer->getColorbuffer(0); - ASSERT(readBuffer); - - RenderTarget9 *readRenderTarget = NULL; - gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(readRenderTarget); - - gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getColorbuffer(0); - ASSERT(drawBuffer); - - RenderTarget9 *drawRenderTarget = NULL; - error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); - if (error.isError()) - { - return error; - } - ASSERT(drawRenderTarget); - - // The getSurface calls do an AddRef so save them until after no errors are possible - IDirect3DSurface9* readSurface = readRenderTarget->getSurface(); - ASSERT(readSurface); - - IDirect3DSurface9* drawSurface = drawRenderTarget->getSurface(); - ASSERT(drawSurface); - - gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); - gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); - - RECT srcRect; - srcRect.left = readRect.x; - srcRect.right = readRect.x + readRect.width; - srcRect.top = readRect.y; - srcRect.bottom = readRect.y + readRect.height; - - RECT dstRect; - dstRect.left = drawRect.x; - dstRect.right = drawRect.x + drawRect.width; - dstRect.top = drawRect.y; - dstRect.bottom = drawRect.y + drawRect.height; - - // Clip the rectangles to the scissor rectangle - if (scissor) - { - if (dstRect.left < scissor->x) - { - srcRect.left += (scissor->x - dstRect.left); - dstRect.left = scissor->x; - } - if (dstRect.top < scissor->y) - { - srcRect.top += (scissor->y - dstRect.top); - dstRect.top = scissor->y; - } - if (dstRect.right > scissor->x + scissor->width) - { - srcRect.right -= (dstRect.right - (scissor->x + scissor->width)); - dstRect.right = scissor->x + scissor->width; - } - if (dstRect.bottom > scissor->y + scissor->height) - { - srcRect.bottom -= (dstRect.bottom - (scissor->y + scissor->height)); - dstRect.bottom = scissor->y + scissor->height; - } - } - - // Clip the rectangles to the destination size - if (dstRect.left < 0) - { - srcRect.left += -dstRect.left; - dstRect.left = 0; - } - if (dstRect.right > dstSize.width) - { - srcRect.right -= (dstRect.right - dstSize.width); - dstRect.right = dstSize.width; - } - if (dstRect.top < 0) - { - srcRect.top += -dstRect.top; - dstRect.top = 0; - } - if (dstRect.bottom > dstSize.height) - { - srcRect.bottom -= (dstRect.bottom - dstSize.height); - dstRect.bottom = dstSize.height; - } - - // Clip the rectangles to the source size - if (srcRect.left < 0) - { - dstRect.left += -srcRect.left; - srcRect.left = 0; - } - if (srcRect.right > srcSize.width) - { - dstRect.right -= (srcRect.right - srcSize.width); - srcRect.right = srcSize.width; - } - if (srcRect.top < 0) - { - dstRect.top += -srcRect.top; - srcRect.top = 0; - } - if (srcRect.bottom > srcSize.height) - { - dstRect.bottom -= (srcRect.bottom - srcSize.height); - srcRect.bottom = srcSize.height; - } - - HRESULT result = mDevice->StretchRect(readSurface, &srcRect, drawSurface, &dstRect, D3DTEXF_NONE); - - SafeRelease(readSurface); - SafeRelease(drawSurface); - - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); - } - } - - if (blitDepth || blitStencil) - { - gl::FramebufferAttachment *readBuffer = readFramebuffer->getDepthOrStencilbuffer(); - ASSERT(readBuffer); - - RenderTarget9 *readDepthStencil = NULL; - gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readDepthStencil); - if (error.isError()) - { - return error; - } - ASSERT(readDepthStencil); - - gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer(); - ASSERT(drawBuffer); - - RenderTarget9 *drawDepthStencil = NULL; - error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawDepthStencil); - if (error.isError()) - { - return error; - } - ASSERT(drawDepthStencil); - - // The getSurface calls do an AddRef so save them until after no errors are possible - IDirect3DSurface9* readSurface = readDepthStencil->getSurface(); - ASSERT(readDepthStencil); - - IDirect3DSurface9* drawSurface = drawDepthStencil->getSurface(); - ASSERT(drawDepthStencil); - - HRESULT result = mDevice->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE); - - SafeRelease(readSurface); - SafeRelease(drawSurface); - - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); - } - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) -{ - ASSERT(pack.pixelBuffer.get() == NULL); - - gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); - ASSERT(colorbuffer); - - RenderTarget9 *renderTarget = NULL; - gl::Error error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget); - if (error.isError()) - { - return error; - } - ASSERT(renderTarget); - - IDirect3DSurface9 *surface = renderTarget->getSurface(); - ASSERT(surface); - - D3DSURFACE_DESC desc; - surface->GetDesc(&desc); - - if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) - { - UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target - SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "ReadPixels is unimplemented for multisampled framebuffer attachments."); - } - - HRESULT result; - IDirect3DSurface9 *systemSurface = NULL; - bool directToPixels = !pack.reverseRowOrder && pack.alignment <= 4 && getShareHandleSupport() && - 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, reinterpret_cast(&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); - SafeRelease(surface); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for ReadPixels."); - } - } - - result = mDevice->GetRenderTargetData(surface, systemSurface); - SafeRelease(surface); - - if (FAILED(result)) - { - SafeRelease(systemSurface); - - // It turns out that D3D will sometimes produce more error - // codes than those documented. - if (d3d9::isDeviceLostError(result)) - { - notifyDeviceLost(); - } - else - { - UNREACHABLE(); - } - - return gl::Error(GL_OUT_OF_MEMORY, "Failed to read internal render target data."); - } - - if (directToPixels) - { - SafeRelease(systemSurface); - return gl::Error(GL_NO_ERROR); - } - - RECT rect; - rect.left = gl::clamp(x, 0L, static_cast(desc.Width)); - rect.top = gl::clamp(y, 0L, static_cast(desc.Height)); - rect.right = gl::clamp(x + width, 0L, static_cast(desc.Width)); - rect.bottom = gl::clamp(y + height, 0L, static_cast(desc.Height)); - - D3DLOCKED_RECT lock; - result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); - - if (FAILED(result)) - { - UNREACHABLE(); - SafeRelease(systemSurface); - - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal render target."); - } - - uint8_t *source; - int inputPitch; - if (pack.reverseRowOrder) - { - source = reinterpret_cast(lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1); - inputPitch = -lock.Pitch; - } - else - { - source = reinterpret_cast(lock.pBits); - inputPitch = lock.Pitch; - } - - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); - const gl::InternalFormat &sourceFormatInfo = gl::GetInternalFormatInfo(d3dFormatInfo.internalFormat); - if (sourceFormatInfo.format == format && sourceFormatInfo.type == type) - { - // Direct copy possible - for (int y = 0; y < rect.bottom - rect.top; y++) - { - memcpy(pixels + y * outputPitch, source + y * inputPitch, (rect.right - rect.left) * sourceFormatInfo.pixelBytes); - } - } - else - { - const d3d9::D3DFormat &sourceD3DFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); - ColorCopyFunction fastCopyFunc = sourceD3DFormatInfo.getFastCopyFunction(format, type); - - const gl::FormatType &destFormatTypeInfo = gl::GetFormatTypeInfo(format, type); - const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(destFormatTypeInfo.internalFormat); - - if (fastCopyFunc) - { - // Fast copy is possible through some special function - for (int y = 0; y < rect.bottom - rect.top; y++) - { - for (int x = 0; x < rect.right - rect.left; x++) - { - uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; - const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; - - fastCopyFunc(src, dest); - } - } - } - else - { - uint8_t temp[sizeof(gl::ColorF)]; - for (int y = 0; y < rect.bottom - rect.top; y++) - { - for (int x = 0; x < rect.right - rect.left; x++) - { - uint8_t *dest = pixels + y * outputPitch + x * destFormatInfo.pixelBytes; - const uint8_t *src = source + y * inputPitch + x * sourceFormatInfo.pixelBytes; - - // readFunc and writeFunc will be using the same type of color, CopyTexImage - // will not allow the copy otherwise. - sourceD3DFormatInfo.colorReadFunction(src, temp); - destFormatTypeInfo.colorWriteFunction(temp, dest); - } - } - } - } - - systemSurface->UnlockRect(); - SafeRelease(systemSurface); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT) -{ - SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); - *outRT = new SurfaceRenderTarget9(swapChain9, depth); - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT) -{ - const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(format); - - const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); - GLuint supportedSamples = textureCaps.getNearestSamples(samples); - - IDirect3DSurface9 *renderTarget = NULL; - if (width > 0 && height > 0) - { - bool requiresInitialization = false; - HRESULT result = D3DERR_INVALIDCALL; - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - result = mDevice->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat, - gl_d3d9::GetMultisampleType(supportedSamples), - 0, FALSE, &renderTarget, NULL); - } - else - { - requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != NULL); - result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat, - gl_d3d9::GetMultisampleType(supportedSamples), - 0, FALSE, &renderTarget, NULL); - } - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target, result: 0x%X.", result); - } - - if (requiresInitialization) - { - // This format requires that the data be initialized before the render target can be used - // Unfortunately this requires a Get call on the d3d device but it is far better than having - // to mark the render target as lockable and copy data to the gpu. - IDirect3DSurface9 *prevRenderTarget = NULL; - mDevice->GetRenderTarget(0, &prevRenderTarget); - mDevice->SetRenderTarget(0, renderTarget); - mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); - mDevice->SetRenderTarget(0, prevRenderTarget); - } - } - - *outRT = new TextureRenderTarget9(renderTarget, format, width, height, 1, supportedSamples); - return gl::Error(GL_NO_ERROR); -} - -ShaderImpl *Renderer9::createShader(const gl::Data &data, GLenum type) -{ - return new ShaderD3D(data, type, this); -} - -ProgramImpl *Renderer9::createProgram() -{ - return new ProgramD3D(this); -} - -void Renderer9::releaseShaderCompiler() -{ - ShaderD3D::releaseCompiler(); -} - -gl::Error Renderer9::loadExecutable(const void *function, size_t length, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutable **outExecutable) -{ - // Transform feedback is not supported in ES2 or D3D9 - ASSERT(transformFeedbackVaryings.size() == 0); - - switch (type) - { - case SHADER_VERTEX: - { - IDirect3DVertexShader9 *vshader = NULL; - gl::Error error = createVertexShader((DWORD*)function, length, &vshader); - if (error.isError()) - { - return error; - } - *outExecutable = new ShaderExecutable9(function, length, vshader); - } - break; - case SHADER_PIXEL: - { - IDirect3DPixelShader9 *pshader = NULL; - gl::Error error = createPixelShader((DWORD*)function, length, &pshader); - if (error.isError()) - { - return error; - } - *outExecutable = new ShaderExecutable9(function, length, pshader); - } - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround, - ShaderExecutable **outExectuable) -{ - // Transform feedback is not supported in ES2 or D3D9 - ASSERT(transformFeedbackVaryings.size() == 0); - - const char *profileType = NULL; - switch (type) - { - case SHADER_VERTEX: - profileType = "vs"; - break; - case SHADER_PIXEL: - profileType = "ps"; - break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2; - unsigned int profileMinorVersion = 0; - std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); - - UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; - - if (workaround == ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION) - { - flags = D3DCOMPILE_SKIP_OPTIMIZATION; - } - else if (workaround == ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION) - { - flags = D3DCOMPILE_OPTIMIZATION_LEVEL3; - } - else ASSERT(workaround == ANGLE_D3D_WORKAROUND_NONE); - - if (gl::perfActive()) - { -#ifndef NDEBUG - flags = D3DCOMPILE_SKIP_OPTIMIZATION; -#endif - - flags |= D3DCOMPILE_DEBUG; - } - - // 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. - std::vector configs; - configs.push_back(CompileConfig(flags, "default" )); - configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control" )); - configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control")); - - ID3DBlob *binary = NULL; - std::string debugInfo; - gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, NULL, &binary, &debugInfo); - if (error.isError()) - { - return error; - } - - // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL - // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. - if (!binary) - { - *outExectuable = NULL; - return gl::Error(GL_NO_ERROR); - } - - error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - transformFeedbackVaryings, separatedOutputBuffers, outExectuable); - - SafeRelease(binary); - if (error.isError()) - { - return error; - } - - if (!debugInfo.empty()) - { - (*outExectuable)->appendDebugInfo(debugInfo); - } - - return gl::Error(GL_NO_ERROR); -} - -UniformStorage *Renderer9::createUniformStorage(size_t storageSize) -{ - return new UniformStorage(storageSize); -} - -gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) -{ - return mBlit->boxFilter(source, dest); -} - -D3DPOOL Renderer9::getTexturePool(DWORD usage) const -{ - if (mD3d9Ex != NULL) - { - return D3DPOOL_DEFAULT; - } - else - { - if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET))) - { - return D3DPOOL_MANAGED; - } - } - - return D3DPOOL_DEFAULT; -} - -gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) -{ - ASSERT(source && dest); - - HRESULT result = D3DERR_OUTOFVIDEOMEMORY; - - if (fromManaged) - { - D3DSURFACE_DESC desc; - source->GetDesc(&desc); - - IDirect3DSurface9 *surf = 0; - result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); - - if (SUCCEEDED(result)) - { - Image9::copyLockableSurfaces(surf, source); - result = mDevice->UpdateSurface(surf, NULL, dest, NULL); - SafeRelease(surf); - } - } - else - { - endScene(); - result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); - } - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit internal texture, result: 0x%X.", result); - } - - return gl::Error(GL_NO_ERROR); -} - -Image *Renderer9::createImage() -{ - return new Image9(); -} - -gl::Error Renderer9::generateMipmap(Image *dest, Image *src) -{ - Image9 *src9 = Image9::makeImage9(src); - Image9 *dst9 = Image9::makeImage9(dest); - return Image9::generateMipmap(dst9, src9); -} - -TextureStorage *Renderer9::createTextureStorage2D(SwapChain *swapChain) -{ - SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); - return new TextureStorage9_2D(this, swapChain9); -} - -TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) -{ - return new TextureStorage9_2D(this, internalformat, renderTarget, width, height, levels); -} - -TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) -{ - return new TextureStorage9_Cube(this, internalformat, renderTarget, size, levels); -} - -TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) -{ - // 3D textures are not supported by the D3D9 backend. - UNREACHABLE(); - - return NULL; -} - -TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) -{ - // 2D array textures are not supported by the D3D9 backend. - UNREACHABLE(); - - return NULL; -} - -TextureImpl *Renderer9::createTexture(GLenum target) -{ - switch(target) - { - case GL_TEXTURE_2D: return new TextureD3D_2D(this); - case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(this); - default: UNREACHABLE(); - } - - return NULL; -} - -RenderbufferImpl *Renderer9::createRenderbuffer() -{ - RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); - return renderbuffer; -} - -RenderbufferImpl *Renderer9::createRenderbuffer(SwapChain *swapChain, bool depth) -{ - RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); - renderbuffer->setStorage(swapChain, depth); - return renderbuffer; -} - -bool Renderer9::getLUID(LUID *adapterLuid) const -{ - adapterLuid->HighPart = 0; - adapterLuid->LowPart = 0; - - if (mD3d9Ex) - { - mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid); - return true; - } - - return false; -} - -VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const -{ - return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).conversionType; -} - -GLenum Renderer9::getVertexComponentType(const gl::VertexFormat &vertexFormat) const -{ - return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).componentType; -} - -void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const -{ - d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, outExtensions); -} - -Workarounds Renderer9::generateWorkarounds() const -{ - return d3d9::GenerateWorkarounds(); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h deleted file mode 100644 index 10d2fb11e8..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h +++ /dev/null @@ -1,352 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// Renderer9.h: Defines a back-end specific class for the D3D9 renderer. - -#ifndef LIBGLESV2_RENDERER_RENDERER9_H_ -#define LIBGLESV2_RENDERER_RENDERER9_H_ - -#include "common/angleutils.h" -#include "common/mathutil.h" -#include "libGLESv2/renderer/d3d/d3d9/ShaderCache.h" -#include "libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h" -#include "libGLESv2/renderer/d3d/HLSLCompiler.h" -#include "libGLESv2/renderer/d3d/RendererD3D.h" -#include "libGLESv2/renderer/RenderTarget.h" - -namespace gl -{ -class FramebufferAttachment; -} - -namespace egl -{ -class AttributeMap; -} - -namespace rx -{ -class VertexDataManager; -class IndexDataManager; -class StreamingIndexBufferInterface; -class StaticIndexBufferInterface; -struct TranslatedAttribute; -class Blit9; - -class Renderer9 : public RendererD3D -{ - public: - Renderer9(egl::Display *display, EGLNativeDisplayType hDc, const egl::AttributeMap &attributes); - virtual ~Renderer9(); - - static Renderer9 *makeRenderer9(Renderer *renderer); - - virtual EGLint initialize(); - virtual bool resetDevice(); - - virtual int generateConfigs(ConfigDesc **configDescList); - virtual void deleteConfigs(ConfigDesc *configDescList); - - void startScene(); - void endScene(); - - virtual gl::Error sync(bool block); - - virtual SwapChain *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); - - gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery); - void freeEventQuery(IDirect3DQuery9* query); - - // resource creation - gl::Error createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader); - gl::Error createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader); - HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); - HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer); - virtual gl::Error generateSwizzle(gl::Texture *texture); - virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler); - virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); - - virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); - - virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); - gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask) override; - virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, - int stencilBackRef, bool frontFaceCCW); - - virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled); - virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, - bool ignoreViewport); - - gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; - virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, - bool rasterizerDiscard, bool transformFeedbackActive); - virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray); - virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount); - virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances); - virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); - - virtual void applyTransformFeedbackBuffers(const gl::State& state); - - virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); - virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, - gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); - - gl::Error clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) override; - - virtual void markAllStateDirty(); - - // lost device - void notifyDeviceLost() override; - bool isDeviceLost() override; - bool testDeviceLost(bool notify) override; - bool testDeviceResettable() override; - - DWORD getAdapterVendor() const override; - std::string getRendererDescription() const override; - GUID getAdapterIdentifier() const override; - - IDirect3DDevice9 *getDevice() { return mDevice; } - - virtual unsigned int getReservedVertexUniformVectors() const; - virtual unsigned int getReservedFragmentUniformVectors() const; - virtual unsigned int getReservedVertexUniformBuffers() const; - virtual unsigned int getReservedFragmentUniformBuffers() const; - virtual bool getShareHandleSupport() const; - virtual bool getPostSubBufferSupport() const; - - virtual int getMajorShaderModel() const; - DWORD getCapsDeclTypes() const; - virtual int getMinSwapInterval() const; - virtual int getMaxSwapInterval() const; - - // Pixel operations - virtual gl::Error copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); - virtual gl::Error copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); - virtual gl::Error copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); - virtual gl::Error copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); - - gl::Error blitRect(const gl::Framebuffer *readTarget, const gl::Rectangle &readRect, - const gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, - bool blitDepth, bool blitStencil, GLenum filter) override; - - virtual gl::Error readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); - - // RenderTarget creation - virtual gl::Error createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT); - virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT); - - // Shader creation - virtual ShaderImpl *createShader(const gl::Data &data, GLenum type); - virtual ProgramImpl *createProgram(); - - // Shader operations - void releaseShaderCompiler() override; - virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, ShaderExecutable **outExecutable); - virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround, - ShaderExecutable **outExectuable); - virtual UniformStorage *createUniformStorage(size_t storageSize); - - // Image operations - virtual Image *createImage(); - gl::Error generateMipmap(Image *dest, Image *source) override; - virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); - virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); - virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); - virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); - virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); - - // Texture creation - virtual TextureImpl *createTexture(GLenum target); - - // Renderbuffer creation - virtual RenderbufferImpl *createRenderbuffer(); - virtual RenderbufferImpl *createRenderbuffer(SwapChain *swapChain, bool depth); - - // Buffer creation - virtual BufferImpl *createBuffer(); - virtual VertexBuffer *createVertexBuffer(); - virtual IndexBuffer *createIndexBuffer(); - - // Vertex Array creation - virtual VertexArrayImpl *createVertexArray(); - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type); - virtual FenceNVImpl *createFenceNV(); - virtual FenceSyncImpl *createFenceSync(); - - // Transform Feedback creation - virtual TransformFeedbackImpl* createTransformFeedback(); - - // Buffer-to-texture and Texture-to-buffer copies - virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; - virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); - - // D3D9-renderer specific methods - gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); - - D3DPOOL getTexturePool(DWORD usage) const; - - virtual bool getLUID(LUID *adapterLuid) const; - virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; - virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; - - gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); - - private: - DISALLOW_COPY_AND_ASSIGN(Renderer9); - - void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override; - Workarounds generateWorkarounds() const override; - - void release(); - - void applyUniformnfv(gl::LinkedUniform *targetUniform, const GLfloat *v); - void applyUniformniv(gl::LinkedUniform *targetUniform, const GLint *v); - void applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v); - - gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); - gl::Error drawIndexedPoints(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); - - gl::Error getCountingIB(size_t count, StaticIndexBufferInterface **outIB); - - gl::Error getNullColorbuffer(gl::FramebufferAttachment *depthbuffer, gl::FramebufferAttachment **outColorBuffer); - - D3DPOOL getBufferPool(DWORD usage) const; - - HMODULE mD3d9Module; - HDC mDc; - - void initializeDevice(); - D3DPRESENT_PARAMETERS getDefaultPresentParameters(); - void releaseDeviceResources(); - - HRESULT getDeviceStatusCode(); - bool isRemovedDeviceResettable() const; - bool resetRemovedDevice(); - - 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. - - HLSLCompiler mCompiler; - - Blit9 *mBlit; - - HWND mDeviceWindow; - - bool mDeviceLost; - D3DCAPS9 mDeviceCaps; - D3DADAPTER_IDENTIFIER9 mAdapterIdentifier; - - D3DPRIMITIVETYPE mPrimitiveType; - int mPrimitiveCount; - GLsizei mRepeatDraw; - - bool mSceneStarted; - int mMinSwapInterval; - int mMaxSwapInterval; - - bool mVertexTextureSupport; - - // current render target states - unsigned int mAppliedRenderTargetSerial; - unsigned int mAppliedDepthbufferSerial; - unsigned int mAppliedStencilbufferSerial; - bool mDepthStencilInitialized; - bool mRenderTargetDescInitialized; - RenderTarget::Desc mRenderTargetDesc; - unsigned int mCurStencilSize; - unsigned int mCurDepthSize; - - IDirect3DStateBlock9 *mMaskedClearSavedState; - - // previously set render states - bool mForceSetDepthStencilState; - gl::DepthStencilState mCurDepthStencilState; - int mCurStencilRef; - int mCurStencilBackRef; - bool mCurFrontFaceCCW; - - bool mForceSetRasterState; - gl::RasterizerState mCurRasterState; - - bool mForceSetScissor; - gl::Rectangle mCurScissor; - bool mScissorEnabled; - - bool mForceSetViewport; - gl::Rectangle mCurViewport; - float mCurNear; - float mCurFar; - float mCurDepthFront; - - bool mForceSetBlendState; - gl::BlendState mCurBlendState; - gl::ColorF mCurBlendColor; - GLuint mCurSampleMask; - - // Currently applied sampler states - std::vector mForceSetVertexSamplerStates; - std::vector mCurVertexSamplerStates; - - std::vector mForceSetPixelSamplerStates; - std::vector mCurPixelSamplerStates; - - // Currently applied textures - std::vector mCurVertexTextureSerials; - std::vector mCurPixelTextureSerials; - - unsigned int mAppliedIBSerial; - IDirect3DVertexShader9 *mAppliedVertexShader; - IDirect3DPixelShader9 *mAppliedPixelShader; - unsigned int mAppliedProgramSerial; - - dx_VertexConstants mVertexConstants; - dx_PixelConstants mPixelConstants; - bool mDxUniformsDirty; - - // A pool of event queries that are currently unused. - std::vector mEventQueryPool; - VertexShaderCache mVertexShaderCache; - PixelShaderCache mPixelShaderCache; - - VertexDataManager *mVertexDataManager; - VertexDeclarationCache mVertexDeclarationCache; - - IndexDataManager *mIndexDataManager; - StreamingIndexBufferInterface *mLineLoopIB; - StaticIndexBufferInterface *mCountingIB; - - enum { NUM_NULL_COLORBUFFER_CACHE_ENTRIES = 12 }; - struct NullColorbufferCacheEntry - { - UINT lruCount; - int width; - int height; - gl::FramebufferAttachment *buffer; - } mNullColorbufferCache[NUM_NULL_COLORBUFFER_CACHE_ENTRIES]; - UINT mMaxNullColorbufferLRU; - -}; - -} -#endif // LIBGLESV2_RENDERER_RENDERER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h deleted file mode 100644 index 6d7d2d648f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h +++ /dev/null @@ -1,110 +0,0 @@ -// -// 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. -// - -// ShaderCache: Defines rx::ShaderCache, a cache of Direct3D shader objects -// keyed by their byte code. - -#ifndef LIBGLESV2_RENDERER_SHADER_CACHE_H_ -#define LIBGLESV2_RENDERER_SHADER_CACHE_H_ - -#include "libGLESv2/Error.h" - -#include "common/debug.h" - -#include -#include -#include - -namespace rx -{ -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; - } - - gl::Error create(const DWORD *function, size_t length, ShaderObject **outShaderObject) - { - std::string key(reinterpret_cast(function), length); - typename Map::iterator it = mMap.find(key); - if (it != mMap.end()) - { - it->second->AddRef(); - *outShaderObject = it->second; - return gl::Error(GL_NO_ERROR); - } - - ShaderObject *shader; - HRESULT result = createShader(function, &shader); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader, result: 0x%X.", result); - } - - // Random eviction policy. - if (mMap.size() >= kMaxMapSize) - { - SafeRelease(mMap.begin()->second); - mMap.erase(mMap.begin()); - } - - shader->AddRef(); - mMap[key] = shader; - - *outShaderObject = shader; - return gl::Error(GL_NO_ERROR); - } - - void clear() - { - for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it) - { - SafeRelease(it->second); - } - - 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); - } - - typedef std::unordered_map Map; - Map mMap; - - IDirect3DDevice9 *mDevice; -}; - -typedef ShaderCache VertexShaderCache; -typedef ShaderCache PixelShaderCache; - -} - -#endif // LIBGLESV2_RENDERER_SHADER_CACHE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp deleted file mode 100644 index bc7120461b..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) 2012-2013 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. -// - -// ShaderExecutable9.cpp: Implements a D3D9-specific class to contain shader -// executable implementation details. - -#include "libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h" - -#include "common/debug.h" - -namespace rx -{ - -ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable) - : ShaderExecutable(function, length) -{ - mPixelExecutable = executable; - mVertexExecutable = NULL; -} - -ShaderExecutable9::ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable) - : ShaderExecutable(function, length) -{ - mVertexExecutable = executable; - mPixelExecutable = NULL; -} - -ShaderExecutable9::~ShaderExecutable9() -{ - SafeRelease(mVertexExecutable); - SafeRelease(mPixelExecutable); -} - -ShaderExecutable9 *ShaderExecutable9::makeShaderExecutable9(ShaderExecutable *executable) -{ - ASSERT(HAS_DYNAMIC_TYPE(ShaderExecutable9*, executable)); - return static_cast(executable); -} - -IDirect3DVertexShader9 *ShaderExecutable9::getVertexShader() const -{ - return mVertexExecutable; -} - -IDirect3DPixelShader9 *ShaderExecutable9::getPixelShader() const -{ - return mPixelExecutable; -} - -} \ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h deleted file mode 100644 index fa1e6c2844..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2012-2013 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. -// - -// ShaderExecutable9.h: Defines a D3D9-specific class to contain shader -// executable implementation details. - -#ifndef LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_ -#define LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_ - -#include "libGLESv2/renderer/ShaderExecutable.h" - -namespace rx -{ - -class ShaderExecutable9 : public ShaderExecutable -{ - public: - ShaderExecutable9(const void *function, size_t length, IDirect3DPixelShader9 *executable); - ShaderExecutable9(const void *function, size_t length, IDirect3DVertexShader9 *executable); - virtual ~ShaderExecutable9(); - - static ShaderExecutable9 *makeShaderExecutable9(ShaderExecutable *executable); - - IDirect3DPixelShader9 *getPixelShader() const; - IDirect3DVertexShader9 *getVertexShader() const; - - private: - DISALLOW_COPY_AND_ASSIGN(ShaderExecutable9); - - IDirect3DPixelShader9 *mPixelExecutable; - IDirect3DVertexShader9 *mVertexExecutable; -}; - -} - -#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_ \ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp deleted file mode 100644 index 95eb1a4371..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp +++ /dev/null @@ -1,422 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// SwapChain9.cpp: Implements a back-end specific class for the D3D9 swap chain. - -#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" - -#include "common/features.h" - -namespace rx -{ - -SwapChain9::SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, - GLenum backBufferFormat, GLenum depthBufferFormat) - : mRenderer(renderer), - SwapChain(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat) -{ - mSwapChain = NULL; - mBackBuffer = NULL; - mDepthStencil = NULL; - mRenderTarget = NULL; - mOffscreenTexture = NULL; - mWidth = -1; - mHeight = -1; - mSwapInterval = -1; -} - -SwapChain9::~SwapChain9() -{ - release(); -} - -void SwapChain9::release() -{ - SafeRelease(mSwapChain); - SafeRelease(mBackBuffer); - SafeRelease(mDepthStencil); - SafeRelease(mRenderTarget); - SafeRelease(mOffscreenTexture); - - if (mNativeWindow.getNativeWindow()) - { - mShareHandle = NULL; - } -} - -static DWORD convertInterval(EGLint interval) -{ -#if ANGLE_VSYNC == ANGLE_DISABLED - return D3DPRESENT_INTERVAL_IMMEDIATE; -#else - 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; -#endif -} - -EGLint SwapChain9::resize(int backbufferWidth, int backbufferHeight) -{ - // D3D9 does not support resizing swap chains without recreating them - return reset(backbufferWidth, backbufferHeight, mSwapInterval); -} - -EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) -{ - IDirect3DDevice9 *device = mRenderer->getDevice(); - - if (device == NULL) - { - return EGL_BAD_ACCESS; - } - - // 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. - SafeRelease(mSwapChain); - SafeRelease(mBackBuffer); - SafeRelease(mOffscreenTexture); - SafeRelease(mDepthStencil); - - HANDLE *pShareHandle = NULL; - if (!mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport()) - { - pShareHandle = &mShareHandle; - } - - const d3d9::TextureFormat &backBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mBackBufferFormat); - result = device->CreateTexture(backbufferWidth, backbufferHeight, 1, D3DUSAGE_RENDERTARGET, - backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, - pShareHandle); - if (FAILED(result)) - { - ERR("Could not create offscreen texture: %08lX", result); - release(); - - if (d3d9::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } - } - - 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; - } - - mRenderer->endScene(); - - result = device->StretchRect(oldRenderTarget, &rect, mRenderTarget, &rect, D3DTEXF_NONE); - ASSERT(SUCCEEDED(result)); - - SafeRelease(oldRenderTarget); - } - - const d3d9::TextureFormat &depthBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mDepthBufferFormat); - - EGLNativeWindowType window = mNativeWindow.getNativeWindow(); - if (window) - { - D3DPRESENT_PARAMETERS presentParameters = {0}; - presentParameters.AutoDepthStencilFormat = depthBufferd3dFormatInfo.renderFormat; - presentParameters.BackBufferCount = 1; - presentParameters.BackBufferFormat = backBufferd3dFormatInfo.renderFormat; - presentParameters.EnableAutoDepthStencil = FALSE; - presentParameters.Flags = 0; - presentParameters.hDeviceWindow = window; - presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented - presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented - presentParameters.PresentationInterval = convertInterval(swapInterval); - 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. - if (mRenderer->getAdapterVendor() == 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 (d3d9::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } - } - - result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); - ASSERT(SUCCEEDED(result)); - InvalidateRect(window, NULL, FALSE); - } - - if (mDepthBufferFormat != GL_NONE) - { - result = device->CreateDepthStencilSurface(backbufferWidth, backbufferHeight, - depthBufferd3dFormatInfo.renderFormat, - 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 (d3d9::isDeviceLostError(result)) - { - return EGL_CONTEXT_LOST; - } - else - { - return EGL_BAD_ALLOC; - } - } - } - - mWidth = backbufferWidth; - mHeight = backbufferHeight; - mSwapInterval = swapInterval; - - return EGL_SUCCESS; -} - -// parameters should be validated/clamped by caller -EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) -{ - if (!mSwapChain) - { - return EGL_SUCCESS; - } - - IDirect3DDevice9 *device = mRenderer->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); - - for (UINT streamIndex = 0; streamIndex < gl::MAX_VERTEX_ATTRIBS; streamIndex++) - { - device->SetStreamSourceFreq(streamIndex, 1); - } - - 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 - - mRenderer->startScene(); - device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); - mRenderer->endScene(); - - device->SetTexture(0, NULL); - - RECT rect = - { - x, mHeight - y - height, - x + width, mHeight - y - }; - - HRESULT result = mSwapChain->Present(&rect, &rect, NULL, NULL, 0); - - mRenderer->markAllStateDirty(); - - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) - { - return EGL_BAD_ALLOC; - } - - // On Windows 8 systems, IDirect3DSwapChain9::Present sometimes returns 0x88760873 when the windows is - // in the process of entering/exiting fullscreen. This code doesn't seem to have any documentation. The - // device appears to be ok after emitting this error so simply return a failure to swap. - if (result == 0x88760873) - { - return EGL_BAD_MATCH; - } - - // http://crbug.com/313210 - // If our swap failed, trigger a device lost event. Resetting will work around an AMD-specific - // device removed bug with lost contexts when reinstalling drivers. - if (FAILED(result)) - { - mRenderer->notifyDeviceLost(); - return EGL_CONTEXT_LOST; - } - - return EGL_SUCCESS; -} - -// Increments refcount on surface. -// caller must Release() the returned surface -// TODO: remove the AddRef to match SwapChain11 -IDirect3DSurface9 *SwapChain9::getRenderTarget() -{ - if (mRenderTarget) - { - mRenderTarget->AddRef(); - } - - return mRenderTarget; -} - -// Increments refcount on surface. -// caller must Release() the returned surface -// TODO: remove the AddRef to match SwapChain11 -IDirect3DSurface9 *SwapChain9::getDepthStencil() -{ - if (mDepthStencil) - { - mDepthStencil->AddRef(); - } - - return mDepthStencil; -} - -// Increments refcount on texture. -// caller must Release() the returned texture -// TODO: remove the AddRef to match SwapChain11 -IDirect3DTexture9 *SwapChain9::getOffscreenTexture() -{ - if (mOffscreenTexture) - { - mOffscreenTexture->AddRef(); - } - - return mOffscreenTexture; -} - -SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain) -{ - ASSERT(HAS_DYNAMIC_TYPE(SwapChain9*, swapChain)); - return static_cast(swapChain); -} - -void SwapChain9::recreate() -{ - if (!mSwapChain) - { - return; - } - - IDirect3DDevice9 *device = mRenderer->getDevice(); - if (device == NULL) - { - return; - } - - D3DPRESENT_PARAMETERS presentParameters; - HRESULT result = mSwapChain->GetPresentParameters(&presentParameters); - ASSERT(SUCCEEDED(result)); - - IDirect3DSwapChain9* newSwapChain = NULL; - result = device->CreateAdditionalSwapChain(&presentParameters, &newSwapChain); - if (FAILED(result)) - { - return; - } - - SafeRelease(mSwapChain); - mSwapChain = newSwapChain; - - SafeRelease(mBackBuffer); - result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); - ASSERT(SUCCEEDED(result)); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h deleted file mode 100644 index cb33bfbc0c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// 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. -// - -// SwapChain9.h: Defines a back-end specific class for the D3D9 swap chain. - -#ifndef LIBGLESV2_RENDERER_SWAPCHAIN9_H_ -#define LIBGLESV2_RENDERER_SWAPCHAIN9_H_ - -#include "common/angleutils.h" -#include "libGLESv2/renderer/SwapChain.h" - -namespace rx -{ -class Renderer9; - -class SwapChain9 : public SwapChain -{ - public: - SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, - GLenum backBufferFormat, GLenum depthBufferFormat); - virtual ~SwapChain9(); - - EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); - virtual void recreate(); - - virtual IDirect3DSurface9 *getRenderTarget(); - virtual IDirect3DSurface9 *getDepthStencil(); - virtual IDirect3DTexture9 *getOffscreenTexture(); - - EGLint getWidth() const { return mWidth; } - EGLint getHeight() const { return mHeight; } - - static SwapChain9 *makeSwapChain9(SwapChain *swapChain); - - private: - DISALLOW_COPY_AND_ASSIGN(SwapChain9); - - void release(); - - Renderer9 *mRenderer; - EGLint mHeight; - EGLint mWidth; - EGLint mSwapInterval; - - IDirect3DSwapChain9 *mSwapChain; - IDirect3DSurface9 *mBackBuffer; - IDirect3DSurface9 *mRenderTarget; - IDirect3DSurface9 *mDepthStencil; - IDirect3DTexture9* mOffscreenTexture; -}; - -} -#endif // LIBGLESV2_RENDERER_SWAPCHAIN9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp deleted file mode 100644 index 0ff4fd3b0f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp +++ /dev/null @@ -1,472 +0,0 @@ -// -// Copyright (c) 2012-2014 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. -// - -// TextureStorage9.cpp: Implements the abstract rx::TextureStorage9 class and its concrete derived -// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the -// D3D9 texture. - -#include "libGLESv2/renderer/d3d/d3d9/TextureStorage9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" -#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/renderer/d3d/TextureD3D.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/main.h" - -namespace rx -{ -TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage) - : mTopLevel(0), - mMipLevels(0), - mTextureWidth(0), - mTextureHeight(0), - mInternalFormat(GL_NONE), - mTextureFormat(D3DFMT_UNKNOWN), - mRenderer(Renderer9::makeRenderer9(renderer)), - mD3DUsage(usage), - mD3DPool(mRenderer->getTexturePool(usage)) -{ -} - -TextureStorage9::~TextureStorage9() -{ -} - -TextureStorage9 *TextureStorage9::makeTextureStorage9(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9*, storage)); - return static_cast(storage); -} - -DWORD TextureStorage9::GetTextureUsage(GLenum internalformat, bool renderTarget) -{ - DWORD d3dusage = 0; - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - d3dusage |= D3DUSAGE_DEPTHSTENCIL; - } - else if (renderTarget && (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)) - { - d3dusage |= D3DUSAGE_RENDERTARGET; - } - - return d3dusage; -} - - -bool TextureStorage9::isRenderTarget() const -{ - return (mD3DUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) != 0; -} - -bool TextureStorage9::isManaged() const -{ - return (mD3DPool == D3DPOOL_MANAGED); -} - -D3DPOOL TextureStorage9::getPool() const -{ - return mD3DPool; -} - -DWORD TextureStorage9::getUsage() const -{ - return mD3DUsage; -} - -int TextureStorage9::getTopLevel() const -{ - return mTopLevel; -} - -int TextureStorage9::getLevelCount() const -{ - return mMipLevels - mTopLevel; -} - -gl::Error TextureStorage9::setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData) -{ - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); -} - -TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain) - : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) -{ - IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); - mTexture = surfaceTexture; - mMipLevels = surfaceTexture->GetLevelCount(); - - mInternalFormat = swapchain->GetBackBufferInternalFormat(); - - D3DSURFACE_DESC surfaceDesc; - surfaceTexture->GetLevelDesc(0, &surfaceDesc); - mTextureWidth = surfaceDesc.Width; - mTextureHeight = surfaceDesc.Height; - mTextureFormat = surfaceDesc.Format; - - mRenderTarget = NULL; - - initializeSerials(1, 1); -} - -TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) - : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) -{ - mTexture = NULL; - mRenderTarget = NULL; - - mInternalFormat = internalformat; - - const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); - mTextureFormat = d3dFormatInfo.texFormat; - - d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel); - mTextureWidth = width; - mTextureHeight = height; - mMipLevels = mTopLevel + levels; - - initializeSerials(getLevelCount(), 1); -} - -TextureStorage9_2D::~TextureStorage9_2D() -{ - SafeRelease(mTexture); - SafeDelete(mRenderTarget); -} - -TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_2D*, storage)); - return static_cast(storage); -} - -// Increments refcount on surface. -// caller must Release() the returned surface -gl::Error TextureStorage9_2D::getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface) -{ - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); - if (error.isError()) - { - return error; - } - - IDirect3DTexture9 *texture = static_cast(baseTexture); - - HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface); - - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); - } - - // With managed textures the driver needs to be informed of updates to the lower mipmap levels - if (level + mTopLevel != 0 && isManaged() && dirty) - { - texture->AddDirtyRect(NULL); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &/*index*/, RenderTarget **outRT) -{ - if (!mRenderTarget && isRenderTarget()) - { - IDirect3DSurface9 *surface = NULL; - gl::Error error = getSurfaceLevel(0, false, &surface); - if (error.isError()) - { - return error; - } - - mRenderTarget = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0); - } - - ASSERT(outRT); - *outRT = mRenderTarget; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) -{ - IDirect3DSurface9 *upper = NULL; - gl::Error error = getSurfaceLevel(sourceIndex.mipIndex, false, &upper); - if (error.isError()) - { - return error; - } - - IDirect3DSurface9 *lower = NULL; - error = getSurfaceLevel(destIndex.mipIndex, true, &lower); - if (error.isError()) - { - SafeRelease(upper); - return error; - } - - ASSERT(upper && lower); - error = mRenderer->boxFilter(upper, lower); - - SafeRelease(upper); - SafeRelease(lower); - - return error; -} - -gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture) -{ - // 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 (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) - { - ASSERT(mMipLevels > 0); - - IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateTexture(mTextureWidth, mTextureHeight, mMipLevels, getUsage(), mTextureFormat, - getPool(), &mTexture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result); - } - } - - *outTexture = mTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) -{ - ASSERT(destStorage); - - TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(destStorage); - - int levels = getLevelCount(); - for (int i = 0; i < levels; ++i) - { - IDirect3DSurface9 *srcSurf = NULL; - gl::Error error = getSurfaceLevel(i, false, &srcSurf); - if (error.isError()) - { - return error; - } - - IDirect3DSurface9 *dstSurf = NULL; - error = dest9->getSurfaceLevel(i, true, &dstSurf); - if (error.isError()) - { - SafeRelease(srcSurf); - return error; - } - - error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged()); - - SafeRelease(srcSurf); - SafeRelease(dstSurf); - - if (error.isError()) - { - return error; - } - } - - return gl::Error(GL_NO_ERROR); -} - -TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels) - : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) -{ - mTexture = NULL; - for (int i = 0; i < CUBE_FACE_COUNT; ++i) - { - mRenderTarget[i] = NULL; - } - - mInternalFormat = internalformat; - - const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); - mTextureFormat = d3dFormatInfo.texFormat; - - int height = size; - d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel); - mTextureWidth = size; - mTextureHeight = size; - mMipLevels = mTopLevel + levels; - - initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT); -} - -TextureStorage9_Cube::~TextureStorage9_Cube() -{ - SafeRelease(mTexture); - - for (int i = 0; i < CUBE_FACE_COUNT; ++i) - { - SafeDelete(mRenderTarget[i]); - } -} - -TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStorage *storage) -{ - ASSERT(HAS_DYNAMIC_TYPE(TextureStorage9_Cube*, storage)); - return static_cast(storage); -} - -// Increments refcount on surface. -// caller must Release() the returned surface -gl::Error TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface) -{ - IDirect3DBaseTexture9 *baseTexture = NULL; - gl::Error error = getBaseTexture(&baseTexture); - if (error.isError()) - { - return error; - } - - IDirect3DCubeTexture9 *texture = static_cast(baseTexture); - - D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget); - HRESULT result = texture->GetCubeMapSurface(face, level + mTopLevel, outSurface); - - ASSERT(SUCCEEDED(result)); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); - } - - // With managed textures the driver needs to be informed of updates to the lower mipmap levels - if (level != 0 && isManaged() && dirty) - { - texture->AddDirtyRect(face, NULL); - } - - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) -{ - ASSERT(outRT); - ASSERT(index.mipIndex == 0); - ASSERT(index.layerIndex >= 0 && index.layerIndex < CUBE_FACE_COUNT); - - if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget()) - { - IDirect3DSurface9 *surface = NULL; - gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, 0, false, &surface); - if (error.isError()) - { - return error; - } - - mRenderTarget[index.layerIndex] = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0); - } - - *outRT = mRenderTarget[index.layerIndex]; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) -{ - IDirect3DSurface9 *upper = NULL; - gl::Error error = getCubeMapSurface(sourceIndex.type, sourceIndex.mipIndex, false, &upper); - if (error.isError()) - { - return error; - } - - IDirect3DSurface9 *lower = NULL; - error = getCubeMapSurface(destIndex.type, destIndex.mipIndex, true, &lower); - if (error.isError()) - { - SafeRelease(upper); - return error; - } - - ASSERT(upper && lower); - error = mRenderer->boxFilter(upper, lower); - - SafeRelease(upper); - SafeRelease(lower); - - return error; -} - -gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture) -{ - // 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 (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) - { - ASSERT(mMipLevels > 0); - ASSERT(mTextureWidth == mTextureHeight); - - IDirect3DDevice9 *device = mRenderer->getDevice(); - HRESULT result = device->CreateCubeTexture(mTextureWidth, mMipLevels, getUsage(), mTextureFormat, getPool(), - &mTexture, NULL); - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube storage texture, result: 0x%X.", result); - } - } - - *outTexture = mTexture; - return gl::Error(GL_NO_ERROR); -} - -gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage) -{ - ASSERT(destStorage); - - TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(destStorage); - - int levels = getLevelCount(); - for (int f = 0; f < CUBE_FACE_COUNT; f++) - { - for (int i = 0; i < levels; i++) - { - IDirect3DSurface9 *srcSurf = NULL; - gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf); - if (error.isError()) - { - return error; - } - - IDirect3DSurface9 *dstSurf = NULL; - error = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf); - if (error.isError()) - { - SafeRelease(srcSurf); - return error; - } - - error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged()); - - SafeRelease(srcSurf); - SafeRelease(dstSurf); - - if (error.isError()) - { - return error; - } - } - } - - return gl::Error(GL_NO_ERROR); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h deleted file mode 100644 index da0e1f2f18..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h +++ /dev/null @@ -1,114 +0,0 @@ -// -// Copyright (c) 2012-2013 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. -// - -// TextureStorage9.h: Defines the abstract rx::TextureStorage9 class and its concrete derived -// classes TextureStorage9_2D and TextureStorage9_Cube, which act as the interface to the -// D3D9 texture. - -#ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_ -#define LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_ - -#include "libGLESv2/renderer/d3d/TextureStorage.h" -#include "common/debug.h" - -namespace rx -{ -class Renderer9; -class SwapChain9; -class RenderTarget; -class RenderTarget9; - -class TextureStorage9 : public TextureStorage -{ - public: - virtual ~TextureStorage9(); - - static TextureStorage9 *makeTextureStorage9(TextureStorage *storage); - - static DWORD GetTextureUsage(GLenum internalformat, bool renderTarget); - - D3DPOOL getPool() const; - DWORD getUsage() const; - - virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) = 0; - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) = 0; - - virtual int getTopLevel() const; - virtual bool isRenderTarget() const; - virtual bool isManaged() const; - virtual int getLevelCount() const; - - virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, - const gl::PixelUnpackState &unpack, const uint8_t *pixelData); - - protected: - int mTopLevel; - size_t mMipLevels; - size_t mTextureWidth; - size_t mTextureHeight; - GLenum mInternalFormat; - D3DFORMAT mTextureFormat; - - Renderer9 *mRenderer; - - TextureStorage9(Renderer9 *renderer, DWORD usage); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage9); - - const DWORD mD3DUsage; - const D3DPOOL mD3DPool; -}; - -class TextureStorage9_2D : public TextureStorage9 -{ - public: - TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain); - TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); - virtual ~TextureStorage9_2D(); - - static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage); - - gl::Error getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture); - virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); - virtual gl::Error copyToStorage(TextureStorage *destStorage); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage9_2D); - - IDirect3DTexture9 *mTexture; - RenderTarget9 *mRenderTarget; -}; - -class TextureStorage9_Cube : public TextureStorage9 -{ - public: - TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels); - virtual ~TextureStorage9_Cube(); - - static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage); - - gl::Error getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface); - virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture); - virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); - virtual gl::Error copyToStorage(TextureStorage *destStorage); - - private: - DISALLOW_COPY_AND_ASSIGN(TextureStorage9_Cube); - - static const size_t CUBE_FACE_COUNT = 6; - - IDirect3DCubeTexture9 *mTexture; - RenderTarget9 *mRenderTarget[CUBE_FACE_COUNT]; -}; - -} - -#endif // LIBGLESV2_RENDERER_TEXTURESTORAGE9_H_ - diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h deleted file mode 100644 index 791c108462..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright 2014 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. -// - -// VertexArray9.h: Defines the rx::VertexArray9 class which implements rx::VertexArrayImpl. - -#ifndef LIBGLESV2_RENDERER_VERTEXARRAY9_H_ -#define LIBGLESV2_RENDERER_VERTEXARRAY9_H_ - -#include "libGLESv2/renderer/VertexArrayImpl.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" - -namespace rx -{ -class Renderer9; - -class VertexArray9 : public VertexArrayImpl -{ - public: - VertexArray9(Renderer9 *renderer) - : VertexArrayImpl(), - mRenderer(renderer) - { - } - - virtual ~VertexArray9() { } - - virtual void setElementArrayBuffer(const gl::Buffer *buffer) { } - virtual void setAttribute(size_t idx, const gl::VertexAttribute &attr) { } - virtual void setAttributeDivisor(size_t idx, GLuint divisor) { } - virtual void enableAttribute(size_t idx, bool enabledState) { } - - private: - DISALLOW_COPY_AND_ASSIGN(VertexArray9); - - Renderer9 *mRenderer; -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXARRAY9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp deleted file mode 100644 index b90133097c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// -// 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. -// - -// VertexBuffer9.cpp: Defines the D3D9 VertexBuffer implementation. - -#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/renderer/vertexconversion.h" -#include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/VertexAttribute.h" -#include "libGLESv2/Buffer.h" - -namespace rx -{ - -VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer) -{ - mVertexBuffer = NULL; - mBufferSize = 0; - mDynamicUsage = false; -} - -VertexBuffer9::~VertexBuffer9() -{ - SafeRelease(mVertexBuffer); -} - -gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) -{ - SafeRelease(mVertexBuffer); - - updateSerial(); - - if (size > 0) - { - DWORD flags = D3DUSAGE_WRITEONLY; - if (dynamicUsage) - { - flags |= D3DUSAGE_DYNAMIC; - } - - HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer); - - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); - } - } - - mBufferSize = size; - mDynamicUsage = dynamicUsage; - return gl::Error(GL_NO_ERROR); -} - -VertexBuffer9 *VertexBuffer9::makeVertexBuffer9(VertexBuffer *vertexBuffer) -{ - ASSERT(HAS_DYNAMIC_TYPE(VertexBuffer9*, vertexBuffer)); - return static_cast(vertexBuffer); -} - -gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int offset) -{ - if (!mVertexBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); - } - - gl::Buffer *buffer = attrib.buffer.get(); - - int inputStride = gl::ComputeVertexAttributeStride(attrib); - int elementSize = gl::ComputeVertexAttributeTypeSize(attrib); - - DWORD lockFlags = mDynamicUsage ? D3DLOCK_NOOVERWRITE : 0; - - uint8_t *mapPtr = NULL; - - unsigned int mapSize; - gl::Error error = spaceRequired(attrib, count, instances, &mapSize); - if (error.isError()) - { - return error; - } - - HRESULT result = mVertexBuffer->Lock(offset, mapSize, reinterpret_cast(&mapPtr), lockFlags); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal vertex buffer, HRESULT: 0x%08x.", result); - } - - const uint8_t *input = NULL; - if (attrib.enabled) - { - if (buffer) - { - BufferD3D *storage = BufferD3D::makeFromBuffer(buffer); - ASSERT(storage); - gl::Error error = storage->getData(&input); - if (error.isError()) - { - return error; - } - input += static_cast(attrib.offset); - } - else - { - input = static_cast(attrib.pointer); - } - } - else - { - input = reinterpret_cast(currentValue.FloatValues); - } - - if (instances == 0 || attrib.divisor == 0) - { - input += inputStride * start; - } - - gl::VertexFormat vertexFormat(attrib, currentValue.Type); - const d3d9::VertexFormat &d3dVertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); - bool needsConversion = (d3dVertexInfo.conversionType & VERTEX_CONVERT_CPU) > 0; - - if (!needsConversion && inputStride == elementSize) - { - size_t copySize = static_cast(count) * static_cast(inputStride); - memcpy(mapPtr, input, copySize); - } - else - { - d3dVertexInfo.copyFunction(input, inputStride, count, mapPtr); - } - - mVertexBuffer->Unlock(); - - return gl::Error(GL_NO_ERROR); -} - -gl::Error VertexBuffer9::getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, - unsigned int *outSpaceRequired) const -{ - return spaceRequired(attrib, count, instances, outSpaceRequired); -} - -unsigned int VertexBuffer9::getBufferSize() const -{ - return mBufferSize; -} - -gl::Error VertexBuffer9::setBufferSize(unsigned int size) -{ - if (size > mBufferSize) - { - return initialize(size, mDynamicUsage); - } - else - { - return gl::Error(GL_NO_ERROR); - } -} - -gl::Error VertexBuffer9::discard() -{ - if (!mVertexBuffer) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal vertex buffer is not initialized."); - } - - void *dummy; - HRESULT result; - - result = mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal buffer for discarding, HRESULT: 0x%08x", result); - } - - result = mVertexBuffer->Unlock(); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock internal buffer for discarding, HRESULT: 0x%08x", result); - } - - return gl::Error(GL_NO_ERROR); -} - -IDirect3DVertexBuffer9 * VertexBuffer9::getBuffer() const -{ - return mVertexBuffer; -} - -gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, - unsigned int *outSpaceRequired) const -{ - gl::VertexFormat vertexFormat(attrib, GL_FLOAT); - const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(mRenderer->getCapsDeclTypes(), vertexFormat); - - if (attrib.enabled) - { - unsigned int elementCount = 0; - if (instances == 0 || attrib.divisor == 0) - { - elementCount = count; - } - else - { - // Round up to divisor, if possible - elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); - } - - if (d3d9VertexInfo.outputElementSize <= std::numeric_limits::max() / elementCount) - { - if (outSpaceRequired) - { - *outSpaceRequired = d3d9VertexInfo.outputElementSize * elementCount; - } - return gl::Error(GL_NO_ERROR); - } - else - { - return gl::Error(GL_OUT_OF_MEMORY, "New vertex buffer size would result in an overflow."); - } - } - else - { - const unsigned int elementSize = 4; - if (outSpaceRequired) - { - *outSpaceRequired = elementSize * 4; - } - return gl::Error(GL_NO_ERROR); - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h deleted file mode 100644 index 9af2b98a6e..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// 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. -// - -// VertexBuffer9.h: Defines the D3D9 VertexBuffer implementation. - -#ifndef LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ -#define LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ - -#include "libGLESv2/renderer/d3d/VertexBuffer.h" - -namespace rx -{ -class Renderer9; - -class VertexBuffer9 : public VertexBuffer -{ - public: - explicit VertexBuffer9(Renderer9 *renderer); - virtual ~VertexBuffer9(); - - virtual gl::Error initialize(unsigned int size, bool dynamicUsage); - - static VertexBuffer9 *makeVertexBuffer9(VertexBuffer *vertexBuffer); - - virtual gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, - GLint start, GLsizei count, GLsizei instances, unsigned int offset); - - virtual gl::Error getSpaceRequired(const gl::VertexAttribute &attrib, GLsizei count, GLsizei instances, unsigned int *outSpaceRequired) const; - - virtual unsigned int getBufferSize() const; - virtual gl::Error setBufferSize(unsigned int size); - virtual gl::Error discard(); - - IDirect3DVertexBuffer9 *getBuffer() const; - - private: - DISALLOW_COPY_AND_ASSIGN(VertexBuffer9); - - Renderer9 *mRenderer; - - IDirect3DVertexBuffer9 *mVertexBuffer; - unsigned int mBufferSize; - bool mDynamicUsage; - - gl::Error spaceRequired(const gl::VertexAttribute &attrib, std::size_t count, GLsizei instances, - unsigned int *outSpaceRequired) const; -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXBUFFER9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp deleted file mode 100644 index cefd786f11..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp +++ /dev/null @@ -1,237 +0,0 @@ -// -// 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. -// - -// VertexDeclarationCache.cpp: Implements a helper class to construct and cache vertex declarations. - -#include "libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h" -#include "libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/VertexAttribute.h" - -namespace rx -{ - -VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0) -{ - for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) - { - mVertexDeclCache[i].vertexDeclaration = NULL; - mVertexDeclCache[i].lruCount = 0; - } - - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - mAppliedVBs[i].serial = 0; - } - - mLastSetVDecl = NULL; - mInstancingEnabled = true; -} - -VertexDeclarationCache::~VertexDeclarationCache() -{ - for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) - { - SafeRelease(mVertexDeclCache[i].vertexDeclaration); - } -} - -gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw) -{ - *repeatDraw = 1; - - int indexedAttribute = gl::MAX_VERTEX_ATTRIBS; - int instancedAttribute = gl::MAX_VERTEX_ATTRIBS; - - if (instances == 0) - { - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; ++i) - { - if (attributes[i].divisor != 0) - { - // If a divisor is set, it still applies even if an instanced draw was not used, so treat - // as a single-instance draw. - instances = 1; - break; - } - } - } - - if (instances > 0) - { - // Find an indexed attribute to be mapped to D3D stream 0 - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - if (attributes[i].active) - { - if (indexedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor == 0) - { - indexedAttribute = i; - } - else if (instancedAttribute == gl::MAX_VERTEX_ATTRIBS && attributes[i].divisor != 0) - { - instancedAttribute = i; - } - if (indexedAttribute != gl::MAX_VERTEX_ATTRIBS && instancedAttribute != gl::MAX_VERTEX_ATTRIBS) - break; // Found both an indexed and instanced attribute - } - } - - // The validation layer checks that there is at least one active attribute with a zero divisor as per - // the GL_ANGLE_instanced_arrays spec. - ASSERT(indexedAttribute != gl::MAX_VERTEX_ATTRIBS); - } - - D3DCAPS9 caps; - device->GetDeviceCaps(&caps); - - D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1]; - D3DVERTEXELEMENT9 *element = &elements[0]; - - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - if (attributes[i].active) - { - // Directly binding the storage buffer is not supported for d3d9 - ASSERT(attributes[i].storage == NULL); - - 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 == gl::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; - } - } - - VertexBuffer9 *vertexBuffer = VertexBuffer9::makeVertexBuffer9(attributes[i].vertexBuffer); - - if (mAppliedVBs[stream].serial != attributes[i].serial || - mAppliedVBs[stream].stride != attributes[i].stride || - mAppliedVBs[stream].offset != attributes[i].offset) - { - device->SetStreamSource(stream, vertexBuffer->getBuffer(), attributes[i].offset, attributes[i].stride); - mAppliedVBs[stream].serial = attributes[i].serial; - mAppliedVBs[stream].stride = attributes[i].stride; - mAppliedVBs[stream].offset = attributes[i].offset; - } - - gl::VertexFormat vertexFormat(*attributes[i].attribute, GL_FLOAT); - const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexFormat); - - element->Stream = stream; - element->Offset = 0; - element->Type = d3d9VertexInfo.nativeFormat; - element->Method = D3DDECLMETHOD_DEFAULT; - element->Usage = D3DDECLUSAGE_TEXCOORD; - element->UsageIndex = programBinary->getSemanticIndex(i); - element++; - } - } - - if (instances == 0 || instancedAttribute == gl::MAX_VERTEX_ATTRIBS) - { - if (mInstancingEnabled) - { - for (int i = 0; i < gl::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::Error(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) - { - SafeRelease(lastCache->vertexDeclaration); - // mLastSetVDecl is set to the replacement, so we don't have to worry - // about it. - } - - memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)); - HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); - if (FAILED(result)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal vertex declaration, result: 0x%X.", result); - } - - device->SetVertexDeclaration(lastCache->vertexDeclaration); - mLastSetVDecl = lastCache->vertexDeclaration; - lastCache->lruCount = ++mMaxLru; - - return gl::Error(GL_NO_ERROR); -} - -void VertexDeclarationCache::markStateDirty() -{ - for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) - { - mAppliedVBs[i].serial = 0; - } - - mLastSetVDecl = NULL; - mInstancingEnabled = true; // Forces it to be disabled when not used -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h deleted file mode 100644 index 9af36e0d7a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h +++ /dev/null @@ -1,59 +0,0 @@ -// -// 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. -// - -// VertexDeclarationCache.h: Defines a helper class to construct and cache vertex declarations. - -#ifndef LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_ -#define LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_ - -#include "libGLESv2/Error.h" -#include "libGLESv2/renderer/d3d/VertexDataManager.h" - -namespace gl -{ -class VertexDataManager; -} - -namespace rx -{ - -class VertexDeclarationCache -{ - public: - VertexDeclarationCache(); - ~VertexDeclarationCache(); - - gl::Error applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::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[gl::MAX_VERTEX_ATTRIBS]; - IDirect3DVertexDeclaration9 *mLastSetVDecl; - bool mInstancingEnabled; - - struct VertexDeclCacheEntry - { - D3DVERTEXELEMENT9 cachedElements[gl::MAX_VERTEX_ATTRIBS + 1]; - UINT lruCount; - IDirect3DVertexDeclaration9 *vertexDeclaration; - } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES]; -}; - -} - -#endif // LIBGLESV2_RENDERER_VERTEXDECLARATIONCACHE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp deleted file mode 100644 index f3acaf7987..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp +++ /dev/null @@ -1,588 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// formatutils9.cpp: Queries for GL image formats and their translations to D3D9 -// formats. - -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" -#include "libGLESv2/renderer/generatemip.h" -#include "libGLESv2/renderer/loadimage.h" -#include "libGLESv2/renderer/copyimage.h" -#include "libGLESv2/renderer/vertexconversion.h" - -namespace rx -{ - -namespace d3d9 -{ - -const D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z'))); -const D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L'))); - -struct D3D9FastCopyFormat -{ - GLenum destFormat; - GLenum destType; - ColorCopyFunction copyFunction; - - D3D9FastCopyFormat(GLenum destFormat, GLenum destType, ColorCopyFunction copyFunction) - : destFormat(destFormat), destType(destType), copyFunction(copyFunction) - { } - - bool operator<(const D3D9FastCopyFormat& other) const - { - return memcmp(this, &other, sizeof(D3D9FastCopyFormat)) < 0; - } -}; - -typedef std::multimap D3D9FastCopyMap; - -static D3D9FastCopyMap BuildFastCopyMap() -{ - D3D9FastCopyMap map; - - map.insert(std::make_pair(D3DFMT_A8R8G8B8, D3D9FastCopyFormat(GL_RGBA, GL_UNSIGNED_BYTE, CopyBGRA8ToRGBA8))); - - return map; -} - -// A map to determine the pixel size and mip generation function of a given D3D format -typedef std::map D3D9FormatInfoMap; - -D3DFormat::D3DFormat() - : pixelBytes(0), - blockWidth(0), - blockHeight(0), - internalFormat(GL_NONE), - mipGenerationFunction(NULL), - colorReadFunction(NULL), - fastCopyFunctions() -{ -} - -ColorCopyFunction D3DFormat::getFastCopyFunction(GLenum format, GLenum type) const -{ - FastCopyFunctionMap::const_iterator iter = fastCopyFunctions.find(std::make_pair(format, type)); - return (iter != fastCopyFunctions.end()) ? iter->second : NULL; -} - -static inline void InsertD3DFormatInfo(D3D9FormatInfoMap *map, D3DFORMAT format, GLuint bits, GLuint blockWidth, - GLuint blockHeight, GLenum internalFormat, MipGenerationFunction mipFunc, - ColorReadFunction colorReadFunc) -{ - D3DFormat info; - info.pixelBytes = bits / 8; - info.blockWidth = blockWidth; - info.blockHeight = blockHeight; - info.internalFormat = internalFormat; - info.mipGenerationFunction = mipFunc; - info.colorReadFunction = colorReadFunc; - - static const D3D9FastCopyMap fastCopyMap = BuildFastCopyMap(); - std::pair fastCopyIter = fastCopyMap.equal_range(format); - for (D3D9FastCopyMap::const_iterator i = fastCopyIter.first; i != fastCopyIter.second; i++) - { - info.fastCopyFunctions.insert(std::make_pair(std::make_pair(i->second.destFormat, i->second.destType), i->second.copyFunction)); - } - - map->insert(std::make_pair(format, info)); -} - -static D3D9FormatInfoMap BuildD3D9FormatInfoMap() -{ - D3D9FormatInfoMap map; - - // | D3DFORMAT | S |W |H | Internal format | Mip generation function | Color read function | - InsertD3DFormatInfo(&map, D3DFMT_NULL, 0, 0, 0, GL_NONE, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_UNKNOWN, 0, 0, 0, GL_NONE, NULL, NULL ); - - InsertD3DFormatInfo(&map, D3DFMT_L8, 8, 1, 1, GL_LUMINANCE8_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A8, 8, 1, 1, GL_ALPHA8_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A8L8, 16, 1, 1, GL_LUMINANCE8_ALPHA8_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A4R4G4B4, 16, 1, 1, GL_BGRA4_ANGLEX, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A1R5G5B5, 16, 1, 1, GL_BGR5_A1_ANGLEX, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_R5G6B5, 16, 1, 1, GL_RGB565, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_X8R8G8B8, 32, 1, 1, GL_BGRA8_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A8R8G8B8, 32, 1, 1, GL_BGRA8_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_R16F, 16, 1, 1, GL_R16F_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_G16R16F, 32, 1, 1, GL_RG16F_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A16B16G16R16F, 64, 1, 1, GL_RGBA16F_EXT, GenerateMip, ReadColor); - InsertD3DFormatInfo(&map, D3DFMT_R32F, 32, 1, 1, GL_R32F_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_G32R32F, 64, 1, 1, GL_RG32F_EXT, GenerateMip, ReadColor ); - InsertD3DFormatInfo(&map, D3DFMT_A32B32G32R32F, 128, 1, 1, GL_RGBA32F_EXT, GenerateMip, ReadColor); - - InsertD3DFormatInfo(&map, D3DFMT_D16, 16, 1, 1, GL_DEPTH_COMPONENT16, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_D24S8, 32, 1, 1, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_D24X8, 32, 1, 1, GL_DEPTH_COMPONENT16, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_D32, 32, 1, 1, GL_DEPTH_COMPONENT32_OES, NULL, NULL ); - - InsertD3DFormatInfo(&map, D3DFMT_INTZ, 32, 1, 1, GL_DEPTH24_STENCIL8_OES, NULL, NULL ); - - InsertD3DFormatInfo(&map, D3DFMT_DXT1, 64, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_DXT3, 128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, NULL, NULL ); - InsertD3DFormatInfo(&map, D3DFMT_DXT5, 128, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, NULL, NULL ); - - return map; -} - -const D3DFormat &GetD3DFormatInfo(D3DFORMAT format) -{ - static const D3D9FormatInfoMap infoMap = BuildD3D9FormatInfoMap(); - D3D9FormatInfoMap::const_iterator iter = infoMap.find(format); - if (iter != infoMap.end()) - { - return iter->second; - } - else - { - static const D3DFormat defaultInfo; - return defaultInfo; - } -} - - - -typedef std::pair InternalFormatInitialzerPair; -typedef std::map InternalFormatInitialzerMap; - -static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap() -{ - InternalFormatInitialzerMap map; - - map.insert(InternalFormatInitialzerPair(GL_RGB16F, Initialize4ComponentData)); - map.insert(InternalFormatInitialzerPair(GL_RGB32F, Initialize4ComponentData)); - - return map; -} - -// Each GL internal format corresponds to one D3D format and data loading function. -// Due to not all formats being available all the time, some of the function/format types are wrapped -// in templates that perform format support queries on a Renderer9 object which is supplied -// when requesting the function or format. - -typedef bool(*FallbackPredicateFunction)(); - -template -static void FallbackLoad(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - if (pred()) - { - prefered(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); - } - else - { - fallback(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); - } -} - -static void UnreachableLoad(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - UNREACHABLE(); -} - -typedef std::pair D3D9FormatPair; -typedef std::map D3D9FormatMap; - -TextureFormat::TextureFormat() - : texFormat(D3DFMT_NULL), - renderFormat(D3DFMT_NULL), - dataInitializerFunction(NULL), - loadFunction(UnreachableLoad) -{ -} - -static inline void InsertD3D9FormatInfo(D3D9FormatMap *map, GLenum internalFormat, D3DFORMAT texFormat, - D3DFORMAT renderFormat, LoadImageFunction loadFunction) -{ - TextureFormat info; - info.texFormat = texFormat; - info.renderFormat = renderFormat; - - static const InternalFormatInitialzerMap dataInitializationMap = BuildInternalFormatInitialzerMap(); - InternalFormatInitialzerMap::const_iterator dataInitIter = dataInitializationMap.find(internalFormat); - info.dataInitializerFunction = (dataInitIter != dataInitializationMap.end()) ? dataInitIter->second : NULL; - - info.loadFunction = loadFunction; - - map->insert(std::make_pair(internalFormat, info)); -} - -static D3D9FormatMap BuildD3D9FormatMap() -{ - D3D9FormatMap map; - - // | Internal format | Texture format | Render format | Load function | - InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad ); - - // We choose to downsample the GL_DEPTH_COMPONENT32_OES format to a 24-bit format because D3DFMT_D32 is not widely - // supported. We're allowed to do this because: - // - The ES spec 2.0.25 sec 3.7.1 states that we're allowed to store texture formats with internal format - // resolutions of our own choosing. - // - OES_depth_texture states that downsampling of the depth formats is allowed. - // - ANGLE_depth_texture does not state minimum required resolutions of the depth texture formats it - // introduces. - // In ES3 however, there are minimum resolutions for the texture formats and this would not be allowed. - - InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT16, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); - InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, D3DFMT_INTZ, D3DFMT_D24X8, UnreachableLoad ); - InsertD3D9FormatInfo(&map, GL_DEPTH24_STENCIL8_OES, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad ); - InsertD3D9FormatInfo(&map, GL_STENCIL_INDEX8, D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ); // TODO: What's the texture format? - - InsertD3D9FormatInfo(&map, GL_RGBA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative ); - InsertD3D9FormatInfo(&map, GL_RGB32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4); - InsertD3D9FormatInfo(&map, GL_RG32F_EXT, D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative ); - InsertD3D9FormatInfo(&map, GL_R32F_EXT, D3DFMT_R32F, D3DFMT_R32F, LoadToNative ); - InsertD3D9FormatInfo(&map, GL_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F ); - InsertD3D9FormatInfo(&map, GL_LUMINANCE32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F ); - InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F ); - - InsertD3D9FormatInfo(&map, GL_RGBA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative ); - InsertD3D9FormatInfo(&map, GL_RGB16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4 ); - InsertD3D9FormatInfo(&map, GL_RG16F_EXT, D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative ); - InsertD3D9FormatInfo(&map, GL_R16F_EXT, D3DFMT_R16F, D3DFMT_R16F, LoadToNative ); - InsertD3D9FormatInfo(&map, GL_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F ); - InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F ); - InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F ); - - InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad); - - InsertD3D9FormatInfo(&map, GL_RGB8_OES, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 ); - InsertD3D9FormatInfo(&map, GL_RGB565, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 ); - InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, FallbackLoad); - InsertD3D9FormatInfo(&map, GL_RGBA4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 ); - InsertD3D9FormatInfo(&map, GL_RGB5_A1, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 ); - InsertD3D9FormatInfo(&map, GL_R8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 ); - InsertD3D9FormatInfo(&map, GL_RG8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 ); - - InsertD3D9FormatInfo(&map, GL_BGRA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative ); - InsertD3D9FormatInfo(&map, GL_BGRA4_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 ); - InsertD3D9FormatInfo(&map, GL_BGR5_A1_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 ); - - InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ); - InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 8> ); - InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ); - InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 16> ); - - // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and - // then changing the format and loading function appropriately. - InsertD3D9FormatInfo(&map, GL_LUMINANCE8_EXT, D3DFMT_L8, D3DFMT_UNKNOWN, LoadToNative ); - InsertD3D9FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, D3DFMT_A8L8, D3DFMT_UNKNOWN, LoadToNative ); - - return map; -} - -const TextureFormat &GetTextureFormatInfo(GLenum internalFormat) -{ - static const D3D9FormatMap formatMap = BuildD3D9FormatMap(); - D3D9FormatMap::const_iterator iter = formatMap.find(internalFormat); - if (iter != formatMap.end()) - { - return iter->second; - } - else - { - static const TextureFormat defaultInfo; - return defaultInfo; - } -} - -static GLenum GetDeclTypeComponentType(D3DDECLTYPE declType) -{ - switch (declType) - { - case D3DDECLTYPE_FLOAT1: return GL_FLOAT; - case D3DDECLTYPE_FLOAT2: return GL_FLOAT; - case D3DDECLTYPE_FLOAT3: return GL_FLOAT; - case D3DDECLTYPE_FLOAT4: return GL_FLOAT; - case D3DDECLTYPE_UBYTE4: return GL_UNSIGNED_INT; - case D3DDECLTYPE_SHORT2: return GL_INT; - case D3DDECLTYPE_SHORT4: return GL_INT; - case D3DDECLTYPE_UBYTE4N: return GL_UNSIGNED_NORMALIZED; - case D3DDECLTYPE_SHORT4N: return GL_SIGNED_NORMALIZED; - case D3DDECLTYPE_USHORT4N: return GL_UNSIGNED_NORMALIZED; - case D3DDECLTYPE_SHORT2N: return GL_SIGNED_NORMALIZED; - case D3DDECLTYPE_USHORT2N: return GL_UNSIGNED_NORMALIZED; - default: UNREACHABLE(); return GL_NONE; - } -} - -// Attribute format conversion -enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 }; - -struct TranslationDescription -{ - DWORD capsFlag; - VertexFormat preferredConversion; - VertexFormat fallbackConversion; -}; - -// 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 : NoWiden { }; -template struct WidenRule : WidenToEven { }; -template struct WidenRule : WidenToEven { }; -template struct WidenRule : WidenToFour { }; -template struct WidenRule : WidenToFour { }; -template struct WidenRule : 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 : Cast::type, typename D3DToCType::type> { }; - -// All conversions from normalized types to float use the Normalize operator. -template struct ConversionRule : Normalize::type> { }; - -// Use a full specialization for this so that it preferentially matches ahead of the generic normalize-to-float rules. -template <> struct ConversionRule : FixedToFloat { }; -template <> struct ConversionRule : 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 : NormalizedDefaultValues { }; -template struct DefaultVertexValuesStage2 : SimpleDefaultValues { }; - -// Work out the default value rule for a D3D type (expressed as the C type) and -template struct DefaultVertexValues : DefaultVertexValuesStage2 { }; -template struct DefaultVertexValues : 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 - : 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 }; -}; - -VertexFormat::VertexFormat() - : conversionType(VERTEX_CONVERT_NONE), - outputElementSize(0), - copyFunction(NULL), - nativeFormat(D3DDECLTYPE_UNUSED), - componentType(GL_NONE) -{ -} - -// Initialize a TranslationInfo -VertexFormat CreateVertexFormatInfo(bool identity, size_t elementSize, VertexCopyFunction copyFunc, D3DDECLTYPE nativeFormat) -{ - VertexFormat formatInfo; - formatInfo.conversionType = identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU; - formatInfo.outputElementSize = elementSize; - formatInfo.copyFunction = copyFunc; - formatInfo.nativeFormat = nativeFormat; - formatInfo.componentType = GetDeclTypeComponentType(nativeFormat); - return formatInfo; -} - -#define TRANSLATION(type, norm, size, preferred) \ - CreateVertexFormatInfo \ - ( \ - 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) }, \ - } - -static inline unsigned int ComputeTypeIndex(GLenum type) -{ - 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; - } -} - -const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat) -{ - static bool initialized = false; - static DWORD intializedDeclTypes = 0; - static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; - if (!initialized) - { - const TranslationDescription translations[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) - }; - 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 (translations[i][j][k].capsFlag == 0 || (supportedDeclTypes & translations[i][j][k].capsFlag) != 0) - { - formatConverters[i][j][k] = translations[i][j][k].preferredConversion; - } - else - { - formatConverters[i][j][k] = translations[i][j][k].fallbackConversion; - } - } - } - } - initialized = true; - intializedDeclTypes = supportedDeclTypes; - } - - ASSERT(intializedDeclTypes == supportedDeclTypes); - - // Pure integer attributes only supported in ES3.0 - ASSERT(!vertexFormat.mPureInteger); - return formatConverters[ComputeTypeIndex(vertexFormat.mType)][vertexFormat.mNormalized][vertexFormat.mComponents - 1]; -} - -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h deleted file mode 100644 index f26fe43b36..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// formatutils9.h: Queries for GL image formats and their translations to D3D9 -// formats. - -#ifndef LIBGLESV2_RENDERER_FORMATUTILS9_H_ -#define LIBGLESV2_RENDERER_FORMATUTILS9_H_ - -#include "libGLESv2/formatutils.h" - -#include - -namespace rx -{ - -class Renderer9; - -namespace d3d9 -{ - -typedef std::map, ColorCopyFunction> FastCopyFunctionMap; - -struct D3DFormat -{ - D3DFormat(); - - GLuint pixelBytes; - GLuint blockWidth; - GLuint blockHeight; - - GLenum internalFormat; - - MipGenerationFunction mipGenerationFunction; - ColorReadFunction colorReadFunction; - - FastCopyFunctionMap fastCopyFunctions; - ColorCopyFunction getFastCopyFunction(GLenum format, GLenum type) const; -}; -const D3DFormat &GetD3DFormatInfo(D3DFORMAT format); - -struct VertexFormat -{ - VertexFormat(); - - VertexConversionType conversionType; - size_t outputElementSize; - VertexCopyFunction copyFunction; - D3DDECLTYPE nativeFormat; - GLenum componentType; -}; -const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, const gl::VertexFormat &vertexFormat); - -struct TextureFormat -{ - TextureFormat(); - - D3DFORMAT texFormat; - D3DFORMAT renderFormat; - - InitializeTextureDataFunction dataInitializerFunction; - - LoadImageFunction loadFunction; -}; -const TextureFormat &GetTextureFormatInfo(GLenum internalFormat); - -} - -} - -#endif // LIBGLESV2_RENDERER_FORMATUTILS9_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp deleted file mode 100644 index a98b2081f3..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp +++ /dev/null @@ -1,558 +0,0 @@ -// -// Copyright (c) 2002-2014 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. -// - -// renderer9_utils.cpp: Conversion functions and other utility routines -// specific to the D3D9 renderer. - -#include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" -#include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" -#include "libGLESv2/renderer/Workarounds.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" - -#include "common/mathutil.h" -#include "common/debug.h" - -#include "third_party/systeminfo/SystemInfo.h" - -namespace rx -{ - -namespace gl_d3d9 -{ - -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::ColorF 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; - case GL_MIN_EXT: d3dBlendOp = D3DBLENDOP_MIN; break; - case GL_MAX_EXT: d3dBlendOp = D3DBLENDOP_MAX; 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; - } -} - -D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) -{ - return (samples > 1) ? static_cast(samples) : D3DMULTISAMPLE_NONE; -} - -} - -namespace d3d9_gl -{ - -GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) -{ - return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; -} - -bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) -{ - GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).internalFormat; - GLenum convertedFormat = gl::GetInternalFormatInfo(internalFormat).format; - return convertedFormat == format; -} - -static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, IDirect3D9 *d3d9, D3DDEVTYPE deviceType, - UINT adapter, D3DFORMAT adapterFormat) -{ - gl::TextureCaps textureCaps; - - const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat); - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); - } - else - { - textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) && - SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat)); - } - - textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); - textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)) || - SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); - - textureCaps.sampleCounts.insert(1); - for (size_t i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++) - { - D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); - - HRESULT result = d3d9->CheckDeviceMultiSampleType(adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, NULL); - if (SUCCEEDED(result)) - { - textureCaps.sampleCounts.insert(i); - } - } - - return textureCaps; -} - -void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, - gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) -{ - D3DCAPS9 deviceCaps; - if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) - { - // Can't continue with out device caps - return; - } - - D3DDISPLAYMODE currentDisplayMode; - d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); - - GLuint maxSamples = 0; - const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); - for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) - { - gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, - currentDisplayMode.Format); - textureCapsMap->insert(*internalFormat, textureCaps); - - maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); - - if (gl::GetInternalFormatInfo(*internalFormat).compressed) - { - caps->compressedTextureFormats.push_back(*internalFormat); - } - } - - // GL core feature limits - caps->maxElementIndex = static_cast(std::numeric_limits::max()); - - // 3D textures are unimplemented in D3D9 - caps->max3DTextureSize = 1; - - // Only one limit in GL, use the minimum dimension - caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight); - - // D3D treats cube maps as a special case of 2D textures - caps->maxCubeMapTextureSize = caps->max2DTextureSize; - - // Array textures are not available in D3D9 - caps->maxArrayTextureLayers = 1; - - // ES3-only feature - caps->maxLODBias = 0.0f; - - // No specific limits on render target size, maximum 2D texture size is equivalent - caps->maxRenderbufferSize = caps->max2DTextureSize; - - // Draw buffers are not supported in D3D9 - caps->maxDrawBuffers = 1; - caps->maxColorAttachments = 1; - - // No specific limits on viewport size, maximum 2D texture size is equivalent - caps->maxViewportWidth = caps->max2DTextureSize; - caps->maxViewportHeight = caps->maxViewportWidth; - - // Point size is clamped to 1.0f when the shader model is less than 3 - caps->minAliasedPointSize = 1.0f; - caps->maxAliasedPointSize = ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize : 1.0f); - - // Wide lines not supported - caps->minAliasedLineWidth = 1.0f; - caps->maxAliasedLineWidth = 1.0f; - - // Primitive count limits (unused in ES2) - caps->maxElementsIndices = 0; - caps->maxElementsVertices = 0; - - // Program and shader binary formats (no supported shader binary formats) - caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); - - // WaitSync is ES3-only, set to zero - caps->maxServerWaitTimeout = 0; - - // Vertex shader limits - caps->maxVertexAttributes = 16; - - const size_t reservedVertexUniformVectors = 2; // dx_ViewAdjust and dx_DepthRange. - const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; - caps->maxVertexUniformVectors = MAX_VERTEX_CONSTANT_VECTORS_D3D9 - reservedVertexUniformVectors; - caps->maxVertexUniformComponents = caps->maxVertexUniformVectors * 4; - - caps->maxVertexUniformBlocks = 0; - - // SM3 only supports 11 output variables, with a special 12th register for PSIZE. - const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 9; - const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 7; - caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3 - : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4; - - // Only Direct3D 10 ready devices support all the necessary vertex texture formats. - // We test this using D3D9 by checking support for the R16F format. - if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) && - SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format, - D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F))) - { - const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4; - caps->maxVertexTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3; - } - else - { - caps->maxVertexTextureImageUnits = 0; - } - - // Fragment shader limits - const size_t reservedPixelUniformVectors = 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. - - const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224; - const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32; - caps->maxFragmentUniformVectors = ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 - : MAX_PIXEL_CONSTANT_VECTORS_SM2) - reservedPixelUniformVectors; - caps->maxFragmentUniformComponents = caps->maxFragmentUniformVectors * 4; - caps->maxFragmentUniformBlocks = 0; - caps->maxFragmentInputComponents = caps->maxVertexOutputComponents; - caps->maxTextureImageUnits = 16; - caps->minProgramTexelOffset = 0; - caps->maxProgramTexelOffset = 0; - - // Aggregate shader limits (unused in ES2) - caps->maxUniformBufferBindings = 0; - caps->maxUniformBlockSize = 0; - caps->uniformBufferOffsetAlignment = 0; - caps->maxCombinedUniformBlocks = 0; - caps->maxCombinedVertexUniformComponents = 0; - caps->maxCombinedFragmentUniformComponents = 0; - caps->maxVaryingComponents = 0; - - // Aggregate shader limits - caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4; - caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; - - // Transform feedback limits - caps->maxTransformFeedbackInterleavedComponents = 0; - caps->maxTransformFeedbackSeparateAttributes = 0; - caps->maxTransformFeedbackSeparateComponents = 0; - - // GL extension support - extensions->setTextureExtensionSupport(*textureCapsMap); - extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16); - extensions->packedDepthStencil = true; - extensions->getProgramBinary = true; - extensions->rgb8rgba8 = true; - extensions->readFormatBGRA = true; - extensions->pixelBufferObject = false; - extensions->mapBuffer = false; - extensions->mapBufferRange = false; - - // ATI cards on XP have problems with non-power-of-two textures. - D3DADAPTER_IDENTIFIER9 adapterId = { 0 }; - if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) - { - extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && - !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && - !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && - !(!isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); - } - else - { - extensions->textureNPOT = false; - } - - extensions->drawBuffers = false; - extensions->textureStorage = true; - - // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec - extensions->textureFilterAnisotropic = (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2; - extensions->maxTextureAnisotropy = static_cast(deviceCaps.MaxAnisotropy); - - // Check occlusion query support by trying to create one - IDirect3DQuery9 *occlusionQuery = NULL; - extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; - SafeRelease(occlusionQuery); - - // Check event query support by trying to create one - IDirect3DQuery9 *eventQuery = NULL; - extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; - SafeRelease(eventQuery); - - extensions->timerQuery = false; // Unimplemented - extensions->robustness = true; - extensions->blendMinMax = true; - extensions->framebufferBlit = true; - extensions->framebufferMultisample = true; - extensions->maxSamples = maxSamples; - extensions->instancedArrays = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); - extensions->packReverseRowOrder = true; - extensions->standardDerivatives = (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; - extensions->shaderTextureLOD = true; - extensions->fragDepth = true; - extensions->textureUsage = true; - extensions->translatedShaderSource = true; - extensions->colorBufferFloat = false; -} - -} - -namespace d3d9 -{ - -GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height) -{ - const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); - GLuint numBlocksWide = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth; - GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight; - return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight); -} - -void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset) -{ - const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); - - int upsampleCount = 0; - // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. - if (isImage || *requestWidth < static_cast(d3dFormatInfo.blockWidth) || - *requestHeight < static_cast(d3dFormatInfo.blockHeight)) - { - while (*requestWidth % d3dFormatInfo.blockWidth != 0 || *requestHeight % d3dFormatInfo.blockHeight != 0) - { - *requestWidth <<= 1; - *requestHeight <<= 1; - upsampleCount++; - } - } - *levelOffset = upsampleCount; -} - -gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget9 **outRT) -{ - RenderTarget *renderTarget = NULL; - gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); - if (error.isError()) - { - return error; - } - *outRT = RenderTarget9::makeRenderTarget9(renderTarget); - return gl::Error(GL_NO_ERROR); -} - -Workarounds GenerateWorkarounds() -{ - Workarounds workarounds; - workarounds.mrtPerfWorkaround = true; - workarounds.setDataFasterThanImageUpload = false; - return workarounds; -} - -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h deleted file mode 100644 index 9760b9735a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h +++ /dev/null @@ -1,86 +0,0 @@ -// -// Copyright (c) 2002-2014 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. -// - -// renderer9_utils.h: Conversion functions and other utility routines -// specific to the D3D9 renderer - -#ifndef LIBGLESV2_RENDERER_RENDERER9_UTILS_H -#define LIBGLESV2_RENDERER_RENDERER9_UTILS_H - -#include "libGLESv2/angletypes.h" -#include "libGLESv2/Caps.h" -#include "libGLESv2/Error.h" - -namespace gl -{ -class FramebufferAttachment; -} - -namespace rx -{ -class RenderTarget9; -struct Workarounds; - -namespace gl_d3d9 -{ - -D3DCMPFUNC ConvertComparison(GLenum comparison); -D3DCOLOR ConvertColor(gl::ColorF 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); - -D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples); - -} - -namespace d3d9_gl -{ - -GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type); - -bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format); - -void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, - gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions); - -} - -namespace d3d9 -{ - -GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height); - -void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsizei *requestHeight, int *levelOffset); - -inline bool isDeviceLostError(HRESULT errorCode) -{ - switch (errorCode) - { - case D3DERR_DRIVERINTERNALERROR: - case D3DERR_DEVICELOST: - case D3DERR_DEVICEHUNG: - case D3DERR_DEVICEREMOVED: - return true; - default: - return false; - } -} - -gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget9 **outRT); -Workarounds GenerateWorkarounds(); - -} - -} - -#endif // LIBGLESV2_RENDERER_RENDERER9_UTILS_H diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps deleted file mode 100644 index eb43eb3e7a..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps +++ /dev/null @@ -1,33 +0,0 @@ -// -// 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 mult : c0; -uniform float4 add : c1; - -// Passthrough Pixel Shader -// Outputs texture 0 sampled at texcoord 0. -float4 PS_passthrough(float4 texcoord : TEXCOORD0) : COLOR -{ - return tex2D(tex, texcoord.xy); -}; - -// Luminance Conversion Pixel Shader -// Performs a mad operation using the LA data from the texture with mult.xw and add.xw. -// Returns data in the form of llla -float4 PS_luminance(float4 texcoord : TEXCOORD0) : COLOR -{ - return (tex2D(tex, texcoord.xy).xw * mult.xw + add.xw).xxxy; -}; - -// RGB/A Component Mask Pixel Shader -// Performs a mad operation using the texture's RGBA data with mult.xyzw and add.xyzw. -// Returns data in the form of rgba -float4 PS_componentmask(float4 texcoord : TEXCOORD0) : COLOR -{ - return tex2D(tex, texcoord.xy) * mult + add; -}; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs deleted file mode 100644 index 3bd611ba5d..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs +++ /dev/null @@ -1,43 +0,0 @@ -// -// 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 VS_standard(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 VS_flipy(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/renderer/generatemip.h b/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.h deleted file mode 100644 index a57b00d444..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2002-2014 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. -// - -// generatemip.h: Defines the GenerateMip function, templated on the format -// type of the image for which mip levels are being generated. - -#ifndef LIBGLESV2_RENDERER_GENERATEMIP_H_ -#define LIBGLESV2_RENDERER_GENERATEMIP_H_ - -#include "libGLESv2/renderer/imageformats.h" -#include "libGLESv2/angletypes.h" - -namespace rx -{ - -template -inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); - -} - -#include "generatemip.inl" - -#endif // LIBGLESV2_RENDERER_GENERATEMIP_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.inl b/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.inl deleted file mode 100644 index 6788a42f03..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/generatemip.inl +++ /dev/null @@ -1,266 +0,0 @@ -// -// Copyright (c) 2014 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. -// - -// generatemip.inl: Defines the GenerateMip function, templated on the format -// type of the image for which mip levels are being generated. - -#include "common/mathutil.h" - -namespace rx -{ - -namespace priv -{ - -template -static inline T *GetPixel(uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) -{ - return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); -} - -template -static inline const T *GetPixel(const uint8_t *data, size_t x, size_t y, size_t z, size_t rowPitch, size_t depthPitch) -{ - return reinterpret_cast(data + (x * sizeof(T)) + (y * rowPitch) + (z * depthPitch)); -} - -template -static void GenerateMip_Y(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth == 1); - ASSERT(sourceHeight > 1); - ASSERT(sourceDepth == 1); - - for (size_t y = 0; y < destHeight; y++) - { - const T *src0 = GetPixel(sourceData, 0, y * 2, 0, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, 0, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, 0, y, 0, destRowPitch, destDepthPitch); - - T::average(dst, src0, src1); - } -} - -template -static void GenerateMip_X(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth > 1); - ASSERT(sourceHeight == 1); - ASSERT(sourceDepth == 1); - - for (size_t x = 0; x < destWidth; x++) - { - const T *src0 = GetPixel(sourceData, x * 2, 0, 0, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, x * 2 + 1, 0, 0, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, x, 0, 0, destRowPitch, destDepthPitch); - - T::average(dst, src0, src1); - } -} - -template -static void GenerateMip_Z(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth == 1); - ASSERT(sourceHeight == 1); - ASSERT(sourceDepth > 1); - - for (size_t z = 0; z < destDepth; z++) - { - const T *src0 = GetPixel(sourceData, 0, 0, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, 0, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, 0, 0, z, destRowPitch, destDepthPitch); - - T::average(dst, src0, src1); - } -} - -template -static void GenerateMip_XY(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth > 1); - ASSERT(sourceHeight > 1); - ASSERT(sourceDepth == 1); - - for (size_t y = 0; y < destHeight; y++) - { - for (size_t x = 0; x < destWidth; x++) - { - const T *src0 = GetPixel(sourceData, x * 2, y * 2, 0, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, x * 2, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); - const T *src2 = GetPixel(sourceData, x * 2 + 1, y * 2, 0, sourceRowPitch, sourceDepthPitch); - const T *src3 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, 0, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, x, y, 0, destRowPitch, destDepthPitch); - - T tmp0, tmp1; - - T::average(&tmp0, src0, src1); - T::average(&tmp1, src2, src3); - T::average(dst, &tmp0, &tmp1); - } - } -} - -template -static void GenerateMip_YZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth == 1); - ASSERT(sourceHeight > 1); - ASSERT(sourceDepth > 1); - - for (size_t z = 0; z < destDepth; z++) - { - for (size_t y = 0; y < destHeight; y++) - { - const T *src0 = GetPixel(sourceData, 0, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, 0, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src2 = GetPixel(sourceData, 0, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src3 = GetPixel(sourceData, 0, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, 0, y, z, destRowPitch, destDepthPitch); - - T tmp0, tmp1; - - T::average(&tmp0, src0, src1); - T::average(&tmp1, src2, src3); - T::average(dst, &tmp0, &tmp1); - } - } -} - -template -static void GenerateMip_XZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth > 1); - ASSERT(sourceHeight == 1); - ASSERT(sourceDepth > 1); - - for (size_t z = 0; z < destDepth; z++) - { - for (size_t x = 0; x < destWidth; x++) - { - const T *src0 = GetPixel(sourceData, x * 2, 0, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, x * 2, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src2 = GetPixel(sourceData, x * 2 + 1, 0, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src3 = GetPixel(sourceData, x * 2 + 1, 0, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, x, 0, z, destRowPitch, destDepthPitch); - - T tmp0, tmp1; - - T::average(&tmp0, src0, src1); - T::average(&tmp1, src2, src3); - T::average(dst, &tmp0, &tmp1); - } - } -} - -template -static void GenerateMip_XYZ(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - ASSERT(sourceWidth > 1); - ASSERT(sourceHeight > 1); - ASSERT(sourceDepth > 1); - - for (size_t z = 0; z < destDepth; z++) - { - for (size_t y = 0; y < destHeight; y++) - { - for (size_t x = 0; x < destWidth; x++) - { - const T *src0 = GetPixel(sourceData, x * 2, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src1 = GetPixel(sourceData, x * 2, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src2 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src3 = GetPixel(sourceData, x * 2, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src4 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src5 = GetPixel(sourceData, x * 2 + 1, y * 2, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - const T *src6 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2, sourceRowPitch, sourceDepthPitch); - const T *src7 = GetPixel(sourceData, x * 2 + 1, y * 2 + 1, z * 2 + 1, sourceRowPitch, sourceDepthPitch); - T *dst = GetPixel(destData, x, y, z, destRowPitch, destDepthPitch); - - T tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - - T::average(&tmp0, src0, src1); - T::average(&tmp1, src2, src3); - T::average(&tmp2, src4, src5); - T::average(&tmp3, src6, src7); - - T::average(&tmp4, &tmp0, &tmp1); - T::average(&tmp5, &tmp2, &tmp3); - - T::average(dst, &tmp4, &tmp5); - } - } - } -} - - -typedef void (*MipGenerationFunction)(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - size_t destWidth, size_t destHeight, size_t destDepth, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch); - -template -static MipGenerationFunction GetMipGenerationFunction(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth) -{ - uint8_t index = ((sourceWidth > 1) ? 1 : 0) | - ((sourceHeight > 1) ? 2 : 0) | - ((sourceDepth > 1) ? 4 : 0); - - switch (index) - { - case 0: return NULL; - case 1: return GenerateMip_X; // W x 1 x 1 - case 2: return GenerateMip_Y; // 1 x H x 1 - case 3: return GenerateMip_XY; // W x H x 1 - case 4: return GenerateMip_Z; // 1 x 1 x D - case 5: return GenerateMip_XZ; // W x 1 x D - case 6: return GenerateMip_YZ; // 1 x H x D - case 7: return GenerateMip_XYZ; // W x H x D - } - - UNREACHABLE(); - return NULL; -} - -} - -template -inline void GenerateMip(size_t sourceWidth, size_t sourceHeight, size_t sourceDepth, - const uint8_t *sourceData, size_t sourceRowPitch, size_t sourceDepthPitch, - uint8_t *destData, size_t destRowPitch, size_t destDepthPitch) -{ - size_t mipWidth = std::max(1, sourceWidth >> 1); - size_t mipHeight = std::max(1, sourceHeight >> 1); - size_t mipDepth = std::max(1, sourceDepth >> 1); - - priv::MipGenerationFunction generationFunction = priv::GetMipGenerationFunction(sourceWidth, sourceHeight, sourceDepth); - ASSERT(generationFunction != NULL); - - generationFunction(sourceWidth, sourceHeight, sourceDepth, sourceData, sourceRowPitch, sourceDepthPitch, - mipWidth, mipHeight, mipDepth, destData, destRowPitch, destDepthPitch); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/imageformats.h b/src/3rdparty/angle/src/libGLESv2/renderer/imageformats.h deleted file mode 100644 index 2140a9ee72..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/imageformats.h +++ /dev/null @@ -1,2029 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// imageformats.h: Defines image format types with functions for mip generation -// and copying. - -#ifndef LIBGLESV2_RENDERER_IMAGEFORMATS_H_ -#define LIBGLESV2_RENDERER_IMAGEFORMATS_H_ - -#include "common/mathutil.h" - -namespace rx -{ - -// Several structures share functionality for reading, writing or mipmapping but the layout -// must match the texture format which the structure represents. If collapsing or typedefing -// structs in this header, make sure the functionality and memory layout is exactly the same. - -struct L8 -{ - unsigned char L; - - static void readColor(gl::ColorF *dst, const L8 *src) - { - const float lum = gl::normalizedToFloat(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = 1.0f; - } - - static void writeColor(L8 *dst, const gl::ColorF *src) - { - dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); - } - - static void average(L8 *dst, const L8 *src1, const L8 *src2) - { - dst->L = gl::average(src1->L, src2->L); - } -}; - -struct R8 -{ - unsigned char R; - - static void readColor(gl::ColorF *dst, const R8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R8 *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R8 *dst, const R8 *src1, const R8 *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct A8 -{ - unsigned char A; - - static void readColor(gl::ColorF *dst, const A8 *src) - { - dst->red = 0.0f; - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void writeColor(A8 *dst, const gl::ColorF *src) - { - dst->A = gl::floatToNormalized(src->alpha); - } - - static void average(A8 *dst, const A8 *src1, const A8 *src2) - { - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct L8A8 -{ - unsigned char L; - unsigned char A; - - static void readColor(gl::ColorF *dst, const L8A8 *src) - { - const float lum = gl::normalizedToFloat(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void writeColor(L8A8 *dst, const gl::ColorF *src) - { - dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void average(L8A8 *dst, const L8A8 *src1, const L8A8 *src2) - { - *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); - } -}; - -struct A8L8 -{ - unsigned char A; - unsigned char L; - - static void readColor(gl::ColorF *dst, const A8L8 *src) - { - const float lum = gl::normalizedToFloat(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void writeColor(A8L8 *dst, const gl::ColorF *src) - { - dst->L = gl::floatToNormalized((src->red + src->green + src->blue) / 3.0f); - dst->A = gl::floatToNormalized(src->alpha); - } - - 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 R8G8 -{ - unsigned char R; - unsigned char G; - - static void readColor(gl::ColorF *dst, const R8G8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R8G8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R8G8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R8G8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R8G8 *dst, const R8G8 *src1, const R8G8 *src2) - { - *(unsigned short*)dst = (((*(unsigned short*)src1 ^ *(unsigned short*)src2) & 0xFEFE) >> 1) + (*(unsigned short*)src1 & *(unsigned short*)src2); - } -}; - -struct R8G8B8 -{ - unsigned char R; - unsigned char G; - unsigned char B; - - static void readColor(gl::ColorF *dst, const R8G8B8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R8G8B8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->G; - dst->alpha = 1; - } - - static void writeColor(R8G8B8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R8G8B8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R8G8B8 *dst, const R8G8B8 *src1, const R8G8B8 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - } -}; - -struct B8G8R8 -{ - unsigned char B; - unsigned char G; - unsigned char R; - - static void readColor(gl::ColorF *dst, const B8G8R8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const B8G8R8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->G; - dst->alpha = 1; - } - - static void writeColor(B8G8R8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(B8G8R8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(B8G8R8 *dst, const B8G8R8 *src1, const B8G8R8 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - } -}; - -struct R5G6B5 -{ - unsigned short RGB; - - static void readColor(gl::ColorF *dst, const R5G6B5 *src) - { - dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 11>(src->RGB)); - dst->green = gl::normalizedToFloat<6>(gl::getShiftedData<6, 5>(src->RGB)); - dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGB)); - dst->alpha = 1.0f; - } - - static void writeColor(R5G6B5 *dst, const gl::ColorF *src) - { - dst->RGB = gl::shiftData<5, 11>(gl::floatToNormalized<5, unsigned short>(src->red)) | - gl::shiftData<6, 5>(gl::floatToNormalized<6, unsigned short>(src->green)) | - gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); - } - - static void average(R5G6B5 *dst, const R5G6B5 *src1, const R5G6B5 *src2) - { - dst->RGB = gl::shiftData<5, 11>(gl::average(gl::getShiftedData<5, 11>(src1->RGB), gl::getShiftedData<5, 11>(src2->RGB))) | - gl::shiftData<6, 5>(gl::average(gl::getShiftedData<6, 5>(src1->RGB), gl::getShiftedData<6, 5>(src2->RGB))) | - gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGB), gl::getShiftedData<5, 0>(src2->RGB))); - } -}; - -struct A8R8G8B8 -{ - unsigned char A; - unsigned char R; - unsigned char G; - unsigned char B; - - static void readColor(gl::ColorF *dst, const A8R8G8B8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const A8R8G8B8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(A8R8G8B8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(A8R8G8B8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - 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 R8G8B8A8 -{ - unsigned char R; - unsigned char G; - unsigned char B; - unsigned char A; - - static void readColor(gl::ColorF *dst, const R8G8B8A8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const R8G8B8A8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R8G8B8A8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R8G8B8A8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R8G8B8A8 *dst, const R8G8B8A8 *src1, const R8G8B8A8 *src2) - { - *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); - } -}; - -struct B8G8R8A8 -{ - unsigned char B; - unsigned char G; - unsigned char R; - unsigned char A; - - static void readColor(gl::ColorF *dst, const B8G8R8A8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const B8G8R8A8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(B8G8R8A8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(B8G8R8A8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(B8G8R8A8 *dst, const B8G8R8A8 *src1, const B8G8R8A8 *src2) - { - *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); - } -}; - -struct B8G8R8X8 -{ - unsigned char B; - unsigned char G; - unsigned char R; - unsigned char X; - - static void readColor(gl::ColorF *dst, const B8G8R8X8 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const B8G8R8X8 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(B8G8R8X8 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->X = 255; - } - - static void writeColor(B8G8R8X8 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->X = 255; - } - - static void average(B8G8R8X8 *dst, const B8G8R8X8 *src1, const B8G8R8X8 *src2) - { - *(unsigned int*)dst = (((*(unsigned int*)src1 ^ *(unsigned int*)src2) & 0xFEFEFEFE) >> 1) + (*(unsigned int*)src1 & *(unsigned int*)src2); - dst->X = 255; - } -}; - -struct B5G5R5A1 -{ - unsigned short BGRA; - - static void readColor(gl::ColorF *dst, const B5G5R5A1 *src) - { - dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->BGRA)); - dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->BGRA)); - dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->BGRA)); - dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->BGRA)); - } - - static void writeColor(B5G5R5A1 *dst, const gl::ColorF *src) - { - dst->BGRA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) | - gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->red)) | - gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) | - gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->blue)); - } - - static void average(B5G5R5A1 *dst, const B5G5R5A1 *src1, const B5G5R5A1 *src2) - { - dst->BGRA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->BGRA), gl::getShiftedData<1, 15>(src2->BGRA))) | - gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->BGRA), gl::getShiftedData<5, 10>(src2->BGRA))) | - gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->BGRA), gl::getShiftedData<5, 5>(src2->BGRA))) | - gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->BGRA), gl::getShiftedData<5, 0>(src2->BGRA))); - } -}; - -struct R5G5B5A1 -{ - unsigned short RGBA; - - static void readColor(gl::ColorF *dst, const R5G5B5A1 *src) - { - dst->alpha = gl::normalizedToFloat<1>(gl::getShiftedData<1, 15>(src->RGBA)); - dst->blue = gl::normalizedToFloat<5>(gl::getShiftedData<5, 10>(src->RGBA)); - dst->green = gl::normalizedToFloat<5>(gl::getShiftedData<5, 5>(src->RGBA)); - dst->red = gl::normalizedToFloat<5>(gl::getShiftedData<5, 0>(src->RGBA)); - } - - static void writeColor(R5G5B5A1 *dst, const gl::ColorF *src) - { - dst->RGBA = gl::shiftData<1, 15>(gl::floatToNormalized<1, unsigned short>(src->alpha)) | - gl::shiftData<5, 10>(gl::floatToNormalized<5, unsigned short>(src->blue)) | - gl::shiftData<5, 5>(gl::floatToNormalized<5, unsigned short>(src->green)) | - gl::shiftData<5, 0>(gl::floatToNormalized<5, unsigned short>(src->red)); - } - - static void average(R5G5B5A1 *dst, const R5G5B5A1 *src1, const R5G5B5A1 *src2) - { - dst->RGBA = gl::shiftData<1, 15>(gl::average(gl::getShiftedData<1, 15>(src1->RGBA), gl::getShiftedData<1, 15>(src2->RGBA))) | - gl::shiftData<5, 10>(gl::average(gl::getShiftedData<5, 10>(src1->RGBA), gl::getShiftedData<5, 10>(src2->RGBA))) | - gl::shiftData<5, 5>(gl::average(gl::getShiftedData<5, 5>(src1->RGBA), gl::getShiftedData<5, 5>(src2->RGBA))) | - gl::shiftData<5, 0>(gl::average(gl::getShiftedData<5, 0>(src1->RGBA), gl::getShiftedData<5, 0>(src2->RGBA))); - } -}; - -struct R4G4B4A4 -{ - unsigned char R : 4; - unsigned char G : 4; - unsigned char B : 4; - unsigned char A : 4; - - static void readColor(gl::ColorF *dst, const R4G4B4A4 *src) - { - dst->red = gl::normalizedToFloat<4>(src->R); - dst->green = gl::normalizedToFloat<4>(src->G); - dst->blue = gl::normalizedToFloat<4>(src->B); - dst->alpha = gl::normalizedToFloat<4>(src->A); - } - - static void writeColor(R4G4B4A4 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized<4, unsigned char>(src->red); - dst->G = gl::floatToNormalized<4, unsigned char>(src->green); - dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); - dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); - } - - static void average(R4G4B4A4 *dst, const R4G4B4A4 *src1, const R4G4B4A4 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct A4R4G4B4 -{ - unsigned char A : 4; - unsigned char R : 4; - unsigned char G : 4; - unsigned char B : 4; - - static void readColor(gl::ColorF *dst, const A4R4G4B4 *src) - { - dst->red = gl::normalizedToFloat<4>(src->R); - dst->green = gl::normalizedToFloat<4>(src->G); - dst->blue = gl::normalizedToFloat<4>(src->B); - dst->alpha = gl::normalizedToFloat<4>(src->A); - } - - static void writeColor(A4R4G4B4 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized<4, unsigned char>(src->red); - dst->G = gl::floatToNormalized<4, unsigned char>(src->green); - dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); - dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); - } - - static void average(A4R4G4B4 *dst, const A4R4G4B4 *src1, const A4R4G4B4 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct B4G4R4A4 -{ - unsigned char B : 4; - unsigned char G : 4; - unsigned char R : 4; - unsigned char A : 4; - - static void readColor(gl::ColorF *dst, const B4G4R4A4 *src) - { - dst->red = gl::normalizedToFloat<4>(src->R); - dst->green = gl::normalizedToFloat<4>(src->G); - dst->blue = gl::normalizedToFloat<4>(src->B); - dst->alpha = gl::normalizedToFloat<4>(src->A); - } - - static void writeColor(B4G4R4A4 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized<4, unsigned char>(src->red); - dst->G = gl::floatToNormalized<4, unsigned char>(src->green); - dst->B = gl::floatToNormalized<4, unsigned char>(src->blue); - dst->A = gl::floatToNormalized<4, unsigned char>(src->alpha); - } - - static void average(B4G4R4A4 *dst, const B4G4R4A4 *src1, const B4G4R4A4 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R16 -{ - unsigned short R; - - static void readColor(gl::ColorF *dst, const R16 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R16 *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R16 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R16 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R16 *dst, const R16 *src1, const R16 *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R16G16 -{ - unsigned short R; - unsigned short G; - - static void readColor(gl::ColorF *dst, const R16G16 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R16G16 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R16G16 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R16G16 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R16G16 *dst, const R16G16 *src1, const R16G16 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R16G16B16 -{ - unsigned short R; - unsigned short G; - unsigned short B; - - static void readColor(gl::ColorF *dst, const R16G16B16 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R16G16B16 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R16G16B16 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R16G16B16 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R16G16B16 *dst, const R16G16B16 *src1, const R16G16B16 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - } -}; - -struct R16G16B16A16 -{ - unsigned short R; - unsigned short G; - unsigned short B; - unsigned short A; - - static void readColor(gl::ColorF *dst, const R16G16B16A16 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const R16G16B16A16 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R16G16B16A16 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R16G16B16A16 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R16G16B16A16 *dst, const R16G16B16A16 *src1, const R16G16B16A16 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R32 -{ - unsigned int R; - - static void readColor(gl::ColorF *dst, const R32 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R32 *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R32 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R32 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R32 *dst, const R32 *src1, const R32 *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R32G32 -{ - unsigned int R; - unsigned int G; - - static void readColor(gl::ColorF *dst, const R32G32 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R32G32 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R32G32 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R32G32 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R32G32 *dst, const R32G32 *src1, const R32G32 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R32G32B32 -{ - unsigned int R; - unsigned int G; - unsigned int B; - - static void readColor(gl::ColorF *dst, const R32G32B32 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorUI *dst, const R32G32B32 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R32G32B32 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R32G32B32 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R32G32B32 *dst, const R32G32B32 *src1, const R32G32B32 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - } -}; - -struct R32G32B32A32 -{ - unsigned int R; - unsigned int G; - unsigned int B; - unsigned int A; - - static void readColor(gl::ColorF *dst, const R32G32B32A32 *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorUI *dst, const R32G32B32A32 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R32G32B32A32 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R32G32B32A32 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R32G32B32A32 *dst, const R32G32B32A32 *src1, const R32G32B32A32 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R8S -{ - char R; - - static void readColor(gl::ColorF *dst, const R8S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R8S *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R8S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R8S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R8S *dst, const R8S *src1, const R8S *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R8G8S -{ - char R; - char G; - - static void readColor(gl::ColorF *dst, const R8G8S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R8G8S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R8G8S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R8G8S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R8G8S *dst, const R8G8S *src1, const R8G8S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R8G8B8S -{ - char R; - char G; - char B; - - static void readColor(gl::ColorF *dst, const R8G8B8S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R8G8B8S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R8G8B8S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R8G8B8S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R8G8B8S *dst, const R8G8B8S *src1, const R8G8B8S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - } -}; - -struct R8G8B8A8S -{ - char R; - char G; - char B; - char A; - - static void readColor(gl::ColorF *dst, const R8G8B8A8S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorI *dst, const R8G8B8A8S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R8G8B8A8S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R8G8B8A8S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R8G8B8A8S *dst, const R8G8B8A8S *src1, const R8G8B8A8S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R16S -{ - short R; - - static void readColor(gl::ColorF *dst, const R16S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R16S *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R16S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R16S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R16S *dst, const R16S *src1, const R16S *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R16G16S -{ - short R; - short G; - - static void readColor(gl::ColorF *dst, const R16G16S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R16G16S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R16G16S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R16G16S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R16G16S *dst, const R16G16S *src1, const R16G16S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R16G16B16S -{ - short R; - short G; - short B; - - static void readColor(gl::ColorF *dst, const R16G16B16S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R16G16B16S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R16G16B16S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R16G16B16S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R16G16B16S *dst, const R16G16B16S *src1, const R16G16B16S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - } -}; - -struct R16G16B16A16S -{ - short R; - short G; - short B; - short A; - - static void readColor(gl::ColorF *dst, const R16G16B16A16S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorI *dst, const R16G16B16A16S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R16G16B16A16S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R16G16B16A16S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R16G16B16A16S *dst, const R16G16B16A16S *src1, const R16G16B16A16S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R32S -{ - int R; - - static void readColor(gl::ColorF *dst, const R32S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R32S *src) - { - dst->red = src->R; - dst->green = 0; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R32S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - } - - static void writeColor(R32S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - } - - static void average(R32S *dst, const R32S *src1, const R32S *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct R32G32S -{ - int R; - int G; - - static void readColor(gl::ColorF *dst, const R32G32S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R32G32S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0; - dst->alpha = 1; - } - - static void writeColor(R32G32S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - } - - static void writeColor(R32G32S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - } - - static void average(R32G32S *dst, const R32G32S *src1, const R32G32S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R32G32B32S -{ - int R; - int G; - int B; - - static void readColor(gl::ColorF *dst, const R32G32B32S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = 1.0f; - } - - static void readColor(gl::ColorI *dst, const R32G32B32S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1; - } - - static void writeColor(R32G32B32S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - } - - static void writeColor(R32G32B32S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - } - - static void average(R32G32B32S *dst, const R32G32B32S *src1, const R32G32B32S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - } -}; - -struct R32G32B32A32S -{ - int R; - int G; - int B; - int A; - - static void readColor(gl::ColorF *dst, const R32G32B32A32S *src) - { - dst->red = gl::normalizedToFloat(src->R); - dst->green = gl::normalizedToFloat(src->G); - dst->blue = gl::normalizedToFloat(src->B); - dst->alpha = gl::normalizedToFloat(src->A); - } - - static void readColor(gl::ColorI *dst, const R32G32B32A32S *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R32G32B32A32S *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized(src->red); - dst->G = gl::floatToNormalized(src->green); - dst->B = gl::floatToNormalized(src->blue); - dst->A = gl::floatToNormalized(src->alpha); - } - - static void writeColor(R32G32B32A32S *dst, const gl::ColorI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R32G32B32A32S *dst, const R32G32B32A32S *src1, const R32G32B32A32S *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct A16B16G16R16F -{ - unsigned short A; - unsigned short R; - unsigned short G; - unsigned short B; - - static void readColor(gl::ColorF *dst, const A16B16G16R16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = gl::float16ToFloat32(src->G); - dst->blue = gl::float16ToFloat32(src->B); - dst->alpha = gl::float16ToFloat32(src->A); - } - - static void writeColor(A16B16G16R16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - dst->G = gl::float32ToFloat16(src->green); - dst->B = gl::float32ToFloat16(src->blue); - dst->A = gl::float32ToFloat16(src->alpha); - } - - static void average(A16B16G16R16F *dst, const A16B16G16R16F *src1, const A16B16G16R16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - dst->G = gl::averageHalfFloat(src1->G, src2->G); - dst->B = gl::averageHalfFloat(src1->B, src2->B); - dst->A = gl::averageHalfFloat(src1->A, src2->A); - } -}; - -struct R16G16B16A16F -{ - unsigned short R; - unsigned short G; - unsigned short B; - unsigned short A; - - static void readColor(gl::ColorF *dst, const R16G16B16A16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = gl::float16ToFloat32(src->G); - dst->blue = gl::float16ToFloat32(src->B); - dst->alpha = gl::float16ToFloat32(src->A); - } - - static void writeColor(R16G16B16A16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - dst->G = gl::float32ToFloat16(src->green); - dst->B = gl::float32ToFloat16(src->blue); - dst->A = gl::float32ToFloat16(src->alpha); - } - - static void average(R16G16B16A16F *dst, const R16G16B16A16F *src1, const R16G16B16A16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - dst->G = gl::averageHalfFloat(src1->G, src2->G); - dst->B = gl::averageHalfFloat(src1->B, src2->B); - dst->A = gl::averageHalfFloat(src1->A, src2->A); - } -}; - -struct R16F -{ - unsigned short R; - - static void readColor(gl::ColorF *dst, const R16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void writeColor(R16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - } - - static void average(R16F *dst, const R16F *src1, const R16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - } -}; - -struct A16F -{ - unsigned short A; - - static void readColor(gl::ColorF *dst, const A16F *src) - { - dst->red = 0.0f; - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = gl::float16ToFloat32(src->A); - } - - static void writeColor(A16F *dst, const gl::ColorF *src) - { - dst->A = gl::float32ToFloat16(src->alpha); - } - - static void average(A16F *dst, const A16F *src1, const A16F *src2) - { - dst->A = gl::averageHalfFloat(src1->A, src2->A); - } -}; - -struct L16F -{ - unsigned short L; - - static void readColor(gl::ColorF *dst, const L16F *src) - { - float lum = gl::float16ToFloat32(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = 1.0f; - } - - static void writeColor(L16F *dst, const gl::ColorF *src) - { - dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); - } - - static void average(L16F *dst, const L16F *src1, const L16F *src2) - { - dst->L = gl::averageHalfFloat(src1->L, src2->L); - } -}; - -struct L16A16F -{ - unsigned short L; - unsigned short A; - - static void readColor(gl::ColorF *dst, const L16A16F *src) - { - float lum = gl::float16ToFloat32(src->L); - dst->red = lum; - dst->green = lum; - dst->blue = lum; - dst->alpha = gl::float16ToFloat32(src->A); - } - - static void writeColor(L16A16F *dst, const gl::ColorF *src) - { - dst->L = gl::float32ToFloat16((src->red + src->green + src->blue) / 3.0f); - dst->A = gl::float32ToFloat16(src->alpha); - } - - static void average(L16A16F *dst, const L16A16F *src1, const L16A16F *src2) - { - dst->L = gl::averageHalfFloat(src1->L, src2->L); - dst->A = gl::averageHalfFloat(src1->A, src2->A); - } -}; - -struct R16G16F -{ - unsigned short R; - unsigned short G; - - static void readColor(gl::ColorF *dst, const R16G16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = gl::float16ToFloat32(src->G); - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void writeColor(R16G16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - dst->G = gl::float32ToFloat16(src->green); - } - - static void average(R16G16F *dst, const R16G16F *src1, const R16G16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - dst->G = gl::averageHalfFloat(src1->G, src2->G); - } -}; - -struct R16G16B16F -{ - unsigned short R; - unsigned short G; - unsigned short B; - - static void readColor(gl::ColorF *dst, const R16G16B16F *src) - { - dst->red = gl::float16ToFloat32(src->R); - dst->green = gl::float16ToFloat32(src->G); - dst->blue = gl::float16ToFloat32(src->B); - dst->alpha = 1.0f; - } - - static void writeColor(R16G16B16F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat16(src->red); - dst->G = gl::float32ToFloat16(src->green); - dst->B = gl::float32ToFloat16(src->blue); - } - - static void average(R16G16B16F *dst, const R16G16B16F *src1, const R16G16B16F *src2) - { - dst->R = gl::averageHalfFloat(src1->R, src2->R); - dst->G = gl::averageHalfFloat(src1->G, src2->G); - dst->B = gl::averageHalfFloat(src1->B, src2->B); - } -}; - -struct A32B32G32R32F -{ - float A; - float R; - float G; - float B; - - static void readColor(gl::ColorF *dst, const A32B32G32R32F *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(A32B32G32R32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - dst->G = src->green; - dst->B = src->blue; - dst->A = src->alpha; - } - - static void average(A32B32G32R32F *dst, const A32B32G32R32F *src1, const A32B32G32R32F *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R32G32B32A32F -{ - float R; - float G; - float B; - float A; - - static void readColor(gl::ColorF *dst, const R32G32B32A32F *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R32G32B32A32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - dst->G = src->green; - dst->B = src->blue; - dst->A = src->alpha; - } - - static void average(R32G32B32A32F *dst, const R32G32B32A32F *src1, const R32G32B32A32F *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R32F -{ - float R; - - static void readColor(gl::ColorF *dst, const R32F *src) - { - dst->red = src->R; - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void writeColor(R32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - } - - static void average(R32F *dst, const R32F *src1, const R32F *src2) - { - dst->R = gl::average(src1->R, src2->R); - } -}; - -struct A32F -{ - float A; - - static void readColor(gl::ColorF *dst, const A32F *src) - { - dst->red = 0.0f; - dst->green = 0.0f; - dst->blue = 0.0f; - dst->alpha = src->A; - } - - static void writeColor(A32F *dst, const gl::ColorF *src) - { - dst->A = src->alpha; - } - - static void average(A32F *dst, const A32F *src1, const A32F *src2) - { - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct L32F -{ - float L; - - static void readColor(gl::ColorF *dst, const L32F *src) - { - dst->red = src->L; - dst->green = src->L; - dst->blue = src->L; - dst->alpha = 1.0f; - } - - static void writeColor(L32F *dst, const gl::ColorF *src) - { - dst->L = (src->red + src->green + src->blue) / 3.0f; - } - - static void average(L32F *dst, const L32F *src1, const L32F *src2) - { - dst->L = gl::average(src1->L, src2->L); - } -}; - -struct L32A32F -{ - float L; - float A; - - static void readColor(gl::ColorF *dst, const L32A32F *src) - { - dst->red = src->L; - dst->green = src->L; - dst->blue = src->L; - dst->alpha = src->A; - } - - static void writeColor(L32A32F *dst, const gl::ColorF *src) - { - dst->L = (src->red + src->green + src->blue) / 3.0f; - dst->A = src->alpha; - } - - static void average(L32A32F *dst, const L32A32F *src1, const L32A32F *src2) - { - dst->L = gl::average(src1->L, src2->L); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R32G32F -{ - float R; - float G; - - static void readColor(gl::ColorF *dst, const R32G32F *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = 0.0f; - dst->alpha = 1.0f; - } - - static void writeColor(R32G32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - dst->G = src->green; - } - - static void average(R32G32F *dst, const R32G32F *src1, const R32G32F *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - } -}; - -struct R32G32B32F -{ - float R; - float G; - float B; - - static void readColor(gl::ColorF *dst, const R32G32B32F *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = 1.0f; - } - - static void writeColor(R32G32B32F *dst, const gl::ColorF *src) - { - dst->R = src->red; - dst->G = src->green; - dst->B = src->blue; - } - - static void average(R32G32B32F *dst, const R32G32B32F *src1, const R32G32B32F *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - } -}; - -struct R10G10B10A2 -{ - unsigned int R : 10; - unsigned int G : 10; - unsigned int B : 10; - unsigned int A : 2; - - static void readColor(gl::ColorF *dst, const R10G10B10A2 *src) - { - dst->red = gl::normalizedToFloat<10>(src->R); - dst->green = gl::normalizedToFloat<10>(src->G); - dst->blue = gl::normalizedToFloat<10>(src->B); - dst->alpha = gl::normalizedToFloat< 2>(src->A); - } - - static void readColor(gl::ColorUI *dst, const R10G10B10A2 *src) - { - dst->red = src->R; - dst->green = src->G; - dst->blue = src->B; - dst->alpha = src->A; - } - - static void writeColor(R10G10B10A2 *dst, const gl::ColorF *src) - { - dst->R = gl::floatToNormalized<10, unsigned int>(src->red); - dst->G = gl::floatToNormalized<10, unsigned int>(src->green); - dst->B = gl::floatToNormalized<10, unsigned int>(src->blue); - dst->A = gl::floatToNormalized< 2, unsigned int>(src->alpha); - } - - static void writeColor(R10G10B10A2 *dst, const gl::ColorUI *src) - { - dst->R = static_cast(src->red); - dst->G = static_cast(src->green); - dst->B = static_cast(src->blue); - dst->A = static_cast(src->alpha); - } - - static void average(R10G10B10A2 *dst, const R10G10B10A2 *src1, const R10G10B10A2 *src2) - { - dst->R = gl::average(src1->R, src2->R); - dst->G = gl::average(src1->G, src2->G); - dst->B = gl::average(src1->B, src2->B); - dst->A = gl::average(src1->A, src2->A); - } -}; - -struct R9G9B9E5 -{ - unsigned int R : 9; - unsigned int G : 9; - unsigned int B : 9; - unsigned int E : 5; - - static void readColor(gl::ColorF *dst, const R9G9B9E5 *src) - { - gl::convert999E5toRGBFloats(gl::bitCast(*src), &dst->red, &dst->green, &dst->blue); - dst->alpha = 1.0f; - } - - static void writeColor(R9G9B9E5 *dst, const gl::ColorF *src) - { - *reinterpret_cast(dst) = gl::convertRGBFloatsTo999E5(src->red, - src->green, - src->blue); - } - - static void average(R9G9B9E5 *dst, const R9G9B9E5 *src1, const R9G9B9E5 *src2) - { - float r1, g1, b1; - gl::convert999E5toRGBFloats(*reinterpret_cast(src1), &r1, &g1, &b1); - - float r2, g2, b2; - gl::convert999E5toRGBFloats(*reinterpret_cast(src2), &r2, &g2, &b2); - - *reinterpret_cast(dst) = gl::convertRGBFloatsTo999E5(gl::average(r1, r2), - gl::average(g1, g2), - gl::average(b1, b2)); - } -}; - -struct R11G11B10F -{ - unsigned int R : 11; - unsigned int G : 11; - unsigned int B : 10; - - static void readColor(gl::ColorF *dst, const R11G11B10F *src) - { - dst->red = gl::float11ToFloat32(src->R); - dst->green = gl::float11ToFloat32(src->G); - dst->blue = gl::float10ToFloat32(src->B); - dst->alpha = 1.0f; - } - - static void writeColor(R11G11B10F *dst, const gl::ColorF *src) - { - dst->R = gl::float32ToFloat11(src->red); - dst->G = gl::float32ToFloat11(src->green); - dst->B = gl::float32ToFloat10(src->blue); - } - - static void average(R11G11B10F *dst, const R11G11B10F *src1, const R11G11B10F *src2) - { - dst->R = gl::averageFloat11(src1->R, src2->R); - dst->G = gl::averageFloat11(src1->G, src2->G); - dst->B = gl::averageFloat10(src1->B, src2->B); - } -}; - -} - -#endif // LIBGLESV2_RENDERER_IMAGEFORMATS_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.cpp deleted file mode 100644 index 1986191a75..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.cpp +++ /dev/null @@ -1,661 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// loadimage.cpp: Defines image loading functions. - -#include "libGLESv2/renderer/loadimage.h" - -namespace rx -{ - -void LoadA8ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = static_cast(source[x]) << 24; - } - } - } -} - -void LoadA8ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - // Same as loading to RGBA - LoadA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); -} - -void LoadA32FToRGBA32F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = 0.0f; - dest[4 * x + 1] = 0.0f; - dest[4 * x + 2] = 0.0f; - dest[4 * x + 3] = source[x]; - } - } - } -} - -void LoadA16FToRGBA16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t 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 LoadL8ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t 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; - } - } - } -} - -void LoadL8ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - // Same as loading to RGBA - LoadL8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); -} - -void LoadL32FToRGBA32F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t 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 LoadL16FToRGBA16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t 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] = gl::Float16One; - } - } - } -} - -void LoadLA8ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t 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 LoadLA8ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - // Same as loading to RGBA - LoadLA8ToRGBA8(width, height, depth, input, inputRowPitch, inputDepthPitch, output, outputRowPitch, outputDepthPitch); -} - -void LoadLA32FToRGBA32F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - float *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t 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 LoadLA16FToRGBA16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t 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 LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t 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 LoadRG8ToBGRX8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = 0x00; - dest[4 * x + 1] = source[x * 2 + 1]; - dest[4 * x + 2] = source[x * 2 + 0]; - dest[4 * x + 3] = 0xFF; - } - } - } -} - -void LoadR8ToBGRX8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[4 * x + 0] = 0x00; - dest[4 * x + 1] = 0x00; - dest[4 * x + 2] = source[x]; - dest[4 * x + 3] = 0xFF; - } - } - } -} - -void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgb = source[x]; - dest[4 * x + 0] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2); - dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9); - dest[4 * x + 2] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13); - dest[4 * x + 3] = 0xFF; - } - } - } -} - -void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgb = source[x]; - dest[4 * x + 0] = ((rgb & 0xF800) >> 8) | ((rgb & 0xF800) >> 13); - dest[4 * x + 1] = ((rgb & 0x07E0) >> 3) | ((rgb & 0x07E0) >> 9); - dest[4 * x + 2] = ((rgb & 0x001F) << 3) | ((rgb & 0x001F) >> 2); - dest[4 * x + 3] = 0xFF; - } - } - } -} - -void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint32_t rgba = source[x]; - dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); - } - } - } -} - -void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t 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 LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgba = source[x]; - dest[4 * x + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); - dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); - dest[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); - dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); - } - } - } -} - -void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t bgra = source[x]; - dest[4 * x + 0] = ((bgra & 0xF000) >> 8) | ((bgra & 0xF000) >> 12); - dest[4 * x + 1] = ((bgra & 0x0F00) >> 4) | ((bgra & 0x0F00) >> 8); - dest[4 * x + 2] = ((bgra & 0x00F0) << 0) | ((bgra & 0x00F0) >> 4); - dest[4 * x + 3] = ((bgra & 0x000F) << 4) | ((bgra & 0x000F) >> 0); - } - } - } -} - -void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t 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 LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t rgba = source[x]; - dest[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); - dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); - dest[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); - dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; - } - } - } -} - - -void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint16_t bgra = source[x]; - dest[4 * x + 0] = ((bgra & 0xF800) >> 8) | ((bgra & 0xF800) >> 13); - dest[4 * x + 1] = ((bgra & 0x07C0) >> 3) | ((bgra & 0x07C0) >> 8); - dest[4 * x + 2] = ((bgra & 0x003E) << 2) | ((bgra & 0x003E) >> 3); - dest[4 * x + 3] = (bgra & 0x0001) ? 0xFF : 0; - } - } - } -} - -void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint32_t rgba = source[x]; - dest[4 * x + 0] = (rgba & 0x000003FF) >> 2; - dest[4 * x + 1] = (rgba & 0x000FFC00) >> 12; - dest[4 * x + 2] = (rgba & 0x3FF00000) >> 22; - dest[4 * x + 3] = ((rgba & 0xC0000000) >> 30) * 0x55; - } - } - } -} - -void LoadRGB16FToRGB9E5(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = gl::convertRGBFloatsTo999E5(gl::float16ToFloat32(source[x * 3 + 0]), - gl::float16ToFloat32(source[x * 3 + 1]), - gl::float16ToFloat32(source[x * 3 + 2])); - } - } - } -} - -void LoadRGB32FToRGB9E5(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = gl::convertRGBFloatsTo999E5(source[x * 3 + 0], source[x * 3 + 1], source[x * 3 + 2]); - } - } - } -} - -void LoadRGB16FToRG11B10F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint16_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 0])) << 0) | - (gl::float32ToFloat11(gl::float16ToFloat32(source[x * 3 + 1])) << 11) | - (gl::float32ToFloat10(gl::float16ToFloat32(source[x * 3 + 2])) << 22); - } - } - } -} - -void LoadRGB32FToRG11B10F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = (gl::float32ToFloat11(source[x * 3 + 0]) << 0) | - (gl::float32ToFloat11(source[x * 3 + 1]) << 11) | - (gl::float32ToFloat10(source[x * 3 + 2]) << 22); - } - } - } -} - -void LoadG8R24ToR24G8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - uint32_t d = source[x] >> 8; - uint8_t s = source[x] & 0xFF; - dest[x] = d | (s << 24); - } - } - } -} - -void LoadRGB32FToRGBA16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x * 4 + 0] = gl::float32ToFloat16(source[x * 3 + 0]); - dest[x * 4 + 1] = gl::float32ToFloat16(source[x * 3 + 1]); - dest[x * 4 + 2] = gl::float32ToFloat16(source[x * 3 + 2]); - dest[x * 4 + 3] = gl::Float16One; - } - } - } -} - -void LoadR32ToR16(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x] = source[x] >> 16; - } - } - } -} - -void LoadR32ToR24G8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < width; x++) - { - dest[x] = source[x] >> 8; - } - } - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.h b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.h deleted file mode 100644 index bcdff24a66..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.h +++ /dev/null @@ -1,193 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// loadimage.h: Defines image loading functions - -#ifndef LIBGLESV2_RENDERER_LOADIMAGE_H_ -#define LIBGLESV2_RENDERER_LOADIMAGE_H_ - -#include "libGLESv2/angletypes.h" - -#include - -namespace rx -{ - -void LoadA8ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadA8ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadA32FToRGBA32F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadA16FToRGBA16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadL8ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadL8ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadL32FToRGBA32F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadL16FToRGBA16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadLA8ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadLA8ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadLA32FToRGBA32F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadLA16FToRGBA16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB8ToBGRX8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRG8ToBGRX8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadR8ToBGRX8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadR5G6B5ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadR5G6B5ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGBA8ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGBA4ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGBA4ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadBGRA4ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB5A1ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB5A1ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadBGR5A1ToBGRA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB10A2ToRGBA8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB16FToRGB9E5(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB32FToRGB9E5(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB16FToRG11B10F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB32FToRG11B10F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadG8R24ToR24G8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -template -inline void LoadToNative(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -template -inline void LoadToNative3To4(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -template -inline void Load32FTo16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadRGB32FToRGBA16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -template -inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadR32ToR16(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -template -inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -void LoadR32ToR24G8(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch); - -template -inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); - -template -inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch); - -} - -#include "loadimage.inl" - -#endif // LIBGLESV2_RENDERER_LOADIMAGE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.inl b/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.inl deleted file mode 100644 index abd0a3673c..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/loadimage.inl +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright (c) 2014 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 "common/mathutil.h" - -namespace rx -{ - -template -inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) -{ - return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); -} - -template -inline const T *OffsetDataPointer(const uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch) -{ - return reinterpret_cast(data + (y * rowPitch) + (z * depthPitch)); -} - -template -inline void LoadToNative(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - const size_t rowSize = width * sizeof(type) * componentCount; - const size_t layerSize = rowSize * height; - const size_t imageSize = layerSize * depth; - - if (layerSize == inputDepthPitch && layerSize == outputDepthPitch) - { - ASSERT(rowSize == inputRowPitch && rowSize == outputRowPitch); - memcpy(output, input, imageSize); - } - else if (rowSize == inputRowPitch && rowSize == outputRowPitch) - { - for (size_t z = 0; z < depth; z++) - { - const type *source = OffsetDataPointer(input, 0, z, inputRowPitch, inputDepthPitch); - type *dest = OffsetDataPointer(output, 0, z, outputRowPitch, outputDepthPitch); - - memcpy(dest, source, layerSize); - } - } - else - { - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const type *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - type *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - memcpy(dest, source, width * sizeof(type) * componentCount); - } - } - } -} - -template -inline void LoadToNative3To4(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - const type fourthValue = gl::bitCast(fourthComponentBits); - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const type *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - type *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - dest[x * 4 + 0] = source[x * 3 + 0]; - dest[x * 4 + 1] = source[x * 3 + 1]; - dest[x * 4 + 2] = source[x * 3 + 2]; - dest[x * 4 + 3] = fourthValue; - } - } - } -} - -template -inline void Load32FTo16F(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - const size_t elementWidth = componentCount * width; - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const float *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint16_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - for (size_t x = 0; x < elementWidth; x++) - { - dest[x] = gl::float32ToFloat16(source[x]); - } - } - } -} - -template -inline void LoadCompressedToNative(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - const size_t columns = (width + (blockWidth - 1)) / blockWidth; - const size_t rows = (height + (blockHeight - 1)) / blockHeight; - - for (size_t z = 0; z < depth; ++z) - { - for (size_t y = 0; y < rows; ++y) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint8_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - memcpy(dest, source, columns * blockSize); - } - } -} - -template -inline void Initialize4ComponentData(size_t width, size_t height, size_t depth, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ - type writeValues[4] = - { - gl::bitCast(firstBits), - gl::bitCast(secondBits), - gl::bitCast(thirdBits), - gl::bitCast(fourthBits), - }; - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - type *destRow = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - for (size_t x = 0; x < width; x++) - { - type* destPixel = destRow + x * 4; - - // This could potentially be optimized by generating an entire row of initialization - // data and copying row by row instead of pixel by pixel. - memcpy(destPixel, writeValues, sizeof(type) * 4); - } - } - } -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp deleted file mode 100644 index 159b4c7e9f..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (c) 2002-2014 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. -// - -// loadimageSSE2.cpp: Defines image loading functions. 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/renderer/loadimage.h" - -namespace rx -{ - -void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ -#if defined(_M_ARM) - // Ensure that this function is reported as not implemented for ARM builds because - // the instructions below are not present for that architecture. - UNIMPLEMENTED(); - return; -#else - __m128i zeroWide = _mm_setzero_si128(); - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint8_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - size_t x = 0; - - // Make output writes aligned - for (; ((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; - } - } - } -#endif -} - -void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) -{ -#if defined(_M_ARM) - // Ensure that this function is reported as not implemented for ARM builds because - // the instructions below are not present for that architecture. - UNIMPLEMENTED(); - return; -#else - __m128i brMask = _mm_set1_epi32(0x00ff00ff); - - for (size_t z = 0; z < depth; z++) - { - for (size_t y = 0; y < height; y++) - { - const uint32_t *source = OffsetDataPointer(input, y, z, inputRowPitch, inputDepthPitch); - uint32_t *dest = OffsetDataPointer(output, y, z, outputRowPitch, outputDepthPitch); - - size_t x = 0; - - // Make output writes aligned - for (; ((reinterpret_cast(&dest[x]) & 15) != 0) && x < width; x++) - { - uint32_t 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++) - { - uint32_t rgba = source[x]; - dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00); - } - } - } -#endif -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/vertexconversion.h b/src/3rdparty/angle/src/libGLESv2/renderer/vertexconversion.h deleted file mode 100644 index 81ba8a0767..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/renderer/vertexconversion.h +++ /dev/null @@ -1,197 +0,0 @@ -// -// 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 - -namespace rx -{ - -// 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 uint8_t *input, size_t stride, size_t n, uint8_t *output) - { - OutputType *out = reinterpret_cast(output); - - for (std::size_t i = 0; i < n; i++) - { - const InputType *ein = reinterpret_cast(input + 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; - } - } - - private: - 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/3rdparty/angle/src/libGLESv2/validationES.cpp b/src/3rdparty/angle/src/libGLESv2/validationES.cpp deleted file mode 100644 index 265f4b4fba..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/validationES.cpp +++ /dev/null @@ -1,1954 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// validationES.h: Validation functions for generic OpenGL ES entry point parameters - -#include "libGLESv2/validationES.h" -#include "libGLESv2/validationES2.h" -#include "libGLESv2/validationES3.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/main.h" -#include "libGLESv2/Query.h" -#include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/TransformFeedback.h" -#include "libGLESv2/VertexArray.h" -#include "libGLESv2/renderer/BufferImpl.h" - -#include "common/mathutil.h" -#include "common/utilities.h" - -// FIXME(jmadill): remove this when we support buffer data caching -#include "libGLESv2/renderer/d3d/BufferD3D.h" - -namespace gl -{ - -bool ValidCap(const Context *context, GLenum cap) -{ - switch (cap) - { - case GL_CULL_FACE: - case GL_POLYGON_OFFSET_FILL: - case GL_SAMPLE_ALPHA_TO_COVERAGE: - case GL_SAMPLE_COVERAGE: - case GL_SCISSOR_TEST: - case GL_STENCIL_TEST: - case GL_DEPTH_TEST: - case GL_BLEND: - case GL_DITHER: - return true; - case GL_PRIMITIVE_RESTART_FIXED_INDEX: - case GL_RASTERIZER_DISCARD: - return (context->getClientVersion() >= 3); - default: - return false; - } -} - -bool ValidTextureTarget(const Context *context, GLenum target) -{ - switch (target) - { - case GL_TEXTURE_2D: - case GL_TEXTURE_CUBE_MAP: - return true; - - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - return (context->getClientVersion() >= 3); - - default: - return false; - } -} - -// This function differs from ValidTextureTarget in that the target must be -// usable as the destination of a 2D operation-- so a cube face is valid, but -// GL_TEXTURE_CUBE_MAP is not. -// Note: duplicate of IsInternalTextureTarget -bool ValidTexture2DDestinationTarget(const Context *context, GLenum target) -{ - switch (target) - { - case GL_TEXTURE_2D: - 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: - return true; - case GL_TEXTURE_2D_ARRAY: - case GL_TEXTURE_3D: - return (context->getClientVersion() >= 3); - default: - return false; - } -} - -bool ValidFramebufferTarget(GLenum target) -{ - META_ASSERT(GL_DRAW_FRAMEBUFFER_ANGLE == GL_DRAW_FRAMEBUFFER && GL_READ_FRAMEBUFFER_ANGLE == GL_READ_FRAMEBUFFER); - - switch (target) - { - case GL_FRAMEBUFFER: return true; - case GL_READ_FRAMEBUFFER: return true; - case GL_DRAW_FRAMEBUFFER: return true; - default: return false; - } -} - -bool ValidBufferTarget(const Context *context, GLenum target) -{ - switch (target) - { - case GL_ARRAY_BUFFER: - case GL_ELEMENT_ARRAY_BUFFER: - return true; - - case GL_PIXEL_PACK_BUFFER: - case GL_PIXEL_UNPACK_BUFFER: - return context->getExtensions().pixelBufferObject; - - case GL_COPY_READ_BUFFER: - case GL_COPY_WRITE_BUFFER: - case GL_TRANSFORM_FEEDBACK_BUFFER: - case GL_UNIFORM_BUFFER: - return (context->getClientVersion() >= 3); - - default: - return false; - } -} - -bool ValidBufferParameter(const Context *context, GLenum pname) -{ - switch (pname) - { - case GL_BUFFER_USAGE: - case GL_BUFFER_SIZE: - return true; - - // GL_BUFFER_MAP_POINTER is a special case, and may only be - // queried with GetBufferPointerv - case GL_BUFFER_ACCESS_FLAGS: - case GL_BUFFER_MAPPED: - case GL_BUFFER_MAP_OFFSET: - case GL_BUFFER_MAP_LENGTH: - return (context->getClientVersion() >= 3); - - default: - return false; - } -} - -bool ValidMipLevel(const Context *context, GLenum target, GLint level) -{ - size_t maxDimension = 0; - switch (target) - { - case GL_TEXTURE_2D: maxDimension = context->getCaps().max2DTextureSize; break; - case GL_TEXTURE_CUBE_MAP: - 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: maxDimension = context->getCaps().maxCubeMapTextureSize; break; - case GL_TEXTURE_3D: maxDimension = context->getCaps().max3DTextureSize; break; - case GL_TEXTURE_2D_ARRAY: maxDimension = context->getCaps().max2DTextureSize; break; - default: UNREACHABLE(); - } - - return level <= gl::log2(maxDimension); -} - -bool ValidImageSize(const Context *context, GLenum target, GLint level, - GLsizei width, GLsizei height, GLsizei depth) -{ - if (level < 0 || width < 0 || height < 0 || depth < 0) - { - return false; - } - - if (!context->getExtensions().textureNPOT && - (level != 0 && (!gl::isPow2(width) || !gl::isPow2(height) || !gl::isPow2(depth)))) - { - return false; - } - - if (!ValidMipLevel(context, target, level)) - { - return false; - } - - return true; -} - -bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height) -{ - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (!formatInfo.compressed) - { - return false; - } - - if (width < 0 || (static_cast(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) || - height < 0 || (static_cast(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0)) - { - return false; - } - - return true; -} - -bool ValidQueryType(const Context *context, GLenum queryType) -{ - META_ASSERT(GL_ANY_SAMPLES_PASSED == GL_ANY_SAMPLES_PASSED_EXT); - META_ASSERT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE == GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT); - - switch (queryType) - { - case GL_ANY_SAMPLES_PASSED: - case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: - return true; - case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: - return (context->getClientVersion() >= 3); - default: - return false; - } -} - -bool ValidProgram(Context *context, GLuint id) -{ - // ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the - // error INVALID_VALUE if the provided name is not the name of either a shader or program object and - // INVALID_OPERATION if the provided name identifies an object that is not the expected type." - - if (context->getProgram(id) != NULL) - { - return true; - } - else if (context->getShader(id) != NULL) - { - // ID is the wrong type - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - // No shader/program object has this ID - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } -} - -bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment) -{ - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) - { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); - - if (colorAttachment >= context->getCaps().maxColorAttachments) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - else - { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - break; - - case GL_DEPTH_STENCIL_ATTACHMENT: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - } - - return true; -} - -bool ValidateRenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height, - bool angleExtension) -{ - switch (target) - { - case GL_RENDERBUFFER: - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (width < 0 || height < 0 || samples < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); - if (!formatCaps.renderable) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be - // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains - // only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the - // internal format must be sized and not an integer format if samples is greater than zero. - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if (formatInfo.pixelBytes == 0) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (static_cast(std::max(width, height)) > context->getCaps().maxRenderbufferSize) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - // ANGLE_framebuffer_multisample states that the value of samples must be less than or equal - // to MAX_SAMPLES_ANGLE (Context::getMaxSupportedSamples) while the ES3.0 spec (section 4.4.2) - // states that samples must be less than or equal to the maximum samples for the specified - // internal format. - if (angleExtension) - { - ASSERT(context->getExtensions().framebufferMultisample); - if (static_cast(samples) > context->getExtensions().maxSamples) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - // Check if this specific format supports enough samples - if (static_cast(samples) > formatCaps.getMaxSamples()) - { - context->recordError(Error(GL_OUT_OF_MEMORY)); - return false; - } - } - else - { - if (static_cast(samples) > formatCaps.getMaxSamples()) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - - GLuint handle = context->getState().getRenderbufferId(); - if (handle == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum target, GLenum attachment, - GLenum renderbuffertarget, GLuint renderbuffer) -{ - if (!ValidFramebufferTarget(target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); - - if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (!ValidateAttachmentTarget(context, attachment)) - { - return false; - } - - // [OpenGL ES 2.0.25] Section 4.4.3 page 112 - // [OpenGL ES 3.0.2] Section 4.4.2 page 201 - // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of - // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated. - if (renderbuffer != 0) - { - if (!context->getRenderbuffer(renderbuffer)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - return true; -} - -static bool IsPartialBlit(gl::Context *context, gl::FramebufferAttachment *readBuffer, gl::FramebufferAttachment *writeBuffer, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) -{ - if (srcX0 != 0 || srcY0 != 0 || dstX0 != 0 || dstY0 != 0 || - dstX1 != writeBuffer->getWidth() || dstY1 != writeBuffer->getHeight() || - srcX1 != readBuffer->getWidth() || srcY1 != readBuffer->getHeight()) - { - return true; - } - else if (context->getState().isScissorTestEnabled()) - { - const Rectangle &scissor = context->getState().getScissor(); - - return scissor.x > 0 || scissor.y > 0 || - scissor.width < writeBuffer->getWidth() || - scissor.height < writeBuffer->getHeight(); - } - else - { - return false; - } -} - -bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, - GLenum filter, bool fromAngleExtension) -{ - switch (filter) - { - case GL_NEAREST: - break; - case GL_LINEAR: - if (fromAngleExtension) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (mask == 0) - { - // ES3.0 spec, section 4.3.2 specifies that a mask of zero is valid and no - // buffers are copied. - return false; - } - - if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)) - { - ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation."); - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // ES3.0 spec, section 4.3.2 states that linear filtering is only available for the - // color buffer, leaving only nearest being unfiltered from above - if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id()) - { - if (fromAngleExtension) - { - ERR("Blits with the same source and destination framebuffer are not supported by this " - "implementation."); - } - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); - gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); - - if (!readFramebuffer || !drawFramebuffer) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - if (!readFramebuffer->completeness(context->getData())) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - if (!drawFramebuffer->completeness(context->getData())) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - if (drawFramebuffer->getSamples(context->getData()) != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1; - - if (mask & GL_COLOR_BUFFER_BIT) - { - gl::FramebufferAttachment *readColorBuffer = readFramebuffer->getReadColorbuffer(); - gl::FramebufferAttachment *drawColorBuffer = drawFramebuffer->getFirstColorbuffer(); - - if (readColorBuffer && drawColorBuffer) - { - GLenum readInternalFormat = readColorBuffer->getActualFormat(); - const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat); - - for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) - { - if (drawFramebuffer->isEnabledColorAttachment(i)) - { - GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat(); - const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat); - - // The GL ES 3.0.2 spec (pg 193) states that: - // 1) If the read buffer is fixed point format, the draw buffer must be as well - // 2) If the read buffer is an unsigned integer format, the draw buffer must be as well - // 3) If the read buffer is a signed integer format, the draw buffer must be as well - if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) && - !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - } - - if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (fromAngleExtension) - { - const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType(); - if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) - { - if (drawFramebuffer->isEnabledColorAttachment(colorAttachment)) - { - FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(colorAttachment); - ASSERT(attachment); - - if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // Return an error if the destination formats do not match - if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - } - - int readSamples = readFramebuffer->getSamples(context->getData()); - - if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer, - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - } - } - - if (mask & GL_DEPTH_BUFFER_BIT) - { - gl::FramebufferAttachment *readDepthBuffer = readFramebuffer->getDepthbuffer(); - gl::FramebufferAttachment *drawDepthBuffer = drawFramebuffer->getDepthbuffer(); - - if (readDepthBuffer && drawDepthBuffer) - { - if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (readDepthBuffer->getSamples() > 0 && !sameBounds) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (fromAngleExtension) - { - if (IsPartialBlit(context, readDepthBuffer, drawDepthBuffer, - srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) - { - ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); - context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted - return false; - } - - if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - } - } - - if (mask & GL_STENCIL_BUFFER_BIT) - { - gl::FramebufferAttachment *readStencilBuffer = readFramebuffer->getStencilbuffer(); - gl::FramebufferAttachment *drawStencilBuffer = drawFramebuffer->getStencilbuffer(); - - if (readStencilBuffer && drawStencilBuffer) - { - if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (readStencilBuffer->getSamples() > 0 && !sameBounds) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (fromAngleExtension) - { - if (IsPartialBlit(context, readStencilBuffer, drawStencilBuffer, - srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1)) - { - ERR("Only whole-buffer depth and stencil blits are supported by this implementation."); - context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted - return false; - } - - if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - } - } - - return true; -} - -bool ValidateGetVertexAttribParameters(Context *context, GLenum pname) -{ - switch (pname) - { - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: - case GL_VERTEX_ATTRIB_ARRAY_SIZE: - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: - case GL_VERTEX_ATTRIB_ARRAY_TYPE: - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: - case GL_CURRENT_VERTEX_ATTRIB: - return true; - - case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: - // Don't verify ES3 context because GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE uses - // the same constant. - META_ASSERT(GL_VERTEX_ATTRIB_ARRAY_DIVISOR == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE); - return true; - - case GL_VERTEX_ATTRIB_ARRAY_INTEGER: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - return true; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } -} - -bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param) -{ - switch (pname) - { - case GL_TEXTURE_WRAP_R: - case GL_TEXTURE_SWIZZLE_R: - case GL_TEXTURE_SWIZZLE_G: - case GL_TEXTURE_SWIZZLE_B: - case GL_TEXTURE_SWIZZLE_A: - case GL_TEXTURE_BASE_LEVEL: - case GL_TEXTURE_MAX_LEVEL: - case GL_TEXTURE_COMPARE_MODE: - case GL_TEXTURE_COMPARE_FUNC: - case GL_TEXTURE_MIN_LOD: - case GL_TEXTURE_MAX_LOD: - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - - default: break; - } - - switch (pname) - { - case GL_TEXTURE_WRAP_S: - case GL_TEXTURE_WRAP_T: - case GL_TEXTURE_WRAP_R: - switch (param) - { - case GL_REPEAT: - case GL_CLAMP_TO_EDGE: - case GL_MIRRORED_REPEAT: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - case GL_TEXTURE_MIN_FILTER: - switch (param) - { - 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: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - - case GL_TEXTURE_MAG_FILTER: - switch (param) - { - case GL_NEAREST: - case GL_LINEAR: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - - case GL_TEXTURE_USAGE_ANGLE: - switch (param) - { - case GL_NONE: - case GL_FRAMEBUFFER_ATTACHMENT_ANGLE: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - - case GL_TEXTURE_MAX_ANISOTROPY_EXT: - if (!context->getExtensions().textureFilterAnisotropic) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - // we assume the parameter passed to this validation method is truncated, not rounded - if (param < 1) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - return true; - - case GL_TEXTURE_MIN_LOD: - case GL_TEXTURE_MAX_LOD: - // any value is permissible - return true; - - case GL_TEXTURE_COMPARE_MODE: - // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17 - switch (param) - { - case GL_NONE: - case GL_COMPARE_REF_TO_TEXTURE: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - - case GL_TEXTURE_COMPARE_FUNC: - // Acceptable function parameters from GLES 3.0.2 spec, table 3.17 - switch (param) - { - case GL_LEQUAL: - case GL_GEQUAL: - case GL_LESS: - case GL_GREATER: - case GL_EQUAL: - case GL_NOTEQUAL: - case GL_ALWAYS: - case GL_NEVER: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - - case GL_TEXTURE_SWIZZLE_R: - case GL_TEXTURE_SWIZZLE_G: - case GL_TEXTURE_SWIZZLE_B: - case GL_TEXTURE_SWIZZLE_A: - switch (param) - { - case GL_RED: - case GL_GREEN: - case GL_BLUE: - case GL_ALPHA: - case GL_ZERO: - case GL_ONE: - return true; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - - case GL_TEXTURE_BASE_LEVEL: - case GL_TEXTURE_MAX_LEVEL: - if (param < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - return true; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } -} - -bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname) -{ - switch (pname) - { - case GL_TEXTURE_MIN_FILTER: - case GL_TEXTURE_MAG_FILTER: - case GL_TEXTURE_WRAP_S: - case GL_TEXTURE_WRAP_T: - case GL_TEXTURE_WRAP_R: - case GL_TEXTURE_MIN_LOD: - case GL_TEXTURE_MAX_LOD: - case GL_TEXTURE_COMPARE_MODE: - case GL_TEXTURE_COMPARE_FUNC: - return true; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } -} - -bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels) -{ - gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - ASSERT(framebuffer); - - if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - if (context->getState().getReadFramebuffer()->id() != 0 && - framebuffer->getSamples(context->getData()) != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (!framebuffer->getReadColorbuffer()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - GLenum currentInternalFormat, currentFormat, currentType; - GLuint clientVersion = context->getClientVersion(); - - context->getCurrentReadFormatType(¤tInternalFormat, ¤tFormat, ¤tType); - - bool validReadFormat = (clientVersion < 3) ? ValidES2ReadFormatType(context, format, type) : - ValidES3ReadFormatType(context, currentInternalFormat, format, type); - - if (!(currentFormat == format && currentType == type) && !validReadFormat) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - GLenum sizedInternalFormat = GetSizedInternalFormat(format, type); - const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat); - - GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment()); - // sized query sanity check - if (bufSize) - { - int requiredSize = outputPitch * height; - if (requiredSize > *bufSize) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - return true; -} - -bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id) -{ - if (!ValidQueryType(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (id == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // 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. - if (context->getState().isQueryActive()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - Query *queryObject = context->getQuery(id, true, target); - - // check that name was obtained with glGenQueries - if (!queryObject) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // check for type mismatch - if (queryObject->getType() != target) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -bool ValidateEndQuery(gl::Context *context, GLenum target) -{ - if (!ValidQueryType(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - const Query *queryObject = context->getState().getActiveQuery(target); - - if (queryObject == NULL) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniformType, - GLint location, GLsizei count, LinkedUniform **uniformOut) -{ - if (count < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary(); - if (!programBinary) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (location == -1) - { - // Silently ignore the uniform command - return false; - } - - if (!programBinary->isValidUniformLocation(location)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - LinkedUniform *uniform = programBinary->getUniformByLocation(location); - - // attempting to write an array to a non-array uniform is an INVALID_OPERATION - if (uniform->elementCount() == 1 && count > 1) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - *uniformOut = uniform; - return true; -} - -bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, GLsizei count) -{ - // Check for ES3 uniform entry points - if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - LinkedUniform *uniform = NULL; - if (!ValidateUniformCommonBase(context, uniformType, location, count, &uniform)) - { - return false; - } - - GLenum targetBoolType = VariableBoolVectorType(uniformType); - bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT); - if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint location, GLsizei count, - GLboolean transpose) -{ - // Check for ES3 uniform entry points - int rows = VariableRowCount(matrixType); - int cols = VariableColumnCount(matrixType); - if (rows != cols && context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (transpose != GL_FALSE && context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - LinkedUniform *uniform = NULL; - if (!ValidateUniformCommonBase(context, matrixType, location, count, &uniform)) - { - return false; - } - - if (uniform->type != matrixType) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams) -{ - if (!context->getQueryParameterInfo(pname, nativeType, numParams)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15) - { - unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0); - - if (colorAttachment >= context->getCaps().maxDrawBuffers) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - switch (pname) - { - case GL_TEXTURE_BINDING_2D: - case GL_TEXTURE_BINDING_CUBE_MAP: - case GL_TEXTURE_BINDING_3D: - case GL_TEXTURE_BINDING_2D_ARRAY: - if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - - case GL_IMPLEMENTATION_COLOR_READ_TYPE: - case GL_IMPLEMENTATION_COLOR_READ_FORMAT: - { - Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - ASSERT(framebuffer); - if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); - if (!attachment) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - break; - - default: - break; - } - - // pname is valid, but there are no parameters to return - if (numParams == 0) - { - return false; - } - - return true; -} - -bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, - GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, - GLint border, GLenum *textureFormatOut) -{ - - if (!ValidTexture2DDestinationTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (std::numeric_limits::max() - xoffset < width || std::numeric_limits::max() - yoffset < height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (border != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (!ValidMipLevel(context, target, level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::Caps &caps = context->getCaps(); - - gl::Texture *texture = NULL; - GLenum textureInternalFormat = GL_NONE; - GLint textureLevelWidth = 0; - GLint textureLevelHeight = 0; - GLint textureLevelDepth = 0; - GLuint maxDimension = 0; - - switch (target) - { - case GL_TEXTURE_2D: - { - gl::Texture2D *texture2d = context->getTexture2D(); - if (texture2d) - { - textureInternalFormat = texture2d->getInternalFormat(level); - textureLevelWidth = texture2d->getWidth(level); - textureLevelHeight = texture2d->getHeight(level); - textureLevelDepth = 1; - texture = texture2d; - maxDimension = caps.max2DTextureSize; - } - } - 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: - { - gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); - if (textureCube) - { - textureInternalFormat = textureCube->getInternalFormat(target, level); - textureLevelWidth = textureCube->getWidth(target, level); - textureLevelHeight = textureCube->getHeight(target, level); - textureLevelDepth = 1; - texture = textureCube; - maxDimension = caps.maxCubeMapTextureSize; - } - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - gl::Texture2DArray *texture2dArray = context->getTexture2DArray(); - if (texture2dArray) - { - textureInternalFormat = texture2dArray->getInternalFormat(level); - textureLevelWidth = texture2dArray->getWidth(level); - textureLevelHeight = texture2dArray->getHeight(level); - textureLevelDepth = texture2dArray->getLayers(level); - texture = texture2dArray; - maxDimension = caps.max2DTextureSize; - } - } - break; - - case GL_TEXTURE_3D: - { - gl::Texture3D *texture3d = context->getTexture3D(); - if (texture3d) - { - textureInternalFormat = texture3d->getInternalFormat(level); - textureLevelWidth = texture3d->getWidth(level); - textureLevelHeight = texture3d->getHeight(level); - textureLevelDepth = texture3d->getDepth(level); - texture = texture3d; - maxDimension = caps.max3DTextureSize; - } - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (!texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (texture->isImmutable() && !isSubImage) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - - if (formatInfo.depthBits > 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (formatInfo.compressed) - { - if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) || - ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - if (isSubImage) - { - if (xoffset + width > textureLevelWidth || - yoffset + height > textureLevelHeight || - zoffset >= textureLevelDepth) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - else - { - if (IsCubemapTextureTarget(target) && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - int maxLevelDimension = (maxDimension >> level); - if (static_cast(width) > maxLevelDimension || static_cast(height) > maxLevelDimension) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - - *textureFormatOut = textureInternalFormat; - return true; -} - -static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount) -{ - switch (mode) - { - case GL_POINTS: - case GL_LINES: - case GL_LINE_LOOP: - case GL_LINE_STRIP: - case GL_TRIANGLES: - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (count < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - const State &state = context->getState(); - - // Check for mapped buffers - if (state.hasMappedBuffer(GL_ARRAY_BUFFER)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::DepthStencilState &depthStencilState = state.getDepthStencilState(); - if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask || - state.getStencilRef() != state.getStencilBackRef() || - depthStencilState.stencilMask != depthStencilState.stencilBackMask) - { - // Note: these separate values are not supported in WebGL, due to D3D's limitations. - // See Section 6.10 of the WebGL 1.0 spec - ERR("This ANGLE implementation does not support separate front/back stencil " - "writemasks, reference values, or stencil mask values."); - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::Framebuffer *fbo = state.getDrawFramebuffer(); - if (!fbo || fbo->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - if (state.getCurrentProgramId() == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - gl::ProgramBinary *programBinary = state.getCurrentProgramBinary(); - if (!programBinary->validateSamplers(NULL, context->getCaps())) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // Buffer validations - const VertexArray *vao = state.getVertexArray(); - for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) - { - const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex); - bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1); - if (attribActive && attrib.enabled) - { - gl::Buffer *buffer = attrib.buffer.get(); - - if (buffer) - { - GLint64 attribStride = static_cast(ComputeVertexAttributeStride(attrib)); - GLint64 maxVertexElement = 0; - - if (attrib.divisor > 0) - { - maxVertexElement = static_cast(primcount) / static_cast(attrib.divisor); - } - else - { - maxVertexElement = static_cast(maxVertex); - } - - GLint64 attribDataSize = maxVertexElement * attribStride; - - // [OpenGL ES 3.0.2] section 2.9.4 page 40: - // We can return INVALID_OPERATION if our vertex attribute does not have - // enough backing data. - if (attribDataSize > buffer->getSize()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - else if (attrib.pointer == NULL) - { - // This is an application error that would normally result in a crash, - // but we catch it and return an error - context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer.")); - return false; - } - } - } - - // No-op if zero count - return (count > 0); -} - -bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) -{ - if (first < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - const State &state = context->getState(); - gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); - if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() && - curTransformFeedback->getDrawMode() != mode) - { - // It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode - // that does not match the current transform feedback object's draw mode (if transform feedback - // is active), (3.0.2, section 2.14, pg 86) - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (!ValidateDrawBase(context, mode, count, count, primcount)) - { - return false; - } - - return true; -} - -bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) -{ - if (primcount < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (!ValidateDrawArrays(context, mode, first, count, primcount)) - { - return false; - } - - // No-op if zero primitive count - return (primcount > 0); -} - -static bool ValidateDrawInstancedANGLE(Context *context) -{ - // Verify there is at least one active attribute with a divisor of zero - const gl::State& state = context->getState(); - - gl::ProgramBinary *programBinary = state.getCurrentProgramBinary(); - - const VertexArray *vao = state.getVertexArray(); - for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) - { - const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex); - bool active = (programBinary->getSemanticIndex(attributeIndex) != -1); - if (active && attrib.divisor == 0) - { - return true; - } - } - - context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute" - "has a divisor of zero.")); - return false; -} - -bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount) -{ - if (!ValidateDrawInstancedANGLE(context)) - { - return false; - } - - return ValidateDrawArraysInstanced(context, mode, first, count, primcount); -} - -bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut) -{ - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT: - break; - case GL_UNSIGNED_INT: - if (!context->getExtensions().elementIndexUint) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - const State &state = context->getState(); - - gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback(); - if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) - { - // It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced - // while transform feedback is active, (3.0.2, section 2.14, pg 86) - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // Check for mapped buffers - if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::VertexArray *vao = state.getVertexArray(); - const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer(); - if (!indices && !elementArrayBuffer) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (elementArrayBuffer) - { - const gl::Type &typeInfo = gl::GetTypeInfo(type); - - GLint64 offset = reinterpret_cast(indices); - GLint64 byteCount = static_cast(typeInfo.bytes) * static_cast(count)+offset; - - // check for integer overflows - if (static_cast(count) > (std::numeric_limits::max() / typeInfo.bytes) || - byteCount > static_cast(std::numeric_limits::max())) - { - context->recordError(Error(GL_OUT_OF_MEMORY)); - return false; - } - - // Check for reading past the end of the bound buffer object - if (byteCount > elementArrayBuffer->getSize()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - else if (!indices) - { - // Catch this programming error here - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // Use max index to validate if our vertex buffers are large enough for the pull. - // TODO: offer fast path, with disabled index validation. - // TODO: also disable index checking on back-ends that are robust to out-of-range accesses. - if (elementArrayBuffer) - { - uintptr_t offset = reinterpret_cast(indices); - if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL)) - { - // FIXME(jmadill): Use buffer data caching instead of the D3D back-end - rx::BufferD3D *bufferD3D = rx::BufferD3D::makeBufferD3D(elementArrayBuffer->getImplementation()); - const uint8_t *dataPointer = NULL; - Error error = bufferD3D->getData(&dataPointer); - if (error.isError()) - { - context->recordError(error); - return false; - } - - const uint8_t *offsetPointer = dataPointer + offset; - *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count); - } - } - else - { - *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count); - } - - if (!ValidateDrawBase(context, mode, count, static_cast(indexRangeOut->end), primcount)) - { - return false; - } - - return true; -} - -bool ValidateDrawElementsInstanced(Context *context, - GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei primcount, - rx::RangeUI *indexRangeOut) -{ - if (primcount < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut)) - { - return false; - } - - // No-op zero primitive count - return (primcount > 0); -} - -bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut) -{ - if (!ValidateDrawInstancedANGLE(context)) - { - return false; - } - - return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut); -} - -bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level) -{ - if (!ValidFramebufferTarget(target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (!ValidateAttachmentTarget(context, attachment)) - { - return false; - } - - if (texture != 0) - { - gl::Texture *tex = context->getTexture(texture); - - if (tex == NULL) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (level < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - - const gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); - - if (framebufferHandle == 0 || !framebuffer) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) -{ - // Attachments are required to be bound to level 0 in ES2 - if (context->getClientVersion() < 3 && level != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) - { - return false; - } - - if (texture != 0) - { - gl::Texture *tex = context->getTexture(texture); - ASSERT(tex); - - const gl::Caps &caps = context->getCaps(); - - switch (textarget) - { - case GL_TEXTURE_2D: - { - if (level > gl::log2(caps.max2DTextureSize)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - if (tex->getTarget() != GL_TEXTURE_2D) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - gl::Texture2D *tex2d = static_cast(tex); - if (tex2d->isCompressed(level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - 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 (level > gl::log2(caps.maxCubeMapTextureSize)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - if (tex->getTarget() != GL_TEXTURE_CUBE_MAP) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - gl::TextureCubeMap *texcube = static_cast(tex); - if (texcube->isCompressed(textarget, level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - } - - return true; -} - -bool ValidateGetUniformBase(Context *context, GLuint program, GLint location) -{ - if (program == 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (!ValidProgram(context, program)) - { - return false; - } - - gl::Program *programObject = context->getProgram(program); - - if (!programObject || !programObject->isLinked()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - if (!programBinary) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (!programBinary->isValidUniformLocation(location)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params) -{ - return ValidateGetUniformBase(context, program, location); -} - -bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params) -{ - return ValidateGetUniformBase(context, program, location); -} - -static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize) -{ - if (!ValidateGetUniformBase(context, program, location)) - { - return false; - } - - gl::Program *programObject = context->getProgram(program); - ASSERT(programObject); - gl::ProgramBinary *programBinary = programObject->getProgramBinary(); - - // sized queries -- ensure the provided buffer is large enough - LinkedUniform *uniform = programBinary->getUniformByLocation(location); - size_t requiredBytes = VariableExternalSize(uniform->type); - if (static_cast(bufSize) < requiredBytes) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params) -{ - return ValidateSizedGetUniform(context, program, location, bufSize); -} - -bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params) -{ - return ValidateSizedGetUniform(context, program, location, bufSize); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/validationES.h b/src/3rdparty/angle/src/libGLESv2/validationES.h deleted file mode 100644 index 1fdb633cb6..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/validationES.h +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// validationES.h: Validation functions for generic OpenGL ES entry point parameters - -#ifndef LIBGLESV2_VALIDATION_ES_H -#define LIBGLESV2_VALIDATION_ES_H - -#include "common/mathutil.h" - -#include -#include - -namespace gl -{ - -class Context; - -bool ValidCap(const Context *context, GLenum cap); -bool ValidTextureTarget(const Context *context, GLenum target); -bool ValidTexture2DDestinationTarget(const Context *context, GLenum target); -bool ValidFramebufferTarget(GLenum target); -bool ValidBufferTarget(const Context *context, GLenum target); -bool ValidBufferParameter(const Context *context, GLenum pname); -bool ValidMipLevel(const Context *context, GLenum target, GLint level); -bool ValidImageSize(const Context *context, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth); -bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height); -bool ValidQueryType(const Context *context, GLenum queryType); -bool ValidProgram(Context *context, GLuint id); - -bool ValidateAttachmentTarget(Context *context, GLenum attachment); -bool ValidateRenderbufferStorageParameters(Context *context, GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height, - bool angleExtension); -bool ValidateFramebufferRenderbufferParameters(Context *context, GLenum target, GLenum attachment, - GLenum renderbuffertarget, GLuint renderbuffer); - -bool ValidateBlitFramebufferParameters(Context *context, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, - GLenum filter, bool fromAngleExtension); - -bool ValidateGetVertexAttribParameters(Context *context, GLenum pname); - -bool ValidateTexParamParameters(Context *context, GLenum pname, GLint param); - -bool ValidateSamplerObjectParameter(Context *context, GLenum pname); - -bool ValidateReadPixelsParameters(Context *context, GLint x, GLint y, GLsizei width, GLsizei height, - GLenum format, GLenum type, GLsizei *bufSize, GLvoid *pixels); - -bool ValidateBeginQuery(Context *context, GLenum target, GLuint id); -bool ValidateEndQuery(Context *context, GLenum target); - -bool ValidateUniform(Context *context, GLenum uniformType, GLint location, GLsizei count); -bool ValidateUniformMatrix(Context *context, GLenum matrixType, GLint location, GLsizei count, - GLboolean transpose); - -bool ValidateStateQuery(Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams); - -bool ValidateCopyTexImageParametersBase(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, - GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, - GLint border, GLenum *textureInternalFormatOut); - -bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); -bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); -bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount); - -bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut); - -bool ValidateDrawElementsInstanced(Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut); -bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut); - -bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level); -bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level); - -bool ValidateGetUniformBase(Context *context, GLuint program, GLint location); -bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params); -bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params); -bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params); -bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params); - -} - -#endif // LIBGLESV2_VALIDATION_ES_H diff --git a/src/3rdparty/angle/src/libGLESv2/validationES2.cpp b/src/3rdparty/angle/src/libGLESv2/validationES2.cpp deleted file mode 100644 index f950454df0..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/validationES2.cpp +++ /dev/null @@ -1,980 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// validationES2.cpp: Validation functions for OpenGL ES 2.0 entry point parameters - -#include "libGLESv2/validationES2.h" -#include "libGLESv2/validationES.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/main.h" -#include "libGLESv2/FramebufferAttachment.h" - -#include "common/mathutil.h" -#include "common/utilities.h" - -namespace gl -{ - -static bool ValidateSubImageParams2D(Context *context, bool compressed, GLsizei width, GLsizei height, - GLint xoffset, GLint yoffset, GLint level, GLenum format, GLenum type, - gl::Texture2D *texture) -{ - if (!texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (compressed != texture->isCompressed(level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (format != GL_NONE) - { - if (gl::GetFormatTypeInfo(format, type).internalFormat != texture->getInternalFormat(level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - if (compressed) - { - if ((width % 4 != 0 && width != texture->getWidth(level)) || - (height % 4 != 0 && height != texture->getHeight(level))) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - if (xoffset + width > texture->getWidth(level) || - yoffset + height > texture->getHeight(level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - return true; -} - -static bool ValidateSubImageParamsCube(Context *context, bool compressed, GLsizei width, GLsizei height, - GLint xoffset, GLint yoffset, GLenum target, GLint level, GLenum format, GLenum type, - gl::TextureCubeMap *texture) -{ - if (!texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (compressed != texture->isCompressed(target, level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (format != GL_NONE) - { - if (gl::GetFormatTypeInfo(format, type).internalFormat != texture->getInternalFormat(target, level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - if (compressed) - { - if ((width % 4 != 0 && width != texture->getWidth(target, 0)) || - (height % 4 != 0 && height != texture->getHeight(target, 0))) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - if (xoffset + width > texture->getWidth(target, level) || - yoffset + height > texture->getHeight(target, level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - return true; -} - -bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, - GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - if (!ValidTexture2DDestinationTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (!ValidImageSize(context, target, level, width, height, 1)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (level < 0 || xoffset < 0 || - std::numeric_limits::max() - xoffset < width || - std::numeric_limits::max() - yoffset < height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (!isSubImage && !isCompressed && internalformat != format) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::Caps &caps = context->getCaps(); - - gl::Texture *texture = NULL; - bool textureCompressed = false; - GLenum textureInternalFormat = GL_NONE; - GLint textureLevelWidth = 0; - GLint textureLevelHeight = 0; - switch (target) - { - case GL_TEXTURE_2D: - { - if (static_cast(width) > (caps.max2DTextureSize >> level) || - static_cast(height) > (caps.max2DTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::Texture2D *tex2d = context->getTexture2D(); - if (tex2d) - { - textureCompressed = tex2d->isCompressed(level); - textureInternalFormat = tex2d->getInternalFormat(level); - textureLevelWidth = tex2d->getWidth(level); - textureLevelHeight = tex2d->getHeight(level); - texture = tex2d; - } - - if (isSubImage && !ValidateSubImageParams2D(context, isCompressed, width, height, xoffset, yoffset, - level, format, type, tex2d)) - { - return false; - } - - texture = tex2d; - } - 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 (!isSubImage && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || - static_cast(height) > (caps.maxCubeMapTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::TextureCubeMap *texCube = context->getTextureCubeMap(); - if (texCube) - { - textureCompressed = texCube->isCompressed(target, level); - textureInternalFormat = texCube->getInternalFormat(target, level); - textureLevelWidth = texCube->getWidth(target, level); - textureLevelHeight = texCube->getHeight(target, level); - texture = texCube; - } - - if (isSubImage && !ValidateSubImageParamsCube(context, isCompressed, width, height, xoffset, yoffset, - target, level, format, type, texCube)) - { - return false; - } - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (!texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (!isSubImage && texture->isImmutable()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // Verify zero border - if (border != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat; - if (isCompressed) - { - if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - switch (actualInternalFormat) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (!context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (!context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (!context->getExtensions().textureCompressionDXT5) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - } - else - { - // 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: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - // 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: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RED: - case GL_RG: - if (!context->getExtensions().textureRG) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_FLOAT: - case GL_HALF_FLOAT_OES: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - 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: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - 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: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_SRGB_EXT: - case GL_SRGB_ALPHA_EXT: - if (!context->getExtensions().sRGB) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - 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: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_DEPTH_STENCIL_OES: - switch (type) - { - case GL_UNSIGNED_INT_24_8_OES: - break; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - switch (format) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (context->getExtensions().textureCompressionDXT3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (context->getExtensions().textureCompressionDXT5) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_OES: - if (!context->getExtensions().depthTextures) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - if (target != GL_TEXTURE_2D) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - // OES_depth_texture supports loading depth data and multiple levels, - // but ANGLE_depth_texture does not - if (pixels != NULL || level != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - default: - break; - } - - if (type == GL_FLOAT) - { - if (!context->getExtensions().textureFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - } - else if (type == GL_HALF_FLOAT_OES) - { - if (!context->getExtensions().textureHalfFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - } - } - - return true; -} - - - -bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, - GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, - GLint border) -{ - GLenum textureInternalFormat = GL_NONE; - - if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, - xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat)) - { - return false; - } - - gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat(); - GLenum textureFormat = gl::GetInternalFormatInfo(textureInternalFormat).format; - - // [OpenGL ES 2.0.24] table 3.9 - if (isSubImage) - { - switch (textureFormat) - { - case GL_ALPHA: - if (colorbufferFormat != GL_ALPHA8_EXT && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_LUMINANCE: - if (colorbufferFormat != GL_R8_EXT && - colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RED_EXT: - if (colorbufferFormat != GL_R8_EXT && - colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RG_EXT: - if (colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RGB: - if (colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - if (colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - 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: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_STENCIL_OES: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - else - { - switch (internalformat) - { - case GL_ALPHA: - if (colorbufferFormat != GL_ALPHA8_EXT && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_LUMINANCE: - if (colorbufferFormat != GL_R8_EXT && - colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RED_EXT: - if (colorbufferFormat != GL_R8_EXT && - colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RG_EXT: - if (colorbufferFormat != GL_RG8_EXT && - colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_RGB: - if (colorbufferFormat != GL_RGB565 && - colorbufferFormat != GL_RGB8_OES && - colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_LUMINANCE_ALPHA: - case GL_RGBA: - if (colorbufferFormat != GL_RGBA4 && - colorbufferFormat != GL_RGB5_A1 && - colorbufferFormat != GL_BGRA8_EXT && - colorbufferFormat != GL_RGBA8_OES) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (context->getExtensions().textureCompressionDXT3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (context->getExtensions().textureCompressionDXT5) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - 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->getExtensions().depthTextures) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - else - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - } - - // If width or height is zero, it is a no-op. Return false without setting an error. - return (width > 0 && height > 0); -} - -bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, - GLsizei width, GLsizei height) -{ - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (width < 1 || height < 1 || levels < 1) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (target == GL_TEXTURE_CUBE_MAP && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (levels != 1 && levels != gl::log2(std::max(width, height)) + 1) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if (formatInfo.format == GL_NONE || formatInfo.type == GL_NONE) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - const gl::Caps &caps = context->getCaps(); - - switch (target) - { - case GL_TEXTURE_2D: - if (static_cast(width) > caps.max2DTextureSize || - static_cast(height) > caps.max2DTextureSize) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - break; - case GL_TEXTURE_CUBE_MAP: - if (static_cast(width) > caps.maxCubeMapTextureSize || - static_cast(height) > caps.maxCubeMapTextureSize) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (levels != 1 && !context->getExtensions().textureNPOT) - { - if (!gl::isPow2(width) || !gl::isPow2(height)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - switch (internalformat) - { - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - if (!context->getExtensions().textureCompressionDXT1) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: - if (!context->getExtensions().textureCompressionDXT3) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: - if (!context->getExtensions().textureCompressionDXT5) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_RGBA32F_EXT: - case GL_RGB32F_EXT: - case GL_ALPHA32F_EXT: - case GL_LUMINANCE32F_EXT: - case GL_LUMINANCE_ALPHA32F_EXT: - if (!context->getExtensions().textureFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_RGBA16F_EXT: - case GL_RGB16F_EXT: - case GL_ALPHA16F_EXT: - case GL_LUMINANCE16F_EXT: - case GL_LUMINANCE_ALPHA16F_EXT: - if (!context->getExtensions().textureHalfFloat) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_R8_EXT: - case GL_RG8_EXT: - case GL_R16F_EXT: - case GL_RG16F_EXT: - case GL_R32F_EXT: - case GL_RG32F_EXT: - if (!context->getExtensions().textureRG) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT32_OES: - case GL_DEPTH24_STENCIL8_OES: - if (!context->getExtensions().depthTextures) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - if (target != GL_TEXTURE_2D) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - // ANGLE_depth_texture only supports 1-level textures - if (levels != 1) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - break; - default: - break; - } - - gl::Texture *texture = NULL; - switch(target) - { - case GL_TEXTURE_2D: - texture = context->getTexture2D(); - break; - case GL_TEXTURE_CUBE_MAP: - texture = context->getTextureCubeMap(); - break; - default: - UNREACHABLE(); - } - - if (!texture || texture->id() == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (texture->isImmutable()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -// check for combinations of format and type that are valid for ReadPixels -bool ValidES2ReadFormatType(Context *context, 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; - case GL_RG_EXT: - case GL_RED_EXT: - if (!context->getExtensions().textureRG) - { - return false; - } - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - return false; - } - break; - - default: - return false; - } - return true; -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/validationES2.h b/src/3rdparty/angle/src/libGLESv2/validationES2.h deleted file mode 100644 index 53a0b630ea..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/validationES2.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// validationES2.h: Validation functions for OpenGL ES 2.0 entry point parameters - -#ifndef LIBGLESV2_VALIDATION_ES2_H -#define LIBGLESV2_VALIDATION_ES2_H - -#include - -namespace gl -{ - -class Context; - -bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, - GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, const GLvoid *pixels); - -bool ValidateES2CopyTexImageParameters(Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage, - GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, - GLint border); - -bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, - GLsizei width, GLsizei height); - -bool ValidES2ReadFormatType(Context *context, GLenum format, GLenum type); - -} - -#endif // LIBGLESV2_VALIDATION_ES2_H diff --git a/src/3rdparty/angle/src/libGLESv2/validationES3.cpp b/src/3rdparty/angle/src/libGLESv2/validationES3.cpp deleted file mode 100644 index 2d3a039e13..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/validationES3.cpp +++ /dev/null @@ -1,1286 +0,0 @@ -// -// Copyright (c) 2013-2014 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. -// - -// validationES3.cpp: Validation functions for OpenGL ES 3.0 entry point parameters - -#include "libGLESv2/validationES3.h" -#include "libGLESv2/validationES.h" -#include "libGLESv2/Context.h" -#include "libGLESv2/Texture.h" -#include "libGLESv2/Framebuffer.h" -#include "libGLESv2/Renderbuffer.h" -#include "libGLESv2/formatutils.h" -#include "libGLESv2/main.h" -#include "libGLESv2/FramebufferAttachment.h" - -#include "common/mathutil.h" - -namespace gl -{ - -struct ES3FormatCombination -{ - GLenum internalFormat; - GLenum format; - GLenum type; -}; - -bool operator<(const ES3FormatCombination& a, const ES3FormatCombination& b) -{ - return memcmp(&a, &b, sizeof(ES3FormatCombination)) < 0; -} - -typedef std::set ES3FormatCombinationSet; - -static inline void InsertES3FormatCombo(ES3FormatCombinationSet *set, GLenum internalFormat, GLenum format, GLenum type) -{ - ES3FormatCombination info; - info.internalFormat = internalFormat; - info.format = format; - info.type = type; - set->insert(info); -} - -ES3FormatCombinationSet BuildES3FormatSet() -{ - ES3FormatCombinationSet set; - - // Format combinations from ES 3.0.1 spec, table 3.2 - - // | Internal format | Format | Type | - // | | | | - InsertES3FormatCombo(&set, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 ); - InsertES3FormatCombo(&set, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV ); - InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV ); - InsertES3FormatCombo(&set, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 ); - InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RGBA32F, GL_RGBA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGBA16F, GL_RGBA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT ); - InsertES3FormatCombo(&set, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT ); - InsertES3FormatCombo(&set, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV ); - InsertES3FormatCombo(&set, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB8_SNORM, GL_RGB, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 ); - InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV ); - InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV ); - InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RGB32F, GL_RGB, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB16F, GL_RGB, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB9_E5, GL_RGB, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT ); - InsertES3FormatCombo(&set, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_RGB32I, GL_RGB_INTEGER, GL_INT ); - InsertES3FormatCombo(&set, GL_RG8, GL_RG, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RG8_SNORM, GL_RG, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_RG32F, GL_RG, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RG16F, GL_RG, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RG8I, GL_RG_INTEGER, GL_BYTE ); - InsertES3FormatCombo(&set, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_RG16I, GL_RG_INTEGER, GL_SHORT ); - InsertES3FormatCombo(&set, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_RG32I, GL_RG_INTEGER, GL_INT ); - InsertES3FormatCombo(&set, GL_R8, GL_RED, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_R8_SNORM, GL_RED, GL_BYTE ); - InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_R32F, GL_RED, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_R16F, GL_RED, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_R8I, GL_RED_INTEGER, GL_BYTE ); - InsertES3FormatCombo(&set, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_R16I, GL_RED_INTEGER, GL_SHORT ); - InsertES3FormatCombo(&set, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_R32I, GL_RED_INTEGER, GL_INT ); - - // Unsized formats - InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 ); - InsertES3FormatCombo(&set, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 ); - InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_SRGB_ALPHA_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_SRGB_EXT, GL_SRGB_EXT, GL_UNSIGNED_BYTE ); - - // Depth stencil formats - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT ); - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ); - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 ); - InsertES3FormatCombo(&set, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV); - - // From GL_EXT_sRGB - InsertES3FormatCombo(&set, GL_SRGB8_ALPHA8_EXT, GL_SRGB_ALPHA_EXT, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_SRGB8, GL_SRGB_EXT, GL_UNSIGNED_BYTE ); - - // From GL_OES_texture_float - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_FLOAT ); - - // From GL_OES_texture_half_float - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES ); - - // From GL_EXT_texture_format_BGRA8888 - InsertES3FormatCombo(&set, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); - - // From GL_EXT_texture_storage - // | Internal format | Format | Type | - // | | | | - InsertES3FormatCombo(&set, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_ALPHA32F_EXT, GL_ALPHA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE32F_EXT, GL_LUMINANCE, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA32F_EXT, GL_LUMINANCE_ALPHA, GL_FLOAT ); - InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_ALPHA16F_EXT, GL_ALPHA, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE16F_EXT, GL_LUMINANCE, GL_HALF_FLOAT_OES ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT ); - InsertES3FormatCombo(&set, GL_LUMINANCE_ALPHA16F_EXT, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES ); - - // From GL_EXT_texture_storage and GL_EXT_texture_format_BGRA8888 - InsertES3FormatCombo(&set, GL_BGRA8_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT); - InsertES3FormatCombo(&set, GL_BGRA4_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); - InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT); - InsertES3FormatCombo(&set, GL_BGR5_A1_ANGLEX, GL_BGRA_EXT, GL_UNSIGNED_BYTE ); - - // From GL_ANGLE_depth_texture - InsertES3FormatCombo(&set, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT_24_8_OES ); - - // Compressed formats - // From ES 3.0.1 spec, table 3.16 - // | Internal format | Format | Type | - // | | | | - InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_R11_EAC, GL_COMPRESSED_R11_EAC, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_R11_EAC, GL_COMPRESSED_SIGNED_R11_EAC, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_RG11_EAC, GL_COMPRESSED_RG11_EAC, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_SIGNED_RG11_EAC, GL_COMPRESSED_SIGNED_RG11_EAC, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_ETC2, GL_COMPRESSED_RGB8_ETC2, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ETC2, GL_COMPRESSED_SRGB8_ETC2, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_UNSIGNED_BYTE); - - - // From GL_EXT_texture_compression_dxt1 - InsertES3FormatCombo(&set, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE); - InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE); - - // From GL_ANGLE_texture_compression_dxt3 - InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, GL_UNSIGNED_BYTE); - - // From GL_ANGLE_texture_compression_dxt5 - InsertES3FormatCombo(&set, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, GL_UNSIGNED_BYTE); - - return set; -} - -static bool ValidateTexImageFormatCombination(gl::Context *context, GLenum internalFormat, GLenum format, GLenum type) -{ - // Note: dEQP 2013.4 expects an INVALID_VALUE error for TexImage3D with an invalid - // internal format. (dEQP-GLES3.functional.negative_api.texture.teximage3d) - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - // The type and format are valid if any supported internal format has that type and format - bool formatSupported = false; - bool typeSupported = false; - - static const ES3FormatCombinationSet es3FormatSet = BuildES3FormatSet(); - for (ES3FormatCombinationSet::const_iterator i = es3FormatSet.begin(); i != es3FormatSet.end(); i++) - { - if (i->format == format || i->type == type) - { - const gl::InternalFormat &info = gl::GetInternalFormatInfo(i->internalFormat); - bool supported = info.textureSupport(context->getClientVersion(), context->getExtensions()); - if (supported && i->type == type) - { - typeSupported = true; - } - if (supported && i->format == format) - { - formatSupported = true; - } - - // Early-out if both type and format are supported now - if (typeSupported && formatSupported) - { - break; - } - } - } - - if (!typeSupported || !formatSupported) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - // Check if this is a valid format combination to load texture data - ES3FormatCombination searchFormat; - searchFormat.internalFormat = internalFormat; - searchFormat.format = format; - searchFormat.type = type; - - if (es3FormatSet.find(searchFormat) == es3FormatSet.end()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return true; -} - -bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, - GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - if (!ValidTexture2DDestinationTarget(context, target)) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - // Validate image size - if (!ValidImageSize(context, target, level, width, height, depth)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - // Verify zero border - if (border != 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (xoffset < 0 || yoffset < 0 || zoffset < 0 || - std::numeric_limits::max() - xoffset < width || - std::numeric_limits::max() - yoffset < height || - std::numeric_limits::max() - zoffset < depth) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - const gl::Caps &caps = context->getCaps(); - - gl::Texture *texture = NULL; - bool textureCompressed = false; - GLenum textureInternalFormat = GL_NONE; - GLint textureLevelWidth = 0; - GLint textureLevelHeight = 0; - GLint textureLevelDepth = 0; - switch (target) - { - case GL_TEXTURE_2D: - { - if (static_cast(width) > (caps.max2DTextureSize >> level) || - static_cast(height) > (caps.max2DTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::Texture2D *texture2d = context->getTexture2D(); - if (texture2d) - { - textureCompressed = texture2d->isCompressed(level); - textureInternalFormat = texture2d->getInternalFormat(level); - textureLevelWidth = texture2d->getWidth(level); - textureLevelHeight = texture2d->getHeight(level); - textureLevelDepth = 1; - texture = texture2d; - } - } - 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 (!isSubImage && width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (static_cast(width) > (caps.maxCubeMapTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); - if (textureCube) - { - textureCompressed = textureCube->isCompressed(target, level); - textureInternalFormat = textureCube->getInternalFormat(target, level); - textureLevelWidth = textureCube->getWidth(target, level); - textureLevelHeight = textureCube->getHeight(target, level); - textureLevelDepth = 1; - texture = textureCube; - } - } - break; - - case GL_TEXTURE_3D: - { - if (static_cast(width) > (caps.max3DTextureSize >> level) || - static_cast(height) > (caps.max3DTextureSize >> level) || - static_cast(depth) > (caps.max3DTextureSize >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::Texture3D *texture3d = context->getTexture3D(); - if (texture3d) - { - textureCompressed = texture3d->isCompressed(level); - textureInternalFormat = texture3d->getInternalFormat(level); - textureLevelWidth = texture3d->getWidth(level); - textureLevelHeight = texture3d->getHeight(level); - textureLevelDepth = texture3d->getDepth(level); - texture = texture3d; - } - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - if (static_cast(width) > (caps.max2DTextureSize >> level) || - static_cast(height) > (caps.max2DTextureSize >> level) || - static_cast(depth) > (caps.maxArrayTextureLayers >> level)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::Texture2DArray *texture2darray = context->getTexture2DArray(); - if (texture2darray) - { - textureCompressed = texture2darray->isCompressed(level); - textureInternalFormat = texture2darray->getInternalFormat(level); - textureLevelWidth = texture2darray->getWidth(level); - textureLevelHeight = texture2darray->getHeight(level); - textureLevelDepth = texture2darray->getLayers(level); - texture = texture2darray; - } - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (!texture) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (texture->isImmutable() && !isSubImage) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // Validate texture formats - GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat; - const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(actualInternalFormat); - if (isCompressed) - { - if (!ValidCompressedImageSize(context, actualInternalFormat, width, height)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (!actualFormatInfo.compressed) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (target == GL_TEXTURE_3D) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - else - { - if (!ValidateTexImageFormatCombination(context, actualInternalFormat, format, type)) - { - return false; - } - - if (target == GL_TEXTURE_3D && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - // Validate sub image parameters - if (isSubImage) - { - if (isCompressed != textureCompressed) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (isCompressed) - { - if ((width % 4 != 0 && width != textureLevelWidth) || - (height % 4 != 0 && height != textureLevelHeight)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - if (width == 0 || height == 0 || depth == 0) - { - return false; - } - - if (xoffset < 0 || yoffset < 0 || zoffset < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (std::numeric_limits::max() - xoffset < width || - std::numeric_limits::max() - yoffset < height || - std::numeric_limits::max() - zoffset < depth) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (xoffset + width > textureLevelWidth || - yoffset + height > textureLevelHeight || - zoffset + depth > textureLevelDepth) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - - // Check for pixel unpack buffer related API errors - gl::Buffer *pixelUnpackBuffer = context->getState().getTargetBuffer(GL_PIXEL_UNPACK_BUFFER); - if (pixelUnpackBuffer != NULL) - { - // ...the data would be unpacked from the buffer object such that the memory reads required - // would exceed the data store size. - size_t widthSize = static_cast(width); - size_t heightSize = static_cast(height); - size_t depthSize = static_cast(depth); - GLenum sizedFormat = GetSizedInternalFormat(actualInternalFormat, type); - - size_t pixelBytes = static_cast(gl::GetInternalFormatInfo(sizedFormat).pixelBytes); - - if (!rx::IsUnsignedMultiplicationSafe(widthSize, heightSize) || - !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize, depthSize) || - !rx::IsUnsignedMultiplicationSafe(widthSize * heightSize * depthSize, pixelBytes)) - { - // Overflow past the end of the buffer - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat); - size_t copyBytes = formatInfo.computeBlockSize(type, width, height); - size_t offset = reinterpret_cast(pixels); - - if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) || - ((offset + copyBytes) > static_cast(pixelUnpackBuffer->getSize()))) - { - // Overflow past the end of the buffer - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - // ...data is not evenly divisible into the number of bytes needed to store in memory a datum - // indicated by type. - if (!isCompressed) - { - size_t dataBytesPerPixel = static_cast(gl::GetTypeInfo(type).bytes); - - if ((offset % dataBytesPerPixel) != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - // ...the buffer object's data store is currently mapped. - if (pixelUnpackBuffer->isMapped()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - return true; -} - -struct EffectiveInternalFormatInfo -{ - GLenum mEffectiveFormat; - GLenum mDestFormat; - GLuint mMinRedBits; - GLuint mMaxRedBits; - GLuint mMinGreenBits; - GLuint mMaxGreenBits; - GLuint mMinBlueBits; - GLuint mMaxBlueBits; - GLuint mMinAlphaBits; - GLuint mMaxAlphaBits; - - EffectiveInternalFormatInfo(GLenum effectiveFormat, GLenum destFormat, GLuint minRedBits, GLuint maxRedBits, - GLuint minGreenBits, GLuint maxGreenBits, GLuint minBlueBits, GLuint maxBlueBits, - GLuint minAlphaBits, GLuint maxAlphaBits) - : mEffectiveFormat(effectiveFormat), mDestFormat(destFormat), mMinRedBits(minRedBits), - mMaxRedBits(maxRedBits), mMinGreenBits(minGreenBits), mMaxGreenBits(maxGreenBits), - mMinBlueBits(minBlueBits), mMaxBlueBits(maxBlueBits), mMinAlphaBits(minAlphaBits), - mMaxAlphaBits(maxAlphaBits) {}; -}; - -typedef std::vector EffectiveInternalFormatList; - -static EffectiveInternalFormatList BuildSizedEffectiveInternalFormatList() -{ - EffectiveInternalFormatList list; - - // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and - // linear source buffer component sizes. - // | Source channel min/max sizes | - // Effective Internal Format | N/A | R | G | B | A | - list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_NONE, 0, 0, 0, 0, 0, 0, 1, 8)); - list.push_back(EffectiveInternalFormatInfo(GL_R8, GL_NONE, 1, 8, 0, 0, 0, 0, 0, 0)); - list.push_back(EffectiveInternalFormatInfo(GL_RG8, GL_NONE, 1, 8, 1, 8, 0, 0, 0, 0)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_NONE, 1, 5, 1, 6, 1, 5, 0, 0)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_NONE, 6, 8, 7, 8, 6, 8, 0, 0)); - list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_NONE, 1, 4, 1, 4, 1, 4, 1, 4)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_NONE, 5, 5, 5, 5, 5, 5, 1, 1)); - list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_NONE, 5, 8, 5, 8, 5, 8, 2, 8)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB10_A2, GL_NONE, 9, 10, 9, 10, 9, 10, 2, 2)); - - return list; -} - -static EffectiveInternalFormatList BuildUnsizedEffectiveInternalFormatList() -{ - EffectiveInternalFormatList list; - - // OpenGL ES 3.0.3 Specification, Table 3.17, pg 141: Effective internal format coresponding to destination internal format and - // linear source buffer component sizes. - // | Source channel min/max sizes | - // Effective Internal Format | Dest Format | R | G | B | A | - list.push_back(EffectiveInternalFormatInfo(GL_ALPHA8_EXT, GL_ALPHA, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); - list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_EXT, GL_LUMINANCE, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 0, UINT_MAX)); - list.push_back(EffectiveInternalFormatInfo(GL_LUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, 1, 8, 0, UINT_MAX, 0, UINT_MAX, 1, 8)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB565, GL_RGB, 1, 5, 1, 6, 1, 5, 0, UINT_MAX)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB8, GL_RGB, 6, 8, 7, 8, 6, 8, 0, UINT_MAX)); - list.push_back(EffectiveInternalFormatInfo(GL_RGBA4, GL_RGBA, 1, 4, 1, 4, 1, 4, 1, 4)); - list.push_back(EffectiveInternalFormatInfo(GL_RGB5_A1, GL_RGBA, 5, 5, 5, 5, 5, 5, 1, 1)); - list.push_back(EffectiveInternalFormatInfo(GL_RGBA8, GL_RGBA, 5, 8, 5, 8, 5, 8, 5, 8)); - - return list; -} - -static bool GetEffectiveInternalFormat(const InternalFormat &srcFormat, const InternalFormat &destFormat, - GLenum *outEffectiveFormat) -{ - const EffectiveInternalFormatList *list = NULL; - GLenum targetFormat = GL_NONE; - - if (destFormat.pixelBytes > 0) - { - static const EffectiveInternalFormatList sizedList = BuildSizedEffectiveInternalFormatList(); - list = &sizedList; - } - else - { - static const EffectiveInternalFormatList unsizedList = BuildUnsizedEffectiveInternalFormatList(); - list = &unsizedList; - targetFormat = destFormat.format; - } - - for (size_t curFormat = 0; curFormat < list->size(); ++curFormat) - { - const EffectiveInternalFormatInfo& formatInfo = list->at(curFormat); - if ((formatInfo.mDestFormat == targetFormat) && - (formatInfo.mMinRedBits <= srcFormat.redBits && formatInfo.mMaxRedBits >= srcFormat.redBits) && - (formatInfo.mMinGreenBits <= srcFormat.greenBits && formatInfo.mMaxGreenBits >= srcFormat.greenBits) && - (formatInfo.mMinBlueBits <= srcFormat.blueBits && formatInfo.mMaxBlueBits >= srcFormat.blueBits) && - (formatInfo.mMinAlphaBits <= srcFormat.alphaBits && formatInfo.mMaxAlphaBits >= srcFormat.alphaBits)) - { - *outEffectiveFormat = formatInfo.mEffectiveFormat; - return true; - } - } - - return false; -} - -struct CopyConversion -{ - GLenum mTextureFormat; - GLenum mFramebufferFormat; - - CopyConversion(GLenum textureFormat, GLenum framebufferFormat) - : mTextureFormat(textureFormat), mFramebufferFormat(framebufferFormat) { } - - bool operator<(const CopyConversion& other) const - { - return memcmp(this, &other, sizeof(CopyConversion)) < 0; - } -}; - -typedef std::set CopyConversionSet; - -static CopyConversionSet BuildValidES3CopyTexImageCombinations() -{ - CopyConversionSet set; - - // From ES 3.0.1 spec, table 3.15 - set.insert(CopyConversion(GL_ALPHA, GL_RGBA)); - set.insert(CopyConversion(GL_LUMINANCE, GL_RED)); - set.insert(CopyConversion(GL_LUMINANCE, GL_RG)); - set.insert(CopyConversion(GL_LUMINANCE, GL_RGB)); - set.insert(CopyConversion(GL_LUMINANCE, GL_RGBA)); - set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_RGBA)); - set.insert(CopyConversion(GL_RED, GL_RED)); - set.insert(CopyConversion(GL_RED, GL_RG)); - set.insert(CopyConversion(GL_RED, GL_RGB)); - set.insert(CopyConversion(GL_RED, GL_RGBA)); - set.insert(CopyConversion(GL_RG, GL_RG)); - set.insert(CopyConversion(GL_RG, GL_RGB)); - set.insert(CopyConversion(GL_RG, GL_RGBA)); - set.insert(CopyConversion(GL_RGB, GL_RGB)); - set.insert(CopyConversion(GL_RGB, GL_RGBA)); - set.insert(CopyConversion(GL_RGBA, GL_RGBA)); - - // Necessary for ANGLE back-buffers - set.insert(CopyConversion(GL_ALPHA, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_LUMINANCE, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_LUMINANCE_ALPHA, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_RED, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_RG, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_RGB, GL_BGRA_EXT)); - set.insert(CopyConversion(GL_RGBA, GL_BGRA_EXT)); - - set.insert(CopyConversion(GL_RED_INTEGER, GL_RED_INTEGER)); - set.insert(CopyConversion(GL_RED_INTEGER, GL_RG_INTEGER)); - set.insert(CopyConversion(GL_RED_INTEGER, GL_RGB_INTEGER)); - set.insert(CopyConversion(GL_RED_INTEGER, GL_RGBA_INTEGER)); - set.insert(CopyConversion(GL_RG_INTEGER, GL_RG_INTEGER)); - set.insert(CopyConversion(GL_RG_INTEGER, GL_RGB_INTEGER)); - set.insert(CopyConversion(GL_RG_INTEGER, GL_RGBA_INTEGER)); - set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGB_INTEGER)); - set.insert(CopyConversion(GL_RGB_INTEGER, GL_RGBA_INTEGER)); - set.insert(CopyConversion(GL_RGBA_INTEGER, GL_RGBA_INTEGER)); - - return set; -} - -static bool IsValidES3CopyTexImageCombination(GLenum textureInternalFormat, GLenum frameBufferInternalFormat, GLuint readBufferHandle) -{ - const InternalFormat &textureInternalFormatInfo = GetInternalFormatInfo(textureInternalFormat); - const InternalFormat &framebufferInternalFormatInfo = GetInternalFormatInfo(frameBufferInternalFormat); - - static const CopyConversionSet conversionSet = BuildValidES3CopyTexImageCombinations(); - if (conversionSet.find(CopyConversion(textureInternalFormatInfo.format, framebufferInternalFormatInfo.format)) != conversionSet.end()) - { - // Section 3.8.5 of the GLES 3.0.3 spec states that source and destination formats - // must both be signed, unsigned, or fixed point and both source and destinations - // must be either both SRGB or both not SRGB. EXT_color_buffer_float adds allowed - // conversion between fixed and floating point. - - if ((textureInternalFormatInfo.colorEncoding == GL_SRGB) != (framebufferInternalFormatInfo.colorEncoding == GL_SRGB)) - { - return false; - } - - if (((textureInternalFormatInfo.componentType == GL_INT) != (framebufferInternalFormatInfo.componentType == GL_INT )) || - ((textureInternalFormatInfo.componentType == GL_UNSIGNED_INT) != (framebufferInternalFormatInfo.componentType == GL_UNSIGNED_INT))) - { - return false; - } - - if ((textureInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || - textureInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED || - textureInternalFormatInfo.componentType == GL_FLOAT) && - !(framebufferInternalFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || - framebufferInternalFormatInfo.componentType == GL_SIGNED_NORMALIZED || - framebufferInternalFormatInfo.componentType == GL_FLOAT)) - { - return false; - } - - // GLES specification 3.0.3, sec 3.8.5, pg 139-140: - // The effective internal format of the source buffer is determined with the following rules applied in order: - // * If the source buffer is a texture or renderbuffer that was created with a sized internal format then the - // effective internal format is the source buffer's sized internal format. - // * If the source buffer is a texture that was created with an unsized base internal format, then the - // effective internal format is the source image array's effective internal format, as specified by table - // 3.12, which is determined from the and that were used when the source image array was - // specified by TexImage*. - // * Otherwise the effective internal format is determined by the row in table 3.17 or 3.18 where - // Destination Internal Format matches internalformat and where the [source channel sizes] are consistent - // with the values of the source buffer's [channel sizes]. Table 3.17 is used if the - // FRAMEBUFFER_ATTACHMENT_ENCODING is LINEAR and table 3.18 is used if the FRAMEBUFFER_ATTACHMENT_ENCODING - // is SRGB. - const InternalFormat *sourceEffectiveFormat = NULL; - if (readBufferHandle != 0) - { - // Not the default framebuffer, therefore the read buffer must be a user-created texture or renderbuffer - if (framebufferInternalFormatInfo.pixelBytes > 0) - { - sourceEffectiveFormat = &framebufferInternalFormatInfo; - } - else - { - // Renderbuffers cannot be created with an unsized internal format, so this must be an unsized-format - // texture. We can use the same table we use when creating textures to get its effective sized format. - const FormatType &typeInfo = GetFormatTypeInfo(framebufferInternalFormatInfo.format, framebufferInternalFormatInfo.type); - sourceEffectiveFormat = &GetInternalFormatInfo(typeInfo.internalFormat); - } - } - else - { - // The effective internal format must be derived from the source framebuffer's channel sizes. - // This is done in GetEffectiveInternalFormat for linear buffers (table 3.17) - if (framebufferInternalFormatInfo.colorEncoding == GL_LINEAR) - { - GLenum effectiveFormat; - if (GetEffectiveInternalFormat(framebufferInternalFormatInfo, textureInternalFormatInfo, &effectiveFormat)) - { - sourceEffectiveFormat = &GetInternalFormatInfo(effectiveFormat); - } - else - { - return false; - } - } - else if (framebufferInternalFormatInfo.colorEncoding == GL_SRGB) - { - // SRGB buffers can only be copied to sized format destinations according to table 3.18 - if ((textureInternalFormatInfo.pixelBytes > 0) && - (framebufferInternalFormatInfo.redBits >= 1 && framebufferInternalFormatInfo.redBits <= 8) && - (framebufferInternalFormatInfo.greenBits >= 1 && framebufferInternalFormatInfo.greenBits <= 8) && - (framebufferInternalFormatInfo.blueBits >= 1 && framebufferInternalFormatInfo.blueBits <= 8) && - (framebufferInternalFormatInfo.alphaBits >= 1 && framebufferInternalFormatInfo.alphaBits <= 8)) - { - sourceEffectiveFormat = &GetInternalFormatInfo(GL_SRGB8_ALPHA8); - } - else - { - return false; - } - } - else - { - UNREACHABLE(); - return false; - } - } - - if (textureInternalFormatInfo.pixelBytes > 0) - { - // Section 3.8.5 of the GLES 3.0.3 spec, pg 139, requires that, if the destination format is sized, - // component sizes of the source and destination formats must exactly match - if (textureInternalFormatInfo.redBits != sourceEffectiveFormat->redBits || - textureInternalFormatInfo.greenBits != sourceEffectiveFormat->greenBits || - textureInternalFormatInfo.blueBits != sourceEffectiveFormat->blueBits || - textureInternalFormatInfo.alphaBits != sourceEffectiveFormat->alphaBits) - { - return false; - } - } - - - return true; // A conversion function exists, and no rule in the specification has precluded conversion - // between these formats. - } - - return false; -} - -bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, - bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, GLsizei width, GLsizei height, GLint border) -{ - GLenum textureInternalFormat; - if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage, - xoffset, yoffset, zoffset, x, y, width, height, - border, &textureInternalFormat)) - { - return false; - } - - gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - - if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - if (context->getState().getReadFramebuffer()->id() != 0 && - framebuffer->getSamples(context->getData()) != 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - gl::FramebufferAttachment *source = framebuffer->getReadColorbuffer(); - GLenum colorbufferInternalFormat = source->getInternalFormat(); - - if (isSubImage) - { - if (!IsValidES3CopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, - context->getState().getReadFramebuffer()->id())) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - else - { - if (!gl::IsValidES3CopyTexImageCombination(internalformat, colorbufferInternalFormat, - context->getState().getReadFramebuffer()->id())) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - // If width or height is zero, it is a no-op. Return false without setting an error. - return (width > 0 && height > 0); -} - -bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, - GLsizei width, GLsizei height, GLsizei depth) -{ - if (width < 1 || height < 1 || depth < 1 || levels < 1) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (levels > gl::log2(std::max(std::max(width, height), depth)) + 1) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::Caps &caps = context->getCaps(); - - gl::Texture *texture = NULL; - switch (target) - { - case GL_TEXTURE_2D: - { - texture = context->getTexture2D(); - - if (static_cast(width) > caps.max2DTextureSize || - static_cast(height) > caps.max2DTextureSize) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - break; - - case GL_TEXTURE_CUBE_MAP: - { - texture = context->getTextureCubeMap(); - - if (width != height) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (static_cast(width) > caps.maxCubeMapTextureSize) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - break; - - case GL_TEXTURE_3D: - { - texture = context->getTexture3D(); - - if (static_cast(width) > caps.max3DTextureSize || - static_cast(height) > caps.max3DTextureSize || - static_cast(depth) > caps.max3DTextureSize) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - texture = context->getTexture2DArray(); - - if (static_cast(width) > caps.max2DTextureSize || - static_cast(height) > caps.max2DTextureSize || - static_cast(depth) > caps.maxArrayTextureLayers) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - } - break; - - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (!texture || texture->id() == 0) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (texture->isImmutable()) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); - if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions())) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (formatInfo.pixelBytes == 0) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - return true; -} - -bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer) -{ - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - if (layer < 0) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level)) - { - return false; - } - - const gl::Caps &caps = context->getCaps(); - if (texture != 0) - { - gl::Texture *tex = context->getTexture(texture); - ASSERT(tex); - - switch (tex->getTarget()) - { - case GL_TEXTURE_2D_ARRAY: - { - if (level > gl::log2(caps.max2DTextureSize)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (static_cast(layer) >= caps.maxArrayTextureLayers) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::Texture2DArray *texArray = static_cast(tex); - if (texArray->isCompressed(level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - break; - - case GL_TEXTURE_3D: - { - if (level > gl::log2(caps.max3DTextureSize)) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - if (static_cast(layer) >= caps.max3DTextureSize) - { - context->recordError(Error(GL_INVALID_VALUE)); - return false; - } - - gl::Texture3D *tex3d = static_cast(tex); - if (tex3d->isCompressed(level)) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - break; - - default: - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - - return true; -} - -bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type) -{ - const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); - - switch (format) - { - case GL_RGBA: - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - if (internalFormat != GL_RGB10_A2) - { - return false; - } - break; - case GL_FLOAT: - if (internalFormatInfo.componentType != GL_FLOAT) - { - return false; - } - break; - default: - return false; - } - break; - case GL_RGBA_INTEGER: - switch (type) - { - case GL_INT: - if (internalFormatInfo.componentType != GL_INT) - { - return false; - } - break; - case GL_UNSIGNED_INT: - if (internalFormatInfo.componentType != GL_UNSIGNED_INT) - { - return false; - } - 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; - case GL_RG_EXT: - case GL_RED_EXT: - if (!context->getExtensions().textureRG) - { - return false; - } - switch (type) - { - case GL_UNSIGNED_BYTE: - break; - default: - return false; - } - break; - default: - return false; - } - return true; -} - -bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GLsizei numAttachments, - const GLenum* attachments) -{ - bool defaultFramebuffer = false; - - switch (target) - { - case GL_DRAW_FRAMEBUFFER: - case GL_FRAMEBUFFER: - defaultFramebuffer = context->getState().getDrawFramebuffer()->id() == 0; - break; - case GL_READ_FRAMEBUFFER: - defaultFramebuffer = context->getState().getReadFramebuffer()->id() == 0; - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - for (int i = 0; i < numAttachments; ++i) - { - if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15) - { - if (defaultFramebuffer) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - - if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getCaps().maxColorAttachments) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - } - else - { - switch (attachments[i]) - { - case GL_DEPTH_ATTACHMENT: - case GL_STENCIL_ATTACHMENT: - case GL_DEPTH_STENCIL_ATTACHMENT: - if (defaultFramebuffer) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - case GL_COLOR: - case GL_DEPTH: - case GL_STENCIL: - if (!defaultFramebuffer) - { - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - break; - default: - context->recordError(Error(GL_INVALID_ENUM)); - return false; - } - } - } - - return true; -} - -bool ValidateClearBuffer(Context *context) -{ - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer(); - if (!fbo || fbo->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) - { - context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); - return false; - } - - return true; -} - -bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params) -{ - if (context->getClientVersion() < 3) - { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; - } - - return ValidateGetUniformBase(context, program, location); -} - -} diff --git a/src/3rdparty/angle/src/libGLESv2/validationES3.h b/src/3rdparty/angle/src/libGLESv2/validationES3.h deleted file mode 100644 index cafacca601..0000000000 --- a/src/3rdparty/angle/src/libGLESv2/validationES3.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright (c) 2013 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. -// - -// validationES3.h: Validation functions for OpenGL ES 3.0 entry point parameters - -#ifndef LIBGLESV2_VALIDATION_ES3_H -#define LIBGLESV2_VALIDATION_ES3_H - -#include - -namespace gl -{ - -class Context; - -bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage, - GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum format, GLenum type, const GLvoid *pixels); - -bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, - bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, - GLsizei width, GLsizei height, GLint border); - -bool ValidateES3TexStorageParameters(Context *context, GLenum target, GLsizei levels, GLenum internalformat, - GLsizei width, GLsizei height, GLsizei depth); - -bool ValidateFramebufferTextureLayer(Context *context, GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer); - -bool ValidES3ReadFormatType(Context *context, GLenum internalFormat, GLenum format, GLenum type); - -bool ValidateInvalidateFramebufferParameters(Context *context, GLenum target, GLsizei numAttachments, - const GLenum* attachments); - -bool ValidateClearBuffer(Context *context); - -bool ValidateGetUniformuiv(Context *context, GLuint program, GLint location, GLuint* params); - -} - -#endif // LIBGLESV2_VALIDATION_ES3_H diff --git a/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.h b/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.h index 30bb7e3b94..27917e6eec 100644 --- a/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.h +++ b/src/3rdparty/angle/src/third_party/compiler/ArrayBoundsClamper.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef THIRD_PARTY_COMPILER_ARRAY_BOUNDS_CLAMPER_H_ -#define THIRD_PARTY_COMPILER_ARRAY_BOUNDS_CLAMPER_H_ +#ifndef THIRD_PARTY_COMPILER_ARRAYBOUNDSCLAMPER_H_ +#define THIRD_PARTY_COMPILER_ARRAYBOUNDSCLAMPER_H_ #include "compiler/translator/InfoSink.h" #include "compiler/translator/IntermNode.h" @@ -57,4 +57,4 @@ private: bool mArrayBoundsClampDefinitionNeeded; }; -#endif // THIRD_PARTY_COMPILER_ARRAY_BOUNDS_CLAMPER_H_ +#endif // THIRD_PARTY_COMPILER_ARRAYBOUNDSCLAMPER_H_ diff --git a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp index dd86292649..a599c26502 100644 --- a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp +++ b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.cpp @@ -29,6 +29,8 @@ #else // defined(_MSC_VER) +// Ignore GCC force inline warnings +#pragma GCC diagnostic ignored "-Wattributes" #define FORCE_INLINE __attribute__((always_inline)) inline uint32_t rotl32 ( uint32_t x, int8_t r ) diff --git a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h index adb52004e2..bb02cd508f 100644 --- a/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h +++ b/src/3rdparty/angle/src/third_party/murmurhash/MurmurHash3.h @@ -20,4 +20,4 @@ void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out //----------------------------------------------------------------------------- -#endif // _MURMURHASH3_H_ \ No newline at end of file +#endif // _MURMURHASH3_H_ diff --git a/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.h b/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.h index 65005ee9c6..226085fbd3 100644 --- a/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.h +++ b/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.h @@ -23,8 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SystemInfo_h -#define SystemInfo_h +#ifndef THIRD_PARTY_SYSTEMINFO_SYSTEMINFO_H_ +#define THIRD_PARTY_SYSTEMINFO_SYSTEMINFO_H_ namespace rx { @@ -32,4 +32,4 @@ bool isWindowsVistaOrGreater(); } // namespace rx -#endif // SystemInfo_h +#endif // THIRD_PARTY_SYSTEMINFO_SYSTEMINFO_H_ diff --git a/src/3rdparty/angle/src/third_party/trace_event/trace_event.h b/src/3rdparty/angle/src/third_party/trace_event/trace_event.h new file mode 100644 index 0000000000..af59dcfcc3 --- /dev/null +++ b/src/3rdparty/angle/src/third_party/trace_event/trace_event.h @@ -0,0 +1,795 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Trace events are for tracking application performance and resource usage. +// Macros are provided to track: +// Begin and end of function calls +// Counters +// +// Events are issued against categories. Whereas LOG's +// categories are statically defined, TRACE categories are created +// implicitly with a string. For example: +// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") +// +// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope: +// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") +// doSomethingCostly() +// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") +// Note: our tools can't always determine the correct BEGIN/END pairs unless +// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you need them +// to be in separate scopes. +// +// A common use case is to trace entire function scopes. This +// issues a trace BEGIN and END automatically: +// void doSomethingCostly() { +// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); +// ... +// } +// +// Additional parameters can be associated with an event: +// void doSomethingCostly2(int howMuch) { +// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", +// "howMuch", howMuch); +// ... +// } +// +// The trace system will automatically add to this information the +// current process id, thread id, and a timestamp in microseconds. +// +// To trace an asynchronous procedure such as an IPC send/receive, use ASYNC_BEGIN and +// ASYNC_END: +// [single threaded sender code] +// static int send_count = 0; +// ++send_count; +// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count); +// Send(new MyMessage(send_count)); +// [receive code] +// void OnMyMessage(send_count) { +// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count); +// } +// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs. +// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process. Pointers can +// be used for the ID parameter, and they will be mangled internally so that +// the same pointer on two different processes will not match. For example: +// class MyTracedClass { +// public: +// MyTracedClass() { +// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this); +// } +// ~MyTracedClass() { +// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this); +// } +// } +// +// Trace event also supports counters, which is a way to track a quantity +// as it varies over time. Counters are created with the following macro: +// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue); +// +// Counters are process-specific. The macro itself can be issued from any +// thread, however. +// +// Sometimes, you want to track two counters at once. You can do this with two +// counter macros: +// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]); +// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]); +// Or you can do it with a combined macro: +// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter", +// "bytesPinned", g_myCounterValue[0], +// "bytesAllocated", g_myCounterValue[1]); +// This indicates to the tracing UI that these counters should be displayed +// in a single graph, as a summed area chart. +// +// Since counters are in a global namespace, you may want to disembiguate with a +// unique ID, by using the TRACE_COUNTER_ID* variations. +// +// By default, trace collection is compiled in, but turned off at runtime. +// Collecting trace data is the responsibility of the embedding +// application. In Chrome's case, navigating to about:tracing will turn on +// tracing and display data collected across all active processes. +// +// +// Memory scoping note: +// Tracing copies the pointers, not the string content, of the strings passed +// in for category, name, and arg_names. Thus, the following code will +// cause problems: +// char* str = strdup("impprtantName"); +// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD! +// free(str); // Trace system now has dangling pointer +// +// To avoid this issue with the |name| and |arg_name| parameters, use the +// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead. +// Notes: The category must always be in a long-lived char* (i.e. static const). +// The |arg_values|, when used, are always deep copied with the _COPY +// macros. +// +// When are string argument values copied: +// const char* arg_values are only referenced by default: +// TRACE_EVENT1("category", "name", +// "arg1", "literal string is only referenced"); +// Use TRACE_STR_COPY to force copying of a const char*: +// TRACE_EVENT1("category", "name", +// "arg1", TRACE_STR_COPY("string will be copied")); +// std::string arg_values are always copied: +// TRACE_EVENT1("category", "name", +// "arg1", std::string("string will be copied")); +// +// +// Thread Safety: +// A thread safe singleton and mutex are used for thread safety. Category +// enabled flags are used to limit the performance impact when the system +// is not enabled. +// +// TRACE_EVENT macros first cache a pointer to a category. The categories are +// statically allocated and safe at all times, even after exit. Fetching a +// category is protected by the TraceLog::lock_. Multiple threads initializing +// the static variable is safe, as they will be serialized by the lock and +// multiple calls will return the same pointer to the category. +// +// Then the category_enabled flag is checked. This is a unsigned char, and +// not intended to be multithread safe. It optimizes access to addTraceEvent +// which is threadsafe internally via TraceLog::lock_. The enabled flag may +// cause some threads to incorrectly call or skip calling addTraceEvent near +// the time of the system being enabled or disabled. This is acceptable as +// we tolerate some data loss while the system is being enabled/disabled and +// because addTraceEvent is threadsafe internally and checks the enabled state +// again under lock. +// +// Without the use of these static category pointers and enabled flags all +// trace points would carry a significant performance cost of aquiring a lock +// and resolving the category. + +#ifndef COMMON_TRACE_EVENT_H_ +#define COMMON_TRACE_EVENT_H_ + +#include + +#include "common/event_tracer.h" + +// By default, const char* argument values are assumed to have long-lived scope +// and will not be copied. Use this macro to force a const char* to be copied. +#define TRACE_STR_COPY(str) \ + WebCore::TraceEvent::TraceStringWithCopy(str) + +// Records a pair of begin and end events called "name" for the current +// scope, with 0, 1 or 2 associated arguments. If the category is not +// enabled, then this does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_EVENT0(category, name) \ + INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name) +#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val) +#define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) + +// Records a single event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_EVENT_INSTANT0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ + arg2_name, arg2_val) +#define TRACE_EVENT_COPY_INSTANT0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ + arg2_name, arg2_val) + +// Records a single BEGIN event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_EVENT_BEGIN0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ + arg2_name, arg2_val) +#define TRACE_EVENT_COPY_BEGIN0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ + arg2_name, arg2_val) + +// Records a single END event for "name" immediately. If the category +// is not enabled, then this does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_EVENT_END0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ + arg2_name, arg2_val) +#define TRACE_EVENT_COPY_END0(category, name) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) +#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ + category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ + arg2_name, arg2_val) + +// Records the value of a counter called "name" immediately. Value +// must be representable as a 32 bit integer. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_COUNTER1(category, name, value) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ + category, name, TRACE_EVENT_FLAG_NONE, \ + "value", static_cast(value)) +#define TRACE_COPY_COUNTER1(category, name, value) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ + category, name, TRACE_EVENT_FLAG_COPY, \ + "value", static_cast(value)) + +// Records the values of a multi-parted counter called "name" immediately. +// The UI will treat value1 and value2 as parts of a whole, displaying their +// values as a stacked-bar chart. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +#define TRACE_COUNTER2(category, name, value1_name, value1_val, \ + value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ + category, name, TRACE_EVENT_FLAG_NONE, \ + value1_name, static_cast(value1_val), \ + value2_name, static_cast(value2_val)) +#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \ + value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ + category, name, TRACE_EVENT_FLAG_COPY, \ + value1_name, static_cast(value1_val), \ + value2_name, static_cast(value2_val)) + +// Records the value of a counter called "name" immediately. Value +// must be representable as a 32 bit integer. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to disambiguate counters with the same name. It must either +// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits +// will be xored with a hash of the process ID so that the same pointer on +// two different processes will not collide. +#define TRACE_COUNTER_ID1(category, name, id, value) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + "value", static_cast(value)) +#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + "value", static_cast(value)) + +// Records the values of a multi-parted counter called "name" immediately. +// The UI will treat value1 and value2 as parts of a whole, displaying their +// values as a stacked-bar chart. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to disambiguate counters with the same name. It must either +// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits +// will be xored with a hash of the process ID so that the same pointer on +// two different processes will not collide. +#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \ + value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + value1_name, static_cast(value1_val), \ + value2_name, static_cast(value2_val)) +#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \ + value2_name, value2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + value1_name, static_cast(value1_val), \ + value2_name, static_cast(value2_val)) + +// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 +// associated arguments. If the category is not enabled, then this +// does nothing. +// - category and name strings must have application lifetime (statics or +// literals). They may not include " chars. +// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC +// events are considered to match if their category, name and id values all +// match. |id| must either be a pointer or an integer value up to 64 bits. If +// it's a pointer, the bits will be xored with a hash of the process ID so +// that the same pointer on two different processes will not collide. +// An asynchronous operation can consist of multiple phases. The first phase is +// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the +// ASYNC_STEP_BEGIN macros. When the operation completes, call ASYNC_END. +// An async operation can span threads and processes, but all events in that +// operation must use the same |name| and |id|. Each event can have its own +// args. +#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + arg1_name, arg1_val, arg2_name, arg2_val) +#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val, arg2_name, arg2_val) + +// Records a single ASYNC_STEP event for |step| immediately. If the category +// is not enabled, then this does nothing. The |name| and |id| must match the +// ASYNC_BEGIN event above. The |step| param identifies this step within the +// async event. This should be called at the beginning of the next phase of an +// asynchronous operation. +#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ + category, name, id, TRACE_EVENT_FLAG_NONE, "step", step) +#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \ + arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ + category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ + category, name, id, TRACE_EVENT_FLAG_COPY, "step", step) +#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \ + arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ + category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \ + arg1_name, arg1_val) + +// Records a single ASYNC_END event for "name" immediately. If the category +// is not enabled, then this does nothing. +#define TRACE_EVENT_ASYNC_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE) +#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) +#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_NONE, \ + arg1_name, arg1_val, arg2_name, arg2_val) +#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY) +#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val) +#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ + arg2_name, arg2_val) \ + INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ + category, name, id, TRACE_EVENT_FLAG_COPY, \ + arg1_name, arg1_val, arg2_name, arg2_val) + +// Creates a scope of a sampling state with the given category and name (both must +// be constant strings). These states are intended for a sampling profiler. +// Implementation note: we store category and name together because we don't +// want the inconsistency/expense of storing two pointers. +// |thread_bucket| is [0..2] and is used to statically isolate samples in one +// thread from others. +// +// { // The sampling state is set within this scope. +// TRACE_EVENT_SAMPLING_STATE_SCOPE_FOR_BUCKET(0, "category", "name"); +// ...; +// } +#define TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(bucket_number, category, name) \ + TraceEvent::SamplingStateScope traceEventSamplingScope(category "\0" name); + +// Returns a current sampling state of the given bucket. +// The format of the returned string is "category\0name". +#define TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(bucket_number) \ + TraceEvent::SamplingStateScope::current() + +// Sets a current sampling state of the given bucket. +// |category| and |name| have to be constant strings. +#define TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(bucket_number, category, name) \ + TraceEvent::SamplingStateScope::set(category "\0" name) + +// Sets a current sampling state of the given bucket. +// |categoryAndName| doesn't need to be a constant string. +// The format of the string is "category\0name". +#define TRACE_EVENT_SET_NONCONST_SAMPLING_STATE_FOR_BUCKET(bucket_number, categoryAndName) \ + TraceEvent::SamplingStateScope::set(categoryAndName) + +// Syntactic sugars for the sampling tracing in the main thread. +#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \ + TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name) +#define TRACE_EVENT_GET_SAMPLING_STATE() \ + TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(0) +#define TRACE_EVENT_SET_SAMPLING_STATE(category, name) \ + TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(0, category, name) +#define TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(categoryAndName) \ + TRACE_EVENT_SET_NONCONST_SAMPLING_STATE_FOR_BUCKET(0, categoryAndName) + +//////////////////////////////////////////////////////////////////////////////// +// Implementation specific tracing API definitions. + +// Get a pointer to the enabled state of the given trace category. Only +// long-lived literal strings should be given as the category name. The returned +// pointer can be held permanently in a local static for example. If the +// unsigned char is non-zero, tracing is enabled. If tracing is enabled, +// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled +// between the load of the tracing state and the call to +// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out +// for best performance when tracing is disabled. +// const unsigned char* +// TRACE_EVENT_API_GET_CATEGORY_ENABLED(const char* category_name) +#define TRACE_EVENT_API_GET_CATEGORY_ENABLED \ + gl::TraceGetTraceCategoryEnabledFlag + +// Add a trace event to the platform tracing system. +// void TRACE_EVENT_API_ADD_TRACE_EVENT( +// char phase, +// const unsigned char* category_enabled, +// const char* name, +// unsigned long long id, +// int num_args, +// const char** arg_names, +// const unsigned char* arg_types, +// const unsigned long long* arg_values, +// unsigned char flags) +#define TRACE_EVENT_API_ADD_TRACE_EVENT \ + gl::TraceAddTraceEvent + +//////////////////////////////////////////////////////////////////////////////// + +// Implementation detail: trace event macros create temporary variables +// to keep instrumentation overhead low. These macros give each temporary +// variable a unique name based on the line number to prevent name collissions. +#define INTERNAL_TRACE_EVENT_UID3(a, b) \ + trace_event_unique_##a##b +#define INTERNAL_TRACE_EVENT_UID2(a, b) \ + INTERNAL_TRACE_EVENT_UID3(a, b) +#define INTERNALTRACEEVENTUID(name_prefix) \ + INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) + +// Implementation detail: internal macro to create static category. +#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category) \ + static const unsigned char* INTERNALTRACEEVENTUID(catstatic) = 0; \ + if (!INTERNALTRACEEVENTUID(catstatic)) \ + INTERNALTRACEEVENTUID(catstatic) = \ + TRACE_EVENT_API_GET_CATEGORY_ENABLED(category); + +// Implementation detail: internal macro to create static category and add +// event if the category is enabled. +#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \ + do { \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + if (*INTERNALTRACEEVENTUID(catstatic)) { \ + gl::TraceEvent::addTraceEvent( \ + phase, INTERNALTRACEEVENTUID(catstatic), name, \ + gl::TraceEvent::noEventId, flags, ##__VA_ARGS__); \ + } \ + } while (0) + +// Implementation detail: internal macro to create static category and add begin +// event if the category is enabled. Also adds the end event when the scope +// ends. +#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + gl::TraceEvent::TraceEndOnScopeClose \ + INTERNALTRACEEVENTUID(profileScope); \ + if (*INTERNALTRACEEVENTUID(catstatic)) { \ + gl::TraceEvent::addTraceEvent( \ + TRACE_EVENT_PHASE_BEGIN, \ + INTERNALTRACEEVENTUID(catstatic), \ + name, gl::TraceEvent::noEventId, \ + TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \ + INTERNALTRACEEVENTUID(profileScope).initialize( \ + INTERNALTRACEEVENTUID(catstatic), name); \ + } + +// Implementation detail: internal macro to create static category and add +// event if the category is enabled. +#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, \ + ...) \ + do { \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ + if (*INTERNALTRACEEVENTUID(catstatic)) { \ + unsigned char traceEventFlags = flags | TRACE_EVENT_FLAG_HAS_ID; \ + gl::TraceEvent::TraceID traceEventTraceID( \ + id, &traceEventFlags); \ + gl::TraceEvent::addTraceEvent( \ + phase, INTERNALTRACEEVENTUID(catstatic), \ + name, traceEventTraceID.data(), traceEventFlags, \ + ##__VA_ARGS__); \ + } \ + } while (0) + +// Notes regarding the following definitions: +// New values can be added and propagated to third party libraries, but existing +// definitions must never be changed, because third party libraries may use old +// definitions. + +// Phase indicates the nature of an event entry. E.g. part of a begin/end pair. +#define TRACE_EVENT_PHASE_BEGIN ('B') +#define TRACE_EVENT_PHASE_END ('E') +#define TRACE_EVENT_PHASE_INSTANT ('I') +#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') +#define TRACE_EVENT_PHASE_ASYNC_STEP ('T') +#define TRACE_EVENT_PHASE_ASYNC_END ('F') +#define TRACE_EVENT_PHASE_METADATA ('M') +#define TRACE_EVENT_PHASE_COUNTER ('C') +#define TRACE_EVENT_PHASE_SAMPLE ('P') + +// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT. +#define TRACE_EVENT_FLAG_NONE (static_cast(0)) +#define TRACE_EVENT_FLAG_COPY (static_cast(1 << 0)) +#define TRACE_EVENT_FLAG_HAS_ID (static_cast(1 << 1)) +#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast(1 << 2)) + +// Type values for identifying types in the TraceValue union. +#define TRACE_VALUE_TYPE_BOOL (static_cast(1)) +#define TRACE_VALUE_TYPE_UINT (static_cast(2)) +#define TRACE_VALUE_TYPE_INT (static_cast(3)) +#define TRACE_VALUE_TYPE_DOUBLE (static_cast(4)) +#define TRACE_VALUE_TYPE_POINTER (static_cast(5)) +#define TRACE_VALUE_TYPE_STRING (static_cast(6)) +#define TRACE_VALUE_TYPE_COPY_STRING (static_cast(7)) + + +namespace gl { + +namespace TraceEvent { + +// Specify these values when the corresponding argument of addTraceEvent is not +// used. +const int zeroNumArgs = 0; +const unsigned long long noEventId = 0; + +// TraceID encapsulates an ID that can either be an integer or pointer. Pointers +// are mangled with the Process ID so that they are unlikely to collide when the +// same pointer is used on different processes. +class TraceID { +public: + explicit TraceID(const void* id, unsigned char* flags) : + m_data(static_cast(reinterpret_cast(id))) + { + *flags |= TRACE_EVENT_FLAG_MANGLE_ID; + } + explicit TraceID(unsigned long long id, unsigned char* flags) : m_data(id) { (void)flags; } + explicit TraceID(unsigned long id, unsigned char* flags) : m_data(id) { (void)flags; } + explicit TraceID(unsigned int id, unsigned char* flags) : m_data(id) { (void)flags; } + explicit TraceID(unsigned short id, unsigned char* flags) : m_data(id) { (void)flags; } + explicit TraceID(unsigned char id, unsigned char* flags) : m_data(id) { (void)flags; } + explicit TraceID(long long id, unsigned char* flags) : + m_data(static_cast(id)) { (void)flags; } + explicit TraceID(long id, unsigned char* flags) : + m_data(static_cast(id)) { (void)flags; } + explicit TraceID(int id, unsigned char* flags) : + m_data(static_cast(id)) { (void)flags; } + explicit TraceID(short id, unsigned char* flags) : + m_data(static_cast(id)) { (void)flags; } + explicit TraceID(signed char id, unsigned char* flags) : + m_data(static_cast(id)) { (void)flags; } + + unsigned long long data() const { return m_data; } + +private: + unsigned long long m_data; +}; + +// Simple union to store various types as unsigned long long. +union TraceValueUnion { + bool m_bool; + unsigned long long m_uint; + long long m_int; + double m_double; + const void* m_pointer; + const char* m_string; +}; + +// Simple container for const char* that should be copied instead of retained. +class TraceStringWithCopy { +public: + explicit TraceStringWithCopy(const char* str) : m_str(str) { } + operator const char* () const { return m_str; } +private: + const char* m_str; +}; + +// Define setTraceValue for each allowed type. It stores the type and +// value in the return arguments. This allows this API to avoid declaring any +// structures so that it is portable to third_party libraries. +#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \ + union_member, \ + value_type_id) \ + static inline void setTraceValue(actual_type arg, \ + unsigned char* type, \ + unsigned long long* value) { \ + TraceValueUnion typeValue; \ + typeValue.union_member = arg; \ + *type = value_type_id; \ + *value = typeValue.m_uint; \ + } +// Simpler form for int types that can be safely casted. +#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \ + value_type_id) \ + static inline void setTraceValue(actual_type arg, \ + unsigned char* type, \ + unsigned long long* value) { \ + *type = value_type_id; \ + *value = static_cast(arg); \ + } + +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) +INTERNAL_DECLARE_SET_TRACE_VALUE(bool, m_bool, TRACE_VALUE_TYPE_BOOL) +INTERNAL_DECLARE_SET_TRACE_VALUE(double, m_double, TRACE_VALUE_TYPE_DOUBLE) +INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, m_pointer, + TRACE_VALUE_TYPE_POINTER) +INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, m_string, + TRACE_VALUE_TYPE_STRING) +INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, m_string, + TRACE_VALUE_TYPE_COPY_STRING) + +#undef INTERNAL_DECLARE_SET_TRACE_VALUE +#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT + +static inline void setTraceValue(const std::string& arg, + unsigned char* type, + unsigned long long* value) { + TraceValueUnion typeValue; + typeValue.m_string = arg.data(); + *type = TRACE_VALUE_TYPE_COPY_STRING; + *value = typeValue.m_uint; +} + +// These addTraceEvent template functions are defined here instead of in the +// macro, because the arg values could be temporary string objects. In order to +// store pointers to the internal c_str and pass through to the tracing API, the +// arg values must live throughout these procedures. + +static inline void addTraceEvent(char phase, + const unsigned char* categoryEnabled, + const char* name, + unsigned long long id, + unsigned char flags) { + TRACE_EVENT_API_ADD_TRACE_EVENT( + phase, categoryEnabled, name, id, + zeroNumArgs, 0, 0, 0, + flags); +} + +template +static inline void addTraceEvent(char phase, + const unsigned char* categoryEnabled, + const char* name, + unsigned long long id, + unsigned char flags, + const char* arg1Name, + const ARG1_TYPE& arg1Val) { + const int numArgs = 1; + unsigned char argTypes[1]; + unsigned long long argValues[1]; + setTraceValue(arg1Val, &argTypes[0], &argValues[0]); + TRACE_EVENT_API_ADD_TRACE_EVENT( + phase, categoryEnabled, name, id, + numArgs, &arg1Name, argTypes, argValues, + flags); +} + +template +static inline void addTraceEvent(char phase, + const unsigned char* categoryEnabled, + const char* name, + unsigned long long id, + unsigned char flags, + const char* arg1Name, + const ARG1_TYPE& arg1Val, + const char* arg2Name, + const ARG2_TYPE& arg2Val) { + const int numArgs = 2; + const char* argNames[2] = { arg1Name, arg2Name }; + unsigned char argTypes[2]; + unsigned long long argValues[2]; + setTraceValue(arg1Val, &argTypes[0], &argValues[0]); + setTraceValue(arg2Val, &argTypes[1], &argValues[1]); + return TRACE_EVENT_API_ADD_TRACE_EVENT( + phase, categoryEnabled, name, id, + numArgs, argNames, argTypes, argValues, + flags); +} + +// Used by TRACE_EVENTx macro. Do not use directly. +class TraceEndOnScopeClose { +public: + // Note: members of m_data intentionally left uninitialized. See initialize. + TraceEndOnScopeClose() : m_pdata(0) { } + ~TraceEndOnScopeClose() + { + if (m_pdata) + addEventIfEnabled(); + } + + void initialize(const unsigned char* categoryEnabled, + const char* name) + { + m_data.categoryEnabled = categoryEnabled; + m_data.name = name; + m_pdata = &m_data; + } + +private: + // Add the end event if the category is still enabled. + void addEventIfEnabled() + { + // Only called when m_pdata is non-null. + if (*m_pdata->categoryEnabled) { + TRACE_EVENT_API_ADD_TRACE_EVENT( + TRACE_EVENT_PHASE_END, + m_pdata->categoryEnabled, + m_pdata->name, noEventId, + zeroNumArgs, 0, 0, 0, + TRACE_EVENT_FLAG_NONE); + } + } + + // This Data struct workaround is to avoid initializing all the members + // in Data during construction of this object, since this object is always + // constructed, even when tracing is disabled. If the members of Data were + // members of this class instead, compiler warnings occur about potential + // uninitialized accesses. + struct Data { + const unsigned char* categoryEnabled; + const char* name; + }; + Data* m_pdata; + Data m_data; +}; + +} // namespace TraceEvent + +} // namespace gl + +#endif diff --git a/src/angle/patches/0000-General-fixes-for-ANGLE-2.1.patch b/src/angle/patches/0000-General-fixes-for-ANGLE-2.1.patch deleted file mode 100644 index ad3187ec7c..0000000000 --- a/src/angle/patches/0000-General-fixes-for-ANGLE-2.1.patch +++ /dev/null @@ -1,477 +0,0 @@ -From bd27c33a4a7c48bd14b9b6c18c8cdce1c3aae155 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Fri, 14 Nov 2014 10:53:40 +0200 -Subject: [PATCH] General fixes for ANGLE 2.1 - -- Fix commit.h include (use hard-coded version) -- Fix export mismatch in libEGL.cpp and libGLESv2.cpp -- Normalize all precompiled shader names and includes -- Remove third-party event tracing; it was hardly used in ANGLE - and not enabled in Qt builds anyway. - -Change-Id: I22254aed62e89a26756ca0784bae95909189c0f9 ---- - src/3rdparty/angle/src/commit.h | 6 +- - src/3rdparty/angle/src/common/version.h | 2 +- - .../src/common/winrt/CoreWindowNativeWindow.cpp | 2 +- - src/3rdparty/angle/src/libEGL/libEGL.cpp | 3 + - src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp | 4 ++ - src/3rdparty/angle/src/libGLESv2/libGLESv2.def | 3 - - .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 3 - - .../src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp | 66 +++++++++++----------- - .../src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 12 ++-- - .../renderer/d3d/d3d11/PixelTransfer11.cpp | 10 ++-- - .../libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp | 4 +- - .../renderer/d3d/d3d11/shaders/Clear11.hlsl | 4 ++ - .../src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp | 20 +++---- - .../src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 12 ---- - .../libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps | 6 +- - .../libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs | 4 +- - 16 files changed, 76 insertions(+), 85 deletions(-) - -diff --git a/src/3rdparty/angle/src/commit.h b/src/3rdparty/angle/src/commit.h -index 4c89a65..08fc893 100644 ---- a/src/3rdparty/angle/src/commit.h -+++ b/src/3rdparty/angle/src/commit.h -@@ -7,8 +7,6 @@ - // This is a default commit hash header, when git is not available. - // - --#define ANGLE_COMMIT_HASH "unknown hash" -+#define ANGLE_COMMIT_HASH "30d6c255d238" - #define ANGLE_COMMIT_HASH_SIZE 12 --#define ANGLE_COMMIT_DATE "unknown date" -- --#define ANGLE_DISABLE_PROGRAM_BINARY_LOAD -+#define ANGLE_COMMIT_DATE "2014-11-13 17:37:03 +0000" -diff --git a/src/3rdparty/angle/src/common/version.h b/src/3rdparty/angle/src/common/version.h -index d9148d1..f01e024 100644 ---- a/src/3rdparty/angle/src/common/version.h -+++ b/src/3rdparty/angle/src/common/version.h -@@ -1,4 +1,4 @@ --#include "id/commit.h" -+#include "../commit.h" - - #define ANGLE_MAJOR_VERSION 2 - #define ANGLE_MINOR_VERSION 1 -diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp -index 0de16f4..0e63fa5 100644 ---- a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp -+++ b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp -@@ -184,4 +184,4 @@ long ConvertDipsToPixels(float dips) - static const float dipsPerInch = 96.0f; - return lround((dips * GetLogicalDpi() / dipsPerInch)); - } --} -\ No newline at end of file -+} -diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp -index 851b723..6110698 100644 ---- a/src/3rdparty/angle/src/libEGL/libEGL.cpp -+++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp -@@ -6,6 +6,9 @@ - - // libEGL.cpp: Implements the exported EGL functions. - -+#undef EGLAPI -+#define EGLAPI -+ - #include - - #include "common/debug.h" -diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp -index 2306168..587950a 100644 ---- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp -@@ -6,6 +6,10 @@ - - // libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions. - -+#undef GL_APICALL -+#define GL_APICALL -+#define GL_GLEXT_PROTOTYPES -+ - #include "common/version.h" - #include "common/utilities.h" - -diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def -index 88dceb3..33557eb 100644 ---- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def -+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def -@@ -294,6 +294,3 @@ EXPORTS - glBindTexImage @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME -- -- ; Setting up TRACE macro callbacks -- SetTraceFunctionPointers @284 -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -index 5c44fe0..bfeaf51 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -@@ -11,8 +11,6 @@ - #include "common/features.h" - #include "common/utilities.h" - --#include "third_party/trace_event/trace_event.h" -- - // Definitions local to the translation unit - namespace - { -@@ -120,7 +118,6 @@ HLSLCompiler::~HLSLCompiler() - - bool HLSLCompiler::initialize() - { -- TRACE_EVENT0("gpu", "initializeCompiler"); - #if !defined(ANGLE_ENABLE_WINDOWS_STORE) - #if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) - // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -index 8ed1650..91e7552 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -@@ -13,39 +13,39 @@ - #include "libGLESv2/main.h" - #include "libGLESv2/formatutils.h" - --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dui11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2di11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dui11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2di11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dui11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2di11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dui11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2di11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum2d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2d11ps.h" -- --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3d11vs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3d11gs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dui11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3di11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dui11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3di11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dui11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3di11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dui11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3di11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum3d11ps.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3d11ps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughdepth2dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2duips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2duips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb2dips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2duips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg2dips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2duips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr2dips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum2dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha2dps.h" -+ -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3dvs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough3dgs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3duips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba3dips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3duips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgb3dips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3duips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrg3dips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3duips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughr3dips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlum3dps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughlumalpha3dps.h" - - #include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" - #include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp -index 12905d0..4630762 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp -@@ -15,14 +15,14 @@ - #include "libGLESv2/FramebufferAttachment.h" - - // Precompiled shaders --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloat11vs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloat11ps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloatvs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearfloatps.h" - --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuint11vs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuint11ps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuintvs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearuintps.h" - --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsint11vs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsint11ps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsintvs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/clearsintps.h" - - namespace rx - { -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -index 1bc2bd8..a4072d8 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -@@ -22,11 +22,11 @@ - #include "libGLESv2/Context.h" - - // Precompiled shaders --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_vs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_gs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4f.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4i.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture11_ps_4ui.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexturevs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexturegs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4fps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4ips.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/buffertotexture_4uips.h" - - namespace rx - { -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -index 3fcacf6..834b7bd 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -@@ -12,8 +12,8 @@ - #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" - - // Precompiled shaders --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2d11vs.h" --#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2d11ps.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" -+#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" - - #include "common/features.h" - #include "common/NativeWindow.h" -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl -index 6deef2b..b4cf380 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl -@@ -13,10 +13,12 @@ struct PS_OutputFloat - float4 color1 : SV_TARGET1; - float4 color2 : SV_TARGET2; - float4 color3 : SV_TARGET3; -+#if SM4 - float4 color4 : SV_TARGET4; - float4 color5 : SV_TARGET5; - float4 color6 : SV_TARGET6; - float4 color7 : SV_TARGET7; -+#endif - }; - - PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inColor : COLOR) -@@ -26,10 +28,12 @@ PS_OutputFloat PS_ClearFloat(in float4 inPosition : SV_POSITION, in float4 inCol - outColor.color1 = inColor; - outColor.color2 = inColor; - outColor.color3 = inColor; -+#if SM4 - outColor.color4 = inColor; - outColor.color5 = inColor; - outColor.color6 = inColor; - outColor.color7 = inColor; -+#endif - return outColor; - } - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp -index d4fcd17..2ca7a9c 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp -@@ -27,20 +27,20 @@ namespace - - const BYTE* const g_shaderCode[] = - { -- g_vs20_standardvs, -- g_vs20_flipyvs, -- g_ps20_passthroughps, -- g_ps20_luminanceps, -- g_ps20_componentmaskps -+ g_vs20_VS_standard, -+ g_vs20_VS_flipy, -+ g_ps20_PS_passthrough, -+ g_ps20_PS_luminance, -+ g_ps20_PS_componentmask - }; - - 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) -+ sizeof(g_vs20_VS_standard), -+ sizeof(g_vs20_VS_flipy), -+ sizeof(g_ps20_PS_passthrough), -+ sizeof(g_ps20_PS_luminance), -+ sizeof(g_ps20_PS_componentmask) - }; - } - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -index 3bac4ba..82963ec 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -@@ -42,8 +42,6 @@ - #include "common/features.h" - #include "common/utilities.h" - --#include "third_party/trace_event/trace_event.h" -- - #include - - // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros -@@ -185,7 +183,6 @@ EGLint Renderer9::initialize() - return EGL_NOT_INITIALIZED; - } - -- TRACE_EVENT0("gpu", "GetModuleHandle_d3d9"); - mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); - - if (mD3d9Module == NULL) -@@ -202,14 +199,12 @@ EGLint Renderer9::initialize() - // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available. - if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) - { -- TRACE_EVENT0("gpu", "D3d9Ex_QueryInterface"); - ASSERT(mD3d9Ex); - mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast(&mD3d9)); - ASSERT(mD3d9); - } - else - { -- TRACE_EVENT0("gpu", "Direct3DCreate9"); - mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); - } - -@@ -228,7 +223,6 @@ EGLint Renderer9::initialize() - - // Give up on getting device caps after about one second. - { -- TRACE_EVENT0("gpu", "GetDeviceCaps"); - for (int i = 0; i < 10; ++i) - { - result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); -@@ -263,7 +257,6 @@ EGLint Renderer9::initialize() - } - - { -- TRACE_EVENT0("gpu", "GetAdapterIdentifier"); - mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); - } - -@@ -300,7 +293,6 @@ EGLint Renderer9::initialize() - static const TCHAR className[] = TEXT("STATIC"); - - { -- TRACE_EVENT0("gpu", "CreateWindowEx"); - mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL); - } - -@@ -308,7 +300,6 @@ EGLint Renderer9::initialize() - DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; - - { -- TRACE_EVENT0("gpu", "D3d9_CreateDevice"); - result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); - } - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) -@@ -318,7 +309,6 @@ EGLint Renderer9::initialize() - - if (FAILED(result)) - { -- TRACE_EVENT0("gpu", "D3d9_CreateDevice2"); - result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); - - if (FAILED(result)) -@@ -330,13 +320,11 @@ EGLint Renderer9::initialize() - - if (mD3d9Ex) - { -- TRACE_EVENT0("gpu", "mDevice_QueryInterface"); - result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void**)&mDeviceEx); - ASSERT(SUCCEEDED(result)); - } - - { -- TRACE_EVENT0("gpu", "ShaderCache initialize"); - mVertexShaderCache.initialize(mDevice); - mPixelShaderCache.initialize(mDevice); - } -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps -index dc357d0..eb43eb3 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps -@@ -11,7 +11,7 @@ uniform float4 add : c1; - - // Passthrough Pixel Shader - // Outputs texture 0 sampled at texcoord 0. --float4 passthroughps(float4 texcoord : TEXCOORD0) : COLOR -+float4 PS_passthrough(float4 texcoord : TEXCOORD0) : COLOR - { - return tex2D(tex, texcoord.xy); - }; -@@ -19,7 +19,7 @@ float4 passthroughps(float4 texcoord : TEXCOORD0) : COLOR - // Luminance Conversion Pixel Shader - // Performs a mad operation using the LA data from the texture with mult.xw and add.xw. - // Returns data in the form of llla --float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR -+float4 PS_luminance(float4 texcoord : TEXCOORD0) : COLOR - { - return (tex2D(tex, texcoord.xy).xw * mult.xw + add.xw).xxxy; - }; -@@ -27,7 +27,7 @@ float4 luminanceps(float4 texcoord : TEXCOORD0) : COLOR - // RGB/A Component Mask Pixel Shader - // Performs a mad operation using the texture's RGBA data with mult.xyzw and add.xyzw. - // Returns data in the form of rgba --float4 componentmaskps(float4 texcoord : TEXCOORD0) : COLOR -+float4 PS_componentmask(float4 texcoord : TEXCOORD0) : COLOR - { - return tex2D(tex, texcoord.xy) * mult + add; - }; -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs -index 3a36980..3bd611b 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs -@@ -17,7 +17,7 @@ uniform float4 halfPixelSize : c0; - // 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 VS_standard(in float4 position : POSITION) - { - VS_OUTPUT Out; - -@@ -32,7 +32,7 @@ VS_OUTPUT standardvs(in float4 position : 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 VS_flipy(in float4 position : POSITION) - { - VS_OUTPUT Out; - --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0001-ANGLE-Improve-Windows-Phone-Support.patch b/src/angle/patches/0001-ANGLE-Improve-Windows-Phone-Support.patch new file mode 100644 index 0000000000..1361b8b656 --- /dev/null +++ b/src/angle/patches/0001-ANGLE-Improve-Windows-Phone-Support.patch @@ -0,0 +1,439 @@ +From ed09eff731b5d286e0bf6a5958b937a50ecc2362 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Tue, 7 Apr 2015 13:24:59 +0300 +Subject: [PATCH 1/5] ANGLE: Improve Windows Phone Support + +This contains compile fixes for Windows Phone as well as improved +orientation handling. + +Change-Id: Ia312b5318b977838a2953f1f530487cbf24974bc +--- + src/3rdparty/angle/src/common/platform.h | 2 ++ + .../renderer/d3d/d3d11/DebugAnnotator11.cpp | 2 +- + .../src/libANGLE/renderer/d3d/d3d11/NativeWindow.h | 4 +++ + .../src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp | 8 +++-- + .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 40 ++++++++++++++++++++++ + .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 31 +++++++++++++++-- + .../d3d/d3d11/winrt/CoreWindowNativeWindow.h | 34 +++++++++++++++++- + .../d3d/d3d11/winrt/InspectableNativeWindow.cpp | 12 +++++++ + .../d3d/d3d11/winrt/InspectableNativeWindow.h | 14 +++++++- + src/3rdparty/angle/src/libANGLE/validationEGL.cpp | 4 ++- + 10 files changed, 142 insertions(+), 9 deletions(-) + +diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h +index 56db297..4e3851c 100644 +--- a/src/3rdparty/angle/src/common/platform.h ++++ b/src/3rdparty/angle/src/common/platform.h +@@ -68,7 +68,9 @@ + # if defined(ANGLE_ENABLE_WINDOWS_STORE) + # include + # if defined(_DEBUG) ++# if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + # include ++# endif + # include + # endif + # endif +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp +index bc7cdcc..fcca904 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp +@@ -60,7 +60,7 @@ bool DebugAnnotator11::getStatus() + { + // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013. + +-#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE) ++#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture. + // This should only be called in DEBUG mode. + // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks. +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h +index ce50c32..81b9ea7 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h +@@ -49,11 +49,15 @@ namespace rx + class NativeWindow + { + public: ++ enum RotationFlags { RotateNone = 0, RotateLeft = 1, RotateRight = 2 }; + explicit NativeWindow(EGLNativeWindowType window); + + bool initialize(); + bool getClientRect(LPRECT rect); + bool isIconic(); ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ RotationFlags rotationFlags() const; ++#endif + static bool isValidNativeWindow(EGLNativeWindowType window); + + HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +index eba40a4..dbed23f 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +@@ -230,7 +230,11 @@ Renderer11::Renderer11(egl::Display *display) + } + } + ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) ++ if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) ++#else + if (requestedMajorVersion == 9 && requestedMinorVersion == 3) ++#endif + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); + } +@@ -587,10 +591,10 @@ egl::ConfigSet Renderer11::generateConfigs() const + config.bindToTextureRGB = (colorBufferFormatInfo.format == GL_RGB); + config.bindToTextureRGBA = (colorBufferFormatInfo.format == GL_RGBA || colorBufferFormatInfo.format == GL_BGRA_EXT); + config.colorBufferType = EGL_RGB_BUFFER; +- config.configCaveat = EGL_NONE; + config.configID = static_cast(configs.size() + 1); + // Can only support a conformant ES2 with feature level greater than 10.0. + config.conformant = (mFeatureLevel >= D3D_FEATURE_LEVEL_10_0) ? (EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT_KHR) : EGL_NONE; ++ config.configCaveat = config.conformant == EGL_NONE ? EGL_NON_CONFORMANT_CONFIG : EGL_NONE; + config.depthSize = depthStencilBufferFormatInfo.depthBits; + config.level = 0; + config.matchNativePixmap = EGL_NONE; +@@ -2290,7 +2294,7 @@ bool Renderer11::getShareHandleSupport() const + // chrome needs BGRA. Once chrome fixes this, we should always support them. + // PIX doesn't seem to support using share handles, so disable them. + // Also disable share handles on Feature Level 9_3, since it doesn't support share handles on RGBA8 textures/swapchains. +- return getRendererExtensions().textureFormatBGRA8888 && !gl::DebugAnnotationsActive() && !(mFeatureLevel <= D3D_FEATURE_LEVEL_9_3); ++ return getRendererExtensions().textureFormatBGRA8888 && !gl::DebugAnnotationsActive();// && !(mFeatureLevel <= D3D_FEATURE_LEVEL_9_3); Qt: we don't care about the 9_3 limitation + } + + bool Renderer11::getPostSubBufferSupport() const +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +index 2558528..bcb2505 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +@@ -154,8 +154,14 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); + + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ const int textureLength = std::max(backbufferWidth, backbufferHeight); ++ offscreenTextureDesc.Width = textureLength; ++ offscreenTextureDesc.Height = textureLength; ++#else + offscreenTextureDesc.Width = backbufferWidth; + offscreenTextureDesc.Height = backbufferHeight; ++#endif + offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; + offscreenTextureDesc.MipLevels = 1; + offscreenTextureDesc.ArraySize = 1; +@@ -235,8 +241,14 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + if (mDepthBufferFormat != GL_NONE) + { + D3D11_TEXTURE2D_DESC depthStencilTextureDesc; ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ const int textureLength = std::max(backbufferWidth, backbufferHeight); ++ depthStencilTextureDesc.Width = textureLength; ++ depthStencilTextureDesc.Height = textureLength; ++#else + depthStencilTextureDesc.Width = backbufferWidth; + depthStencilTextureDesc.Height = backbufferHeight; ++#endif + depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; + depthStencilTextureDesc.MipLevels = 1; + depthStencilTextureDesc.ArraySize = 1; +@@ -337,6 +349,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) + return EGL_SUCCESS; + } + ++#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + // Can only call resize if we have already created our swap buffer and resources + ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); + +@@ -379,6 +392,12 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) + } + + return resetOffscreenTexture(backbufferWidth, backbufferHeight); ++#else ++ // Do nothing on Windows Phone apart from updating the internal buffer/width height ++ mWidth = backbufferWidth; ++ mHeight = backbufferHeight; ++ return EGL_SUCCESS; ++#endif + } + + EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swapInterval) +@@ -539,6 +558,21 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; + float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; + ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ const float dim = std::max(mWidth, mHeight); ++ float u1 = x / dim; ++ float v1 = y / dim; ++ float u2 = (x + width) / dim; ++ float v2 = (y + height) / dim; ++ ++ const NativeWindow::RotationFlags flags = mNativeWindow.rotationFlags(); ++ const bool rotateL = flags == NativeWindow::RotateLeft; ++ const bool rotateR = flags == NativeWindow::RotateRight; ++ d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); ++ d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); ++ d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); ++ d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); ++#else + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); +@@ -548,6 +582,7 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2); + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); ++#endif + + deviceContext->Unmap(mQuadVB, 0); + +@@ -577,8 +612,13 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ viewport.Width = (rotateL || rotateR) ? mHeight : mWidth; ++ viewport.Height = (rotateL || rotateR) ? mWidth : mHeight; ++#else + viewport.Width = mWidth; + viewport.Height = mHeight; ++#endif + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +index 8cfaa84..350526c 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +@@ -8,8 +8,6 @@ + + #include "libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h" + +-#include +- + using namespace ABI::Windows::Foundation::Collections; + + namespace rx +@@ -21,6 +19,7 @@ CoreWindowNativeWindow::~CoreWindowNativeWindow() + + bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) + { ++ mOrientationChangedEventToken.value = 0; + ComPtr props = propertySet; + ComPtr win = window; + SIZE swapChainSize = {}; +@@ -68,6 +67,16 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet + + if (SUCCEEDED(result)) + { ++ ComPtr displayInformation; ++ result = GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), &displayInformation); ++ if (SUCCEEDED(result)) ++ { ++ result = displayInformation->GetForCurrentView(&mDisplayInformation); ++ } ++ } ++ ++ if (SUCCEEDED(result)) ++ { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); +@@ -85,6 +94,15 @@ bool CoreWindowNativeWindow::registerForSizeChangeEvents() + result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); + } + ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ ComPtr orientationChangedHandler; ++ result = sizeChangedHandler.As(&orientationChangedHandler); ++ if (SUCCEEDED(result)) ++ { ++ result = mDisplayInformation->add_OrientationChanged(orientationChangedHandler.Get(), &mOrientationChangedEventToken); ++ } ++#endif ++ + if (SUCCEEDED(result)) + { + return true; +@@ -99,7 +117,14 @@ void CoreWindowNativeWindow::unregisterForSizeChangeEvents() + { + (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken); + } ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ if (mDisplayInformation) ++ { ++ (void)mDisplayInformation->remove_OrientationChanged(mOrientationChangedEventToken); ++ } ++#endif + mSizeChangedEventToken.value = 0; ++ mOrientationChangedEventToken.value = 0; + } + + HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +@@ -128,7 +153,7 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor + if (SUCCEEDED(result)) + { + +-#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++#if 0 //(WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // Qt: allow Windows Phone to resize, but don't modify the backing texture in the swap chain. + // Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On + // other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed + // (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations. +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h +index c230c84..59df9d5 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h +@@ -12,8 +12,10 @@ + #include "libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h" + + #include ++#include + + typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t IWindowSizeChangedEventHandler; ++typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CGraphics__CDisplay__CDisplayInformation_IInspectable_t IDisplayOrientationEventHandler; + + namespace rx + { +@@ -32,11 +34,13 @@ class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enabl + private: + ComPtr mCoreWindow; + ComPtr> mPropertyMap; ++ ComPtr mDisplayInformation; ++ EventRegistrationToken mOrientationChangedEventToken; + }; + + [uuid(7F924F66-EBAE-40E5-A10B-B8F35E245190)] + class CoreWindowSizeChangedHandler : +- public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler> ++ public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler, IDisplayOrientationEventHandler> + { + public: + CoreWindowSizeChangedHandler() { } +@@ -68,6 +72,34 @@ class CoreWindowSizeChangedHandler : + return S_OK; + } + ++ IFACEMETHOD(Invoke)(ABI::Windows::Graphics::Display::IDisplayInformation *displayInformation, IInspectable *) ++ { ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ NativeWindow::RotationFlags flags = NativeWindow::RotateNone; ++ ABI::Windows::Graphics::Display::DisplayOrientations orientation; ++ if (SUCCEEDED(displayInformation->get_CurrentOrientation(&orientation))) ++ { ++ switch (orientation) ++ { ++ case ABI::Windows::Graphics::Display::DisplayOrientations_Landscape: ++ flags = NativeWindow::RotateLeft; ++ break; ++ case ABI::Windows::Graphics::Display::DisplayOrientations_LandscapeFlipped: ++ flags = NativeWindow::RotateRight; ++ break; ++ default: ++ break; ++ } ++ } ++ std::shared_ptr host = mHost.lock(); ++ if (host) ++ { ++ host->setRotationFlags(flags); ++ } ++#endif ++ return S_OK; ++ } ++ + private: + std::weak_ptr mHost; + }; +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp +index 7ac53c7..2bf48c5 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp +@@ -69,6 +69,18 @@ bool NativeWindow::getClientRect(RECT *rect) + return false; + } + ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++NativeWindow::RotationFlags NativeWindow::rotationFlags() const ++{ ++ if (mImpl) ++ { ++ return mImpl->rotationFlags(); ++ } ++ ++ return NativeWindow::RotateNone; ++} ++#endif ++ + bool NativeWindow::isIconic() + { + return false; +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h +index e89c900..575bdf8 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h +@@ -34,7 +34,8 @@ class InspectableNativeWindow + mRequiresSwapChainScaling(false), + mClientRectChanged(false), + mClientRect({0,0,0,0}), +- mNewClientRect({0,0,0,0}) ++ mNewClientRect({0,0,0,0}), ++ mRotationFlags(NativeWindow::RotateNone) + { + mSizeChangedEventToken.value = 0; + } +@@ -72,12 +73,23 @@ class InspectableNativeWindow + } + } + ++ NativeWindow::RotationFlags rotationFlags() const ++ { ++ return mRotationFlags; ++ } ++ ++ void setRotationFlags(NativeWindow::RotationFlags flags) ++ { ++ mRotationFlags = flags; ++ } ++ + protected: + bool mSupportsSwapChainResize; + bool mRequiresSwapChainScaling; + RECT mClientRect; + RECT mNewClientRect; + bool mClientRectChanged; ++ NativeWindow::RotationFlags mRotationFlags; + + EventRegistrationToken mSizeChangedEventToken; + }; +diff --git a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp +index 4e3b44b..12ee6a2 100644 +--- a/src/3rdparty/angle/src/libANGLE/validationEGL.cpp ++++ b/src/3rdparty/angle/src/libANGLE/validationEGL.cpp +@@ -160,7 +160,7 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context + return Error(EGL_BAD_CONFIG); + } + +- if (clientMajorVersion == 3 && !(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR)) ++ if (clientMajorVersion == 3 && !(configuration->conformant & EGL_OPENGL_ES3_BIT_KHR) && !(configuration->configCaveat & EGL_NON_CONFORMANT_CONFIG)) + { + return Error(EGL_BAD_CONFIG); + } +@@ -488,11 +488,13 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E + return Error(EGL_BAD_ATTRIBUTE); + } + ++#if !defined(ANGLE_ENABLE_WINDOWS_STORE) // On Windows Store, we know the originating texture came from D3D11, so bypass this check + const Caps &caps = display->getCaps(); + if (textureFormat != EGL_NO_TEXTURE && !caps.textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) + { + return Error(EGL_BAD_MATCH); + } ++#endif + } + + return Error(EGL_SUCCESS); +-- +2.1.4 + diff --git a/src/angle/patches/0002-ANGLE-Fix-compilation-with-MinGW.patch b/src/angle/patches/0002-ANGLE-Fix-compilation-with-MinGW.patch new file mode 100644 index 0000000000..e28bc797e3 --- /dev/null +++ b/src/angle/patches/0002-ANGLE-Fix-compilation-with-MinGW.patch @@ -0,0 +1,927 @@ +From 6f98a957829fd37106fb1f1c9f43a5bad626cdfc Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Wed, 25 Mar 2015 20:21:33 +0200 +Subject: [PATCH 2/5] ANGLE: Fix compilation with MinGW + +This adds definition guards for Direct3D 11 and DirectX SDK layers, which +are only available in very recent versions (4.9.2 rev 4) of MinGW builds. +It additionally adds a few missing includes needed for compilation. + +Change-Id: I254c208209c0071fae5efb6727f2b3cfd5542da6 +--- + src/3rdparty/angle/src/common/mathutil.h | 4 + + src/3rdparty/angle/src/common/platform.h | 10 +- + src/3rdparty/angle/src/libANGLE/angletypes.h | 1 + + .../src/libANGLE/renderer/d3d/HLSLCompiler.cpp | 9 ++ + .../src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp | 6 + + .../src/libANGLE/renderer/d3d/d3d11/Clear11.cpp | 4 + + .../renderer/d3d/d3d11/DebugAnnotator11.cpp | 10 ++ + .../libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h | 2 + + .../src/libANGLE/renderer/d3d/d3d11/Query11.cpp | 7 + + .../src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp | 83 +++++++++-- + .../src/libANGLE/renderer/d3d/d3d11/Renderer11.h | 3 +- + .../renderer/d3d/d3d11/renderer11_utils.cpp | 152 +++++++++++++++++++++ + .../src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp | 4 +- + 13 files changed, 283 insertions(+), 12 deletions(-) + +diff --git a/src/3rdparty/angle/src/common/mathutil.h b/src/3rdparty/angle/src/common/mathutil.h +index e096b1a..1015bd2 100644 +--- a/src/3rdparty/angle/src/common/mathutil.h ++++ b/src/3rdparty/angle/src/common/mathutil.h +@@ -119,6 +119,9 @@ inline bool supportsSSE2() + return supports; + } + ++#if defined(__GNUC__) ++ supports = __builtin_cpu_supports("sse2"); ++#else + int info[4]; + __cpuid(info, 0); + +@@ -128,6 +131,7 @@ inline bool supportsSSE2() + + supports = (info[3] >> 26) & 1; + } ++#endif + + checked = true; + +diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h +index 4e3851c..be4cb94 100644 +--- a/src/3rdparty/angle/src/common/platform.h ++++ b/src/3rdparty/angle/src/common/platform.h +@@ -59,9 +59,17 @@ + # if defined(ANGLE_ENABLE_D3D11) + # include + # include +-# include + # include ++# if defined(__MINGW32__) && !defined(__d3d11sdklayers_h__) ++# define ANGLE_MINGW32_COMPAT ++# endif ++# if defined(_MSC_VER) && _MSC_VER >= 1800 ++# define ANGLE_ENABLE_D3D11_1 ++# endif ++# if defined(ANGLE_ENABLE_D3D11_1) ++# include + # include ++# endif + # include + # endif + +diff --git a/src/3rdparty/angle/src/libANGLE/angletypes.h b/src/3rdparty/angle/src/libANGLE/angletypes.h +index a5f471d..e4e08b5 100644 +--- a/src/3rdparty/angle/src/libANGLE/angletypes.h ++++ b/src/3rdparty/angle/src/libANGLE/angletypes.h +@@ -13,6 +13,7 @@ + #include "libANGLE/RefCountObject.h" + + #include ++#include + + namespace gl + { +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp +index d709dca..9c72d6f 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp +@@ -22,6 +22,15 @@ namespace + + #define CREATE_COMPILER_FLAG_INFO(flag) { flag, #flag } + ++#if defined(ANGLE_MINGW32_COMPAT) ++#ifndef D3DCOMPILE_RESERVED16 ++#define D3DCOMPILE_RESERVED16 0x10000 ++#endif ++#ifndef D3DCOMPILE_RESERVED17 ++#define D3DCOMPILE_RESERVED17 0x20000 ++#endif ++#endif ++ + struct CompilerFlagInfo + { + UINT mFlag; +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp +index 3b36c64..d56b0ea 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp +@@ -12,6 +12,12 @@ + #include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + #include "libANGLE/renderer/d3d/d3d11/formatutils11.h" + ++#if defined(ANGLE_MINGW32_COMPAT) ++typedef enum D3D11_MAP_FLAG { ++ D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000 ++} D3D11_MAP_FLAG; ++#endif ++ + namespace rx + { + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp +index ae373f5..057c3be 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp +@@ -133,12 +133,14 @@ Clear11::Clear11(Renderer11 *renderer) + mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); + } + ++#if defined(ANGLE_ENABLE_D3D11_1) + if (renderer->getDeviceContext1IfSupported()) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; + device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + mSupportsClearView = (d3d11Options.ClearView != FALSE); + } ++#endif + } + + Clear11::~Clear11() +@@ -321,6 +323,7 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl + + if (needScissoredClear) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + // We shouldn't reach here if deviceContext1 is unavailable. + ASSERT(deviceContext1); + +@@ -331,6 +334,7 @@ gl::Error Clear11::clearFramebuffer(const ClearParameters &clearParams, const gl + rect.bottom = clearParams.scissor.y + clearParams.scissor.height; + + deviceContext1->ClearView(framebufferRTV, clearValues, &rect, 1); ++#endif + } + else + { +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp +index fcca904..f1fe2bb 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp +@@ -27,7 +27,9 @@ DebugAnnotator11::~DebugAnnotator11() + { + if (mInitialized) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + SafeRelease(mUserDefinedAnnotation); ++#endif + + #if !defined(ANGLE_ENABLE_WINDOWS_STORE) + FreeLibrary(mD3d11Module); +@@ -39,21 +41,27 @@ void DebugAnnotator11::beginEvent(const std::wstring &eventName) + { + initializeDevice(); + ++#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->BeginEvent(eventName.c_str()); ++#endif + } + + void DebugAnnotator11::endEvent() + { + initializeDevice(); + ++#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->EndEvent(); ++#endif + } + + void DebugAnnotator11::setMarker(const std::wstring &markerName) + { + initializeDevice(); + ++#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation->SetMarker(markerName.c_str()); ++#endif + } + + bool DebugAnnotator11::getStatus() +@@ -96,8 +104,10 @@ void DebugAnnotator11::initializeDevice() + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context); + ASSERT(SUCCEEDED(hr)); + ++#if defined(ANGLE_ENABLE_D3D11_1) + mUserDefinedAnnotation = d3d11::DynamicCastComObject(context); + ASSERT(mUserDefinedAnnotation != nullptr); ++#endif + + SafeRelease(device); + SafeRelease(context); +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h +index 0638364..3df62b0 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h +@@ -11,6 +11,8 @@ + + #include "common/debug.h" + ++struct ID3DUserDefinedAnnotation; ++ + namespace rx + { + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp +index e010190..4979ff5 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp +@@ -13,6 +13,13 @@ + + #include + ++#if defined(ANGLE_MINGW32_COMPAT) ++typedef struct D3D11_QUERY_DATA_SO_STATISTICS { ++ UINT64 NumPrimitivesWritten; ++ UINT64 PrimitivesStorageNeeded; ++} D3D11_QUERY_DATA_SO_STATISTICS; ++#endif ++ + namespace rx + { + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +index dbed23f..5291a3a 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +@@ -62,6 +62,67 @@ + #define ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS 1 + #endif + ++#ifndef __d3d11sdklayers_h__ ++#define D3D11_MESSAGE_CATEGORY UINT ++#define D3D11_MESSAGE_SEVERITY UINT ++#define D3D11_MESSAGE_ID UINT ++struct D3D11_MESSAGE; ++typedef struct D3D11_INFO_QUEUE_FILTER_DESC ++{ ++ UINT NumCategories; ++ D3D11_MESSAGE_CATEGORY *pCategoryList; ++ UINT NumSeverities; ++ D3D11_MESSAGE_SEVERITY *pSeverityList; ++ UINT NumIDs; ++ D3D11_MESSAGE_ID *pIDList; ++} D3D11_INFO_QUEUE_FILTER_DESC; ++typedef struct D3D11_INFO_QUEUE_FILTER ++{ ++ D3D11_INFO_QUEUE_FILTER_DESC AllowList; ++ D3D11_INFO_QUEUE_FILTER_DESC DenyList; ++} D3D11_INFO_QUEUE_FILTER; ++static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 }; ++MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown ++{ ++public: ++ virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0; ++ virtual void __stdcall ClearStoredMessages() = 0; ++ virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0; ++ virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0; ++ virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0; ++ virtual UINT64 __stdcall GetNumStoredMessages() = 0; ++ virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0; ++ virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0; ++ virtual UINT64 __stdcall GetMessageCountLimit() = 0; ++ virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; ++ virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; ++ virtual void __stdcall ClearStorageFilter() = 0; ++ virtual HRESULT __stdcall PushEmptyStorageFilter() = 0; ++ virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0; ++ virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0; ++ virtual void __stdcall PopStorageFilter() = 0; ++ virtual UINT __stdcall GetStorageFilterStackSize() = 0; ++ virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; ++ virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; ++ virtual void __stdcall ClearRetrievalFilter() = 0; ++ virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0; ++ virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0; ++ virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0; ++ virtual void __stdcall PopRetrievalFilter() = 0; ++ virtual UINT __stdcall GetRetrievalFilterStackSize() = 0; ++ virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0; ++ virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0; ++ virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0; ++ virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0; ++ virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0; ++ virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0; ++ virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0; ++ virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0; ++ virtual void __stdcall SetMuteDebugOutput(BOOL) = 0; ++ virtual BOOL __stdcall GetMuteDebugOutput() = 0; ++}; ++#endif ++ + namespace rx + { + +@@ -164,8 +225,7 @@ void CalculateConstantBufferParams(GLintptr offset, GLsizeiptr size, UINT *outFi + + Renderer11::Renderer11(egl::Display *display) + : RendererD3D(display), +- mStateCache(this), +- mDebug(nullptr) ++ mStateCache(this) + { + // Initialize global annotator + gl::InitializeDebugAnnotations(&mAnnotator); +@@ -398,7 +458,9 @@ egl::Error Renderer11::initialize() + // Cast the DeviceContext to a DeviceContext1. + // This could fail on Windows 7 without the Platform Update. + // Don't error in this case- just don't use mDeviceContext1. ++#if defined(ANGLE_ENABLE_D3D11_1) + mDeviceContext1 = d3d11::DynamicCastComObject(mDeviceContext); ++#endif + + IDXGIDevice *dxgiDevice = NULL; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); +@@ -421,6 +483,7 @@ egl::Error Renderer11::initialize() + + SafeRelease(dxgiDevice); + ++#if defined(ANGLE_ENABLE_D3D11_1) + IDXGIAdapter2 *dxgiAdapter2 = d3d11::DynamicCastComObject(mDxgiAdapter); + + // On D3D_FEATURE_LEVEL_9_*, IDXGIAdapter::GetDesc returns "Software Adapter" for the description string. +@@ -447,6 +510,7 @@ egl::Error Renderer11::initialize() + } + + SafeRelease(dxgiAdapter2); ++#endif + + memset(mDescription, 0, sizeof(mDescription)); + wcstombs(mDescription, mAdapterDescription.Description, sizeof(mDescription) - 1); +@@ -463,7 +527,7 @@ egl::Error Renderer11::initialize() + // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log + #if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) + ID3D11InfoQueue *infoQueue; +- result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue); ++ result = mDevice->QueryInterface(IID_ID3D11InfoQueue, (void **)&infoQueue); + + if (SUCCEEDED(result)) + { +@@ -481,10 +545,6 @@ egl::Error Renderer11::initialize() + } + #endif + +-#if !defined(NDEBUG) +- mDebug = d3d11::DynamicCastComObject(mDevice); +-#endif +- + initializeDevice(); + + return egl::Error(EGL_SUCCESS); +@@ -525,12 +585,14 @@ void Renderer11::initializeDevice() + + const gl::Caps &rendererCaps = getRendererCaps(); + ++#if defined(ANGLE_ENABLE_D3D11_1) + if (getDeviceContext1IfSupported()) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS d3d11Options; + mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &d3d11Options, sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS)); + mSupportsConstantBufferOffsets = (d3d11Options.ConstantBufferOffsetting != FALSE); + } ++#endif + + mForceSetVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); + mCurVertexSamplerStates.resize(rendererCaps.maxVertexTextureImageUnits); +@@ -853,6 +915,7 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, + mCurrentConstantBufferVSOffset[uniformBufferIndex] != uniformBufferOffset || + mCurrentConstantBufferVSSize[uniformBufferIndex] != uniformBufferSize) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + if (mSupportsConstantBufferOffsets && uniformBufferSize != 0) + { + UINT firstConstant = 0, numConstants = 0; +@@ -861,6 +924,7 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, + 1, &constantBuffer, &firstConstant, &numConstants); + } + else ++#endif + { + ASSERT(uniformBufferOffset == 0); + mDeviceContext->VSSetConstantBuffers(getReservedVertexUniformBuffers() + uniformBufferIndex, +@@ -901,6 +965,7 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, + mCurrentConstantBufferPSOffset[uniformBufferIndex] != uniformBufferOffset || + mCurrentConstantBufferPSSize[uniformBufferIndex] != uniformBufferSize) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + if (mSupportsConstantBufferOffsets && uniformBufferSize != 0) + { + UINT firstConstant = 0, numConstants = 0; +@@ -909,6 +974,7 @@ gl::Error Renderer11::setUniformBuffers(const gl::Data &data, + 1, &constantBuffer, &firstConstant, &numConstants); + } + else ++#endif + { + ASSERT(uniformBufferOffset == 0); + mDeviceContext->PSSetConstantBuffers(getReservedFragmentUniformBuffers() + uniformBufferIndex, +@@ -2194,7 +2260,9 @@ void Renderer11::release() + SafeRelease(mDxgiFactory); + SafeRelease(mDxgiAdapter); + ++#if defined(ANGLE_ENABLE_D3D11_1) + SafeRelease(mDeviceContext1); ++#endif + + if (mDeviceContext) + { +@@ -2204,7 +2272,6 @@ void Renderer11::release() + } + + SafeRelease(mDevice); +- SafeRelease(mDebug); + + if (mD3d11Module) + { +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h +index d1fec55..cc7d6c2 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h +@@ -20,6 +20,8 @@ + #include "libANGLE/renderer/d3d/d3d11/InputLayoutCache.h" + #include "libANGLE/renderer/d3d/d3d11/RenderStateCache.h" + ++struct ID3D11DeviceContext1; ++ + namespace gl + { + class FramebufferAttachment; +@@ -390,7 +392,6 @@ class Renderer11 : public RendererD3D + DXGI_ADAPTER_DESC mAdapterDescription; + char mDescription[128]; + DXGIFactory *mDxgiFactory; +- ID3D11Debug *mDebug; + + DebugAnnotator11 mAnnotator; + }; +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +index 70b2b79..63085f4 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +@@ -20,6 +20,88 @@ + + #include + ++#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY ++# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2 ++#endif ++#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT ++# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1 ++#endif ++#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT ++# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4 ++#endif ++#ifndef D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT ++# define D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT 65535 ++#endif ++#ifndef D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT ++# define D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT 1048575 ++#endif ++#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION ++# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512 ++#endif ++#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION ++# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096 ++#endif ++#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION ++# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048 ++#endif ++#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION ++# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256 ++#endif ++#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION ++# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 ++#endif ++#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION ++# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 ++#endif ++#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION ++# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 ++#endif ++#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION ++# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 ++#endif ++#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP ++# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 ++#endif ++#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP ++# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 ++#endif ++#ifndef D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT ++# define D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT 32 ++#endif ++#ifndef D3D11_STANDARD_VERTEX_ELEMENT_COUNT ++# define D3D11_STANDARD_VERTEX_ELEMENT_COUNT 32 ++#endif ++#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT ++# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 ++#endif ++#ifndef D3D11_SO_BUFFER_SLOT_COUNT ++# define D3D11_SO_BUFFER_SLOT_COUNT 4 ++#endif ++#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT ++# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 ++#endif ++#ifndef D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT ++# define D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT 16 ++#endif ++#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE ++# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -8 ++#endif ++#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE ++# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE 7 ++#endif ++#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT ++# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 ++#endif ++#ifndef D3D11_PS_INPUT_REGISTER_COUNT ++# define D3D11_PS_INPUT_REGISTER_COUNT 32 ++#endif ++#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT ++# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 ++#endif ++#if defined(ANGLE_MINGW32_COMPAT) ++static const IID WKPDID_D3DDebugObjectName = { 0x429b8c22, 0x9188, 0x4b0c, 0x87, 0x42, 0xac, 0xb0, 0xbf, 0x85, 0xc2, 0x00 }; ++#endif ++ + namespace rx + { + +@@ -232,7 +314,9 @@ GLint GetMaximumClientVersion(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 3; +@@ -298,7 +382,9 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; +@@ -316,7 +402,9 @@ static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; + + case D3D_FEATURE_LEVEL_10_1: +@@ -336,7 +424,9 @@ static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; +@@ -356,7 +446,9 @@ static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) + + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: +@@ -374,7 +466,9 @@ static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) + + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; +@@ -397,7 +491,9 @@ static bool GetFramebufferMultisampleSupport(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; +@@ -414,7 +510,9 @@ static bool GetFramebufferBlitSupport(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; +@@ -437,7 +535,9 @@ static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) + + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: +@@ -453,7 +553,9 @@ static bool GetShaderTextureLODSupport(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return true; +@@ -472,7 +574,9 @@ static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel + + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; + + case D3D_FEATURE_LEVEL_10_1: +@@ -490,7 +594,9 @@ static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: +@@ -508,7 +614,9 @@ static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: +@@ -526,7 +634,9 @@ static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: +@@ -544,7 +654,9 @@ static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + + case D3D_FEATURE_LEVEL_10_1: +@@ -562,7 +674,9 @@ static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; + + case D3D_FEATURE_LEVEL_10_1: +@@ -586,7 +700,9 @@ static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) + + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); +@@ -608,7 +724,9 @@ static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) + + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); +@@ -625,7 +743,9 @@ static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT; +@@ -645,7 +765,9 @@ static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) + // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: +@@ -670,7 +792,9 @@ static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); + + case D3D_FEATURE_LEVEL_10_1: +@@ -698,7 +822,9 @@ static size_t GetReservedVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) + // We must reserve one output vector for dx_Position. + // We also reserve one for gl_Position, which we unconditionally output on Feature Levels 10_0+, + // even if it's unused in the shader (e.g. for transform feedback). TODO: This could be improved. ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return 2; +@@ -720,7 +846,9 @@ static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) + + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); +@@ -739,7 +867,9 @@ static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: +@@ -761,7 +891,9 @@ static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) + // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: +@@ -786,7 +918,9 @@ static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); + + case D3D_FEATURE_LEVEL_10_1: +@@ -805,7 +939,9 @@ static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(featureLevel); + + case D3D_FEATURE_LEVEL_10_1: +@@ -824,7 +960,9 @@ static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: +@@ -843,7 +981,9 @@ static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; + + case D3D_FEATURE_LEVEL_10_1: +@@ -862,7 +1002,9 @@ static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; +@@ -885,7 +1027,9 @@ static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) + + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; + + case D3D_FEATURE_LEVEL_10_1: +@@ -904,7 +1048,9 @@ static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return D3D11_SO_BUFFER_SLOT_COUNT; + + case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SO_BUFFER_SLOT_COUNT; +@@ -922,7 +1068,9 @@ static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL feat + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: + + case D3D_FEATURE_LEVEL_10_1: +@@ -940,7 +1088,9 @@ static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL feature + { + switch (featureLevel) + { ++#if defined(ANGLE_ENABLE_D3D11_1) + case D3D_FEATURE_LEVEL_11_1: ++#endif + case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / + GetMaximumStreamOutputBuffers(featureLevel); + +@@ -1054,6 +1204,7 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl:: + + // Setting a large alignment forces uniform buffers to bind with zero offset + caps->uniformBufferOffsetAlignment = static_cast(std::numeric_limits::max()); ++#if defined(ANGLE_ENABLE_D3D11_1) + ID3D11DeviceContext1 *deviceContext1 = d3d11::DynamicCastComObject(deviceContext); + + if (deviceContext1) +@@ -1070,6 +1221,7 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, gl:: + + SafeRelease(deviceContext1); + } ++#endif + + caps->maxCombinedUniformBlocks = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; + caps->maxCombinedVertexUniformComponents = (static_cast(caps->maxVertexUniformBlocks) * static_cast(caps->maxUniformBlockSize / 4)) + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +index c59808d..bf1c367 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +@@ -206,7 +206,7 @@ egl::Error Renderer9::initialize() + { + TRACE_EVENT0("gpu", "D3d9Ex_QueryInterface"); + ASSERT(mD3d9Ex); +- mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast(&mD3d9)); ++ mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast(&mD3d9)); + ASSERT(mD3d9); + } + else +@@ -314,7 +314,7 @@ egl::Error Renderer9::initialize() + if (mD3d9Ex) + { + TRACE_EVENT0("gpu", "mDevice_QueryInterface"); +- result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void**)&mDeviceEx); ++ result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); + ASSERT(SUCCEEDED(result)); + } + +-- +2.1.4 + diff --git a/src/angle/patches/0003-ANGLE-Fix-compilation-on-MSVC2010-2012.patch b/src/angle/patches/0003-ANGLE-Fix-compilation-on-MSVC2010-2012.patch new file mode 100644 index 0000000000..62300e1e9b --- /dev/null +++ b/src/angle/patches/0003-ANGLE-Fix-compilation-on-MSVC2010-2012.patch @@ -0,0 +1,363 @@ +From 11304df7f66d0d8bc5dfdc960b86b5cac0f18313 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Wed, 8 Apr 2015 17:09:47 +0300 +Subject: [PATCH 3/5] ANGLE: Fix compilation on MSVC2010/2012 + +Allow the D3D11 renderer to build with the June 2010 DirectX SDK. +This mainly addresses C++11 language incompatibilities, such as replacing +range-based for loops with iterators. + +Change-Id: I2343acedab16845d6a0d4a53cf3145f583efc4a7 +--- + src/3rdparty/angle/src/common/angleutils.h | 2 ++ + src/3rdparty/angle/src/common/platform.h | 9 +++++++ + .../angle/src/compiler/translator/OutputHLSL.cpp | 31 +++++++++++++--------- + src/3rdparty/angle/src/libANGLE/Context.cpp | 4 +-- + src/3rdparty/angle/src/libANGLE/Error.h | 1 + + src/3rdparty/angle/src/libANGLE/Framebuffer.cpp | 23 ++++++++-------- + src/3rdparty/angle/src/libANGLE/State.cpp | 3 ++- + src/3rdparty/angle/src/libANGLE/Texture.cpp | 2 +- + .../angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp | 6 +++-- + .../src/libANGLE/renderer/d3d/RendererD3D.cpp | 4 +-- + .../libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp | 3 ++- + 11 files changed, 55 insertions(+), 33 deletions(-) + +diff --git a/src/3rdparty/angle/src/common/angleutils.h b/src/3rdparty/angle/src/common/angleutils.h +index f3d2019..4cf84a3 100644 +--- a/src/3rdparty/angle/src/common/angleutils.h ++++ b/src/3rdparty/angle/src/common/angleutils.h +@@ -25,12 +25,14 @@ namespace angle + + class NonCopyable + { ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) + public: + NonCopyable() = default; + ~NonCopyable() = default; + protected: + NonCopyable(const NonCopyable&) = delete; + void operator=(const NonCopyable&) = delete; ++#endif + }; + + } +diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h +index be4cb94..3a2aa91 100644 +--- a/src/3rdparty/angle/src/common/platform.h ++++ b/src/3rdparty/angle/src/common/platform.h +@@ -53,7 +53,9 @@ + + # if defined(ANGLE_ENABLE_D3D9) + # include ++# if !defined(ANGLE_TRANSLATOR_IMPLEMENTATION) + # include ++# endif + # endif + + # if defined(ANGLE_ENABLE_D3D11) +@@ -70,7 +72,9 @@ + # include + # include + # endif ++# if !defined(ANGLE_TRANSLATOR_IMPLEMENTATION) + # include ++# endif + # endif + + # if defined(ANGLE_ENABLE_WINDOWS_STORE) +@@ -83,6 +87,11 @@ + # endif + # endif + ++# if defined(_MSC_VER) && (_MSC_VER <= 1600) ++# define final ++# define override ++# endif ++ + # undef near + # undef far + #endif +diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp +index c3240f5..94225b8 100644 +--- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp ++++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp +@@ -158,13 +158,13 @@ OutputHLSL::~OutputHLSL() + SafeDelete(mUnfoldShortCircuit); + SafeDelete(mStructureHLSL); + SafeDelete(mUniformHLSL); +- for (auto &eqFunction : mStructEqualityFunctions) ++ for (auto it = mStructEqualityFunctions.begin(); it != mStructEqualityFunctions.end(); ++it) + { +- SafeDelete(eqFunction); ++ SafeDelete(*it); + } +- for (auto &eqFunction : mArrayEqualityFunctions) ++ for (auto it = mArrayEqualityFunctions.begin(); it != mArrayEqualityFunctions.end(); ++it) + { +- SafeDelete(eqFunction); ++ SafeDelete(*it); + } + } + +@@ -340,17 +340,17 @@ void OutputHLSL::header(const BuiltInFunctionEmulator *builtInFunctionEmulator) + if (!mEqualityFunctions.empty()) + { + out << "\n// Equality functions\n\n"; +- for (const auto &eqFunction : mEqualityFunctions) ++ for (auto it = mEqualityFunctions.cbegin(); it != mEqualityFunctions.cend(); ++it) + { +- out << eqFunction->functionDefinition << "\n"; ++ out << (*it)->functionDefinition << "\n"; + } + } + if (!mArrayAssignmentFunctions.empty()) + { + out << "\n// Assignment functions\n\n"; +- for (const auto &assignmentFunction : mArrayAssignmentFunctions) ++ for (auto it = mArrayAssignmentFunctions.cbegin(); it != mArrayAssignmentFunctions.cend(); ++it) + { +- out << assignmentFunction.functionDefinition << "\n"; ++ out << it->functionDefinition << "\n"; + } + } + +@@ -1858,8 +1858,9 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) + + if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration + { +- for (const auto &seqElement : *sequence) ++ for (auto it = sequence->cbegin(); it != sequence->cend(); ++it) + { ++ const auto &seqElement = *it; + if (isSingleStatement(seqElement)) + { + mUnfoldShortCircuit->traverse(seqElement); +@@ -2941,8 +2942,9 @@ void OutputHLSL::writeDeferredGlobalInitializers(TInfoSinkBase &out) + << "void initializeDeferredGlobals()\n" + << "{\n"; + +- for (const auto &deferredGlobal : mDeferredGlobalInitializers) ++ for (auto it = mDeferredGlobalInitializers.cbegin(); it != mDeferredGlobalInitializers.cend(); ++it) + { ++ const auto &deferredGlobal = *it; + TIntermSymbol *symbol = deferredGlobal.first; + TIntermTyped *expression = deferredGlobal.second; + ASSERT(symbol); +@@ -2967,8 +2969,9 @@ TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) + { + const TFieldList &fields = structure.fields(); + +- for (const auto &eqFunction : mStructEqualityFunctions) ++ for (auto it = mStructEqualityFunctions.cbegin(); it != mStructEqualityFunctions.cend(); ++it) + { ++ auto *eqFunction = *it; + if (eqFunction->structure == &structure) + { + return eqFunction->functionName; +@@ -3021,8 +3024,9 @@ TString OutputHLSL::addStructEqualityFunction(const TStructure &structure) + + TString OutputHLSL::addArrayEqualityFunction(const TType& type) + { +- for (const auto &eqFunction : mArrayEqualityFunctions) ++ for (auto it = mArrayEqualityFunctions.cbegin(); it != mArrayEqualityFunctions.cend(); ++it) + { ++ const auto &eqFunction = *it; + if (eqFunction->type == type) + { + return eqFunction->functionName; +@@ -3072,8 +3076,9 @@ TString OutputHLSL::addArrayEqualityFunction(const TType& type) + + TString OutputHLSL::addArrayAssignmentFunction(const TType& type) + { +- for (const auto &assignFunction : mArrayAssignmentFunctions) ++ for (auto it = mArrayAssignmentFunctions.cbegin(); it != mArrayAssignmentFunctions.cend(); ++it) + { ++ const auto &assignFunction = *it; + if (assignFunction.type == type) + { + return assignFunction.functionName; +diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp +index 5ea039f..1da5fda 100644 +--- a/src/3rdparty/angle/src/libANGLE/Context.cpp ++++ b/src/3rdparty/angle/src/libANGLE/Context.cpp +@@ -158,9 +158,9 @@ Context::~Context() + deleteTransformFeedback(mTransformFeedbackMap.begin()->first); + } + +- for (auto &zeroTexture : mZeroTextures) ++ for (auto it = mZeroTextures.begin(); it != mZeroTextures.end(); ++it) + { +- zeroTexture.second.set(NULL); ++ it->second.set(NULL); + } + mZeroTextures.clear(); + +diff --git a/src/3rdparty/angle/src/libANGLE/Error.h b/src/3rdparty/angle/src/libANGLE/Error.h +index 5812943..896b777 100644 +--- a/src/3rdparty/angle/src/libANGLE/Error.h ++++ b/src/3rdparty/angle/src/libANGLE/Error.h +@@ -10,6 +10,7 @@ + #define LIBANGLE_ERROR_H_ + + #include "angle_gl.h" ++#include "common/platform.h" + #include + + #include +diff --git a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp +index 5fa7513..b1dd4a1 100644 +--- a/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp ++++ b/src/3rdparty/angle/src/libANGLE/Framebuffer.cpp +@@ -48,9 +48,9 @@ Framebuffer::Data::Data(const Caps &caps) + + Framebuffer::Data::~Data() + { +- for (auto &colorAttachment : mColorAttachments) ++ for (auto it = mColorAttachments.begin(); it != mColorAttachments.end(); ++it) + { +- SafeDelete(colorAttachment); ++ SafeDelete(*it); + } + SafeDelete(mDepthAttachment); + SafeDelete(mStencilAttachment); +@@ -66,11 +66,11 @@ FramebufferAttachment *Framebuffer::Data::getReadAttachment() const + + FramebufferAttachment *Framebuffer::Data::getFirstColorAttachment() const + { +- for (FramebufferAttachment *colorAttachment : mColorAttachments) ++ for (auto it = mColorAttachments.cbegin(); it != mColorAttachments.cend(); ++it) + { +- if (colorAttachment != nullptr) ++ if (*it != nullptr) + { +- return colorAttachment; ++ return *it; + } + } + +@@ -115,9 +115,9 @@ void Framebuffer::detachRenderbuffer(GLuint renderbufferId) + + void Framebuffer::detachResourceById(GLenum resourceType, GLuint resourceId) + { +- for (auto &colorAttachment : mData.mColorAttachments) ++ for (auto it = mData.mColorAttachments.begin(); it != mData.mColorAttachments.end(); ++it) + { +- DeleteMatchingAttachment(colorAttachment, resourceType, resourceId); ++ DeleteMatchingAttachment(*it, resourceType, resourceId); + } + + DeleteMatchingAttachment(mData.mDepthAttachment, resourceType, resourceId); +@@ -278,8 +278,9 @@ GLenum Framebuffer::checkStatus(const gl::Data &data) const + int samples = -1; + bool missingAttachment = true; + +- for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments) ++ for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { ++ const auto &colorAttachment = *it; + if (colorAttachment != nullptr) + { + if (colorAttachment->getWidth() == 0 || colorAttachment->getHeight() == 0) +@@ -533,11 +534,11 @@ int Framebuffer::getSamples(const gl::Data &data) const + { + // for a complete framebuffer, all attachments must have the same sample count + // in this case return the first nonzero sample size +- for (const FramebufferAttachment *colorAttachment : mData.mColorAttachments) ++ for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { +- if (colorAttachment != nullptr) ++ if (*it != nullptr) + { +- return colorAttachment->getSamples(); ++ return (*it)->getSamples(); + } + } + } +diff --git a/src/3rdparty/angle/src/libANGLE/State.cpp b/src/3rdparty/angle/src/libANGLE/State.cpp +index 15274c6..4c044d2 100644 +--- a/src/3rdparty/angle/src/libANGLE/State.cpp ++++ b/src/3rdparty/angle/src/libANGLE/State.cpp +@@ -633,8 +633,9 @@ void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) + + void State::initializeZeroTextures(const TextureMap &zeroTextures) + { +- for (const auto &zeroTexture : zeroTextures) ++ for (auto it = zeroTextures.cbegin(); it != zeroTextures.cend(); ++it) + { ++ const auto &zeroTexture = *it; + auto &samplerTextureArray = mSamplerTextures[zeroTexture.first]; + + for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) +diff --git a/src/3rdparty/angle/src/libANGLE/Texture.cpp b/src/3rdparty/angle/src/libANGLE/Texture.cpp +index 2d68bec..cd4584f 100644 +--- a/src/3rdparty/angle/src/libANGLE/Texture.cpp ++++ b/src/3rdparty/angle/src/libANGLE/Texture.cpp +@@ -316,7 +316,7 @@ void Texture::setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInt + } + + Texture::ImageDesc::ImageDesc() +- : ImageDesc(Extents(0, 0, 0), GL_NONE) ++ : size(0, 0, 0), internalFormat(GL_NONE) + { + } + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp +index db5f445..add5d62 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/DisplayD3D.cpp +@@ -276,8 +276,9 @@ bool DisplayD3D::testDeviceLost() + egl::Error DisplayD3D::restoreLostDevice() + { + // Release surface resources to make the Reset() succeed +- for (auto &surface : mSurfaceSet) ++ for (auto it = mSurfaceSet.cbegin(); it != mSurfaceSet.cend(); ++it) + { ++ const auto &surface = *it; + if (surface->getBoundTexture()) + { + surface->releaseTexImage(EGL_BACK_BUFFER); +@@ -292,8 +293,9 @@ egl::Error DisplayD3D::restoreLostDevice() + } + + // Restore any surfaces that may have been lost +- for (const auto &surface : mSurfaceSet) ++ for (auto it = mSurfaceSet.cbegin(); it != mSurfaceSet.cend(); ++it) + { ++ const auto &surface = *it; + SurfaceD3D *surfaceD3D = GetImplAs(surface); + + egl::Error error = surfaceD3D->resetSwapChain(); +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp +index ff9600e..2ce0ce5 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/RendererD3D.cpp +@@ -47,9 +47,9 @@ RendererD3D::~RendererD3D() + void RendererD3D::cleanup() + { + mScratchMemoryBuffer.resize(0); +- for (auto &incompleteTexture : mIncompleteTextures) ++ for (auto it = mIncompleteTextures.begin(); it != mIncompleteTextures.end(); ++it) + { +- incompleteTexture.second.set(NULL); ++ it->second.set(NULL); + } + mIncompleteTextures.clear(); + } +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp +index ab2a902..da01f32 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp +@@ -64,8 +64,9 @@ static gl::Error InvalidateAttachmentSwizzles(const gl::FramebufferAttachment *a + + gl::Error Framebuffer11::invalidateSwizzles() const + { +- for (gl::FramebufferAttachment *colorAttachment : mData.mColorAttachments) ++ for (auto it = mData.mColorAttachments.cbegin(); it != mData.mColorAttachments.cend(); ++it) + { ++ gl::FramebufferAttachment *colorAttachment = *it; + gl::Error error = InvalidateAttachmentSwizzles(colorAttachment); + if (error.isError()) + { +-- +2.1.4 + diff --git a/src/angle/patches/0004-ANGLE-Dynamically-load-D3D-compiler-from-a-list.patch b/src/angle/patches/0004-ANGLE-Dynamically-load-D3D-compiler-from-a-list.patch new file mode 100644 index 0000000000..ff93920317 --- /dev/null +++ b/src/angle/patches/0004-ANGLE-Dynamically-load-D3D-compiler-from-a-list.patch @@ -0,0 +1,61 @@ +From bbb62a69dd2b49d7cc4214937077c22b6997ffac Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Fri, 27 Mar 2015 17:27:38 +0200 +Subject: [PATCH 4/5] ANGLE: Dynamically load D3D compiler from a list + +If the default compiler cannot be found, load it from a list of DLL names, +including a non-versioned proxy DLL provided by Qt. On Desktop Windows, +the default compiler can also be specified by an environment variable, +QT_D3DCOMPILER_DLL. + +Change-Id: I0d7a8a8a36cc571836f8fa59ea14513b9b19c19b +--- + .../src/libANGLE/renderer/d3d/HLSLCompiler.cpp | 25 ++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp +index 9c72d6f..8961a36 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/HLSLCompiler.cpp +@@ -12,6 +12,10 @@ + + #include "third_party/trace_event/trace_event.h" + ++#ifndef QT_D3DCOMPILER_DLL ++#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL ++#endif ++ + // Definitions local to the translation unit + namespace + { +@@ -143,6 +147,27 @@ bool HLSLCompiler::initialize() + } + #endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES + ++ // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL ++ const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); ++ if (!defaultCompiler) ++ defaultCompiler = QT_D3DCOMPILER_DLL; ++ ++ const wchar_t *compilerDlls[] = { ++ defaultCompiler, ++ L"d3dcompiler_47.dll", ++ L"d3dcompiler_46.dll", ++ L"d3dcompiler_43.dll", ++ 0 ++ }; ++ ++ // Load the first available known compiler DLL ++ for (int i = 0; compilerDlls[i]; ++i) ++ { ++ mD3DCompilerModule = LoadLibrary(compilerDlls[i]); ++ if (mD3DCompilerModule) ++ break; ++ } ++ + if (!mD3DCompilerModule) + { + // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. +-- +2.1.4 + diff --git a/src/angle/patches/0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch b/src/angle/patches/0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch deleted file mode 100644 index 45a3f17cca..0000000000 --- a/src/angle/patches/0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 3a39939b5eba9f788789961c4800ba62618f758c Mon Sep 17 00:00:00 2001 -From: Friedemann Kleint -Date: Tue, 11 Nov 2014 10:26:32 +0200 -Subject: [PATCH 04/16] Make it possible to link ANGLE statically for - single-thread use. - -Fix exports and provide static instances of thread-local -data depending on QT_OPENGL_ES_2_ANGLE_STATIC. - -Change-Id: Ifab25a820adf5953bb3b09036de53dbf7f1a7fd5 ---- - src/3rdparty/angle/include/KHR/khrplatform.h | 2 +- - src/3rdparty/angle/src/libEGL/main.cpp | 10 ++++++++++ - src/3rdparty/angle/src/libGLESv2/main.cpp | 10 ++++++++-- - 3 files changed, 19 insertions(+), 3 deletions(-) - -diff --git a/src/3rdparty/angle/include/KHR/khrplatform.h b/src/3rdparty/angle/include/KHR/khrplatform.h -index c9e6f17..1ac2d3f 100644 ---- a/src/3rdparty/angle/include/KHR/khrplatform.h -+++ b/src/3rdparty/angle/include/KHR/khrplatform.h -@@ -97,7 +97,7 @@ - *------------------------------------------------------------------------- - * This precedes the return type of the function in the function prototype. - */ --#if defined(_WIN32) && !defined(__SCITECH_SNAP__) -+#if defined(_WIN32) && !defined(__SCITECH_SNAP__) && !defined(QT_OPENGL_ES_2_ANGLE_STATIC) - # define KHRONOS_APICALL __declspec(dllimport) - #elif defined (__SYMBIAN32__) - # define KHRONOS_APICALL IMPORT_C -diff --git a/src/3rdparty/angle/src/libEGL/main.cpp b/src/3rdparty/angle/src/libEGL/main.cpp -index d1489f2..e88cad7 100644 ---- a/src/3rdparty/angle/src/libEGL/main.cpp -+++ b/src/3rdparty/angle/src/libEGL/main.cpp -@@ -49,6 +49,8 @@ void DeallocateCurrent() - - } - -+#ifndef QT_OPENGL_ES_2_ANGLE_STATIC -+ - extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) - { - switch (reason) -@@ -108,16 +110,24 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved - return TRUE; - } - -+#endif // !QT_OPENGL_ES_2_ANGLE_STATIC -+ - namespace egl - { - - Current *GetCurrentData() - { -+#ifndef QT_OPENGL_ES_2_ANGLE_STATIC - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - - // ANGLE issue 488: when the dll is loaded after thread initialization, - // thread local storage (current) might not exist yet. - return (current ? current : AllocateCurrent()); -+#else -+ // No precautions for thread safety taken as ANGLE is used single-threaded in Qt. -+ static Current current = { EGL_SUCCESS, EGL_OPENGL_ES_API, EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE }; -+ return ¤t; -+#endif - } - - void recordError(const Error &error) -diff --git a/src/3rdparty/angle/src/libGLESv2/main.cpp b/src/3rdparty/angle/src/libGLESv2/main.cpp -index 3ac00d5..00f63ae 100644 ---- a/src/3rdparty/angle/src/libGLESv2/main.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/main.cpp -@@ -74,7 +74,7 @@ void DeallocateCurrent() - - } - --#ifdef ANGLE_PLATFORM_WINDOWS -+#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(QT_OPENGL_ES_2_ANGLE_STATIC) - extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) - { - switch (reason) -@@ -117,18 +117,24 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved - - return TRUE; - } --#endif -+#endif // ANGLE_PLATFORM_WINDOWS && !QT_OPENGL_ES_2_ANGLE_STATIC - - namespace gl - { - - Current *GetCurrentData() - { -+#ifndef QT_OPENGL_ES_2_ANGLE_STATIC - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - - // ANGLE issue 488: when the dll is loaded after thread initialization, - // thread local storage (current) might not exist yet. - return (current ? current : AllocateCurrent()); -+#else -+ // No precautions for thread safety taken as ANGLE is used single-threaded in Qt. -+ static Current current = { 0, 0 }; -+ return ¤t; -+#endif - } - - void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface) --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0005-ANGLE-Add-support-for-querying-platform-device.patch b/src/angle/patches/0005-ANGLE-Add-support-for-querying-platform-device.patch new file mode 100644 index 0000000000..8a5bffebe4 --- /dev/null +++ b/src/angle/patches/0005-ANGLE-Add-support-for-querying-platform-device.patch @@ -0,0 +1,84 @@ +From f6bfeecf2c7d14e9fd2b637e6ce9555489e3a256 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Fri, 27 Mar 2015 17:58:41 +0200 +Subject: [PATCH 5/5] ANGLE: Add support for querying platform device + +The EGL_EXT_device_base extension allows for querying the platform +device of the graphics hardware via eglQueryDisplayAttribEXT(). +As that extension is not supported by ANGLE, this patch adds similar +functionality to the existing eglQuerySurfacePointerANGLE API. When +EGL_DEVICE_EXT is passed as the queried attribute, the underlying +D3D/DXGI device pointer is passed back to the caller via the value +argument. + +The D3D device is needed for video support in QtMultimedia as well as +the IDXGIDevice3::Trim() calls required by the Windows Store. + +Change-Id: Ibdf228d81d6604e56db9dd8597d7cd2983ebc428 +--- + src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 7 +++++-- + src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h | 1 + + src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 5 +++++ + src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h | 2 ++ + 4 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +index a3c457d..4fde295 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +@@ -385,8 +385,11 @@ EGLint SurfaceD3D::isPostSubBufferSupported() const + + egl::Error SurfaceD3D::querySurfacePointerANGLE(EGLint attribute, void **value) + { +- ASSERT(attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE); +- *value = mSwapChain->getShareHandle(); ++ ASSERT(attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || attribute == EGL_DEVICE_EXT); ++ if (attribute == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE) ++ *value = mSwapChain->getShareHandle(); ++ else if (attribute == EGL_DEVICE_EXT) ++ *value = mSwapChain->getDevice(); + return egl::Error(EGL_SUCCESS); + } + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h +index 3bde92e..da36e52 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SwapChainD3D.h +@@ -41,6 +41,7 @@ class SwapChainD3D : angle::NonCopyable + virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0; + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0; + virtual void recreate() = 0; ++ virtual void *getDevice() { return NULL; } + + virtual RenderTargetD3D *getColorRenderTarget() = 0; + virtual RenderTargetD3D *getDepthStencilRenderTarget() = 0; +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +index bcb2505..298f3cc 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +@@ -703,4 +703,9 @@ void SwapChain11::recreate() + // possibly should use this method instead of reset + } + ++void *rx::SwapChain11::getDevice() ++{ ++ return mRenderer->getDevice(); ++} ++ + } +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h +index 4ea6778..48c808a 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h +@@ -43,6 +43,8 @@ class SwapChain11 : public SwapChainD3D + EGLint getWidth() const { return mWidth; } + EGLint getHeight() const { return mHeight; } + ++ virtual void *getDevice(); ++ + static SwapChain11 *makeSwapChain11(SwapChainD3D *swapChain); + + private: +-- +2.1.4 + diff --git a/src/angle/patches/0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t.patch b/src/angle/patches/0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t.patch deleted file mode 100644 index 801db67682..0000000000 --- a/src/angle/patches/0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 4a5960465d1632ab089320fcbba4af294d58fd9a Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Fri, 7 Nov 2014 14:05:36 +0200 -Subject: [PATCH 08/16] ANGLE: Dynamically load D3D compiler from a list or the - environment - -If the default compiler cannot be found, load it from a list of DLL names, -including a non-versioned proxy DLL provided by Qt. On Desktop Windows, -the default compiler can also be specified by an environment variable, -QT_D3DCOMPILER_DLL. - -Change-Id: I0d7a8a8a36cc571836f8fa59ea14513b9b19c19b ---- - .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 27 ++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -index bfeaf51..9d003b4 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -@@ -11,6 +11,10 @@ - #include "common/features.h" - #include "common/utilities.h" - -+#ifndef QT_D3DCOMPILER_DLL -+#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL -+#endif -+ - // Definitions local to the translation unit - namespace - { -@@ -132,6 +136,29 @@ bool HLSLCompiler::initialize() - } - #endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES - -+ // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL -+ const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); -+ if (!defaultCompiler) -+ defaultCompiler = QT_D3DCOMPILER_DLL; -+ -+ const wchar_t *compilerDlls[] = { -+ defaultCompiler, -+ L"d3dcompiler_47.dll", -+ L"d3dcompiler_46.dll", -+ L"d3dcompiler_45.dll", -+ L"d3dcompiler_44.dll", -+ L"d3dcompiler_43.dll", -+ 0 -+ }; -+ -+ // Load the first available known compiler DLL -+ for (int i = 0; compilerDlls[i]; ++i) -+ { -+ mD3DCompilerModule = LoadLibrary(compilerDlls[i]); -+ if (mD3DCompilerModule) -+ break; -+ } -+ - if (!mD3DCompilerModule) - { - // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0009-ANGLE-Support-WinRT.patch b/src/angle/patches/0009-ANGLE-Support-WinRT.patch deleted file mode 100644 index a38fb4ea13..0000000000 --- a/src/angle/patches/0009-ANGLE-Support-WinRT.patch +++ /dev/null @@ -1,837 +0,0 @@ -From 4d150ba3814f824f1cadaedbdb83d0ac79d0e1a2 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Fri, 14 Nov 2014 09:28:11 +0200 -Subject: [PATCH 09/16] ANGLE: Support WinRT - -Tweak ANGLE's existing support for WinRT to allow for changing the -window size on Windows Phone. - -Change-Id: Ia312b5318b977838a2953f1f530487cbf24974bc ---- - src/3rdparty/angle/include/EGL/eglplatform.h | 5 +- - src/3rdparty/angle/src/common/NativeWindow.h | 7 +- - src/3rdparty/angle/src/common/platform.h | 4 +- - .../angle/src/common/win32/NativeWindow.cpp | 2 +- - .../src/common/winrt/CoreWindowNativeWindow.cpp | 87 +++++++++++++--------- - .../src/common/winrt/CoreWindowNativeWindow.h | 48 ++---------- - .../src/common/winrt/InspectableNativeWindow.cpp | 8 +- - .../src/common/winrt/InspectableNativeWindow.h | 7 +- - .../common/winrt/SwapChainPanelNativeWindow.cpp | 2 +- - .../src/common/winrt/SwapChainPanelNativeWindow.h | 2 +- - src/3rdparty/angle/src/libEGL/Display.h | 1 + - src/3rdparty/angle/src/libEGL/Surface.cpp | 45 ++++++++--- - src/3rdparty/angle/src/libEGL/Surface.h | 4 + - src/3rdparty/angle/src/libEGL/libEGL.cpp | 20 +++++ - .../src/libGLESv2/renderer/d3d/d3d11/Renderer11.h | 2 +- - .../libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp | 74 +++++++++++------- - .../src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h | 2 + - 17 files changed, 189 insertions(+), 131 deletions(-) - -diff --git a/src/3rdparty/angle/include/EGL/eglplatform.h b/src/3rdparty/angle/include/EGL/eglplatform.h -index 3793e57..2eb3674 100644 ---- a/src/3rdparty/angle/include/EGL/eglplatform.h -+++ b/src/3rdparty/angle/include/EGL/eglplatform.h -@@ -73,13 +73,14 @@ - #endif - #include - --typedef HDC EGLNativeDisplayType; - typedef HBITMAP EGLNativePixmapType; - --#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP /* Windows Store */ -+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) /* Windows Store */ - #include -+typedef IInspectable* EGLNativeDisplayType; - typedef IInspectable* EGLNativeWindowType; - #else -+typedef HDC EGLNativeDisplayType; - typedef HWND EGLNativeWindowType; - #endif - -diff --git a/src/3rdparty/angle/src/common/NativeWindow.h b/src/3rdparty/angle/src/common/NativeWindow.h -index dc5fc8f..9e93aea 100644 ---- a/src/3rdparty/angle/src/common/NativeWindow.h -+++ b/src/3rdparty/angle/src/common/NativeWindow.h -@@ -44,10 +44,11 @@ typedef IDXGIFactory DXGIFactory; - - namespace rx - { -+ - class NativeWindow - { -- public: -- explicit NativeWindow(EGLNativeWindowType window); -+public: -+ explicit NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display); - - bool initialize(); - bool getClientRect(LPRECT rect); -@@ -58,9 +59,11 @@ class NativeWindow - DXGISwapChain** swapChain); - - inline EGLNativeWindowType getNativeWindow() const { return mWindow; } -+ inline EGLNativeDisplayType getNativeDisplay() const { return mDisplay; } - - private: - EGLNativeWindowType mWindow; -+ EGLNativeDisplayType mDisplay; - - #if defined(ANGLE_ENABLE_WINDOWS_STORE) - std::shared_ptr mImpl; -diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index cd12dba..0065ec7 100644 ---- a/src/3rdparty/angle/src/common/platform.h -+++ b/src/3rdparty/angle/src/common/platform.h -@@ -34,7 +34,7 @@ - #endif - - #ifdef ANGLE_PLATFORM_WINDOWS --# if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP -+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - # define ANGLE_ENABLE_WINDOWS_STORE 1 - # endif - # ifndef STRICT -@@ -67,7 +67,9 @@ - # if defined(ANGLE_ENABLE_WINDOWS_STORE) - # include - # if defined(_DEBUG) -+# if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) - # include -+# endif - # include - # endif - # endif -diff --git a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp -index aa2bfa4..2440747 100644 ---- a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp -+++ b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp -@@ -16,7 +16,7 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window) - return (IsWindow(window) == TRUE); - } - --NativeWindow::NativeWindow(EGLNativeWindowType window) : mWindow(window) -+NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) : mWindow(window), mDisplay(display) - { - } - -diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp -index 0e63fa5..9b65c15 100644 ---- a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp -+++ b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp -@@ -6,21 +6,25 @@ - - // CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types. - --#include -+#include - #include "common/winrt/CoreWindowNativeWindow.h" - using namespace ABI::Windows::Foundation::Collections; - - namespace rx - { -+ -+typedef ITypedEventHandler SizeChangedHandler; -+ - CoreWindowNativeWindow::~CoreWindowNativeWindow() - { - unregisterForSizeChangeEvents(); - } - --bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) -+bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) - { - ComPtr props = propertySet; - ComPtr win = window; -+ ComPtr displayInformation = display; - SIZE swapChainSize = {}; - bool swapChainSizeSpecified = false; - HRESULT result = S_OK; -@@ -47,6 +51,29 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet - - if (SUCCEEDED(result)) - { -+ result = displayInformation.As(&mDisplayInformation); -+ } -+ -+ if (SUCCEEDED(result)) -+ { -+#if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -+ ComPtr displayInformation2; -+ result = mDisplayInformation.As(&displayInformation2); -+ ASSERT(SUCCEEDED(result)); -+ -+ result = displayInformation2->get_RawPixelsPerViewPixel(&mScaleFactor); -+ ASSERT(SUCCEEDED(result)); -+#else -+ ABI::Windows::Graphics::Display::ResolutionScale resolutionScale; -+ result = mDisplayInformation->get_ResolutionScale(&resolutionScale); -+ ASSERT(SUCCEEDED(result)); -+ -+ mScaleFactor = DOUBLE(resolutionScale) / 100.0; -+#endif -+ } -+ -+ if (SUCCEEDED(result)) -+ { - // If a swapchain size is specfied, then the automatic resize - // behaviors implemented by the host should be disabled. The swapchain - // will be still be scaled when being rendered to fit the bounds -@@ -60,7 +87,14 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet - } - else - { -- result = GetCoreWindowSizeInPixels(mCoreWindow, &mClientRect); -+ ABI::Windows::Foundation::Rect rect; -+ HRESULT result = mCoreWindow->get_Bounds(&rect); -+ if (SUCCEEDED(result)) -+ { -+ LONG width = std::floor(rect.Width * mScaleFactor + 0.5); -+ LONG height = std::floor(rect.Height * mScaleFactor + 0.5); -+ mClientRect = { 0, 0, width, height }; -+ } - } - } - -@@ -76,12 +110,8 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet - - bool CoreWindowNativeWindow::registerForSizeChangeEvents() - { -- ComPtr sizeChangedHandler; -- HRESULT result = Microsoft::WRL::MakeAndInitialize(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); -- if (SUCCEEDED(result)) -- { -- result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); -- } -+ HRESULT result = mCoreWindow->add_SizeChanged(Callback(this, &CoreWindowNativeWindow::onSizeChanged).Get(), -+ &mSizeChangedEventToken); - - if (SUCCEEDED(result)) - { -@@ -126,7 +156,7 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor - if (SUCCEEDED(result)) - { - --#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) -+#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // This block is disabled for Qt applications, as the resize events are expected - // Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On - // other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed - // (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations. -@@ -152,36 +182,19 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor - return result; - } - --HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize) -+// Basically, this shouldn't be used on Phone -+HRESULT CoreWindowNativeWindow::onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *e) - { -- ABI::Windows::Foundation::Rect bounds; -- HRESULT result = coreWindow->get_Bounds(&bounds); -- if (SUCCEEDED(result)) -+ ABI::Windows::Foundation::Size size; -+ if (SUCCEEDED(e->get_Size(&size))) - { -- *windowSize = { 0, 0, ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) }; -+ SIZE windowSizeInPixels = { -+ std::floor(size.Width * mScaleFactor + 0.5), -+ std::floor(size.Height * mScaleFactor + 0.5) -+ }; -+ setNewClientSize(windowSizeInPixels); - } - -- return result; --} -- --static float GetLogicalDpi() --{ -- ComPtr displayProperties; -- float dpi = 96.0f; -- -- if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) -- { -- if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) -- { -- return dpi; -- } -- } -- return dpi; --} -- --long ConvertDipsToPixels(float dips) --{ -- static const float dipsPerInch = 96.0f; -- return lround((dips * GetLogicalDpi() / dipsPerInch)); -+ return S_OK; - } - } -diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h -index 0c6222d..1c55124 100644 ---- a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h -+++ b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h -@@ -11,67 +11,29 @@ - - #include "common/winrt/InspectableNativeWindow.h" - #include -- --typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t IWindowSizeChangedEventHandler; -+#include - - namespace rx - { --long ConvertDipsToPixels(float dips); - - class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this - { - public: - ~CoreWindowNativeWindow(); - -- bool initialize(EGLNativeWindowType window, IPropertySet *propertySet); -+ bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet); - bool registerForSizeChangeEvents(); - void unregisterForSizeChangeEvents(); - HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); - - private: -+ HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); -+ - ComPtr mCoreWindow; -+ ComPtr mDisplayInformation; - ComPtr> mPropertyMap; - }; - --[uuid(7F924F66-EBAE-40E5-A10B-B8F35E245190)] --class CoreWindowSizeChangedHandler : -- public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler> --{ -- public: -- CoreWindowSizeChangedHandler() { } -- HRESULT RuntimeClassInitialize(std::shared_ptr host) -- { -- if (!host) -- { -- return E_INVALIDARG; -- } -- -- mHost = host; -- return S_OK; -- } -- -- // IWindowSizeChangedEventHandler -- IFACEMETHOD(Invoke)(ABI::Windows::UI::Core::ICoreWindow *sender, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *sizeChangedEventArgs) -- { -- std::shared_ptr host = mHost.lock(); -- if (host) -- { -- ABI::Windows::Foundation::Size windowSize; -- if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) -- { -- SIZE windowSizeInPixels = { ConvertDipsToPixels(windowSize.Width), ConvertDipsToPixels(windowSize.Height) }; -- host->setNewClientSize(windowSizeInPixels); -- } -- } -- -- return S_OK; -- } -- -- private: -- std::weak_ptr mHost; --}; -- --HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize); - } - - #endif // COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_ -diff --git a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp -index c062a48..0589f6d 100644 ---- a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp -+++ b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp -@@ -11,9 +11,9 @@ - - namespace rx - { --NativeWindow::NativeWindow(EGLNativeWindowType window) -+NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) -+ : mWindow(window), mDisplay(display) - { -- mWindow = window; - } - - bool NativeWindow::initialize() -@@ -40,7 +40,7 @@ bool NativeWindow::initialize() - mImpl = std::make_shared(); - if (mImpl) - { -- return mImpl->initialize(mWindow, propertySet.Get()); -+ return mImpl->initialize(mWindow, mDisplay, propertySet.Get()); - } - } - else if (IsSwapChainPanel(mWindow, &swapChainPanel)) -@@ -48,7 +48,7 @@ bool NativeWindow::initialize() - mImpl = std::make_shared(); - if (mImpl) - { -- return mImpl->initialize(mWindow, propertySet.Get()); -+ return mImpl->initialize(mWindow, mDisplay, propertySet.Get()); - } - } - else -diff --git a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h -index c625348..402941a 100644 ---- a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h -+++ b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h -@@ -32,13 +32,14 @@ class InspectableNativeWindow - mRequiresSwapChainScaling(false), - mClientRectChanged(false), - mClientRect({0,0,0,0}), -- mNewClientRect({0,0,0,0}) -+ mNewClientRect({0,0,0,0}), -+ mScaleFactor(1.0) - { - mSizeChangedEventToken.value = 0; - } - virtual ~InspectableNativeWindow(){} - -- virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0; -+ virtual bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) = 0; - virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0; - virtual bool registerForSizeChangeEvents() = 0; - virtual void unregisterForSizeChangeEvents() = 0; -@@ -49,6 +50,7 @@ class InspectableNativeWindow - if (mClientRectChanged && mSupportsSwapChainResize) - { - mClientRect = mNewClientRect; -+ mClientRectChanged = false; - } - - *rect = mClientRect; -@@ -76,6 +78,7 @@ protected: - RECT mClientRect; - RECT mNewClientRect; - bool mClientRectChanged; -+ DOUBLE mScaleFactor; - - EventRegistrationToken mSizeChangedEventToken; - }; -diff --git a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp -index 4e4fb6d..268dfbd 100644 ---- a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp -+++ b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp -@@ -18,7 +18,7 @@ SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow() - unregisterForSizeChangeEvents(); - } - --bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) -+bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) - { - ComPtr props = propertySet; - ComPtr win = window; -diff --git a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h -index e88f554..5bbf274 100644 ---- a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h -+++ b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h -@@ -18,7 +18,7 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e - public: - ~SwapChainPanelNativeWindow(); - -- bool initialize(EGLNativeWindowType window, IPropertySet *propertySet); -+ bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet); - bool registerForSizeChangeEvents(); - void unregisterForSizeChangeEvents(); - HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); -diff --git a/src/3rdparty/angle/src/libEGL/Display.h b/src/3rdparty/angle/src/libEGL/Display.h -index 378323a..b3ffcc8 100644 ---- a/src/3rdparty/angle/src/libEGL/Display.h -+++ b/src/3rdparty/angle/src/libEGL/Display.h -@@ -67,6 +67,7 @@ class Display - - const char *getExtensionString() const; - const char *getVendorString() const; -+ EGLNativeDisplayType getDisplayId() const { return mDisplayId; } - - private: - DISALLOW_COPY_AND_ASSIGN(Display); -diff --git a/src/3rdparty/angle/src/libEGL/Surface.cpp b/src/3rdparty/angle/src/libEGL/Surface.cpp -index 3414656..b664a85 100644 ---- a/src/3rdparty/angle/src/libEGL/Surface.cpp -+++ b/src/3rdparty/angle/src/libEGL/Surface.cpp -@@ -31,7 +31,7 @@ namespace egl - { - - Surface::Surface(Display *display, const Config *config, EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported) -- : mDisplay(display), mConfig(config), mNativeWindow(window), mPostSubBufferSupported(postSubBufferSupported) -+ : mDisplay(display), mConfig(config), mNativeWindow(window, display->getDisplayId()), mPostSubBufferSupported(postSubBufferSupported) - { - //TODO(jmadill): MANGLE refactor. (note, can't call makeRendererD3D because of dll export issues) - mRenderer = static_cast(mDisplay->getRenderer()); -@@ -47,6 +47,8 @@ Surface::Surface(Display *display, const Config *config, EGLNativeWindowType win - mSwapInterval = -1; - mWidth = width; - mHeight = height; -+ mFixedWidth = mWidth; -+ mFixedHeight = mHeight; - setSwapInterval(1); - mFixedSize = fixedSize; - -@@ -54,7 +56,7 @@ Surface::Surface(Display *display, const Config *config, EGLNativeWindowType win - } - - Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType) -- : mDisplay(display), mNativeWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) -+ : mDisplay(display), mNativeWindow(NULL, NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) - { - //TODO(jmadill): MANGLE refactor. (note, can't call makeRendererD3D because of dll export issues) - mRenderer = static_cast(mDisplay->getRenderer()); -@@ -71,6 +73,8 @@ Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGL - setSwapInterval(1); - // This constructor is for offscreen surfaces, which are always fixed-size. - mFixedSize = EGL_TRUE; -+ mFixedWidth = mWidth; -+ mFixedHeight = mHeight; - } - - Surface::~Surface() -@@ -157,10 +161,13 @@ Error Surface::resetSwapChain() - - Error Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight) - { -- ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); - ASSERT(mSwapChain); - -- EGLint status = mSwapChain->resize(std::max(1, backbufferWidth), std::max(1, backbufferHeight)); -+#if !defined(ANGLE_ENABLE_WINDOWS_STORE) -+ backbufferWidth = std::max(1, backbufferWidth); -+ backbufferHeight = std::max(1, backbufferHeight); -+#endif -+ EGLint status = mSwapChain->resize(backbufferWidth, backbufferHeight); - - if (status == EGL_CONTEXT_LOST) - { -@@ -209,14 +216,14 @@ Error Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) - return Error(EGL_SUCCESS); - } - -- if (x + width > mWidth) -+ if (x + width > abs(mWidth)) - { -- width = mWidth - x; -+ width = abs(mWidth) - x; - } - -- if (y + height > mHeight) -+ if (y + height > abs(mHeight)) - { -- height = mHeight - y; -+ height = abs(mHeight) - y; - } - - if (width == 0 || height == 0) -@@ -224,6 +231,9 @@ Error Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) - return Error(EGL_SUCCESS); - } - -+ ASSERT(width > 0); -+ ASSERT(height > 0); -+ - EGLint status = mSwapChain->swapRect(x, y, width, height); - - if (status == EGL_CONTEXT_LOST) -@@ -352,6 +362,13 @@ bool Surface::checkForOutOfDateSwapChain() - sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); - } - -+ if (mFixedSize && (mWidth != mFixedWidth || mHeight != mFixedHeight)) -+ { -+ clientWidth = mFixedWidth; -+ clientHeight = mFixedHeight; -+ sizeDirty = true; -+ } -+ - bool wasDirty = (mSwapIntervalDirty || sizeDirty); - - if (mSwapIntervalDirty) -@@ -378,7 +395,7 @@ bool Surface::checkForOutOfDateSwapChain() - - Error Surface::swap() - { -- return swapRect(0, 0, mWidth, mHeight); -+ return swapRect(0, 0, abs(mWidth), abs(mHeight)); - } - - Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) -@@ -471,6 +488,16 @@ EGLint Surface::isFixedSize() const - return mFixedSize; - } - -+void Surface::setFixedWidth(EGLint width) -+{ -+ mFixedWidth = width; -+} -+ -+void Surface::setFixedHeight(EGLint height) -+{ -+ mFixedHeight = height; -+} -+ - EGLenum Surface::getFormat() const - { - return mConfig->mRenderTargetFormat; -diff --git a/src/3rdparty/angle/src/libEGL/Surface.h b/src/3rdparty/angle/src/libEGL/Surface.h -index 662fe21..46382d0 100644 ---- a/src/3rdparty/angle/src/libEGL/Surface.h -+++ b/src/3rdparty/angle/src/libEGL/Surface.h -@@ -70,6 +70,8 @@ class Surface - virtual gl::Texture2D *getBoundTexture() const; - - EGLint isFixedSize() const; -+ void setFixedWidth(EGLint width); -+ void setFixedHeight(EGLint height); - - private: - DISALLOW_COPY_AND_ASSIGN(Surface); -@@ -91,6 +93,8 @@ class Surface - const egl::Config *mConfig; // EGL config surface was created with - EGLint mHeight; // Height of surface - EGLint mWidth; // Width of surface -+ EGLint mFixedHeight; // Pending height of the surface -+ EGLint mFixedWidth; // Pending width of the surface - // EGLint horizontalResolution; // Horizontal dot pitch - // EGLint verticalResolution; // Vertical dot pitch - // EGLBoolean largestPBuffer; // If true, create largest pbuffer possible -diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp -index 6110698..dc20d85 100644 ---- a/src/3rdparty/angle/src/libEGL/libEGL.cpp -+++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp -@@ -706,6 +706,26 @@ EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint - return EGL_FALSE; - } - -+ switch (attribute) -+ { -+ case EGL_WIDTH: -+ if (!eglSurface->isFixedSize() || !value) { -+ recordError(egl::Error(EGL_BAD_PARAMETER)); -+ return EGL_FALSE; -+ } -+ eglSurface->setFixedWidth(value); -+ return EGL_TRUE; -+ case EGL_HEIGHT: -+ if (!eglSurface->isFixedSize() || !value) { -+ recordError(egl::Error(EGL_BAD_PARAMETER)); -+ return EGL_FALSE; -+ } -+ eglSurface->setFixedHeight(value); -+ return EGL_TRUE; -+ default: -+ break; -+ } -+ - UNIMPLEMENTED(); // FIXME - - recordError(egl::Error(EGL_SUCCESS)); -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -index 1655f1d..c789cae 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -@@ -231,7 +231,7 @@ class Renderer11 : public RendererD3D - - HMODULE mD3d11Module; - HMODULE mDxgiModule; -- HDC mDc; -+ EGLNativeDisplayType mDc; - std::vector mAvailableFeatureLevels; - D3D_DRIVER_TYPE mDriverType; - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -index 834b7bd..52c8a81 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -@@ -42,6 +42,8 @@ SwapChain11::SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE - mPassThroughPS = NULL; - mWidth = -1; - mHeight = -1; -+ mRotateL = false; -+ mRotateR = false; - mSwapInterval = 0; - mAppCreatedShareHandle = mShareHandle != NULL; - mPassThroughResourcesInit = false; -@@ -92,10 +94,11 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - ASSERT(device != NULL); - - // D3D11 does not allow zero size textures -- ASSERT(backbufferWidth >= 1); -- ASSERT(backbufferHeight >= 1); -+ ASSERT(backbufferWidth != 0); -+ ASSERT(backbufferHeight != 0); - - // Preserve the render target content -+#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; - if (previousOffscreenTexture) - { -@@ -103,6 +106,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - } - const int previousWidth = mWidth; - const int previousHeight = mHeight; -+#endif - - releaseOffscreenTexture(); - -@@ -136,8 +140,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; - mOffscreenTexture->GetDesc(&offscreenTextureDesc); - -- if (offscreenTextureDesc.Width != (UINT)backbufferWidth || -- offscreenTextureDesc.Height != (UINT)backbufferHeight || -+ if (offscreenTextureDesc.Width != UINT(abs(backbufferWidth)) || -+ offscreenTextureDesc.Height != UINT(abs(backbufferHeight)) || - offscreenTextureDesc.Format != backbufferFormatInfo.texFormat || - offscreenTextureDesc.MipLevels != 1 || - offscreenTextureDesc.ArraySize != 1) -@@ -152,8 +156,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); - - D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; -- offscreenTextureDesc.Width = backbufferWidth; -- offscreenTextureDesc.Height = backbufferHeight; -+ offscreenTextureDesc.Width = abs(backbufferWidth); -+ offscreenTextureDesc.Height = abs(backbufferHeight); - offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; - offscreenTextureDesc.MipLevels = 1; - offscreenTextureDesc.ArraySize = 1; -@@ -233,8 +237,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - if (mDepthBufferFormat != GL_NONE) - { - D3D11_TEXTURE2D_DESC depthStencilTextureDesc; -- depthStencilTextureDesc.Width = backbufferWidth; -- depthStencilTextureDesc.Height = backbufferHeight; -+ depthStencilTextureDesc.Width = abs(backbufferWidth); -+ depthStencilTextureDesc.Height = abs(backbufferHeight); - depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; - depthStencilTextureDesc.MipLevels = 1; - depthStencilTextureDesc.ArraySize = 1; -@@ -286,6 +290,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - mWidth = backbufferWidth; - mHeight = backbufferHeight; - -+#if !defined(ANGLE_ENABLE_WINDOWS_STORE) - if (previousOffscreenTexture != NULL) - { - D3D11_BOX sourceBox = {0}; -@@ -307,6 +312,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - swapRect(0, 0, mWidth, mHeight); - } - } -+#endif - - return EGL_SUCCESS; - } -@@ -320,8 +326,16 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) - return EGL_BAD_ACCESS; - } - -+ // Windows Phone works around the rotation limitation by using negative values for the swap chain size -+#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) -+ mRotateL = backbufferWidth < 0; // Landscape/InvertedLandscape -+ mRotateR = backbufferHeight < 0; // InvertedPortrait/InvertedLandscape -+ backbufferWidth = abs(backbufferWidth); -+ backbufferHeight = abs(backbufferHeight); -+#endif -+ - // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains -- if (backbufferWidth < 1 || backbufferHeight < 1) -+ if (backbufferWidth == 0 || backbufferHeight == 0) - { - return EGL_SUCCESS; - } -@@ -329,6 +343,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) - // Can only call resize if we have already created our swap buffer and resources - ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); - -+#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // The swap chain is not directly resized on Windows Phone - SafeRelease(mBackBufferTexture); - SafeRelease(mBackBufferRTView); - -@@ -366,6 +381,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) - { - d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); - } -+#endif - - return resetOffscreenTexture(backbufferWidth, backbufferHeight); - } -@@ -512,16 +528,6 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - -- // Set vertices -- D3D11_MAPPED_SUBRESOURCE mappedResource; -- HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); -- if (FAILED(result)) -- { -- return EGL_BAD_ACCESS; -- } -- -- d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); -- - // Create a quad in homogeneous coordinates - float x1 = (x / float(mWidth)) * 2.0f - 1.0f; - float y1 = (y / float(mHeight)) * 2.0f - 1.0f; -@@ -533,10 +539,23 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) - float u2 = (x + width) / float(mWidth); - float v2 = (y + height) / float(mHeight); - -- d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, u1, v1); -- d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2); -- d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); -- d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); -+ const bool rotateL = mRotateL; -+ const bool rotateR = mRotateR; -+ -+ // Set vertices -+ D3D11_MAPPED_SUBRESOURCE mappedResource; -+ HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); -+ if (FAILED(result)) -+ { -+ return EGL_BAD_ACCESS; -+ } -+ -+ d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); -+ -+ d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); -+ d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); -+ d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); -+ d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); - - deviceContext->Unmap(mQuadVB, 0); - -@@ -564,10 +583,11 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) - - // Set the viewport - D3D11_VIEWPORT viewport; -- viewport.TopLeftX = 0; -- viewport.TopLeftY = 0; -- viewport.Width = mWidth; -- viewport.Height = mHeight; -+ viewport.TopLeftX = 0.0f; -+ viewport.TopLeftY = 0.0f; -+ const bool invertViewport = (mRotateL || mRotateR) && !(mRotateL && mRotateR); -+ viewport.Width = FLOAT(invertViewport ? mHeight : mWidth); -+ viewport.Height = FLOAT(invertViewport ? mWidth : mHeight); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - deviceContext->RSSetViewports(1, &viewport); -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h -index 22401d8..77509ed 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h -@@ -52,6 +52,8 @@ class SwapChain11 : public SwapChain - Renderer11 *mRenderer; - EGLint mHeight; - EGLint mWidth; -+ bool mRotateL; -+ bool mRotateR; - bool mAppCreatedShareHandle; - unsigned int mSwapInterval; - bool mPassThroughResourcesInit; --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch b/src/angle/patches/0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch deleted file mode 100644 index dd2768cf3e..0000000000 --- a/src/angle/patches/0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch +++ /dev/null @@ -1,637 +0,0 @@ -From 829bf86c57357d3c8ec598b92fcfdb1849e84075 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Tue, 11 Nov 2014 17:11:54 +0200 -Subject: [PATCH 10/16] ANGLE: Enable D3D11 for feature level 9 cards - -Enable use of ANGLE on lower-end hardware, such as Surface RT and -Windows Phone 8. - -Change-Id: Ice536802e4eedc1d264abd0dd65960638fce59e4 ---- - src/3rdparty/angle/src/libGLESv2/angletypes.cpp | 6 +- - .../src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp | 69 ++++--- - .../src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp | 4 +- - .../src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 7 +- - .../renderer/d3d/d3d11/PixelTransfer11.cpp | 9 +- - .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 226 +++++++++++++-------- - .../src/libGLESv2/renderer/d3d/d3d11/Renderer11.h | 1 + - .../renderer/d3d/d3d11/TextureStorage11.cpp | 4 +- - .../libGLESv2/renderer/d3d/d3d11/formatutils11.cpp | 4 +- - .../renderer/d3d/d3d11/renderer11_utils.cpp | 2 +- - 10 files changed, 208 insertions(+), 124 deletions(-) - -diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp -index 6fd02e0..5a0cfc5 100644 ---- a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp -@@ -12,6 +12,8 @@ - #include "libGLESv2/State.h" - #include "libGLESv2/VertexArray.h" - -+#include -+ - namespace gl - { - -@@ -24,8 +26,8 @@ SamplerState::SamplerState() - maxAnisotropy(1.0f), - baseLevel(0), - maxLevel(1000), -- minLod(-1000.0f), -- maxLod(1000.0f), -+ minLod(-FLT_MAX), -+ maxLod(FLT_MAX), - compareMode(GL_NONE), - compareFunc(GL_LEQUAL), - swizzleRed(GL_RED), -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -index 91e7552..06aea9b 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -@@ -209,7 +209,7 @@ Blit11::Blit11(Renderer11 *renderer) - pointSamplerDesc.BorderColor[2] = 0.0f; - pointSamplerDesc.BorderColor[3] = 0.0f; - pointSamplerDesc.MinLOD = 0.0f; -- pointSamplerDesc.MaxLOD = 0.0f; -+ pointSamplerDesc.MaxLOD = mRenderer->isLevel9() ? D3D11_FLOAT32_MAX : 0.0f; - - result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); - ASSERT(SUCCEEDED(result)); -@@ -228,7 +228,7 @@ Blit11::Blit11(Renderer11 *renderer) - linearSamplerDesc.BorderColor[2] = 0.0f; - linearSamplerDesc.BorderColor[3] = 0.0f; - linearSamplerDesc.MinLOD = 0.0f; -- linearSamplerDesc.MaxLOD = 0.0f; -+ linearSamplerDesc.MaxLOD = mRenderer->isLevel9() ? D3D11_FLOAT32_MAX : 0.0f; - - result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); - ASSERT(SUCCEEDED(result)); -@@ -290,28 +290,31 @@ Blit11::Blit11(Renderer11 *renderer) - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuad2DVS, "Blit11 2D vertex shader"); - -- result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS); -- ASSERT(SUCCEEDED(result)); -- d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader"); -- -- D3D11_INPUT_ELEMENT_DESC quad3DLayout[] = -+ if (!renderer->isLevel9()) - { -- { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, -- { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, -- { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, -- }; -- -- result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL); -- ASSERT(SUCCEEDED(result)); -- d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout"); -- -- result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); -- ASSERT(SUCCEEDED(result)); -- d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); -+ result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS); -+ ASSERT(SUCCEEDED(result)); -+ d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader"); - -- result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS); -- ASSERT(SUCCEEDED(result)); -- d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader"); -+ D3D11_INPUT_ELEMENT_DESC quad3DLayout[] = -+ { -+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, -+ { "LAYER", 0, DXGI_FORMAT_R32_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, -+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, -+ }; -+ -+ result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL); -+ ASSERT(SUCCEEDED(result)); -+ d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout"); -+ -+ result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); -+ ASSERT(SUCCEEDED(result)); -+ d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); -+ -+ result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS); -+ ASSERT(SUCCEEDED(result)); -+ d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader"); -+ } - - buildShaderMap(); - -@@ -970,22 +973,27 @@ void Blit11::buildShaderMap() - ID3D11Device *device = mRenderer->getDevice(); - - add2DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader" )); -- add2DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader" )); -- add2DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader" )); - add2DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D BGRA pixel shader" )); - add2DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2D, "Blit11 2D RGB pixel shader" )); -- add2DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader" )); -- add2DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader" )); - add2DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG2D, "Blit11 2D RG pixel shader" )); -- add2DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader" )); -- add2DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader" )); - add2DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR2D, "Blit11 2D R pixel shader" )); -- add2DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader" )); -- add2DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader" )); - add2DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D alpha pixel shader" )); - add2DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum2D, "Blit11 2D lum pixel shader" )); - add2DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha2D, "Blit11 2D luminance alpha pixel shader")); - -+ addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader" )); -+ -+ if (mRenderer->isLevel9()) -+ return; -+ -+ add2DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DUI, "Blit11 2D RGBA UI pixel shader" )); -+ add2DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA2DI, "Blit11 2D RGBA I pixel shader" )); -+ add2DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB2DUI, "Blit11 2D RGB UI pixel shader" )); -+ add2DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB2DI, "Blit11 2D RGB I pixel shader" )); -+ add2DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG2DUI, "Blit11 2D RG UI pixel shader" )); -+ add2DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG2DI, "Blit11 2D RG I pixel shader" )); -+ add2DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR2DUI, "Blit11 2D R UI pixel shader" )); -+ add2DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR2DI, "Blit11 2D R I pixel shader" )); - add3DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader" )); - add3DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader" )); - add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" )); -@@ -1003,7 +1011,6 @@ void Blit11::buildShaderMap() - add3DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader" )); - add3DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader")); - -- addSwizzleShaderToMap(GL_FLOAT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleF2D, "Blit11 2D F swizzle pixel shader" )); - addSwizzleShaderToMap(GL_UNSIGNED_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleUI2D, "Blit11 2D UI swizzle pixel shader")); - addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader" )); - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp -index 2d5fa3c..5aab379 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp -@@ -753,7 +753,9 @@ void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Ren - - case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: - bufferDesc->Usage = D3D11_USAGE_DEFAULT; -- bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT; -+ bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; -+ if (!renderer->isLevel9()) -+ bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; - bufferDesc->CPUAccessFlags = 0; - break; - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp -index 4630762..7185a05 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp -@@ -104,7 +104,7 @@ Clear11::Clear11(Renderer11 *renderer) - rsDesc.DepthBias = 0; - rsDesc.DepthBiasClamp = 0.0f; - rsDesc.SlopeScaledDepthBias = 0.0f; -- rsDesc.DepthClipEnable = FALSE; -+ rsDesc.DepthClipEnable = renderer->isLevel9(); - rsDesc.ScissorEnable = FALSE; - rsDesc.MultisampleEnable = FALSE; - rsDesc.AntialiasedLineEnable = FALSE; -@@ -114,6 +114,11 @@ Clear11::Clear11(Renderer11 *renderer) - d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); - - mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat); -+ if (mRenderer->isLevel9()) { -+ memset(&mUintClearShader, 0, sizeof(ClearShader)); -+ memset(&mIntClearShader, 0, sizeof(ClearShader)); -+ return; -+ } - mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint ); - mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); - } -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -index a4072d8..6a3d347 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -@@ -133,10 +133,13 @@ gl::Error PixelTransfer11::loadResources() - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture vertex shader."); - } - -- mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); -- if (!mBufferToTextureGS) -+ if (!mRenderer->isLevel9()) - { -- return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); -+ mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); -+ if (!mBufferToTextureGS) -+ { -+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); -+ } - } - - gl::Error error = buildShaderMap(); -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index ffc6cc9..f6ba930 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -153,6 +153,24 @@ Renderer11::Renderer11(egl::Display *display, EGLNativeDisplayType hDc, const eg - } - } - -+#if !defined(ANGLE_ENABLE_D3D9) -+ if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) -+ { -+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3) -+ { -+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); -+ } -+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 2) -+ { -+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_2); -+ } -+ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) -+ { -+ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_1); -+ } -+ } -+#endif -+ - mDriverType = (attributes.get(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_FALSE) == EGL_TRUE) ? D3D_DRIVER_TYPE_WARP - : D3D_DRIVER_TYPE_HARDWARE; - } -@@ -1170,6 +1188,83 @@ gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, cons - return gl::Error(GL_NO_ERROR); - } - } -+template -+static void fillLineLoopIndices(GLenum type, GLsizei count, const GLvoid *indices, T *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(); -+ } -+} -+ -+template -+static void fillTriangleFanIndices(GLenum type, unsigned int numTris, const GLvoid *indices, T *data) -+{ -+ switch (type) -+ { -+ case GL_NONE: // Non-indexed draw -+ for (unsigned int i = 0; i < numTris; i++) -+ { -+ data[i*3 + 0] = 0; -+ data[i*3 + 1] = i + 1; -+ data[i*3 + 2] = i + 2; -+ } -+ break; -+ case GL_UNSIGNED_BYTE: -+ for (unsigned int i = 0; i < numTris; i++) -+ { -+ data[i*3 + 0] = static_cast(indices)[0]; -+ data[i*3 + 1] = static_cast(indices)[i + 1]; -+ data[i*3 + 2] = static_cast(indices)[i + 2]; -+ } -+ break; -+ case GL_UNSIGNED_SHORT: -+ for (unsigned int i = 0; i < numTris; i++) -+ { -+ data[i*3 + 0] = static_cast(indices)[0]; -+ data[i*3 + 1] = static_cast(indices)[i + 1]; -+ data[i*3 + 2] = static_cast(indices)[i + 2]; -+ } -+ break; -+ case GL_UNSIGNED_INT: -+ for (unsigned int i = 0; i < numTris; i++) -+ { -+ data[i*3 + 0] = static_cast(indices)[0]; -+ data[i*3 + 1] = static_cast(indices)[i + 1]; -+ data[i*3 + 2] = static_cast(indices)[i + 2]; -+ } -+ break; -+ default: UNREACHABLE(); -+ } -+} - - gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) - { -@@ -1189,10 +1284,13 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind - indices = bufferData + offset; - } - -+ // TODO: some level 9 hardware supports 32-bit indices; test and store support instead -+ const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; -+ - if (!mLineLoopIB) - { - mLineLoopIB = new StreamingIndexBufferInterface(this); -- gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); -+ gl::Error error = mLineLoopIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, indexType); - if (error.isError()) - { - SafeDelete(mLineLoopIB); -@@ -1203,7 +1301,8 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind - // Checked by Renderer11::applyPrimitiveType - ASSERT(count >= 0); - -- if (static_cast(count) + 1 > (std::numeric_limits::max() / sizeof(unsigned int))) -+ int indexTypeSize = indexType == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int); -+ if (static_cast(count) + 1 > (std::numeric_limits::max() / indexTypeSize)) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); - } -@@ -1223,42 +1322,12 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind - return error; - } - -- unsigned int *data = reinterpret_cast(mappedMemory); -+ if (indexType == GL_UNSIGNED_SHORT) -+ fillLineLoopIndices(type, count, indices, reinterpret_cast(mappedMemory)); -+ else -+ fillLineLoopIndices(type, count, indices, reinterpret_cast(mappedMemory)); - unsigned int indexBufferOffset = offset; - -- 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(); -- } -- - error = mLineLoopIB->unmapBuffer(); - if (error.isError()) - { -@@ -1300,10 +1369,12 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * - indices = bufferData + offset; - } - -+ const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; -+ - if (!mTriangleFanIB) - { - mTriangleFanIB = new StreamingIndexBufferInterface(this); -- gl::Error error = mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); -+ gl::Error error = mTriangleFanIB->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, indexType); - if (error.isError()) - { - SafeDelete(mTriangleFanIB); -@@ -1316,13 +1387,14 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * - - const unsigned int numTris = count - 2; - -- if (numTris > (std::numeric_limits::max() / (sizeof(unsigned int) * 3))) -+ int indexTypeSize = indexType == GL_UNSIGNED_SHORT ? sizeof(unsigned short) : sizeof(unsigned int); -+ if (numTris > (std::numeric_limits::max() / (indexTypeSize * 3))) - { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a scratch index buffer for GL_TRIANGLE_FAN, too many indices required."); - } - -- const unsigned int spaceNeeded = (numTris * 3) * sizeof(unsigned int); -- gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); -+ const unsigned int spaceNeeded = (numTris * 3) * indexTypeSize; -+ gl::Error error = mTriangleFanIB->reserveBufferSpace(spaceNeeded, indexType); - if (error.isError()) - { - return error; -@@ -1336,45 +1408,12 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * - return error; - } - -- unsigned int *data = reinterpret_cast(mappedMemory); -- unsigned int indexBufferOffset = offset; -+ if (indexType == GL_UNSIGNED_SHORT) -+ fillTriangleFanIndices(type, numTris, indices, reinterpret_cast(mappedMemory)); -+ else -+ fillTriangleFanIndices(type, numTris, indices, reinterpret_cast(mappedMemory)); - -- switch (type) -- { -- case GL_NONE: // Non-indexed draw -- for (unsigned int i = 0; i < numTris; i++) -- { -- data[i*3 + 0] = 0; -- data[i*3 + 1] = i + 1; -- data[i*3 + 2] = i + 2; -- } -- break; -- case GL_UNSIGNED_BYTE: -- for (unsigned int i = 0; i < numTris; i++) -- { -- data[i*3 + 0] = static_cast(indices)[0]; -- data[i*3 + 1] = static_cast(indices)[i + 1]; -- data[i*3 + 2] = static_cast(indices)[i + 2]; -- } -- break; -- case GL_UNSIGNED_SHORT: -- for (unsigned int i = 0; i < numTris; i++) -- { -- data[i*3 + 0] = static_cast(indices)[0]; -- data[i*3 + 1] = static_cast(indices)[i + 1]; -- data[i*3 + 2] = static_cast(indices)[i + 2]; -- } -- break; -- case GL_UNSIGNED_INT: -- for (unsigned int i = 0; i < numTris; i++) -- { -- data[i*3 + 0] = static_cast(indices)[0]; -- data[i*3 + 1] = static_cast(indices)[i + 1]; -- data[i*3 + 2] = static_cast(indices)[i + 2]; -- } -- break; -- default: UNREACHABLE(); -- } -+ unsigned int indexBufferOffset = offset; - - error = mTriangleFanIB->unmapBuffer(); - if (error.isError()) -@@ -1634,7 +1673,7 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto - } - - // needed for the point sprite geometry shader -- if (mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) -+ if (mFeatureLevel >= D3D_FEATURE_LEVEL_10_0 && mCurrentGeometryConstantBuffer != mDriverConstantBufferPS) - { - mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); - mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; -@@ -1938,7 +1977,10 @@ int Renderer11::getMajorShaderModel() const - { - case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 -- case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MAJOR_VERSION; // 4 -+ case D3D_FEATURE_LEVEL_10_0: -+ case D3D_FEATURE_LEVEL_9_3: -+ case D3D_FEATURE_LEVEL_9_2: -+ case D3D_FEATURE_LEVEL_9_1: return D3D10_SHADER_MAJOR_VERSION; // 4 - default: UNREACHABLE(); return 0; - } - } -@@ -1949,7 +1991,10 @@ int Renderer11::getMinorShaderModel() const - { - case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 -- case D3D_FEATURE_LEVEL_10_0: return D3D10_SHADER_MINOR_VERSION; // 0 -+ case D3D_FEATURE_LEVEL_10_0: -+ case D3D_FEATURE_LEVEL_9_3: -+ case D3D_FEATURE_LEVEL_9_2: -+ case D3D_FEATURE_LEVEL_9_1: return D3D10_SHADER_MINOR_VERSION; // 0 - default: UNREACHABLE(); return 0; - } - } -@@ -2455,6 +2500,7 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::strin - - unsigned int profileMajorVersion = 0; - unsigned int profileMinorVersion = 0; -+ const char *profileSuffix = NULL; - switch (mFeatureLevel) - { - case D3D_FEATURE_LEVEL_11_0: -@@ -2469,12 +2515,30 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::strin - profileMajorVersion = 4; - profileMinorVersion = 0; - break; -+ case D3D_FEATURE_LEVEL_9_3: -+ profileMajorVersion = 4; -+ profileMinorVersion = 0; -+ profileSuffix = "_level_9_3"; -+ break; -+ case D3D_FEATURE_LEVEL_9_2: -+ profileMajorVersion = 4; -+ profileMinorVersion = 0; -+ profileSuffix = "_level_9_2"; -+ break; -+ case D3D_FEATURE_LEVEL_9_1: -+ profileMajorVersion = 4; -+ profileMinorVersion = 0; -+ profileSuffix = "_level_9_1"; -+ break; -+ break; - default: - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); - } - - std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); -+ if (profileSuffix) -+ profile += profileSuffix; - - UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2; - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -index c789cae..d44bd2f 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -@@ -188,6 +188,7 @@ class Renderer11 : public RendererD3D - ID3D11Device *getDevice() { return mDevice; } - ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; - DXGIFactory *getDxgiFactory() { return mDxgiFactory; }; -+ bool isLevel9() { return mFeatureLevel <= D3D_FEATURE_LEVEL_9_3; } - - Blit11 *getBlitter() { return mBlit; } - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp -index 4287918..74af27e 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp -@@ -744,7 +744,7 @@ gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource) - D3D11_TEXTURE2D_DESC desc; - desc.Width = mTextureWidth; // Compressed texture size constraints? - desc.Height = mTextureHeight; -- desc.MipLevels = mMipLevels; -+ desc.MipLevels = mRenderer->isLevel9() ? 1 : mMipLevels; - desc.ArraySize = 1; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; -@@ -863,7 +863,7 @@ gl::Error TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORM - srvDesc.Format = format; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; -- srvDesc.Texture2D.MipLevels = mipLevels; -+ srvDesc.Texture2D.MipLevels = mRenderer->isLevel9() ? -1 : mipLevels; - - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp -index 1ea916d..90a879e 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp -@@ -557,7 +557,7 @@ D3D11LoadFunctionMap BuildD3D11LoadFunctionMap() - InsertLoadFunction(&map, GL_ALPHA, GL_HALF_FLOAT_OES, LoadA16FToRGBA16F ); - - // From GL_EXT_texture_storage -- InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadToNative ); -+ InsertLoadFunction(&map, GL_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadA8ToRGBA8 ); - InsertLoadFunction(&map, GL_LUMINANCE8_EXT, GL_UNSIGNED_BYTE, LoadL8ToRGBA8 ); - InsertLoadFunction(&map, GL_LUMINANCE8_ALPHA8_EXT, GL_UNSIGNED_BYTE, LoadLA8ToRGBA8 ); - InsertLoadFunction(&map, GL_ALPHA32F_EXT, GL_FLOAT, LoadA32FToRGBA32F ); -@@ -795,7 +795,7 @@ static D3D11ES3FormatMap BuildD3D11FormatMap() - - // From GL_EXT_texture_storage - // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | -- InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN ); -+ InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_LUMINANCE8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); - InsertD3D11FormatInfo(&map, GL_LUMINANCE32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -index 9ffc32e..cbfe557 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -@@ -284,7 +284,7 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx - case D3D_FEATURE_LEVEL_9_3: - case D3D_FEATURE_LEVEL_9_2: -- case D3D_FEATURE_LEVEL_9_1: return false; -+ case D3D_FEATURE_LEVEL_9_1: return true; // Provided that mipmaps & wrap modes are not used - - default: UNREACHABLE(); return false; - } --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0012-ANGLE-fix-semantic-index-lookup.patch b/src/angle/patches/0012-ANGLE-fix-semantic-index-lookup.patch deleted file mode 100644 index afc9f256a1..0000000000 --- a/src/angle/patches/0012-ANGLE-fix-semantic-index-lookup.patch +++ /dev/null @@ -1,48 +0,0 @@ -From bbfd3cfcf6e1195d86368b61ce39504ce6acda50 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Wed, 12 Nov 2014 17:09:23 +0200 -Subject: [PATCH 12/16] ANGLE: fix semantic index lookup - -The sorted semantic index table was returning a direct mapping to the -new indices, instead of the old indices. This caused a mismatch in the -GL type lookup for the translated attribute. - -Change-Id: I75d05ed707f56c45210e3dcbc277f894e3dc5a48 ---- - src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp | 2 +- - .../angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp -index 0619023..6d64b38 100644 ---- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp -@@ -1216,7 +1216,7 @@ void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MA - for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) - { - int oldIndex = mAttributesByLayout[i]; -- sortedSemanticIndices[i] = mSemanticIndex[oldIndex]; -+ sortedSemanticIndices[i] = oldIndex; - attributes[i] = oldTranslatedAttributes[oldIndex]; - } - } -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp -index e41f238..ff90a6a 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp -@@ -113,10 +113,10 @@ gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl - // Record the type of the associated vertex shader vector in our key - // This will prevent mismatched vertex shaders from using the same input layout - GLint attributeSize; -- programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL); -+ programBinary->getActiveAttribute(sortedSemanticIndices[i], 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL); - - ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName; -- ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i]; -+ ilKey.elements[ilKey.elementCount].desc.SemanticIndex = i; - ilKey.elements[ilKey.elementCount].desc.Format = vertexFormatInfo.nativeFormat; - ilKey.elements[ilKey.elementCount].desc.InputSlot = i; - ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0013-ANGLE-Add-support-for-querying-platform-device.patch b/src/angle/patches/0013-ANGLE-Add-support-for-querying-platform-device.patch deleted file mode 100644 index b43dcc368b..0000000000 --- a/src/angle/patches/0013-ANGLE-Add-support-for-querying-platform-device.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 5ef9348de2624c21be1c9fddd265fec5a0851d25 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Thu, 13 Nov 2014 15:34:26 +0200 -Subject: [PATCH 13/16] ANGLE: Add support for querying platform device - -The EGL_EXT_device_base extension allows for querying the platform -device of the graphics hardware via eglQueryDisplayAttribEXT(). -As that extension is not supported by ANGLE, this patch adds similar -functionality to the existing eglQuerySurfacePointerANGLE API. When -EGL_DEVICE_EXT is passed as the queried attribute, the underlying -D3D/DXGI device pointer is passed back to the caller via the value -argument. - -The D3D device is needed for video support in QtMultimedia as well as -the IDXGIDevice3::Trim() calls required by the Windows Store. - -Change-Id: Ibdf228d81d6604e56db9dd8597d7cd2983ebc428 ---- - src/3rdparty/angle/src/libEGL/libEGL.cpp | 50 +++++++++++++++++++++++++------- - 1 file changed, 39 insertions(+), 11 deletions(-) - -diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp -index dc20d85..68399d6 100644 ---- a/src/3rdparty/angle/src/libEGL/libEGL.cpp -+++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp -@@ -17,6 +17,9 @@ - #include "libGLESv2/Texture.h" - #include "libGLESv2/main.h" - #include "libGLESv2/renderer/SwapChain.h" -+#if defined(ANGLE_ENABLE_D3D11) -+# include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" -+#endif - - #include "libEGL/main.h" - #include "libEGL/Display.h" -@@ -582,25 +585,50 @@ EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surf - egl::Display *display = static_cast(dpy); - egl::Surface *eglSurface = (egl::Surface*)surface; - -- if (!validateSurface(display, eglSurface)) -- { -- return EGL_FALSE; -- } -- -- if (surface == EGL_NO_SURFACE) -- { -- recordError(egl::Error(EGL_BAD_SURFACE)); -- return EGL_FALSE; -- } -- - switch (attribute) - { - case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE: - { -+ if (!validateSurface(display, eglSurface)) -+ { -+ return EGL_FALSE; -+ } -+ -+ if (surface == EGL_NO_SURFACE) -+ { -+ recordError(egl::Error(EGL_BAD_SURFACE)); -+ return EGL_FALSE; -+ } -+ - rx::SwapChain *swapchain = eglSurface->getSwapChain(); - *value = (void*) (swapchain ? swapchain->getShareHandle() : NULL); - } - break; -+#if defined(ANGLE_ENABLE_D3D11) -+ case EGL_DEVICE_EXT: -+ { -+ if (!validateDisplay(display)) -+ { -+ return EGL_FALSE; -+ } -+ -+ rx::Renderer *renderer = display->getRenderer(); -+ if (!renderer) -+ { -+ *value = NULL; -+ break; -+ } -+ -+ if (renderer->getMajorShaderModel() < 4) -+ { -+ recordError(egl::Error(EGL_BAD_CONTEXT)); -+ return EGL_FALSE; -+ } -+ -+ *value = static_cast(renderer)->getDevice(); -+ } -+ break; -+#endif - default: - recordError(egl::Error(EGL_BAD_ATTRIBUTE)); - return EGL_FALSE; --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch b/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch deleted file mode 100644 index 9ceb34d964..0000000000 --- a/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 5b3bc73210ed1847d9bd7a94f06cc0d5de8e0b89 Mon Sep 17 00:00:00 2001 -From: Michael Bruning -Date: Thu, 13 Nov 2014 15:40:10 +0200 -Subject: [PATCH 14/16] Let ANGLE use multithreaded devices if necessary. - -This is needed to prevent lock-ups in application that use ANGLE from -multiple threads, as e.g. QtWebEngine based applications do. - -The environment variable QT_D3DCREATE_MULTITHREADED is used to -communicate this from the QtWebEngine module. - -Change-Id: Ibd5a5c75eb68af567d420d9a35efb3490c93b27c ---- - src/3rdparty/angle/src/common/platform.h | 1 + - .../angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 10 ++++++++++ - .../angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 4 ++++ - 3 files changed, 15 insertions(+) - -diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index 0065ec7..8b2190d 100644 ---- a/src/3rdparty/angle/src/common/platform.h -+++ b/src/3rdparty/angle/src/common/platform.h -@@ -57,6 +57,7 @@ - - # if defined(ANGLE_ENABLE_D3D11) - # include -+# include - # include - # include - # include -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index f6ba930..46b9984 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -258,6 +258,16 @@ EGLint Renderer11::initialize() - } - - #if !defined(ANGLE_ENABLE_WINDOWS_STORE) -+ static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); -+ if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) -+ { -+ ID3D10Multithread *multithread; -+ result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread)); -+ ASSERT(SUCCEEDED(result)); -+ result = multithread->SetMultithreadProtected(true); -+ ASSERT(SUCCEEDED(result)); -+ multithread->Release(); -+ } - #if !ANGLE_SKIP_DXGI_1_2_CHECK - // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. - // The easiest way to check is to query for a IDXGIDevice2. -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -index 82963ec..4c552b2 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -@@ -299,6 +299,10 @@ EGLint Renderer9::initialize() - D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); - DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; - -+ static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); -+ if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) -+ behaviorFlags |= D3DCREATE_MULTITHREADED; -+ - { - result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); - } --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch b/src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch deleted file mode 100644 index f78474f11a..0000000000 --- a/src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch +++ /dev/null @@ -1,536 +0,0 @@ -From d9a9219ea2181dd4c1939d05747a21b67f16a906 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Thu, 13 Nov 2014 16:33:53 +0200 -Subject: [PATCH 15/16] ANGLE: Fix -angle-d3d11 on MSVC2010 - -Allow the D3D11 renderer to build with the June 2010 DirectX SDK. - -Change-Id: I2343acedab16845d6a0d4a53cf3145f583efc4a7 ---- - src/3rdparty/angle/src/common/platform.h | 8 +- - src/3rdparty/angle/src/libGLESv2/Context.cpp | 8 +- - src/3rdparty/angle/src/libGLESv2/Data.h | 2 +- - src/3rdparty/angle/src/libGLESv2/State.cpp | 6 +- - .../src/libGLESv2/renderer/d3d/RendererD3D.cpp | 4 +- - .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 4 +- - .../renderer/d3d/d3d11/renderer11_utils.cpp | 137 +++++++++++++++++++++ - 7 files changed, 156 insertions(+), 13 deletions(-) - -diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index 8b2190d..972eee2 100644 ---- a/src/3rdparty/angle/src/common/platform.h -+++ b/src/3rdparty/angle/src/common/platform.h -@@ -52,17 +52,23 @@ - - # if defined(ANGLE_ENABLE_D3D9) - # include -+# if !defined(COMPILER_IMPLEMENTATION) - # include -+# endif - # endif - - # if defined(ANGLE_ENABLE_D3D11) - # include - # include - # include --# include - # include -+# if defined(_MSC_VER) && (_MSC_VER >= 1700) -+# include - # include -+# endif -+# if !defined(COMPILER_IMPLEMENTATION) - # include -+# endif - # endif - - # if defined(ANGLE_ENABLE_WINDOWS_STORE) -diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp -index fe9b1a2..b87689c 100644 ---- a/src/3rdparty/angle/src/libGLESv2/Context.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp -@@ -168,9 +168,9 @@ Context::~Context() - } - mIncompleteTextures.clear(); - -- for (auto &zeroTexture : mZeroTextures) -+ for (TextureMap::iterator i = mZeroTextures.begin(); i != mZeroTextures.end(); i++) - { -- zeroTexture.second.set(NULL); -+ i->second.set(NULL); - } - mZeroTextures.clear(); - -@@ -354,7 +354,7 @@ void Context::deleteFenceSync(GLsync fenceSync) - - void Context::deleteVertexArray(GLuint vertexArray) - { -- auto vertexArrayObject = mVertexArrayMap.find(vertexArray); -+ VertexArrayMap::iterator vertexArrayObject = mVertexArrayMap.find(vertexArray); - - if (vertexArrayObject != mVertexArrayMap.end()) - { -@@ -460,7 +460,7 @@ FenceSync *Context::getFenceSync(GLsync handle) const - - VertexArray *Context::getVertexArray(GLuint handle) const - { -- auto vertexArray = mVertexArrayMap.find(handle); -+ VertexArrayMap::const_iterator vertexArray = mVertexArrayMap.find(handle); - - if (vertexArray == mVertexArrayMap.end()) - { -diff --git a/src/3rdparty/angle/src/libGLESv2/Data.h b/src/3rdparty/angle/src/libGLESv2/Data.h -index cff872a..9234403 100644 ---- a/src/3rdparty/angle/src/libGLESv2/Data.h -+++ b/src/3rdparty/angle/src/libGLESv2/Data.h -@@ -14,7 +14,7 @@ - namespace gl - { - --struct Data final -+struct Data - { - public: - Data(GLint clientVersion, const State &state, const Caps &caps, -diff --git a/src/3rdparty/angle/src/libGLESv2/State.cpp b/src/3rdparty/angle/src/libGLESv2/State.cpp -index e7acda2..b5b62f5 100644 ---- a/src/3rdparty/angle/src/libGLESv2/State.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/State.cpp -@@ -665,13 +665,13 @@ void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) - - void State::initializeZeroTextures(const TextureMap &zeroTextures) - { -- for (const auto &zeroTexture : zeroTextures) -+ for (TextureMap::const_iterator i = zeroTextures.begin(); i != zeroTextures.end(); i++) - { -- auto &samplerTextureArray = mSamplerTextures[zeroTexture.first]; -+ TextureBindingVector &samplerTextureArray = mSamplerTextures[i->first]; - - for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) - { -- samplerTextureArray[textureUnit].set(zeroTexture.second.get()); -+ samplerTextureArray[textureUnit].set(i->second.get()); - } - } - } -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp -index 6f58243..97da6da 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp -@@ -27,9 +27,9 @@ RendererD3D::RendererD3D(egl::Display *display) - - RendererD3D::~RendererD3D() - { -- for (auto &incompleteTexture : mIncompleteTextures) -+ for (gl::TextureMap::iterator i = mIncompleteTextures.begin(); i != mIncompleteTextures.end(); ++i) - { -- incompleteTexture.second.set(NULL); -+ i->second.set(NULL); - } - mIncompleteTextures.clear(); - } -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index 46b9984..a28fd78 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -873,7 +873,7 @@ bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count) - - void Renderer11::unsetSRVsWithResource(gl::SamplerType samplerType, const ID3D11Resource *resource) - { -- auto ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); -+ std::vector ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); - - for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex) - { -@@ -3398,7 +3398,7 @@ Workarounds Renderer11::generateWorkarounds() const - - void Renderer11::setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv) - { -- auto ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); -+ std::vector ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); - - ASSERT(static_cast(resourceSlot) < currentSRVs.size()); - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -index cbfe557..5831c57 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -@@ -18,6 +18,85 @@ - - #include - -+#ifndef D3D_FL9_1_DEFAULT_MAX_ANISOTROPY -+# define D3D_FL9_1_DEFAULT_MAX_ANISOTROPY 2 -+#endif -+#ifndef D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT -+# define D3D_FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT 1 -+#endif -+#ifndef D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT -+# define D3D_FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT 4 -+#endif -+#ifndef D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT -+# define D3D_FL9_1_IA_PRIMITIVE_MAX_COUNT 65535 -+#endif -+#ifndef D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT -+# define D3D_FL9_2_IA_PRIMITIVE_MAX_COUNT 1048575 -+#endif -+#ifndef D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION -+# define D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION 512 -+#endif -+#ifndef D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION -+# define D3D_FL9_3_REQ_TEXTURECUBE_DIMENSION 4096 -+#endif -+#ifndef D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION -+# define D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION 2048 -+#endif -+#ifndef D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION -+# define D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 256 -+#endif -+#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION -+# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 -+#endif -+#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION -+# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 -+#endif -+#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION -+# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 -+#endif -+#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION -+# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 -+#endif -+#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP -+# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 -+#endif -+#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP -+# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 -+#endif -+#ifndef D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT -+# define D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT 32 -+#endif -+#ifndef D3D11_STANDARD_VERTEX_ELEMENT_COUNT -+# define D3D11_STANDARD_VERTEX_ELEMENT_COUNT 32 -+#endif -+#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT -+# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 -+#endif -+#ifndef D3D11_SO_BUFFER_SLOT_COUNT -+# define D3D11_SO_BUFFER_SLOT_COUNT 4 -+#endif -+#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT -+# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 -+#endif -+#ifndef D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT -+# define D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT 16 -+#endif -+#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -+# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -8 -+#endif -+#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE -+# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE 7 -+#endif -+#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT -+# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 -+#endif -+#ifndef D3D11_PS_INPUT_REGISTER_COUNT -+# define D3D11_PS_INPUT_REGISTER_COUNT 32 -+#endif -+#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT -+# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 -+#endif -+ - namespace rx - { - -@@ -276,7 +355,9 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; -@@ -294,7 +375,9 @@ static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; - - case D3D_FEATURE_LEVEL_10_1: -@@ -314,7 +397,9 @@ static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return true; -@@ -334,7 +419,9 @@ static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) - - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: -@@ -352,7 +439,9 @@ static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) - - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: -@@ -375,7 +464,9 @@ static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) - - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: -@@ -393,7 +484,9 @@ static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel - - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; - - case D3D_FEATURE_LEVEL_10_1: -@@ -411,7 +504,9 @@ static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: -@@ -429,7 +524,9 @@ static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: -@@ -447,7 +544,9 @@ static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: -@@ -465,7 +564,9 @@ static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - - case D3D_FEATURE_LEVEL_10_1: -@@ -483,7 +584,9 @@ static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; - - case D3D_FEATURE_LEVEL_10_1: -@@ -507,7 +610,9 @@ static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) - - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); -@@ -529,7 +634,9 @@ static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) - - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); -@@ -546,7 +653,9 @@ static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT; -@@ -566,7 +675,9 @@ static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) - // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: -@@ -591,7 +702,9 @@ static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); - - case D3D_FEATURE_LEVEL_10_1: -@@ -618,7 +731,9 @@ static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) - - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); - - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); -@@ -637,7 +752,9 @@ static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: -@@ -659,7 +776,9 @@ static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) - // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: -@@ -684,7 +803,9 @@ static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); - - case D3D_FEATURE_LEVEL_10_1: -@@ -703,7 +824,9 @@ static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); - - case D3D_FEATURE_LEVEL_10_1: -@@ -722,7 +845,9 @@ static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: -@@ -741,7 +866,9 @@ static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; - - case D3D_FEATURE_LEVEL_10_1: -@@ -760,7 +887,9 @@ static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; -@@ -783,7 +912,9 @@ static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) - - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; - - case D3D_FEATURE_LEVEL_10_1: -@@ -802,7 +933,9 @@ static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return D3D11_SO_BUFFER_SLOT_COUNT; - - case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SO_BUFFER_SLOT_COUNT; -@@ -820,7 +953,9 @@ static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL feat - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: - - case D3D_FEATURE_LEVEL_10_1: -@@ -838,7 +973,9 @@ static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL feature - { - switch (featureLevel) - { -+#if !defined(_MSC_VER) || (_MSC_VER >= 1800) - case D3D_FEATURE_LEVEL_11_1: -+#endif - case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / - GetMaximumStreamOutputBuffers(featureLevel); - --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0016-ANGLE-Fix-compilation-with-MinGW-D3D11.patch b/src/angle/patches/0016-ANGLE-Fix-compilation-with-MinGW-D3D11.patch deleted file mode 100644 index e3df95d8bf..0000000000 --- a/src/angle/patches/0016-ANGLE-Fix-compilation-with-MinGW-D3D11.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 43c8ceb17ccd6d5ae13a07c6d01b45eb40983917 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Tue, 11 Nov 2014 14:36:43 +0200 -Subject: [PATCH 16/16] ANGLE: Fix compilation with MinGW + D3D11 - -Provide workarounds for things GCC doesn't like, and define a few -missing definitions not found in the MinGW headers. - -Change-Id: I254c208209c0071fae5efb6727f2b3cfd5542da6 ---- - src/3rdparty/angle/src/common/platform.h | 73 ++++++++++++++++++++++ - .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 6 ++ - .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 2 +- - .../renderer/d3d/d3d11/renderer11_utils.cpp | 2 +- - .../src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 4 +- - 5 files changed, 83 insertions(+), 4 deletions(-) - -diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index 972eee2..0001e71 100644 ---- a/src/3rdparty/angle/src/common/platform.h -+++ b/src/3rdparty/angle/src/common/platform.h -@@ -81,6 +81,79 @@ - # endif - # endif - -+# if defined(__MINGW32__) // Missing defines on MinGW -+typedef enum D3D11_MAP_FLAG -+{ -+ D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000L -+} D3D11_MAP_FLAG; -+typedef struct D3D11_QUERY_DATA_SO_STATISTICS -+{ -+ UINT64 NumPrimitivesWritten; -+ UINT64 PrimitivesStorageNeeded; -+} D3D11_QUERY_DATA_SO_STATISTICS; -+typedef HRESULT (WINAPI *PFN_D3D11_CREATE_DEVICE)( -+ IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL *, -+ UINT FeatureLevels, UINT, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **); -+#define D3D11_MESSAGE_CATEGORY UINT -+#define D3D11_MESSAGE_SEVERITY UINT -+#define D3D11_MESSAGE_ID UINT -+struct D3D11_MESSAGE; -+typedef struct D3D11_INFO_QUEUE_FILTER_DESC -+{ -+ UINT NumCategories; -+ D3D11_MESSAGE_CATEGORY *pCategoryList; -+ UINT NumSeverities; -+ D3D11_MESSAGE_SEVERITY *pSeverityList; -+ UINT NumIDs; -+ D3D11_MESSAGE_ID *pIDList; -+} D3D11_INFO_QUEUE_FILTER_DESC; -+typedef struct D3D11_INFO_QUEUE_FILTER -+{ -+ D3D11_INFO_QUEUE_FILTER_DESC AllowList; -+ D3D11_INFO_QUEUE_FILTER_DESC DenyList; -+} D3D11_INFO_QUEUE_FILTER; -+static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 }; -+MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown -+{ -+public: -+ virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0; -+ virtual void __stdcall ClearStoredMessages() = 0; -+ virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0; -+ virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0; -+ virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0; -+ virtual UINT64 __stdcall GetNumStoredMessages() = 0; -+ virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0; -+ virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0; -+ virtual UINT64 __stdcall GetMessageCountLimit() = 0; -+ virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; -+ virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; -+ virtual void __stdcall ClearStorageFilter() = 0; -+ virtual HRESULT __stdcall PushEmptyStorageFilter() = 0; -+ virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0; -+ virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0; -+ virtual void __stdcall PopStorageFilter() = 0; -+ virtual UINT __stdcall GetStorageFilterStackSize() = 0; -+ virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; -+ virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; -+ virtual void __stdcall ClearRetrievalFilter() = 0; -+ virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0; -+ virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0; -+ virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0; -+ virtual void __stdcall PopRetrievalFilter() = 0; -+ virtual UINT __stdcall GetRetrievalFilterStackSize() = 0; -+ virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0; -+ virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0; -+ virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0; -+ virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0; -+ virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0; -+ virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0; -+ virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0; -+ virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0; -+ virtual void __stdcall SetMuteDebugOutput(BOOL) = 0; -+ virtual BOOL __stdcall GetMuteDebugOutput() = 0; -+}; -+#endif // __MINGW32__ -+ - # undef near - # undef far - #endif -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -index 9d003b4..776d92b 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -@@ -14,6 +14,12 @@ - #ifndef QT_D3DCOMPILER_DLL - #define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL - #endif -+#ifndef D3DCOMPILE_RESERVED16 -+#define D3DCOMPILE_RESERVED16 (1 << 16) -+#endif -+#ifndef D3DCOMPILE_RESERVED17 -+#define D3DCOMPILE_RESERVED17 (1 << 17) -+#endif - - // Definitions local to the translation unit - namespace -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index a28fd78..e6d7f30 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -333,7 +333,7 @@ EGLint Renderer11::initialize() - // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log - #if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) - ID3D11InfoQueue *infoQueue; -- result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue); -+ result = mDevice->QueryInterface(IID_ID3D11InfoQueue, (void **)&infoQueue); - - if (SUCCEEDED(result)) - { -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -index 5831c57..121aa3b 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -@@ -1196,7 +1196,7 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo - - HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) - { --#if defined(_DEBUG) -+#if defined(_DEBUG) && !defined(__MINGW32__) - return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); - #else - return S_OK; -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -index 4c552b2..601cd24 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -@@ -200,7 +200,7 @@ EGLint Renderer9::initialize() - if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) - { - ASSERT(mD3d9Ex); -- mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast(&mD3d9)); -+ mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast(&mD3d9)); - ASSERT(mD3d9); - } - else -@@ -324,7 +324,7 @@ EGLint Renderer9::initialize() - - if (mD3d9Ex) - { -- result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void**)&mDeviceEx); -+ result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**)&mDeviceEx); - ASSERT(SUCCEEDED(result)); - } - --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0017-ANGLE-Fix-compilation-with-D3D9.patch b/src/angle/patches/0017-ANGLE-Fix-compilation-with-D3D9.patch deleted file mode 100644 index 4ada6d41d2..0000000000 --- a/src/angle/patches/0017-ANGLE-Fix-compilation-with-D3D9.patch +++ /dev/null @@ -1,62 +0,0 @@ -From d7839cc052de126cc3b457fe41963fd9c7e91846 Mon Sep 17 00:00:00 2001 -From: Kai Koehne -Date: Mon, 17 Nov 2014 15:10:10 +0100 -Subject: [PATCH] ANGLE: Fix compilation with D3D9 - -Fixes a regression introduced in c6df5fe3ed0f2a722 that -broke compilation with d3d9 (namely, -target xp). - -Task-number: QTBUG-42714 -Change-Id: I1a5e9682d5463bfa082a5d0c062399a131a7cf52 ---- - src/3rdparty/angle/src/common/NativeWindow.h | 7 ++++++- - src/3rdparty/angle/src/common/platform.h | 1 + - src/3rdparty/angle/src/common/win32/NativeWindow.cpp | 2 +- - 3 files changed, 8 insertions(+), 2 deletions(-) - -diff --git a/src/3rdparty/angle/src/common/NativeWindow.h b/src/3rdparty/angle/src/common/NativeWindow.h -index 9e93aea..c4a0e42 100644 ---- a/src/3rdparty/angle/src/common/NativeWindow.h -+++ b/src/3rdparty/angle/src/common/NativeWindow.h -@@ -54,7 +54,12 @@ public: - bool getClientRect(LPRECT rect); - bool isIconic(); - -- HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, -+# if defined(ANGLE_ENABLE_D3D11) -+ typedef ID3D11Device Device; -+#else -+ typedef IDirect3DDevice9 Device; -+#endif -+ HRESULT createSwapChain(Device* device, DXGIFactory* factory, - DXGI_FORMAT format, UINT width, UINT height, - DXGISwapChain** swapChain); - -diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index 0001e71..5bf97f9 100644 ---- a/src/3rdparty/angle/src/common/platform.h -+++ b/src/3rdparty/angle/src/common/platform.h -@@ -52,6 +52,7 @@ - - # if defined(ANGLE_ENABLE_D3D9) - # include -+# include - # if !defined(COMPILER_IMPLEMENTATION) - # include - # endif -diff --git a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp -index 2440747..46082a2 100644 ---- a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp -+++ b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp -@@ -35,7 +35,7 @@ bool NativeWindow::isIconic() - return IsIconic(mWindow) == TRUE; - } - --HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, -+HRESULT NativeWindow::createSwapChain(NativeWindow::Device* device, DXGIFactory* factory, - DXGI_FORMAT format, unsigned int width, unsigned int height, - DXGISwapChain** swapChain) - { --- -1.9.4.msysgit.0 - diff --git a/src/angle/patches/0018-ANGLE-Fix-releasing-textures-after-we-kill-D3D11.patch b/src/angle/patches/0018-ANGLE-Fix-releasing-textures-after-we-kill-D3D11.patch deleted file mode 100644 index 97847ad684..0000000000 --- a/src/angle/patches/0018-ANGLE-Fix-releasing-textures-after-we-kill-D3D11.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 014d3fcf6011109491b0489da9c1abb1fdc6dbdc Mon Sep 17 00:00:00 2001 -From: Kai Koehne -Date: Mon, 24 Nov 2014 10:52:03 +0100 -Subject: [PATCH] ANGLE: Fix releasing textures after we kill D3D11 - -Cherry-pick upstream commit cc4cd2925b9a4f1142a86df131345a861c9d7cd9 -to fix crashes on exit. - -Task-number: QTBUG-42772 -Change-Id: Ib74be17f2b5fdd58f9e0568e1da74ba19e943019 ---- - src/3rdparty/angle/src/libGLESv2/Context.cpp | 6 ------ - src/3rdparty/angle/src/libGLESv2/Context.h | 1 - - src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp | 5 +++++ - src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h | 2 ++ - src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 2 ++ - src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 2 ++ - 6 files changed, 11 insertions(+), 7 deletions(-) - -diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp -index b87689c..3772da6 100644 ---- a/src/3rdparty/angle/src/libGLESv2/Context.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp -@@ -162,12 +162,6 @@ Context::~Context() - deleteTransformFeedback(mTransformFeedbackMap.begin()->first); - } - -- for (TextureMap::iterator i = mIncompleteTextures.begin(); i != mIncompleteTextures.end(); i++) -- { -- i->second.set(NULL); -- } -- mIncompleteTextures.clear(); -- - for (TextureMap::iterator i = mZeroTextures.begin(); i != mZeroTextures.end(); i++) - { - i->second.set(NULL); -diff --git a/src/3rdparty/angle/src/libGLESv2/Context.h b/src/3rdparty/angle/src/libGLESv2/Context.h -index 1e890de..0699592 100644 ---- a/src/3rdparty/angle/src/libGLESv2/Context.h -+++ b/src/3rdparty/angle/src/libGLESv2/Context.h -@@ -247,7 +247,6 @@ class Context - int mClientVersion; - - TextureMap mZeroTextures; -- TextureMap mIncompleteTextures; - - typedef std::unordered_map FramebufferMap; - FramebufferMap mFramebufferMap; -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp -index 97da6da..5cddd8a 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp -@@ -27,6 +27,11 @@ RendererD3D::RendererD3D(egl::Display *display) - - RendererD3D::~RendererD3D() - { -+ cleanup(); -+} -+ -+void RendererD3D::cleanup() -+{ - for (gl::TextureMap::iterator i = mIncompleteTextures.begin(); i != mIncompleteTextures.end(); ++i) - { - i->second.set(NULL); -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h -index 9919207..a2f7787 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h -@@ -160,6 +160,8 @@ class RendererD3D : public Renderer - const gl::Rectangle *scissor, bool blitRenderTarget, - bool blitDepth, bool blitStencil, GLenum filter) = 0; - -+ void cleanup(); -+ - egl::Display *mDisplay; - - private: -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index e6d7f30..777308e 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -1870,6 +1870,8 @@ bool Renderer11::testDeviceResettable() - - void Renderer11::release() - { -+ RendererD3D::cleanup(); -+ - releaseShaderCompiler(); - releaseDeviceResources(); - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -index 601cd24..18e6e2d 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -@@ -151,6 +151,8 @@ Renderer9::~Renderer9() - - void Renderer9::release() - { -+ RendererD3D::cleanup(); -+ - releaseShaderCompiler(); - releaseDeviceResources(); - --- -1.9.4.msysgit.0 - diff --git a/src/angle/patches/0019-ANGLE-Fix-handling-of-shader-source-with-fixed-lengt.patch b/src/angle/patches/0019-ANGLE-Fix-handling-of-shader-source-with-fixed-lengt.patch deleted file mode 100644 index 5fa244c1b5..0000000000 --- a/src/angle/patches/0019-ANGLE-Fix-handling-of-shader-source-with-fixed-lengt.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 5e277b05a16e7be24d36c600f158f8119ee583d8 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Mon, 1 Dec 2014 11:58:08 +0200 -Subject: [PATCH] ANGLE: Fix handling of shader source with fixed length - -This is a cherry-pick of upstream f60fab6d154f4c9bf599e92976cd8cee7f8633e0 -(See https://chromium-review.googlesource.com/231612) - -Task-number: QTBUG-42882 -Change-Id: I7b4bdc4b68a1b93ff514f09ce35dbf4e9360af9b ---- - src/3rdparty/angle/src/libGLESv2/Shader.cpp | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp -index 1cc17a0..5bca746 100644 ---- a/src/3rdparty/angle/src/libGLESv2/Shader.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/Shader.cpp -@@ -51,7 +51,14 @@ void Shader::setSource(GLsizei count, const char *const *string, const GLint *le - - for (int i = 0; i < count; i++) - { -- stream << string[i]; -+ if (length == nullptr || length[i] < 0) -+ { -+ stream.write(string[i], std::strlen(string[i])); -+ } -+ else -+ { -+ stream.write(string[i], length[i]); -+ } - } - - mSource = stream.str(); --- -1.9.4.msysgit.1 - diff --git a/src/angle/patches/0020-ANGLE-Do-not-use-std-strlen.patch b/src/angle/patches/0020-ANGLE-Do-not-use-std-strlen.patch deleted file mode 100644 index 324244f6eb..0000000000 --- a/src/angle/patches/0020-ANGLE-Do-not-use-std-strlen.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 071b8936386b0b44475c91511d85479e5c633bc5 Mon Sep 17 00:00:00 2001 -From: Kai Koehne -Date: Thu, 11 Dec 2014 13:54:23 +0100 -Subject: [PATCH] ANGLE: Do not use std::strlen - -This is a cherry-pick from upstream change - -e7cfb3dd2029c1bfe5c175ad994c03cac221ad4d - -Change-Id: Iefe01545319f9ad268c0c6bf8e8b2181e09d8a84 ---- - src/3rdparty/angle/src/libGLESv2/Shader.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp -index 5bca746..024ef8f 100644 ---- a/src/3rdparty/angle/src/libGLESv2/Shader.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/Shader.cpp -@@ -53,7 +53,7 @@ void Shader::setSource(GLsizei count, const char *const *string, const GLint *le - { - if (length == nullptr || length[i] < 0) - { -- stream.write(string[i], std::strlen(string[i])); -+ stream.write(string[i], strlen(string[i])); - } - else - { --- -1.9.4.msysgit.0 - diff --git a/src/angle/patches/0020-ANGLE-Fix-compilation-with-MSVC2013-Update4.patch b/src/angle/patches/0020-ANGLE-Fix-compilation-with-MSVC2013-Update4.patch deleted file mode 100644 index 49b229d905..0000000000 --- a/src/angle/patches/0020-ANGLE-Fix-compilation-with-MSVC2013-Update4.patch +++ /dev/null @@ -1,43 +0,0 @@ -From a48dfb3f1ecb57a59084c0e87155506586b73188 Mon Sep 17 00:00:00 2001 -From: Maurice Kalinowski -Date: Thu, 11 Dec 2014 13:11:55 +0100 -Subject: [PATCH] [ANGLE] Fix compilation with MSVC2013 Update4 - -Update4 provides a native Sleep implementation. Hence the wrapper -needs to be disabled. - -Change-Id: I162da45934b02c262ac09b557c66c3363c276e54 ---- - src/3rdparty/angle/src/common/utilities.cpp | 2 +- - src/3rdparty/angle/src/common/utilities.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/3rdparty/angle/src/common/utilities.cpp b/src/3rdparty/angle/src/common/utilities.cpp -index 9d797a6..924573e 100644 ---- a/src/3rdparty/angle/src/common/utilities.cpp -+++ b/src/3rdparty/angle/src/common/utilities.cpp -@@ -486,7 +486,7 @@ void writeFile(const char* path, const void* content, size_t size) - } - #endif // !ANGLE_ENABLE_WINDOWS_STORE - --#if defined(ANGLE_ENABLE_WINDOWS_STORE) -+#if defined(ANGLE_ENABLE_WINDOWS_STORE) && _MSC_FULL_VER < 180031101 - - void Sleep(unsigned long dwMilliseconds) - { -diff --git a/src/3rdparty/angle/src/common/utilities.h b/src/3rdparty/angle/src/common/utilities.h -index 2cf6bed..7583d3e 100644 ---- a/src/3rdparty/angle/src/common/utilities.h -+++ b/src/3rdparty/angle/src/common/utilities.h -@@ -51,7 +51,7 @@ std::string getTempPath(); - void writeFile(const char* path, const void* data, size_t size); - #endif - --#if defined(ANGLE_ENABLE_WINDOWS_STORE) -+#if defined(ANGLE_ENABLE_WINDOWS_STORE) && _MSC_FULL_VER < 180031101 - void Sleep(_In_ unsigned long dwMilliseconds); - #endif - --- -1.9.4.msysgit.2 - diff --git a/src/angle/src/common/common.pri b/src/angle/src/common/common.pri index 7d3f46d65f..63b80347d1 100644 --- a/src/angle/src/common/common.pri +++ b/src/angle/src/common/common.pri @@ -46,20 +46,4 @@ win32-msvc2012|win32-msvc2013|winrt { } } -static: DEFINES *= QT_OPENGL_ES_2_ANGLE_STATIC - -HEADERS += \ - $$ANGLE_DIR/src/common/angleutils.h \ - $$ANGLE_DIR/src/common/debug.h \ - $$ANGLE_DIR/src/common/mathutil.h \ - $$ANGLE_DIR/src/common/platform.h \ - $$ANGLE_DIR/src/common/RefCountObject.h \ - $$ANGLE_DIR/src/common/tls.h \ - $$ANGLE_DIR/src/common/version.h - -SOURCES += \ - $$ANGLE_DIR/src/common/angleutils.cpp \ - $$ANGLE_DIR/src/common/debug.cpp \ - $$ANGLE_DIR/src/common/RefCountObject.cpp \ - $$ANGLE_DIR/src/common/tls.cpp - +static: DEFINES *= LIBGLESV2_EXPORT_H_ ANGLE_EXPORT= diff --git a/src/angle/src/compiler/preprocessor/preprocessor.pro b/src/angle/src/compiler/preprocessor/preprocessor.pro index 420cb90b36..8c5b1555dc 100644 --- a/src/angle/src/compiler/preprocessor/preprocessor.pro +++ b/src/angle/src/compiler/preprocessor/preprocessor.pro @@ -48,7 +48,7 @@ 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.commands = $$addGnuPath(win_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 diff --git a/src/angle/src/compiler/translator.pro b/src/angle/src/compiler/translator.pro index 6f0128d6de..e9d16ca5af 100644 --- a/src/angle/src/compiler/translator.pro +++ b/src/angle/src/compiler/translator.pro @@ -1,14 +1,11 @@ CONFIG += static include(../config.pri) -# Mingw 4.7 chokes on implicit move semantics, so disable C++11 here -mingw: CONFIG -= c++11 - INCLUDEPATH += \ $$ANGLE_DIR/src \ $$ANGLE_DIR/include -DEFINES += _SECURE_SCL=0 _LIB COMPILER_IMPLEMENTATION +DEFINES += _SECURE_SCL=0 _LIB ANGLE_TRANSLATOR_IMPLEMENTATION ANGLE_TRANSLATOR_STATIC ANGLE_ENABLE_HLSL FLEX_SOURCES = $$ANGLE_DIR/src/compiler/translator/glslang.l BISON_SOURCES = $$ANGLE_DIR/src/compiler/translator/glslang.y @@ -23,26 +20,31 @@ HEADERS += \ $$ANGLE_DIR/src/common/platform.h \ $$ANGLE_DIR/src/common/tls.h \ $$ANGLE_DIR/src/common/utilities.h \ + $$ANGLE_DIR/src/compiler/translator/blocklayout.h \ + $$ANGLE_DIR/src/compiler/translator/blocklayoutHLSL.h \ $$ANGLE_DIR/src/compiler/translator/BaseTypes.h \ $$ANGLE_DIR/src/compiler/translator/BuiltInFunctionEmulator.h \ + $$ANGLE_DIR/src/compiler/translator/BuiltInFunctionEmulatorGLSL.h \ + $$ANGLE_DIR/src/compiler/translator/BuiltInFunctionEmulatorHLSL.h \ $$ANGLE_DIR/src/compiler/translator/Common.h \ - $$ANGLE_DIR/src/compiler/translator/Compiler.h \ $$ANGLE_DIR/src/compiler/translator/compilerdebug.h \ + $$ANGLE_DIR/src/compiler/translator/Compiler.h \ $$ANGLE_DIR/src/compiler/translator/ConstantUnion.h \ - $$ANGLE_DIR/src/compiler/translator/depgraph/DependencyGraph.h \ $$ANGLE_DIR/src/compiler/translator/depgraph/DependencyGraphBuilder.h \ + $$ANGLE_DIR/src/compiler/translator/depgraph/DependencyGraph.h \ $$ANGLE_DIR/src/compiler/translator/depgraph/DependencyGraphOutput.h \ $$ANGLE_DIR/src/compiler/translator/DetectCallDepth.h \ $$ANGLE_DIR/src/compiler/translator/DetectDiscontinuity.h \ $$ANGLE_DIR/src/compiler/translator/Diagnostics.h \ $$ANGLE_DIR/src/compiler/translator/DirectiveHandler.h \ $$ANGLE_DIR/src/compiler/translator/ExtensionBehavior.h \ + $$ANGLE_DIR/src/compiler/translator/EmulatePrecision.h \ $$ANGLE_DIR/src/compiler/translator/FlagStd140Structs.h \ $$ANGLE_DIR/src/compiler/translator/ForLoopUnroll.h \ $$ANGLE_DIR/src/compiler/translator/HashNames.h \ $$ANGLE_DIR/src/compiler/translator/InfoSink.h \ - $$ANGLE_DIR/src/compiler/translator/Initialize.h \ $$ANGLE_DIR/src/compiler/translator/InitializeDll.h \ + $$ANGLE_DIR/src/compiler/translator/Initialize.h \ $$ANGLE_DIR/src/compiler/translator/InitializeParseContext.h \ $$ANGLE_DIR/src/compiler/translator/InitializeVariables.h \ $$ANGLE_DIR/src/compiler/translator/intermediate.h \ @@ -51,21 +53,23 @@ HEADERS += \ $$ANGLE_DIR/src/compiler/translator/MMap.h \ $$ANGLE_DIR/src/compiler/translator/NodeSearch.h \ $$ANGLE_DIR/src/compiler/translator/osinclude.h \ + $$ANGLE_DIR/src/compiler/translator/Operator.h \ $$ANGLE_DIR/src/compiler/translator/OutputESSL.h \ - $$ANGLE_DIR/src/compiler/translator/OutputGLSL.h \ $$ANGLE_DIR/src/compiler/translator/OutputGLSLBase.h \ + $$ANGLE_DIR/src/compiler/translator/OutputGLSL.h \ $$ANGLE_DIR/src/compiler/translator/OutputHLSL.h \ $$ANGLE_DIR/src/compiler/translator/ParseContext.h \ $$ANGLE_DIR/src/compiler/translator/PoolAlloc.h \ $$ANGLE_DIR/src/compiler/translator/Pragma.h \ $$ANGLE_DIR/src/compiler/translator/QualifierAlive.h \ $$ANGLE_DIR/src/compiler/translator/RegenerateStructNames.h \ - $$ANGLE_DIR/src/compiler/translator/RemoveTree.h \ + $$ANGLE_DIR/src/compiler/translator/RemoveSwitchFallThrough.h \ $$ANGLE_DIR/src/compiler/translator/RenameFunction.h \ $$ANGLE_DIR/src/compiler/translator/RewriteElseBlocks.h \ $$ANGLE_DIR/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.h \ $$ANGLE_DIR/src/compiler/translator/SearchSymbol.h \ $$ANGLE_DIR/src/compiler/translator/ShHandle.h \ + $$ANGLE_DIR/src/compiler/translator/SimplifyArrayAssignment.h \ $$ANGLE_DIR/src/compiler/translator/StructureHLSL.h \ $$ANGLE_DIR/src/compiler/translator/SymbolTable.h \ $$ANGLE_DIR/src/compiler/translator/timing/RestrictFragmentShaderTiming.h \ @@ -74,13 +78,14 @@ HEADERS += \ $$ANGLE_DIR/src/compiler/translator/TranslatorGLSL.h \ $$ANGLE_DIR/src/compiler/translator/TranslatorHLSL.h \ $$ANGLE_DIR/src/compiler/translator/Types.h \ - $$ANGLE_DIR/src/compiler/translator/UnfoldShortCircuit.h \ $$ANGLE_DIR/src/compiler/translator/UnfoldShortCircuitAST.h \ + $$ANGLE_DIR/src/compiler/translator/UnfoldShortCircuit.h \ $$ANGLE_DIR/src/compiler/translator/UniformHLSL.h \ - $$ANGLE_DIR/src/compiler/translator/UtilsHLSL.h \ $$ANGLE_DIR/src/compiler/translator/util.h \ + $$ANGLE_DIR/src/compiler/translator/UtilsHLSL.h \ $$ANGLE_DIR/src/compiler/translator/ValidateLimitations.h \ $$ANGLE_DIR/src/compiler/translator/ValidateOutputs.h \ + $$ANGLE_DIR/src/compiler/translator/ValidateSwitch.h \ $$ANGLE_DIR/src/compiler/translator/VariableInfo.h \ $$ANGLE_DIR/src/compiler/translator/VariablePacker.h \ $$ANGLE_DIR/src/compiler/translator/VersionGLSL.h \ @@ -89,7 +94,11 @@ HEADERS += \ SOURCES += \ $$ANGLE_DIR/src/common/tls.cpp \ + $$ANGLE_DIR/src/compiler/translator/blocklayout.cpp \ + $$ANGLE_DIR/src/compiler/translator/blocklayoutHLSL.cpp \ $$ANGLE_DIR/src/compiler/translator/BuiltInFunctionEmulator.cpp \ + $$ANGLE_DIR/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp \ + $$ANGLE_DIR/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp \ $$ANGLE_DIR/src/compiler/translator/CodeGen.cpp \ $$ANGLE_DIR/src/compiler/translator/Compiler.cpp \ $$ANGLE_DIR/src/compiler/translator/compilerdebug.cpp \ @@ -101,6 +110,7 @@ SOURCES += \ $$ANGLE_DIR/src/compiler/translator/DetectDiscontinuity.cpp \ $$ANGLE_DIR/src/compiler/translator/Diagnostics.cpp \ $$ANGLE_DIR/src/compiler/translator/DirectiveHandler.cpp \ + $$ANGLE_DIR/src/compiler/translator/EmulatePrecision.cpp \ $$ANGLE_DIR/src/compiler/translator/FlagStd140Structs.cpp \ $$ANGLE_DIR/src/compiler/translator/ForLoopUnroll.cpp \ $$ANGLE_DIR/src/compiler/translator/InfoSink.cpp \ @@ -113,6 +123,7 @@ SOURCES += \ $$ANGLE_DIR/src/compiler/translator/intermOut.cpp \ $$ANGLE_DIR/src/compiler/translator/IntermTraverse.cpp \ $$ANGLE_DIR/src/compiler/translator/LoopInfo.cpp \ + $$ANGLE_DIR/src/compiler/translator/Operator.cpp \ $$ANGLE_DIR/src/compiler/translator/OutputESSL.cpp \ $$ANGLE_DIR/src/compiler/translator/OutputGLSL.cpp \ $$ANGLE_DIR/src/compiler/translator/OutputGLSLBase.cpp \ @@ -122,12 +133,13 @@ SOURCES += \ $$ANGLE_DIR/src/compiler/translator/PoolAlloc.cpp \ $$ANGLE_DIR/src/compiler/translator/QualifierAlive.cpp \ $$ANGLE_DIR/src/compiler/translator/RegenerateStructNames.cpp \ - $$ANGLE_DIR/src/compiler/translator/RemoveTree.cpp \ + $$ANGLE_DIR/src/compiler/translator/RemoveSwitchFallThrough.cpp \ $$ANGLE_DIR/src/compiler/translator/RewriteElseBlocks.cpp \ $$ANGLE_DIR/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp \ $$ANGLE_DIR/src/compiler/translator/SearchSymbol.cpp \ $$ANGLE_DIR/src/compiler/translator/ShaderLang.cpp \ $$ANGLE_DIR/src/compiler/translator/ShaderVars.cpp \ + $$ANGLE_DIR/src/compiler/translator/SimplifyArrayAssignment.cpp \ $$ANGLE_DIR/src/compiler/translator/StructureHLSL.cpp \ $$ANGLE_DIR/src/compiler/translator/SymbolTable.cpp \ $$ANGLE_DIR/src/compiler/translator/timing/RestrictFragmentShaderTiming.cpp \ @@ -143,6 +155,7 @@ SOURCES += \ $$ANGLE_DIR/src/compiler/translator/util.cpp \ $$ANGLE_DIR/src/compiler/translator/ValidateLimitations.cpp \ $$ANGLE_DIR/src/compiler/translator/ValidateOutputs.cpp \ + $$ANGLE_DIR/src/compiler/translator/ValidateSwitch.cpp \ $$ANGLE_DIR/src/compiler/translator/VariableInfo.cpp \ $$ANGLE_DIR/src/compiler/translator/VariablePacker.cpp \ $$ANGLE_DIR/src/compiler/translator/VersionGLSL.cpp \ @@ -157,7 +170,7 @@ 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 \ +bison.commands = $$addGnuPath(win_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 diff --git a/src/angle/src/config.pri b/src/angle/src/config.pri index 9a7bc8a68c..0d75245ec5 100644 --- a/src/angle/src/config.pri +++ b/src/angle/src/config.pri @@ -37,8 +37,6 @@ DEFINES += _WINDOWS \ NOMINMAX \ WIN32_LEAN_AND_MEAN=1 -!winrt: DEFINES += ANGLE_ENABLE_D3D9 ANGLE_SKIP_DXGI_1_2_CHECK - CONFIG += angle_d3d11 # Remove to disable D3D11 renderer equals(QMAKE_TARGET_OS, xp): CONFIG -= angle_d3d11 @@ -70,11 +68,12 @@ msvc { # 4245: 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch # 4267: coversion from 'size_t' to 'int', possible loss of data # 4275: non - DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier' + # 4480: nonstandard extension used: specifying underlying type for enum # 4512: 'class' : assignment operator could not be generated # 4702: unreachable code # 4996: Function call with parameters that may be unsafe QMAKE_CFLAGS_WARN_ON -= -W3 - QMAKE_CFLAGS_WARN_ON += -W4 -wd"4100" -wd"4127" -wd"4189" -wd"4239" -wd"4244" -wd"4245" -wd"4267" -wd"4275" -wd"4512" -wd"4702" -wd"4996" + QMAKE_CFLAGS_WARN_ON += -W4 -wd"4100" -wd"4127" -wd"4189" -wd"4239" -wd"4244" -wd"4245" -wd"4267" -wd"4275" -wd"4512" -wd"4702" -wd"4996" -wd"4480" # Optimizations # /Oy: Omits frame pointer (x86 only). # /Gy: Enables function-level linking. diff --git a/src/angle/src/libEGL/libEGL.pro b/src/angle/src/libEGL/libEGL.pro index a16249309f..94fcebda6b 100644 --- a/src/angle/src/libEGL/libEGL.pro +++ b/src/angle/src/libEGL/libEGL.pro @@ -5,40 +5,13 @@ winrt: LIBS_PRIVATE += -ld3d11 LIBS_PRIVATE += -ldxguid -L$$QT_BUILD_TREE/lib -l$$qtLibraryTarget(libGLESv2) +DEFINES += GL_APICALL= GL_GLEXT_PROTOTYPES= EGLAPI= LIBEGL_IMPLEMENTATION + HEADERS += \ - $$ANGLE_DIR/src/common/NativeWindow.h \ - $$ANGLE_DIR/src/libEGL/AttributeMap.h \ - $$ANGLE_DIR/src/libEGL/Config.h \ - $$ANGLE_DIR/src/libEGL/Display.h \ - $$ANGLE_DIR/src/libEGL/Error.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 + $$ANGLE_DIR/src/libEGL/resource.h SOURCES += \ - $$ANGLE_DIR/src/libEGL/AttributeMap.cpp \ - $$ANGLE_DIR/src/libEGL/Config.cpp \ - $$ANGLE_DIR/src/libEGL/Display.cpp \ - $$ANGLE_DIR/src/libEGL/Error.cpp \ - $$ANGLE_DIR/src/libEGL/libEGL.cpp \ - $$ANGLE_DIR/src/libEGL/main.cpp \ - $$ANGLE_DIR/src/libEGL/Surface.cpp - -!winrt { - SOURCES += \ - $$ANGLE_DIR/src/common/win32/NativeWindow.cpp -} else { - HEADERS += \ - $$ANGLE_DIR/src/common/winrt/CoreWindowNativeWindow.h \ - $$ANGLE_DIR/src/common/winrt/InspectableNativeWindow.h \ - $$ANGLE_DIR/src/common/winrt/SwapChainPanelNativeWindow.h - - SOURCES += \ - $$ANGLE_DIR/src/common/winrt/CoreWindowNativeWindow.cpp \ - $$ANGLE_DIR/src/common/winrt/InspectableNativeWindow.cpp \ - $$ANGLE_DIR/src/common/winrt/SwapChainPanelNativeWindow.cpp -} + $$ANGLE_DIR/src/libEGL/libEGL.cpp !static { DEF_FILE = $$ANGLE_DIR/src/libEGL/$${TARGET}.def diff --git a/src/angle/src/libGLESv2/libGLESv2.pro b/src/angle/src/libGLESv2/libGLESv2.pro index 705768d17d..a783318bb1 100644 --- a/src/angle/src/libGLESv2/libGLESv2.pro +++ b/src/angle/src/libGLESv2/libGLESv2.pro @@ -1,7 +1,7 @@ CONFIG += simd installed include(../common/common.pri) -INCLUDEPATH += $$OUT_PWD/.. $$ANGLE_DIR/src/libGLESv2 +INCLUDEPATH += $$OUT_PWD/.. $$ANGLE_DIR/src/libANGLE # Remember to adapt tools/configure/configureapp.cpp if the Direct X version changes. !winrt: \ @@ -20,237 +20,310 @@ for(libname, STATICLIBS) { PRE_TARGETDEPS += $$staticlib } +DEFINES += LIBANGLE_IMPLEMENTATION LIBGLESV2_IMPLEMENTATION GL_APICALL= GL_GLEXT_PROTOTYPES= EGLAPI= ANGLE_ENABLE_D3D11 +!winrt: DEFINES += ANGLE_ENABLE_D3D9 ANGLE_SKIP_DXGI_1_2_CHECK + HEADERS += \ $$ANGLE_DIR/src/common/blocklayout.h \ + $$ANGLE_DIR/src/common/NativeWindow.h \ $$ANGLE_DIR/src/common/shadervars.h \ $$ANGLE_DIR/src/common/utilities.h \ - $$ANGLE_DIR/src/common/NativeWindow.h \ - $$ANGLE_DIR/src/libGLESv2/angletypes.h \ - $$ANGLE_DIR/src/libGLESv2/BinaryStream.h \ - $$ANGLE_DIR/src/libGLESv2/Buffer.h \ - $$ANGLE_DIR/src/libGLESv2/Caps.h \ - $$ANGLE_DIR/src/libGLESv2/Context.h \ - $$ANGLE_DIR/src/libGLESv2/Data.h \ - $$ANGLE_DIR/src/libGLESv2/Error.h \ - $$ANGLE_DIR/src/libGLESv2/Fence.h \ - $$ANGLE_DIR/src/libGLESv2/formatutils.h \ - $$ANGLE_DIR/src/libGLESv2/Framebuffer.h \ - $$ANGLE_DIR/src/libGLESv2/FramebufferAttachment.h \ - $$ANGLE_DIR/src/libGLESv2/HandleAllocator.h \ - $$ANGLE_DIR/src/libGLESv2/ImageIndex.h \ - $$ANGLE_DIR/src/libGLESv2/main.h \ - $$ANGLE_DIR/src/libGLESv2/Program.h \ - $$ANGLE_DIR/src/libGLESv2/ProgramBinary.h \ - $$ANGLE_DIR/src/libGLESv2/Query.h \ - $$ANGLE_DIR/src/libGLESv2/queryconversions.h \ - $$ANGLE_DIR/src/libGLESv2/Renderbuffer.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/BufferImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/copyimage.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/copyvertex.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/BufferD3D.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/DynamicHLSL.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/HLSLCompiler.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ImageD3D.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/IndexBuffer.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/IndexDataManager.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/MemoryBuffer.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ProgramD3D.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/RenderbufferD3D.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/RendererD3D.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ShaderD3D.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TextureD3D.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TextureStorage.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/VertexArrayImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/VertexBuffer.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/vertexconversion.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/VertexDataManager.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/FenceImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/generatemip.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/Image.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/imageformats.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/IndexCacheRange.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/loadimage.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/ProgramImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/QueryImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/RenderbufferImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/Renderer.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/RenderTarget.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/ShaderExecutable.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/ShaderImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/SwapChain.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/TextureImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/TextureFeedbackImpl.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/VertexDeclarationCache.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/Workarounds.h \ + $$ANGLE_DIR/src/common/MemoryBuffer.h \ + $$ANGLE_DIR/src/common/angleutils.h \ + $$ANGLE_DIR/src/common/debug.h \ + $$ANGLE_DIR/src/common/event_tracer.h \ + $$ANGLE_DIR/src/libANGLE/angletypes.h \ + $$ANGLE_DIR/src/libANGLE/AttributeMap.h \ + $$ANGLE_DIR/src/libANGLE/BinaryStream.h \ + $$ANGLE_DIR/src/libANGLE/Buffer.h \ + $$ANGLE_DIR/src/libANGLE/Caps.h \ + $$ANGLE_DIR/src/libANGLE/Compiler.h \ + $$ANGLE_DIR/src/libANGLE/Config.h \ + $$ANGLE_DIR/src/libANGLE/Constants.h \ + $$ANGLE_DIR/src/libANGLE/Context.h \ + $$ANGLE_DIR/src/libANGLE/Data.h \ + $$ANGLE_DIR/src/libANGLE/Display.h \ + $$ANGLE_DIR/src/libANGLE/Error.h \ + $$ANGLE_DIR/src/libANGLE/features.h \ + $$ANGLE_DIR/src/libANGLE/Fence.h \ + $$ANGLE_DIR/src/libANGLE/formatutils.h \ + $$ANGLE_DIR/src/libANGLE/Framebuffer.h \ + $$ANGLE_DIR/src/libANGLE/FramebufferAttachment.h \ + $$ANGLE_DIR/src/libANGLE/HandleAllocator.h \ + $$ANGLE_DIR/src/libANGLE/ImageIndex.h \ + $$ANGLE_DIR/src/libANGLE/Program.h \ + $$ANGLE_DIR/src/libANGLE/Query.h \ + $$ANGLE_DIR/src/libANGLE/queryconversions.h \ + $$ANGLE_DIR/src/libANGLE/RefCountObject.h \ + $$ANGLE_DIR/src/libANGLE/Renderbuffer.h \ + $$ANGLE_DIR/src/libANGLE/ResourceManager.h \ + $$ANGLE_DIR/src/libANGLE/Sampler.h \ + $$ANGLE_DIR/src/libANGLE/Shader.h \ + $$ANGLE_DIR/src/libANGLE/State.h \ + $$ANGLE_DIR/src/libANGLE/Surface.h \ + $$ANGLE_DIR/src/libANGLE/Texture.h \ + $$ANGLE_DIR/src/libANGLE/TransformFeedback.h \ + $$ANGLE_DIR/src/libANGLE/Uniform.h \ + $$ANGLE_DIR/src/libANGLE/validationEGL.h \ + $$ANGLE_DIR/src/libANGLE/validationES.h \ + $$ANGLE_DIR/src/libANGLE/validationES2.h \ + $$ANGLE_DIR/src/libANGLE/validationES3.h \ + $$ANGLE_DIR/src/libANGLE/VertexArray.h \ + $$ANGLE_DIR/src/libANGLE/VertexAttribute.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/BufferD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/CompilerD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/copyimage.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/DisplayD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/DynamicHLSL.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/formatutilsD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/FramebufferD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/generatemip.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/HLSLCompiler.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/ImageD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/imageformats.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/IndexBuffer.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/IndexDataManager.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/loadimage.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/ProgramD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/RenderbufferD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/RendererD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/RenderTargetD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/ShaderD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/ShaderExecutableD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/SurfaceD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/SwapChainD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/TextureD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/TextureStorage.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/TransformFeedbackD3D.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/VertexBuffer.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/VertexDataManager.h \ + $$ANGLE_DIR/src/libANGLE/renderer/BufferImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/CompilerImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/DisplayImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/FenceNVImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/FenceSyncImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/FramebufferImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/Image.h \ + $$ANGLE_DIR/src/libANGLE/renderer/ImplFactory.h \ + $$ANGLE_DIR/src/libANGLE/renderer/IndexRangeCache.h \ + $$ANGLE_DIR/src/libANGLE/renderer/ProgramImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/QueryImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/RenderbufferImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/Renderer.h \ + $$ANGLE_DIR/src/libANGLE/renderer/ShaderImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/SurfaceImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/TextureImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/TransformFeedbackImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/VertexArrayImpl.h \ + $$ANGLE_DIR/src/libANGLE/renderer/Workarounds.h \ + $$ANGLE_DIR/src/libANGLE/resource.h \ + $$ANGLE_DIR/src/libANGLE/ResourceManager.h \ + $$ANGLE_DIR/src/libANGLE/Sampler.h \ + $$ANGLE_DIR/src/libANGLE/Shader.h \ + $$ANGLE_DIR/src/libANGLE/State.h \ + $$ANGLE_DIR/src/libANGLE/Texture.h \ + $$ANGLE_DIR/src/libANGLE/TransformFeedback.h \ + $$ANGLE_DIR/src/libANGLE/Uniform.h \ + $$ANGLE_DIR/src/libANGLE/validationES2.h \ + $$ANGLE_DIR/src/libANGLE/validationES3.h \ + $$ANGLE_DIR/src/libANGLE/validationES.h \ + $$ANGLE_DIR/src/libANGLE/VertexArray.h \ + $$ANGLE_DIR/src/libANGLE/VertexAttribute.h \ + $$ANGLE_DIR/src/libANGLE/vertexconversion.h \ + $$ANGLE_DIR/src/libGLESv2/entry_points_egl.h \ + $$ANGLE_DIR/src/libGLESv2/entry_points_egl_ext.h \ + $$ANGLE_DIR/src/libGLESv2/entry_points_gles_2_0.h \ + $$ANGLE_DIR/src/libGLESv2/entry_points_gles_2_0_ext.h \ + $$ANGLE_DIR/src/libGLESv2/entry_points_gles_3_0.h \ + $$ANGLE_DIR/src/libGLESv2/entry_points_gles_3_0_ext.h \ + $$ANGLE_DIR/src/libGLESv2/global_state.h \ $$ANGLE_DIR/src/libGLESv2/resource.h \ - $$ANGLE_DIR/src/libGLESv2/ResourceManager.h \ - $$ANGLE_DIR/src/libGLESv2/Sampler.h \ - $$ANGLE_DIR/src/libGLESv2/Shader.h \ - $$ANGLE_DIR/src/libGLESv2/State.h \ - $$ANGLE_DIR/src/libGLESv2/Texture.h \ - $$ANGLE_DIR/src/libGLESv2/TransformFeedback.h \ - $$ANGLE_DIR/src/libGLESv2/Uniform.h \ - $$ANGLE_DIR/src/libGLESv2/validationES.h \ - $$ANGLE_DIR/src/libGLESv2/validationES2.h \ - $$ANGLE_DIR/src/libGLESv2/validationES3.h \ - $$ANGLE_DIR/src/libGLESv2/VertexArray.h \ - $$ANGLE_DIR/src/libGLESv2/VertexAttribute.h \ - $$ANGLE_DIR/src/libGLESv2/vertexconversion.h \ - $$ANGLE_DIR/src/third_party/murmurhash/MurmurHash3.h \ + $$ANGLE_DIR/src/third_party/murmurhash/MurmurHash3.h SOURCES += \ - $$ANGLE_DIR/src/common/blocklayout.cpp \ $$ANGLE_DIR/src/common/mathutil.cpp \ $$ANGLE_DIR/src/common/utilities.cpp \ + $$ANGLE_DIR/src/common/MemoryBuffer.cpp \ + $$ANGLE_DIR/src/common/angleutils.cpp \ + $$ANGLE_DIR/src/common/debug.cpp \ + $$ANGLE_DIR/src/common/event_tracer.cpp \ $$ANGLE_DIR/src/third_party/murmurhash/MurmurHash3.cpp \ - $$ANGLE_DIR/src/libGLESv2/angletypes.cpp \ - $$ANGLE_DIR/src/libGLESv2/Buffer.cpp \ - $$ANGLE_DIR/src/libGLESv2/Caps.cpp \ - $$ANGLE_DIR/src/libGLESv2/Context.cpp \ - $$ANGLE_DIR/src/libGLESv2/Data.cpp \ - $$ANGLE_DIR/src/libGLESv2/Error.cpp \ - $$ANGLE_DIR/src/libGLESv2/Fence.cpp \ - $$ANGLE_DIR/src/libGLESv2/Float16ToFloat32.cpp \ - $$ANGLE_DIR/src/libGLESv2/Framebuffer.cpp \ - $$ANGLE_DIR/src/libGLESv2/FramebufferAttachment.cpp \ - $$ANGLE_DIR/src/libGLESv2/formatutils.cpp \ - $$ANGLE_DIR/src/libGLESv2/HandleAllocator.cpp \ - $$ANGLE_DIR/src/libGLESv2/ImageIndex.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/queryconversions.cpp \ - $$ANGLE_DIR/src/libGLESv2/Renderbuffer.cpp \ - $$ANGLE_DIR/src/libGLESv2/ResourceManager.cpp \ - $$ANGLE_DIR/src/libGLESv2/Sampler.cpp \ - $$ANGLE_DIR/src/libGLESv2/Shader.cpp \ - $$ANGLE_DIR/src/libGLESv2/State.cpp \ - $$ANGLE_DIR/src/libGLESv2/Texture.cpp \ - $$ANGLE_DIR/src/libGLESv2/TransformFeedback.cpp \ - $$ANGLE_DIR/src/libGLESv2/Uniform.cpp \ - $$ANGLE_DIR/src/libGLESv2/validationES.cpp \ - $$ANGLE_DIR/src/libGLESv2/validationES2.cpp \ - $$ANGLE_DIR/src/libGLESv2/validationES3.cpp \ - $$ANGLE_DIR/src/libGLESv2/VertexArray.cpp \ - $$ANGLE_DIR/src/libGLESv2/VertexAttribute.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/copyimage.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/loadimage.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/Image.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/IndexRangeCache.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/ProgramImpl.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/RenderbufferImpl.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/Renderer.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/RenderTarget.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/BufferD3D.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ImageD3D.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/IndexBuffer.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/IndexDataManager.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ProgramD3D.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/RendererD3D.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ShaderD3D.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TextureD3D.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TextureStorage.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TransformFeedbackD3D.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/VertexBuffer.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/VertexDataManager.cpp + $$ANGLE_DIR/src/libANGLE/angletypes.cpp \ + $$ANGLE_DIR/src/libANGLE/AttributeMap.cpp \ + $$ANGLE_DIR/src/libANGLE/Buffer.cpp \ + $$ANGLE_DIR/src/libANGLE/Caps.cpp \ + $$ANGLE_DIR/src/libANGLE/Compiler.cpp \ + $$ANGLE_DIR/src/libANGLE/Config.cpp \ + $$ANGLE_DIR/src/libANGLE/Context.cpp \ + $$ANGLE_DIR/src/libANGLE/Data.cpp \ + $$ANGLE_DIR/src/libANGLE/Display.cpp \ + $$ANGLE_DIR/src/libANGLE/Error.cpp \ + $$ANGLE_DIR/src/libANGLE/Fence.cpp \ + $$ANGLE_DIR/src/libANGLE/Float16ToFloat32.cpp \ + $$ANGLE_DIR/src/libANGLE/formatutils.cpp \ + $$ANGLE_DIR/src/libANGLE/Framebuffer.cpp \ + $$ANGLE_DIR/src/libANGLE/FramebufferAttachment.cpp \ + $$ANGLE_DIR/src/libANGLE/HandleAllocator.cpp \ + $$ANGLE_DIR/src/libANGLE/ImageIndex.cpp \ + $$ANGLE_DIR/src/libANGLE/Platform.cpp \ + $$ANGLE_DIR/src/libANGLE/Program.cpp \ + $$ANGLE_DIR/src/libANGLE/Query.cpp \ + $$ANGLE_DIR/src/libANGLE/queryconversions.cpp \ + $$ANGLE_DIR/src/libANGLE/RefCountObject.cpp \ + $$ANGLE_DIR/src/libANGLE/Renderbuffer.cpp \ + $$ANGLE_DIR/src/libANGLE/ResourceManager.cpp \ + $$ANGLE_DIR/src/libANGLE/Sampler.cpp \ + $$ANGLE_DIR/src/libANGLE/Shader.cpp \ + $$ANGLE_DIR/src/libANGLE/State.cpp \ + $$ANGLE_DIR/src/libANGLE/Surface.cpp \ + $$ANGLE_DIR/src/libANGLE/Texture.cpp \ + $$ANGLE_DIR/src/libANGLE/TransformFeedback.cpp \ + $$ANGLE_DIR/src/libANGLE/Uniform.cpp \ + $$ANGLE_DIR/src/libANGLE/validationEGL.cpp \ + $$ANGLE_DIR/src/libANGLE/validationES.cpp \ + $$ANGLE_DIR/src/libANGLE/validationES2.cpp \ + $$ANGLE_DIR/src/libANGLE/validationES3.cpp \ + $$ANGLE_DIR/src/libANGLE/VertexArray.cpp \ + $$ANGLE_DIR/src/libANGLE/VertexAttribute.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/DisplayImpl.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/IndexRangeCache.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/ProgramImpl.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/RenderbufferImpl.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/Renderer.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/SurfaceImpl.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/BufferD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/CompilerD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/copyimage.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/DisplayD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/DynamicHLSL.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/formatutilsD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/FramebufferD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/HLSLCompiler.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/ImageD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/IndexBuffer.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/IndexDataManager.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/loadimage.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/loadimageSSE2.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/ProgramD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/RendererD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/RenderTargetD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/ShaderD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/ShaderExecutableD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/SurfaceD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/TextureD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/TextureStorage.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/TransformFeedbackD3D.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/VertexBuffer.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/VertexDataManager.cpp \ + $$ANGLE_DIR/src/libGLESv2/entry_points_egl.cpp \ + $$ANGLE_DIR/src/libGLESv2/entry_points_egl_ext.cpp \ + $$ANGLE_DIR/src/libGLESv2/entry_points_gles_2_0.cpp \ + $$ANGLE_DIR/src/libGLESv2/entry_points_gles_2_0_ext.cpp \ + $$ANGLE_DIR/src/libGLESv2/entry_points_gles_3_0.cpp \ + $$ANGLE_DIR/src/libGLESv2/entry_points_gles_3_0_ext.cpp \ + $$ANGLE_DIR/src/libGLESv2/global_state.cpp \ + $$ANGLE_DIR/src/libGLESv2/libGLESv2.cpp + angle_d3d11 { HEADERS += \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Blit11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Clear11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Fence11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/formatutils11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Image11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Query11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Blit11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Buffer11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Clear11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Fence11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/formatutils11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Image11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Query11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Renderer11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/SwapChain11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Trim11.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.h SOURCES += \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Blit11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Clear11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/DebugAnnotator11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Framebuffer11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/formatutils11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Image11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/IndexBuffer11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/PixelTransfer11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Query11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/RenderTarget11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/RenderStateCache.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/ShaderExecutable11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Trim11.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/VertexBuffer11.cpp } -SSE2_SOURCES += $$ANGLE_DIR/src/libGLESv2/renderer/loadimageSSE2.cpp - !winrt { HEADERS += \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Blit9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Fence9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/formatutils9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Image9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Query9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Blit9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Buffer9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Fence9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/formatutils9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Image9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Query9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Renderer9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/SwapChain9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.h \ $$ANGLE_DIR/src/third_party/systeminfo/SystemInfo.h SOURCES += \ - $$ANGLE_DIR/src/common/win32/NativeWindow.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/formatutils9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/ShaderExecutable9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Blit9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Buffer9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/DebugAnnotator9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Fence9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Framebuffer9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/formatutils9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Image9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/IndexBuffer9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Query9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/RenderTarget9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/ShaderExecutable9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/SwapChain9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/TextureStorage9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/VertexBuffer9.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp \ $$ANGLE_DIR/src/third_party/systeminfo/SystemInfo.cpp } else { HEADERS += \ - $$ANGLE_DIR/src/common/winrt/CoreWindowNativeWindow.h \ - $$ANGLE_DIR/src/common/winrt/InspectableNativeWindow.h \ - $$ANGLE_DIR/src/common/winrt/SwapChainPanelNativeWindow.h + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.h \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.h SOURCES += \ - $$ANGLE_DIR/src/common/winrt/CoreWindowNativeWindow.cpp \ - $$ANGLE_DIR/src/common/winrt/InspectableNativeWindow.cpp \ - $$ANGLE_DIR/src/common/winrt/SwapChainPanelNativeWindow.cpp + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp \ + $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/winrt/SwapChainPanelNativeWindow.cpp } !static { @@ -259,87 +332,234 @@ SSE2_SOURCES += $$ANGLE_DIR/src/libGLESv2/renderer/loadimageSSE2.cpp } float_converter.target = float_converter -float_converter.commands = python $$ANGLE_DIR/src/libGLESv2/Float16ToFloat32.py \ - > $$ANGLE_DIR/src/libGLESv2/Float16ToFloat32.cpp +float_converter.commands = python $$ANGLE_DIR/src/libANGLE/Float16ToFloat32.py \ + > $$ANGLE_DIR/src/libANGLE/Float16ToFloat32.cpp QMAKE_EXTRA_TARGETS += float_converter -# Generate the shader header files. -SHADER9_INPUT_DIR = $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/shaders -SHADER11_INPUT_DIR = $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/shaders +# HLSL shaders +BLITVS = $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.vs +standardvs.input = BLITVS +standardvs.type = vs_2_0 +standardvs.output = standardvs.h +flipyvs.input = BLITVS +flipyvs.type = vs_2_0 +flipyvs.output = flipyvs.h + +BLITPS = $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d9/shaders/Blit.ps +passthroughps.input = BLITPS +passthroughps.type = ps_2_0 +passthroughps.output = passthroughps.h +luminanceps.input = BLITPS +luminanceps.type = ps_2_0 +luminanceps.output = luminanceps.h +componentmaskps.input = BLITPS +componentmaskps.type = ps_2_0 +componentmaskps.output = componentmaskps.h -BLITPS_INPUT = $$SHADER9_INPUT_DIR/Blit.ps -BLITPS.shaders = PS_passthrough PS_luminance PS_componentmask -BLITPS.profile = 2_0 +PASSTHROUGH2D = $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough2D11.hlsl +VS_Passthrough2D.input = PASSTHROUGH2D +VS_Passthrough2D.type = vs_4_0_level_9_3 +VS_Passthrough2D.output = passthrough2d11vs.h +PS_PassthroughRGBA2D.input = PASSTHROUGH2D +PS_PassthroughRGBA2D.type = ps_4_0_level_9_3 +PS_PassthroughRGBA2D.output = passthroughrgba2d11ps.h +PS_PassthroughRGB2D.input = PASSTHROUGH2D +PS_PassthroughRGB2D.type = ps_4_0_level_9_3 +PS_PassthroughRGB2D.output = passthroughrgb2d11ps.h +PS_PassthroughRG2D.input = PASSTHROUGH2D +PS_PassthroughRG2D.type = ps_4_0_level_9_3 +PS_PassthroughRG2D.output = passthroughrg2d11ps.h +PS_PassthroughR2D.input = PASSTHROUGH2D +PS_PassthroughR2D.type = ps_4_0_level_9_3 +PS_PassthroughR2D.output = passthroughr2d11ps.h +PS_PassthroughLum2D.input = PASSTHROUGH2D +PS_PassthroughLum2D.type = ps_4_0_level_9_3 +PS_PassthroughLum2D.output = passthroughlum2d11ps.h +PS_PassthroughLumAlpha2D.input = PASSTHROUGH2D +PS_PassthroughLumAlpha2D.type = ps_4_0_level_9_3 +PS_PassthroughLumAlpha2D.output = passthroughlumalpha2d11ps.h +PS_PassthroughDepth2D.input = PASSTHROUGH2D +PS_PassthroughDepth2D.type = ps_4_0 +PS_PassthroughDepth2D.output = passthroughdepth2d11ps.h +PS_PassthroughRGBA2DUI.input = PASSTHROUGH2D +PS_PassthroughRGBA2DUI.type = ps_4_0 +PS_PassthroughRGBA2DUI.output = passthroughrgba2dui11ps.h +PS_PassthroughRGBA2DI.input = PASSTHROUGH2D +PS_PassthroughRGBA2DI.type = ps_4_0 +PS_PassthroughRGBA2DI.output = passthroughrgba2di11ps.h +PS_PassthroughRGB2DUI.input = PASSTHROUGH2D +PS_PassthroughRGB2DUI.type = ps_4_0 +PS_PassthroughRGB2DUI.output = passthroughrgb2dui11ps.h +PS_PassthroughRGB2DI.input = PASSTHROUGH2D +PS_PassthroughRGB2DI.type = ps_4_0 +PS_PassthroughRGB2DI.output = passthroughrgb2di11ps.h +PS_PassthroughRG2DUI.input = PASSTHROUGH2D +PS_PassthroughRG2DUI.type = ps_4_0 +PS_PassthroughRG2DUI.output = passthroughrg2dui11ps.h +PS_PassthroughRG2DI.input = PASSTHROUGH2D +PS_PassthroughRG2DI.type = ps_4_0 +PS_PassthroughRG2DI.output = passthroughrg2di11ps.h +PS_PassthroughR2DUI.input = PASSTHROUGH2D +PS_PassthroughR2DUI.type = ps_4_0 +PS_PassthroughR2DUI.output = passthroughr2dui11ps.h +PS_PassthroughR2DI.input = PASSTHROUGH2D +PS_PassthroughR2DI.type = ps_4_0 +PS_PassthroughR2DI.output = passthroughr2di11ps.h -BLITVS_INPUT = $$SHADER9_INPUT_DIR/Blit.vs -BLITVS.shaders = VS_standard VS_flipy -BLITVS.profile = 2_0 +CLEAR = $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/shaders/Clear11.hlsl +VS_ClearFloat.input = CLEAR +VS_ClearFloat.type = vs_4_0_level_9_3 +VS_ClearFloat.output = clearfloat11vs.h +PS_ClearFloat_FL9.input = CLEAR +PS_ClearFloat_FL9.type = ps_4_0_level_9_3 +PS_ClearFloat_FL9.output = clearfloat11_fl9ps.h +PS_ClearFloat.input = CLEAR +PS_ClearFloat.type = ps_4_0 +PS_ClearFloat.output = clearfloat11ps.h +VS_ClearUint.input = CLEAR +VS_ClearUint.type = vs_4_0 +VS_ClearUint.output = clearuint11vs.h +PS_ClearUint.input = CLEAR +PS_ClearUint.type = ps_4_0 +PS_ClearUint.output = clearuint11ps.h +VS_ClearSint.input = CLEAR +VS_ClearSint.type = vs_4_0 +VS_ClearSint.output = clearsint11vs.h +PS_ClearSint.input = CLEAR +PS_ClearSint.type = ps_4_0 +PS_ClearSint.output = clearsint11ps.h -BUFFERTOTEXTURE_INPUT = $$SHADER11_INPUT_DIR/BufferToTexture11.hlsl -BUFFERTOTEXTURE.shaders = \ - PS_BufferToTexture_4F PS_BufferToTexture_4I PS_BufferToTexture_4UI \ - VS_BufferToTexture GS_BufferToTexture -BUFFERTOTEXTURE.profile = 4_0 +PASSTHROUGH3D = $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/shaders/Passthrough3D11.hlsl +VS_Passthrough3D.input = PASSTHROUGH3D +VS_Passthrough3D.type = vs_4_0 +VS_Passthrough3D.output = passthrough3d11vs.h +GS_Passthrough3D.input = PASSTHROUGH3D +GS_Passthrough3D.type = gs_4_0 +GS_Passthrough3D.output = passthrough3d11gs.h +PS_PassthroughRGBA3D.input = PASSTHROUGH3D +PS_PassthroughRGBA3D.type = ps_4_0 +PS_PassthroughRGBA3D.output = passthroughrgba3d11ps.h +PS_PassthroughRGBA3DUI.input = PASSTHROUGH3D +PS_PassthroughRGBA3DUI.type = ps_4_0 +PS_PassthroughRGBA3DUI.output = passthroughrgba3dui11ps.h +PS_PassthroughRGBA3DI.input = PASSTHROUGH3D +PS_PassthroughRGBA3DI.type = ps_4_0 +PS_PassthroughRGBA3DI.output = passthroughrgba3di11ps.h +PS_PassthroughRGB3D.input = PASSTHROUGH3D +PS_PassthroughRGB3D.type = ps_4_0 +PS_PassthroughRGB3D.output = passthroughrgb3d11ps.h +PS_PassthroughRGB3DUI.input = PASSTHROUGH3D +PS_PassthroughRGB3DUI.type = ps_4_0 +PS_PassthroughRGB3DUI.output = passthroughrgb3dui11ps.h +PS_PassthroughRGB3DI.input = PASSTHROUGH3D +PS_PassthroughRGB3DI.type = ps_4_0 +PS_PassthroughRGB3DI.output = passthroughrgb3di11ps.h +PS_PassthroughRG3D.input = PASSTHROUGH3D +PS_PassthroughRG3D.type = ps_4_0 +PS_PassthroughRG3D.output = passthroughrg3d11ps.h +PS_PassthroughRG3DUI.input = PASSTHROUGH3D +PS_PassthroughRG3DUI.type = ps_4_0 +PS_PassthroughRG3DUI.output = passthroughrg3dui11ps.h +PS_PassthroughRG3DI.input = PASSTHROUGH3D +PS_PassthroughRG3DI.type = ps_4_0 +PS_PassthroughRG3DI.output = passthroughrg3di11ps.h +PS_PassthroughR3D.input = PASSTHROUGH3D +PS_PassthroughR3D.type = ps_4_0 +PS_PassthroughR3D.output = passthroughr3d11ps.h +PS_PassthroughR3DUI.input = PASSTHROUGH3D +PS_PassthroughR3DUI.type = ps_4_0 +PS_PassthroughR3DUI.output = passthroughr3dui11ps.h +PS_PassthroughR3DI.input = PASSTHROUGH3D +PS_PassthroughR3DI.type = ps_4_0 +PS_PassthroughR3DI.output = passthroughr3di11ps.h +PS_PassthroughLum3D.input = PASSTHROUGH3D +PS_PassthroughLum3D.type = ps_4_0 +PS_PassthroughLum3D.output = passthroughlum3d11ps.h +PS_PassthroughLumAlpha3D.input = PASSTHROUGH3D +PS_PassthroughLumAlpha3D.type = ps_4_0 +PS_PassthroughLumAlpha3D.output = passthroughlumalpha3d11ps.h -CLEAR_INPUT = $$SHADER11_INPUT_DIR/Clear11.hlsl -CLEAR.shaders = \ - PS_ClearUint PS_ClearSint \ - VS_ClearUint VS_ClearSint -CLEAR.shaders_compat = PS_ClearFloat VS_ClearFloat -CLEAR.profile = 4_0 +SWIZZLE = $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/shaders/Swizzle11.hlsl +PS_SwizzleF2D.input = SWIZZLE +PS_SwizzleF2D.type = ps_4_0 +PS_SwizzleF2D.output = swizzlef2dps.h +PS_SwizzleI2D.input = SWIZZLE +PS_SwizzleI2D.type = ps_4_0 +PS_SwizzleI2D.output = swizzlei2dps.h +PS_SwizzleUI2D.input = SWIZZLE +PS_SwizzleUI2D.type = ps_4_0 +PS_SwizzleUI2D.output = swizzleui2dps.h +PS_SwizzleF3D.input = SWIZZLE +PS_SwizzleF3D.type = ps_4_0 +PS_SwizzleF3D.output = swizzlef3dps.h +PS_SwizzleI3D.input = SWIZZLE +PS_SwizzleI3D.type = ps_4_0 +PS_SwizzleI3D.output = swizzlei3dps.h +PS_SwizzleUI3D.input = SWIZZLE +PS_SwizzleUI3D.type = ps_4_0 +PS_SwizzleUI3D.output = swizzleui3dps.h +PS_SwizzleF2DArray.input = SWIZZLE +PS_SwizzleF2DArray.type = ps_4_0 +PS_SwizzleF2DArray.output = swizzlef2darrayps.h +PS_SwizzleI2DArray.input = SWIZZLE +PS_SwizzleI2DArray.type = ps_4_0 +PS_SwizzleI2DArray.output = swizzlei2darrayps.h +PS_SwizzleUI2DArray.input = SWIZZLE +PS_SwizzleUI2DArray.type = ps_4_0 +PS_SwizzleUI2DArray.output = swizzleui2darrayps.h -PASSTHROUGH2D_INPUT = $$SHADER11_INPUT_DIR/Passthrough2D11.hlsl -PASSTHROUGH2D.shaders = \ - PS_PassthroughRGBA2DUI PS_PassthroughRGBA2DI \ - PS_PassthroughRGB2DUI PS_PassthroughRGB2DI \ - PS_PassthroughRG2DUI PS_PassthroughRG2DI \ - PS_PassthroughR2DUI PS_PassthroughR2DI \ - PS_PassthroughDepth2D -PASSTHROUGH2D.shaders_compat = \ - PS_PassthroughRGBA2D PS_PassthroughRGB2D \ - PS_PassthroughRG2D PS_PassthroughR2D \ - PS_PassthroughLum2D PS_PassthroughLumAlpha2D \ - VS_Passthrough2D -PASSTHROUGH2D.profile = 4_0 +BUFFERTOTEXTURE = $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/shaders/BufferToTexture11.hlsl +VS_BufferToTexture.input = BUFFERTOTEXTURE +VS_BufferToTexture.type = vs_4_0 +VS_BufferToTexture.output = buffertotexture11_vs.h +GS_BufferToTexture.input = BUFFERTOTEXTURE +GS_BufferToTexture.type = gs_4_0 +GS_BufferToTexture.output = buffertotexture11_gs.h +PS_BufferToTexture_4F.input = BUFFERTOTEXTURE +PS_BufferToTexture_4F.type = ps_4_0 +PS_BufferToTexture_4F.output = buffertotexture11_ps_4f.h +PS_BufferToTexture_4I.input = BUFFERTOTEXTURE +PS_BufferToTexture_4I.type = ps_4_0 +PS_BufferToTexture_4I.output = buffertotexture11_ps_4i.h +PS_BufferToTexture_4UI.input = BUFFERTOTEXTURE +PS_BufferToTexture_4UI.type = ps_4_0 +PS_BufferToTexture_4UI.output = buffertotexture11_ps_4ui.h -PASSTHROUGH3D_INPUT = $$SHADER11_INPUT_DIR/Passthrough3D11.hlsl -PASSTHROUGH3D.shaders = \ +# D3D11 +angle_d3d11: SHADERS = VS_Passthrough2D \ + PS_PassthroughRGB2D PS_PassthroughRGB2DUI PS_PassthroughRGB2DI \ + PS_PassthroughRGBA2D PS_PassthroughRGBA2DUI PS_PassthroughRGBA2DI \ + PS_PassthroughRG2D PS_PassthroughRG2DUI PS_PassthroughRG2DI \ + PS_PassthroughR2D PS_PassthroughR2DUI PS_PassthroughR2DI \ + PS_PassthroughLum2D PS_PassthroughLumAlpha2D PS_PassthroughDepth2D \ + VS_ClearFloat VS_ClearUint VS_ClearSint \ + PS_ClearFloat PS_ClearFloat_FL9 PS_ClearUint PS_ClearSint \ + VS_Passthrough3D GS_Passthrough3D \ PS_PassthroughRGBA3D PS_PassthroughRGBA3DUI PS_PassthroughRGBA3DI \ PS_PassthroughRGB3D PS_PassthroughRGB3DUI PS_PassthroughRGB3DI \ PS_PassthroughRG3D PS_PassthroughRG3DUI PS_PassthroughRG3DI \ PS_PassthroughR3D PS_PassthroughR3DUI PS_PassthroughR3DI \ PS_PassthroughLum3D PS_PassthroughLumAlpha3D \ - VS_Passthrough3D GS_Passthrough3D -PASSTHROUGH3D.profile = 4_0 - -SWIZZLE_INPUT = $$SHADER11_INPUT_DIR/Swizzle11.hlsl -SWIZZLE.shaders = \ - PS_SwizzleI2D PS_SwizzleUI2D \ + PS_SwizzleF2D PS_SwizzleI2D PS_SwizzleUI2D \ PS_SwizzleF3D PS_SwizzleI3D PS_SwizzleUI3D \ - PS_SwizzleF2DArray PS_SwizzleI2DArray PS_SwizzleUI2DArray -SWIZZLE.shaders_compat = PS_SwizzleF2D -SWIZZLE.profile = 4_0 + PS_SwizzleF2DArray PS_SwizzleI2DArray PS_SwizzleUI2DArray \ + VS_BufferToTexture GS_BufferToTexture \ + PS_BufferToTexture_4F PS_BufferToTexture_4I PS_BufferToTexture_4UI -angle_d3d11: FXC_JOBS = BUFFERTOTEXTURE CLEAR PASSTHROUGH2D PASSTHROUGH3D SWIZZLE -!winrt: FXC_JOBS += BLITPS BLITVS +# D3D9 +!winrt: SHADERS += standardvs flipyvs passthroughps luminanceps componentmaskps -for (JOB, FXC_JOBS) { - INPUT = $${JOB}_INPUT - OUT_DIR = $$OUT_PWD/$$relative_path($$dirname($$INPUT), $$ANGLE_DIR/src/libGLESv2)/compiled - SHADERS_COMPAT = $$eval($${JOB}.shaders_compat) - SHADERS = $$eval($${JOB}.shaders) $$SHADERS_COMPAT - for(SHADER, SHADERS) { - TYPE = $$lower($$section(SHADER, _, 0, 0)) - PROFILE = $${TYPE}_$$eval($${JOB}.profile) - contains(SHADERS_COMPAT, $$SHADER): PROFILE = $${PROFILE}_level_9_1 - fxc_$${SHADER}_$${PROFILE}.commands = $$FXC /nologo /E $${SHADER} /T $${PROFILE} /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} - fxc_$${SHADER}_$${PROFILE}.output = $$OUT_DIR/$$section(SHADER, _, 1)$${TYPE}.h - fxc_$${SHADER}_$${PROFILE}.input = $$INPUT - fxc_$${SHADER}_$${PROFILE}.dependency_type = TYPE_C - fxc_$${SHADER}_$${PROFILE}.variable_out = HEADERS - fxc_$${SHADER}_$${PROFILE}.CONFIG += target_predeps - QMAKE_EXTRA_COMPILERS += fxc_$${SHADER}_$${PROFILE} - } +# Generate headers +for (SHADER, SHADERS) { + INPUT = $$eval($${SHADER}.input) + OUT_DIR = $$OUT_PWD/libANGLE/$$relative_path($$dirname($$INPUT), $$ANGLE_DIR/src/libANGLE)/compiled + fxc_$${SHADER}.commands = $$FXC /nologo /E $${SHADER} /T $$eval($${SHADER}.type) /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} + fxc_$${SHADER}.output = $$OUT_DIR/$$eval($${SHADER}.output) + fxc_$${SHADER}.input = $$INPUT + fxc_$${SHADER}.dependency_type = TYPE_C + fxc_$${SHADER}.variable_out = HEADERS + fxc_$${SHADER}.CONFIG += target_predeps + QMAKE_EXTRA_COMPILERS += fxc_$${SHADER} } khr_headers.files = $$ANGLE_DIR/include/KHR/khrplatform.h -- cgit v1.2.3 From 310488a19636a0f33ad11f4100c6af16c2261c07 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 18 Mar 2015 18:40:20 +0200 Subject: windows: Fix platform plugin compilation with new angle The identifiers for configuring a software renderer changed. Change-Id: I739cedbb0a00bc6be94df716d66cd1520d4f7c9d Reviewed-by: Friedemann Kleint Reviewed-by: Maurice Kalinowski Reviewed-by: Kai Koehne --- src/plugins/platforms/windows/qwindowseglcontext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 7db6abd8ef..0184877fdd 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -366,7 +366,8 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: const EGLint anglePlatformAttributes[][5] = { { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE }, { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_NONE }, - { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_TRUE, EGL_NONE } + { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, EGL_NONE } }; const EGLint *attributes = 0; if (preferredType & QWindowsOpenGLTester::AngleRendererD3d11) -- cgit v1.2.3 From c32048c62f3c592ab6bca9345ba61031e5a23742 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 25 Mar 2015 22:06:34 +0200 Subject: winrt: Fix platform plugin after ANGLE upgrade Remove manual EGL window resizing as this is now handled inside ANGLE. Change-Id: I0d4c4df71114c60f4ce75e9010f40a0fd58dee1a Reviewed-by: Maurice Kalinowski --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index d53b4e6ab9..c4512b4d2d 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -580,7 +580,7 @@ QWinRTScreen::QWinRTScreen() d->orientation = d->nativeOrientation; onOrientationChanged(Q_NULLPTR, Q_NULLPTR); - d->eglDisplay = eglGetDisplay(d->displayInformation.Get()); + d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (d->eglDisplay == EGL_NO_DISPLAY) qCritical("Failed to initialize EGL display: 0x%x", eglGetError()); @@ -616,14 +616,7 @@ QWinRTScreen::QWinRTScreen() d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->surfaceFormat); d->surfaceFormat = q_glFormatFromConfig(d->eglDisplay, d->eglConfig, d->surfaceFormat); - const QRect bounds = geometry(); - EGLint windowAttributes[] = { - EGL_FIXED_SIZE_ANGLE, EGL_TRUE, - EGL_WIDTH, bounds.width(), - EGL_HEIGHT, bounds.height(), - EGL_NONE - }; - d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), windowAttributes); + d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), NULL); if (d->eglSurface == EGL_NO_SURFACE) qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); } @@ -1087,14 +1080,6 @@ HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs * d->logicalSize = logicalSize; if (d->eglDisplay) { const QRect newGeometry = geometry(); - int width = newGeometry.width(); - int height = newGeometry.height(); -#ifdef Q_OS_WINPHONE // Windows Phone can pass in a negative size to provide orientation information - width *= (d->orientation == Qt::InvertedPortraitOrientation || d->orientation == Qt::LandscapeOrientation) ? -1 : 1; - height *= (d->orientation == Qt::InvertedPortraitOrientation || d->orientation == Qt::InvertedLandscapeOrientation) ? -1 : 1; -#endif - eglSurfaceAttrib(d->eglDisplay, d->eglSurface, EGL_WIDTH, width); - eglSurfaceAttrib(d->eglDisplay, d->eglSurface, EGL_HEIGHT, height); QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); QPlatformScreen::resizeMaximizedWindows(); handleExpose(); -- cgit v1.2.3 From a11ffc7bc6dd3013a4d6986020232d461b4ee250 Mon Sep 17 00:00:00 2001 From: Caroline Chao Date: Wed, 8 Apr 2015 14:03:39 +0200 Subject: testlib: Detect msvc version for blacklisting Check _MSC_VER to detect the msvc version (2010, 2012 or 2013). Change-Id: I96a73d316a6124e38b2c48c5752dfc22357f8d00 Reviewed-by: Simon Hausmann --- src/testlib/qtestblacklist.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp index cd115bdcae..f8285c3ea9 100644 --- a/src/testlib/qtestblacklist.cpp +++ b/src/testlib/qtestblacklist.cpp @@ -103,6 +103,15 @@ const char *matchedConditions[] = #endif #ifdef Q_CC_MSVC "msvc", + #ifdef _MSC_VER + #if _MSC_VER == 1800 + "msvc-2013", + #elif _MSC_VER == 1700 + "msvc-2012", + #elif _MSC_VER == 1600 + "msvc-2010", + #endif + #endif #endif #ifdef Q_AUTOTEST_EXPORT -- cgit v1.2.3 From 68c137cc725ceadec68c455e0e3e365ecb00f2c1 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Wed, 8 Apr 2015 12:30:36 +0200 Subject: Update bundled libpng to version 1.6.17 Merged in the upstream version, which obsoleted many of the local patches. The remaining diff to clean 1.6.17 is archived in the qtpatches.diff file. Change-Id: I5065435dc5a922d3f4a46eb37a23a4877dde2ee6 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/3rdparty/libpng.pri | 1 + src/3rdparty/libpng/ANNOUNCE | 86 +- src/3rdparty/libpng/CHANGES | 1452 ++++++++++++- src/3rdparty/libpng/INSTALL | 316 ++- src/3rdparty/libpng/LICENSE | 6 +- src/3rdparty/libpng/README | 63 +- src/3rdparty/libpng/libpng-manual.txt | 1399 +++++++++---- src/3rdparty/libpng/png.c | 2766 +++++++++++++++++++----- src/3rdparty/libpng/png.h | 1902 +++++++++++------ src/3rdparty/libpng/pngconf.h | 468 +++-- src/3rdparty/libpng/pngdebug.h | 22 +- src/3rdparty/libpng/pngerror.c | 434 +++- src/3rdparty/libpng/pngget.c | 563 ++--- src/3rdparty/libpng/pnginfo.h | 76 +- src/3rdparty/libpng/pnglibconf.h | 183 +- src/3rdparty/libpng/pngmem.c | 672 ++---- src/3rdparty/libpng/pngpread.c | 426 ++-- src/3rdparty/libpng/pngpriv.h | 1649 ++++++++------- src/3rdparty/libpng/pngread.c | 3689 +++++++++++++++++++++++++++++---- src/3rdparty/libpng/pngrio.c | 74 +- src/3rdparty/libpng/pngrtran.c | 1725 ++++++++------- src/3rdparty/libpng/pngrutil.c | 3235 ++++++++++++++++------------- src/3rdparty/libpng/pngset.c | 1115 ++++++---- src/3rdparty/libpng/pngstruct.h | 213 +- src/3rdparty/libpng/pngtrans.c | 180 +- src/3rdparty/libpng/pngwio.c | 114 +- src/3rdparty/libpng/pngwrite.c | 1742 +++++++++++----- src/3rdparty/libpng/pngwtran.c | 255 +-- src/3rdparty/libpng/pngwutil.c | 1858 ++++++++--------- src/3rdparty/libpng/qtpatches.diff | 77 + 30 files changed, 17795 insertions(+), 8966 deletions(-) create mode 100644 src/3rdparty/libpng/qtpatches.diff (limited to 'src') diff --git a/src/3rdparty/libpng.pri b/src/3rdparty/libpng.pri index ae71032e8c..f8516bd5db 100644 --- a/src/3rdparty/libpng.pri +++ b/src/3rdparty/libpng.pri @@ -1,4 +1,5 @@ DEFINES *= QT_USE_BUNDLED_LIBPNG +DEFINES += PNG_ARM_NEON_OPT=0 INCLUDEPATH += $$PWD/libpng SOURCES += $$PWD/libpng/png.c \ $$PWD/libpng/pngerror.c \ diff --git a/src/3rdparty/libpng/ANNOUNCE b/src/3rdparty/libpng/ANNOUNCE index dbc2ed1730..131e0aa369 100644 --- a/src/3rdparty/libpng/ANNOUNCE +++ b/src/3rdparty/libpng/ANNOUNCE @@ -1,5 +1,4 @@ - -Libpng 1.5.10 - March 29, 2012 +Libpng 1.6.17 - March 26, 2015 This is a public release of libpng, intended for use in production codes. @@ -8,52 +7,61 @@ Files available for download: Source files with LF line endings (for Unix/Linux) and with a "configure" script - libpng-1.5.10.tar.xz (LZMA-compressed, recommended) - libpng-1.5.10.tar.gz - libpng-1.5.10.tar.bz2 + libpng-1.6.17.tar.xz (LZMA-compressed, recommended) + libpng-1.6.17.tar.gz Source files with CRLF line endings (for Windows), without the "configure" script - lpng1510.7z (LZMA-compressed, recommended) - lpng1510.zip + lpng1617.7z (LZMA-compressed, recommended) + lpng1617.zip Other information: - libpng-1.5.10-README.txt - libpng-1.5.10-LICENSE.txt + libpng-1.6.17-README.txt + libpng-1.6.17-LICENSE.txt + libpng-1.6.17-*.asc (armored detached GPG signatures) -Changes since the last public release (1.5.9): +Changes since the last public release (1.6.16): - Removed two useless #ifdef directives from pngread.c and one from pngrutil.c - Always put the CMAKE_LIBRARY in "lib" (removed special WIN32 case). - Removed empty vstudio/pngstest directory (Clifford Yapp). - Eliminated redundant png_push_read_tEXt|zTXt|iTXt|unknown code from - pngpread.c and use the sequential png_handle_tEXt, etc., in pngrutil.c; - now that png_ptr->buffer is inaccessible to applications, the special - handling is no longer useful. - Fixed bug with png_handle_hIST with odd chunk length (Frank Busse). - Added PNG_SAFE_LIMITS feature to pnglibconf.dfa and code in pngconf.h - to reset the user limits to safe ones if PNG_SAFE_LIMITS is defined. - To enable, use "CPPFLAGS=-DPNG_SAFE_LIMITS_SUPPORTED" on the configure - command or put "#define PNG_SAFE_LIMITS_SUPPORTED" in pnglibconf.h. - Revised the SAFE_LIMITS feature to be the same as the feature in libpng16. - Added information about the new limits in the manual. - Updated Makefile.in - Removed unused "current_text" members of png_struct and the png_free() - of png_ptr->current_text from pngread.c - Fixed PNG_LIBPNG_BUILD_BASE_TYPE definition. - Fixed CMF optimization of non-IDAT compressed chunks, which was added at - libpng-1.5.4. It sometimes produced too small of a window. - Reject all iCCP chunks after the first, even if the first one is invalid. - Added palette-index checking. Issue a png_benign_error() if an invalid - index is found. - Revised example.c to put text strings in a temporary character array - instead of directly assigning string constants to png_textp members. - This avoids compiler warnings when -Wwrite-strings is enabled. - Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice. - Revised png_set_text_2() to avoid potential memory corruption (fixes - CVE-2011-3048). + Removed duplicate PNG_SAFE_LIMITS_SUPPORTED handling from pngconf.h + Corrected the width limit calculation in png_check_IHDR(). + Removed user limits from pngfix. Also pass NULL pointers to + png_read_row to skip the unnecessary row de-interlace stuff. + Added testing of png_set_packing() to pngvalid.c + Regenerated configure scripts in the *.tar distributions with libtool-2.4.4 + Implement previously untested cases of libpng transforms in pngvalid.c + Fixed byte order in 2-byte filler, in png_do_read_filler(). + Made the check for out-of-range values in png_set_tRNS() detect + values that are exactly 2^bit_depth, and work on 16-bit platforms. + Merged some parts of libpng-1.6.17beta01 and libpng-1.7.0beta47. + Added #ifndef __COVERITY__ where needed in png.c, pngrutil.c and + pngset.c to avoid warnings about dead code. + Do not build png_product2() when it is unused. + Display user limits in the output from pngtest. + Eliminated the PNG_SAFE_LIMITS macro and restored the 1-million-column + and 1-million-row default limits in pnglibconf.dfa, that can be reset + by the user at build time or run time. This provides a more robust + defense against DOS and as-yet undiscovered overflows. + Added PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED macro, on by default. + Allow user to call png_get_IHDR() with NULL arguments (Reuben Hawkins). + Rebuilt configure scripts with automake-1.15 and libtool-2.4.6 + Moved png_set_filter() prototype into a PNG_WRITE_SUPPORTED block + of png.h. + Avoid runtime checks when converting integer to png_byte with + Visual Studio (Sergey Kosarevsky) + Removed some comments that the configure script did not handle + properly from scripts/pnglibconf.dfa and pnglibconf.h.prebuilt. + Free the unknown_chunks structure even when it contains no data. + Updated CMakeLists.txt to add OSX framework, change YES/NO to ON/OFF + for consistency, and remove some useless tests (Alexey Petruchik). + Remove pnglibconf.h, pnglibconf.c, pnglibconf.pre, pnglibconf.dfn, + and pnglibconf.out instead of pnglibconf.* in "make clean" (Cosmin). + Fixed simplified 8-bit-linear to sRGB alpha. The calculated alpha + value was wrong. It's not clear if this affected the final stored + value; in the obvious code path the upper and lower 8-bits of the + alpha value were identical and the alpha was truncated to 8-bits + rather than dividing by 257 (John Bowler). Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/src/3rdparty/libpng/CHANGES b/src/3rdparty/libpng/CHANGES index 70af8273e7..1be09e9385 100644 --- a/src/3rdparty/libpng/CHANGES +++ b/src/3rdparty/libpng/CHANGES @@ -1,4 +1,4 @@ -#if 0 + CHANGES - changes for libpng Version 0.2 @@ -2102,7 +2102,7 @@ Version 1.4.0beta24 [July 25, 2008] png_decompress_chunk(), and remove "chunkdata" from parameter list. Put a call to png_check_chunk_name() in png_read_chunk_header(). Revised png_check_chunk_name() to reject a name with a lowercase 3rd byte. - Removed two calls to png_check_chunk_name() occuring later in the process. + Removed two calls to png_check_chunk_name() occurring later in the process. Define PNG_NO_ERROR_NUMBERS by default in pngconf.h Version 1.4.0beta25 [July 30, 2008] @@ -3672,7 +3672,8 @@ Version 1.5.6 [November 3, 2011] No changes. Version 1.5.7beta01 [November 4, 2011] - Added support for ARM processor (Mans Rullgard) + Added support for ARM processor, when decoding all PNG up-filtered rows + and any other-filtered rows with 3 or 4 bytes per pixel (Mans Rullgard). Fixed bug in pngvalid on early allocation failure; fixed type cast in pngmem.c; pngvalid would attempt to call png_error() if the allocation of a png_struct or png_info failed. This would probably have led to a @@ -3775,84 +3776,1434 @@ Version 1.5.7rc03 [December 7, 2011] Version 1.5.7 [December 15, 2011] Minor fixes to pngvalid.c for gcc 4.6.2 compatibility to remove warnings reported by earlier versions. - -Version 1.5.8beta01 [January 15, 2011] - Removed '#include config.h"' from contrib/libtests/pngvalid.c. It's not - needed and causes trouble for VPATH building. + Fixed minor memset/sizeof errors in pngvalid.c. + +Version 1.6.0beta01 [December 15, 2011] + Removed machine-generated configure files from the GIT repository (they will + continue to appear in the tarball distributions and in the libpng15 and + earlier GIT branches). + Restored the new 'simplified' API, which was started in libpng-1.5.7beta02 + but later deleted from libpng-1.5.7beta05. + Added example programs for the new 'simplified' API. + Added ANSI-C (C90) headers and require them, and take advantage of the + change. Also fixed some of the projects/* and contrib/* files that needed + updates for libpng16 and the move of pngvalid.c. + With this change the required ANSI-C header files are assumed to exist: the + implementation must provide float.h, limits.h, stdarg.h and stddef.h and + libpng relies on limits.h and stddef.h existing and behaving as defined + (the other two required headers aren't used). Non-ANSI systems that don't + have stddef.h or limits.h will have to provide an appropriate fake + containing the relevant types and #defines. + The use of FAR/far has been eliminated and the definition of png_alloc_size_t + is now controlled by a flag so that 'small size_t' systems can select it + if necessary. Libpng 1.6 may not currently work on such systems -- it + seems likely that it will ask 'malloc' for more than 65535 bytes with any + image that has a sufficiently large row size (rather than simply failing + to read such images). + New tools directory containing tools used to generate libpng code. + Fixed race conditions in parallel make builds. With higher degrees of + parallelism during 'make' the use of the same temporary file names such + as 'dfn*' can result in a race where a temporary file from one arm of the + build is deleted or overwritten in another arm. This changes the + temporary files for suffix rules to always use $* and ensures that the + non-suffix rules use unique file names. + +Version 1.6.0beta02 [December 21, 2011] + Correct configure builds where build and source directories are separate. + The include path of 'config.h' was erroneously made relative in pngvalid.c + in libpng 1.5.7. + +Version 1.6.0beta03 [December 22, 2011] + Start-up code size improvements, error handler flexibility. These changes + alter how the tricky allocation of the initial png_struct and png_info + structures are handled. png_info is now handled in pretty much the same + way as everything else, except that the allocations handle NULL return + silently. png_struct is changed in a similar way on allocation and on + deallocation a 'safety' error handler is put in place (which should never + be required). The error handler itself is changed to permit mismatches + in the application and libpng error buffer size; however, this means a + silent change to the API to return the jmp_buf if the size doesn't match + the size from the libpng compilation; libpng now allocates the memory and + this may fail. Overall these changes result in slight code size + reductions; however, this is a reduction in code that is always executed + so is particularly valuable. Overall on a 64-bit system the libpng DLL + decreases in code size by 1733 bytes. pngerror.o increases in size by + about 465 bytes because of the new functionality. + Added png_convert_to_rfc1123_buffer() and deprecated png_convert_to_rfc1123() + to avoid including a spurious buffer in the png_struct. + +Version 1.6.0beta04 [December 30, 2011] + Regenerated configure scripts with automake-1.11.2 + Eliminated png_info_destroy(). It is now used only in png.c and only calls + one other internal function and memset(). + Enabled png_get_sCAL_fixed() if floating point APIs are enabled. Previously + it was disabled whenever internal fixed point arithmetic was selected, + which meant it didn't exist even on systems where FP was available but not + preferred. + Added pngvalid.c compile time checks for const APIs. + Implemented 'restrict' for png_info and png_struct. Because of the way + libpng works both png_info and png_struct are always accessed via a + single pointer. This means adding C99 'restrict' to the pointer gives + the compiler some opportunity to optimize the code. This change allows + that. Moved AC_MSG_CHECKING([if libraries can be versioned]) later to the proper location in configure.ac (Gilles Espinasse). + Changed png_memcpy to C assignment where appropriate. Changed all those + uses of png_memcpy that were doing a simple assignment to assignments + (all those cases where the thing being copied is a non-array C L-value). + Added some error checking to png_set_*() routines. + Removed the reference to the non-exported function png_memcpy() from + example.c. + Fixed the Visual C 64-bit build - it requires jmp_buf to be aligned, but + it had become misaligned. + Revised contrib/pngminus/pnm2png.c to avoid warnings when png_uint_32 + and unsigned long are of different sizes. + +Version 1.6.0beta05 [January 15, 2012] + Updated manual with description of the simplified API (copied from png.h) Fix bug in pngerror.c: some long warnings were being improperly truncated (CVE-2011-3464, bug introduced in libpng-1.5.3beta05). -Version 1.5.8rc01 [January 21, 2012] - No changes. - -Version 1.5.8rc02 [January 25, 2012] +Version 1.6.0beta06 [January 24, 2012] + Added palette support to the simplified APIs. This commit + changes some of the macro definitions in png.h, app code + may need corresponding changes. + Increased the formatted warning buffer to 192 bytes. + Added color-map support to simplified API. This is an initial version for + review; the documentation has not yet been updated. Fixed Min/GW uninstall to remove libpng.dll.a - Conditionalize the install rules for MINGW and CYGWIN in CMakeLists.txt - -Version 1.5.8 [February 1, 2012] - No changes. - -Version 1.5.9beta01 [February 3, 2012] - Rebuilt configure scripts in the tar distributions. -Version 1.5.9beta02 [February 16, 2012] - Removed two unused definitions from scripts/pnglibconf.h.prebuilt +Version 1.6.0beta07 [January 28, 2012] + Eliminated Intel icc/icl compiler warnings. The Intel (GCC derived) + compiler issues slightly different warnings from those issued by the + current vesions of GCC. This eliminates those warnings by + adding/removing casts and small code rewrites. + Updated configure.ac from autoupdate: added --enable-werror option. + Also some layout regularization and removal of introduced tab characters + (replaced with 3-character indentation). Obsolete macros identified by + autoupdate have been removed; the replacements are all in 2.59 so + the pre-req hasn't been changed. --enable-werror checks for support + for -Werror (or the given argument) in the compiler. This mimics the + gcc configure option by allowing -Werror to be turned on safely; without + the option the tests written in configure itself fail compilation because + they cause compiler warnings. + Rewrote autogen.sh to run autoreconf instead of running tools one-by-one. + Conditionalize the install rules for MINGW and CYGWIN in CMakeLists.txt and + set CMAKE_LIBRARY_OUTPUT_DIRECTORY to "lib" on all platforms (C. Yapp). + Freeze libtool files in the 'scripts' directory. This version of autogen.sh + attempts to dissuade people from running it when it is not, or should not, + be necessary. In fact, autogen.sh does not work when run in a libpng + directory extracted from a tar distribution anymore. You must run it in + a GIT clone instead. + Added two images to contrib/pngsuite (1-bit and 2-bit transparent grayscale), + and renamed three whose names were inconsistent with those in + pngsuite/README.txt. + +Version 1.6.0beta08 [February 1, 2012] + Fixed Image::colormap misalignment in pngstest.c + Check libtool/libtoolize version number (2.4.2) in configure.ac + Divide test-pngstest.sh into separate pngstest runs for basic and + transparent images. + Moved automake options to AM_INIT_AUTOMAKE in configure.ac + Added color-tests, silent-rules (Not yet implemented in Makefile.am) and + version checking to configure.ac + Improved pngstest speed by not doing redundant tests and add const to + the background parameter of png_image_finish_read. The --background + option is now done automagically only when required, so that commandline + option no longer exists. + Cleaned up pngpriv.h to consistently declare all functions and data. + Also eliminated PNG_CONST_DATA, which is apparently not needed but we + can't be sure until it is gone. + Added symbol prefixing that allows all the libpng external symbols + to be prefixed (suggested by Reuben Hawkins). + Updated "ftbb*.png" list in the owatcom and vstudio projects. + Fixed 'prefix' builds on clean systems. The generation of pngprefix.h + should not require itself. + Updated INSTALL to explain that autogen.sh must be run in a GIT clone, + not in a libpng directory extracted from a tar distribution. + +Version 1.6.0beta09 [February 1, 2012] + Reverted the prebuilt configure files to libpng-1.6.0beta05 condition. + +Version 1.6.0beta10 [February 3, 2012] + Added Z_SOLO for zlib-1.2.6+ and correct pngstest tests + Updated list of test images in CMakeLists.txt + Updated the prebuilt configure files to current condition. + Revised INSTALL information about autogen.sh; it works in tar distributions. + +Version 1.6.0beta11 [February 16, 2012] + Fix character count in pngstest command in projects/owatcom/pngstest.tgt + Revised test-pngstest.sh to report PASS/FAIL for each image. + Updated documentation about the simplified API. + Corrected estimate of error in libpng png_set_rgb_to_gray API. The API is + extremely inaccurate for sRGB conversions because it uses an 8-bit + intermediate linear value and it does not use the sRGB transform, so it + suffers from the known instability in gamma transforms for values close + to 0 (see Poynton). The net result is that the calculation has a maximum + error of 14.99/255; 0.5/255^(1/2.2). pngstest now uses 15 for the + permitted 8-bit error. This may still not be enough because of arithmetic + error. Removed some unused arrays (with #ifdef) from png_read_push_finish_row(). + Fixed a memory overwrite bug in simplified read of RGB PNG with + non-linear gamma Also bugs in the error checking in pngread.c and changed + quite a lot of the checks in pngstest.c to be correct; either correctly + written or not over-optimistic. The pngstest changes are insufficient to + allow all possible RGB transforms to be passed; pngstest cmppixel needs + to be rewritten to make it clearer which errors it allows and then changed + to permit known inaccuracies. Removed tests for no-longer-used *_EMPTY_PLTE_SUPPORTED from pngstruct.h - -Version 1.5.9rc01 [February 17, 2012] + Fixed fixed/float API export conditionals. 1) If FIXED_POINT or + FLOATING_POINT options were switched off, png.h ended up with lone ';' + characters. This is not valid ANSI-C outside a function. The ';' + characters have been moved inside the definition of PNG_FP_EXPORT and + PNG_FIXED_EXPORT. 2) If either option was switched off, the declaration + of the corresponding functions were completely omitted, even though some + of them are still used internally. The result is still valid, but + produces warnings from gcc with some warning options (including -Wall). The + fix is to cause png.h to declare the functions with PNG_INTERNAL_FUNCTION + when png.h is included from pngpriv.h. + Check for invalid palette index while reading paletted PNG. When one is + found, issue a warning and increase png_ptr->num_palette accordingly. + Apps are responsible for checking to see if that happened. + +Version 1.6.0beta12 [February 18, 2012] + Do not increase num_palette on invalid_index. + Relocated check for invalid palette index to pngrtran.c, after unpacking + the sub-8-bit pixels. Fixed CVE-2011-3026 buffer overrun bug. This bug was introduced when iCCP chunk support was added at libpng-1.0.6. Deal more correctly with the test on iCCP chunk length. Also removed spurious casts that may hide problems on 16-bit systems. -Version 1.5.9 [February 18, 2012] - No changes. - -Version 1.5.10beta01 [February 24, 2012] - Removed two useless #ifdef directives from pngread.c and one from pngrutil.c - Always put the CMAKE_LIBRARY in "lib" (removed special WIN32 case). - Removed empty vstudio/pngstest directory (Clifford Yapp). +Version 1.6.0beta13 [February 24, 2012] Eliminated redundant png_push_read_tEXt|zTXt|iTXt|unknown code from pngpread.c and use the sequential png_handle_tEXt, etc., in pngrutil.c; now that png_ptr->buffer is inaccessible to applications, the special handling is no longer useful. - Fixed bug with png_handle_hIST with odd chunk length (Frank Busse). - Added PNG_SAFE_LIMITS feature to pnglibconf.dfa and code in pngconf.h - to reset the user limits to safe ones if PNG_SAFE_LIMITS is defined. - To enable, use "CPPFLAGS=-DPNG_SAFE_LIMITS_SUPPORTED" on the configure - command or put "#define PNG_SAFE_LIMITS_SUPPORTED" in pnglibconf.h. - Revised the SAFE_LIMITS feature to be the same as the feature in libpng16. - Added information about the new limits in the manual. + Added PNG_SAFE_LIMITS feature to pnglibconf.dfa, pngpriv.h, and new + pngusr.dfa to reset the user limits to safe ones if PNG_SAFE_LIMITS is + defined. To enable, use "CPPFLAGS=-DPNG_SAFE_LIMITS_SUPPORTED=1" on the + configure command or put #define PNG_SAFE_LIMITS_SUPPORTED in + pnglibconf.h.prebuilt and pnglibconf.h. -Version 1.5.10beta02 [February 27, 2012] +Version 1.6.0beta14 [February 27, 2012] + Added information about the new limits in the manual. Updated Makefile.in -Version 1.5.10beta03 [March 6, 2012] +Version 1.6.0beta15 [March 2, 2012] Removed unused "current_text" members of png_struct and the png_free() of png_ptr->current_text from pngread.c - Added palette-index checking. Issue a png_warning() if an invalid index is - found. - -Version 1.5.10beta04 [March 10, 2012] - Fixed PNG_LIBPNG_BUILD_BASE_TYPE definition. - Fixed CMF optimization of non-IDAT compressed chunks, which was added at - libpng-1.5.4. It sometimes produced too small of a window. - -Version 1.5.10beta05 [March 10, 2012] + Rewrote pngstest.c for substantial speed improvement. + Fixed transparent pixel and 16-bit rgb tests in pngstest and removed a + spurious check in pngwrite.c + Added PNG_IMAGE_FLAG_FAST for the benefit of applications that store + intermediate files, or intermediate in-memory data, while processing + image data with the simplified API. The option makes the files larger + but faster to write and read. pngstest now uses this by default; this + can be disabled with the --slow option. + Improved pngstest fine tuning of error numbers, new test file generator. + The generator generates images that test the full range of sample values, + allow the error numbers in pngstest to be tuned and checked. makepng + also allows generation of images with extra chunks, although this is + still work-in-progress. + Added check for invalid palette index while reading. + Fixed some bugs in ICC profile writing. The code should now accept + all potentially valid ICC profiles and reject obviously invalid ones. + It now uses png_error() to do so rather than casually writing a PNG + without the necessary color data. + Removed whitespace from the end of lines in all source files and scripts. + +Version 1.6.0beta16 [March 6, 2012] + Relocated palette-index checking function from pngrutil.c to pngtrans.c + Added palette-index checking while writing. + Changed png_inflate() and calling routines to avoid overflow problems. + This is an intermediate check-in that solves the immediate problems and + introduces one performance improvement (avoiding a copy via png_ptr->zbuf.) + Further changes will be made to make ICC profile handling more secure. + Fixed build warnings (MSVC, GCC, GCC v3). Cygwin GCC with default options + declares 'index' as a global, causing a warning if it is used as a local + variable. GCC 64-bit warns about assigning a (size_t) (unsigned 64-bit) + to an (int) (signed 32-bit). MSVC, however, warns about using the + unary '-' operator on an unsigned value (even though it is well defined + by ANSI-C to be ~x+1). The padding calculation was changed to use a + different method. Removed the tests on png_ptr->pass. + Added contrib/libtests/tarith.c to test internal arithmetic functions from + png.c. This is a libpng maintainer program used to validate changes to the + internal arithmetic functions. + Made read 'inflate' handling like write 'deflate' handling. The read + code now claims and releases png_ptr->zstream, like the write code. + The bug whereby the progressive reader failed to release the zstream + is now fixed, all initialization is delayed, and the code checks for + changed parameters on deflate rather than always calling + deflatedEnd/deflateInit. + Validate the zTXt strings in pngvalid. + Added code to validate the windowBits value passed to deflateInit2(). + If the call to deflateInit2() is wrong a png_warning will be issued + (in fact this is harmless, but the PNG data produced may be sub-optimal). + +Version 1.6.0beta17 [March 10, 2012] + Fixed PNG_LIBPNG_BUILD_BASE_TYPE definition. Reject all iCCP chunks after the first, even if the first one is invalid. + Deflate/inflate was reworked to move common zlib calls into single + functions [rw]util.c. A new shared keyword check routine was also added + and the 'zbuf' is no longer allocated on progressive read. It is now + possible to call png_inflate() incrementally. A warning is no longer + issued if the language tag or translated keyword in the iTXt chunk + has zero length. + If benign errors are disabled use maximum window on ancilliary inflate. + This works round a bug introduced in 1.5.4 where compressed ancillary + chunks could end up with a too-small windowBits value in the deflate + header. + +Version 1.6.0beta18 [March 16, 2012] Issue a png_benign_error() instead of png_warning() about bad palette index. + In pngtest, treat benign errors as errors if "-strict" is present. Fixed an off-by-one error in the palette index checking function. + Fixed a compiler warning under Cygwin (Windows-7, 32-bit system) Revised example.c to put text strings in a temporary character array instead of directly assigning string constants to png_textp members. This avoids compiler warnings when -Wwrite-strings is enabled. - -Version 1.5.10 [March 29, 2012] + Added output flushing to aid debugging under Visual Studio. Unfortunately + this is necessary because the VS2010 output window otherwise simply loses + the error messages on error (they weren't flushed to the window before + the process exited, apparently!) + Added configuration support for benign errors and changed the read + default. Also changed some warnings in the iCCP and sRGB handling + from to benign errors. Configuration now makes read benign + errors warnings and write benign errors to errors by default (thus + changing the behavior on read). The simplified API always forces + read benign errors to warnings (regardless of the system default, unless + this is disabled in which case the simplified API can't be built.) + +Version 1.6.0beta19 [March 18, 2012] + Work around for duplicate row start calls; added warning messages. + This turns on PNG_FLAG_DETECT_UNINITIALIZED to detect app code that + fails to call one of the 'start' routines (not enabled in libpng-1.5 + because it is technically an API change, since it did normally work + before.) It also makes duplicate calls to png_read_start_row (an + internal function called at the start of the image read) benign, as + they were before changes to use png_inflate_claim. Somehow webkit is + causing this to happen; this is probably a mis-feature in the zlib + changes so this commit is only a work-round. + Removed erroneous setting of DETECT_UNINITIALIZED and added more + checks. The code now does a png_error if an attempt is made to do the + row initialization twice; this is an application error and it has + serious consequences because the transform data in png_struct is + changed by each call. + Added application error reporting and added chunk names to read + benign errors; also added --strict to pngstest - not enabled + yet because a warning is produced. + Avoid the double gamma correction warning in the simplified API. + This allows the --strict option to pass in the pngstest checks + +Version 1.6.0beta20 [March 29, 2012] + Changed chunk handler warnings into benign errors, incrementally load iCCP + Added checksum-icc.c to contrib/tools Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice. + Recognize known sRGB ICC profiles while reading; prefer writing the + iCCP profile over writing the sRGB chunk, controlled by the + PNG_sRGB_PROFILE_CHECKS option. Revised png_set_text_2() to avoid potential memory corruption (fixes - CVE-2011-3048). + CVE-2011-3048, also known as CVE-2012-3425). + +Version 1.6.0beta21 [April 27, 2012] + Revised scripts/makefile.darwin: use system zlib; remove quotes around + architecture list; add missing ppc architecture; add architecture options + to shared library link; don't try to create a shared lib based on missing + RELEASE variable. + Enable png_set_check_for_invalid_index() for both read and write. + Removed #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED in pngpriv.h around + declaration of png_handle_unknown(). + Added -lssp_nonshared in a comment in scripts/makefile.freebsd + and changed deprecated NOOBJ and NOPROFILE to NO_OBJ and NO_PROFILE. + +Version 1.6.0beta22 [May 23, 2012] + Removed need for -Wno-cast-align with clang. clang correctly warns on + alignment increasing pointer casts when -Wcast-align is passed. This + fixes the cases that clang warns about either by eliminating the + casts from png_bytep to png_uint_16p (pngread.c), or, for pngrutil.c + where the cast is previously verified or pngstest.c where it is OK, by + introducing new png_aligncast macros to do the cast in a way that clang + accepts. + +Version 1.6.0beta23 [June 6, 2012] + Revised CMakeLists.txt to not attempt to make a symlink under mingw. + Made fixes for new optimization warnings from gcc 4.7.0. The compiler + performs an optimization which is safe; however it then warns about it. + Changing the type of 'palette_number' in pngvalid.c removes the warning. + Do not depend upon a GCC feature macro being available for use in generating + the linker mapfile symbol prefix. + Improved performance of new do_check_palette_indexes() function (only + update the value when it actually increases, move test for whether + the check is wanted out of the function. + +Version 1.6.0beta24 [June 7, 2012] + Don't check palette indexes if num_palette is 0 (as it can be in MNG files). + +Version 1.6.0beta25 [June 16, 2012] + Revised png_set_keep_unknown_chunks() so num_chunks < 0 means ignore all + unknown chunks and all known chunks except for IHDR, PLTE, tRNS, IDAT, + and IEND. Previously it only meant ignore all unknown chunks, the + same as num_chunks == 0. Revised png_image_skip_unused_chunks() to + provide a list of chunks to be processed instead of a list of chunks to + ignore. Revised contrib/gregbook/readpng2.c accordingly. + +Version 1.6.0beta26 [July 10, 2012] + Removed scripts/makefile.cegcc from the *.zip and *.7z distributions; it + depends on configure, which is not included in those archives. + Moved scripts/chkfmt to contrib/tools. + Changed "a+w" to "u+w" in Makefile.in to fix CVE-2012-3386. + +Version 1.6.0beta27 [August 11, 2012] + Do not compile PNG_DEPRECATED, PNG_ALLOC and PNG_PRIVATE when __GNUC__ < 3. + Do not use __restrict when GNUC is <= 3.1 + Removed references to png_zalloc() and png_zfree() from the manual. + Fixed configurations where floating point is completely disabled. Because + of the changes to support symbol prefixing PNG_INTERNAL_FUNCTION declares + floating point APIs during libpng builds even if they are completely + disabled. This requires the png floating point types (png_double*) to be + declared even though the functions are never actually defined. This + change provides a dummy definition so that the declarations work, yet any + implementation will fail to compile because of an incomplete type. + Re-eliminated the use of strcpy() in pngtest.c. An unncessary use of + strcpy() was accidentally re-introduced in libpng16; this change replaces + it with strncpy(). + Eliminated use of png_sizeof(); use sizeof() instead. + Use a consistent style for (sizeof type) and (sizeof (array)) + Cleanup of png_set_filler(). This function does very different things on + read and write. In libpng 1.6 the two cases can be distinguished and + considerable code cleanup, and extra error checking, is possible. This + makes calls on the write side that have no effect be ignored with a + png_app_error(), which can be disabled in the app using + png_set_benign_errors(), and removes the spurious use of usr_channels + on the read side. + Insist on autotools 1.12.1 for git builds because there are security issues + with 1.12 and insisting on anything less would allow 1.12 to be used. + Removed info_ptr->signature[8] from WRITE-only builds. + Add some conditions for compiling png_fixed(). This is a small function + but it requires "-lm" on some platforms. + Cause pngtest --strict to fail on any warning from libpng (not just errors) + and cause it not to fail at the comparison step if libpng lacks support + for writing chunks that it reads from the input (currently only implemented + for compressed text chunks). + Make all three "make check" test programs work without READ or WRITE support. + Now "make check" will succeed even if libpng is compiled with -DPNG_NO_READ + or -DPNG_NO_WRITE. The tests performed are reduced, but the basic reading + and writing of a PNG file is always tested by one or more of the tests. + Consistently use strlen(), memset(), memcpy(), and memcmp() instead of the + png_strlen(), png_memset(), png_memcpy(), and png_memcmp() macros. + Removed the png_sizeof(), png_strlen(), png_memset(), png_memcpy(), and + png_memcmp() macros. + Work around gcc 3.x and Microsoft Visual Studio 2010 complaints. Both object + to the split initialization of num_chunks. + +Version 1.6.0beta28 [August 29, 2012] + Unknown handling fixes and clean up. This adds more correct option + control of the unknown handling, corrects the pre-existing bug where + the per-chunk 'keep' setting is ignored and makes it possible to skip + IDAT chunks in the sequential reader (broken in earlier 1.6 versions). + There is a new test program, test-unknown.c, which is a work in progress + (not currently part of the test suite). Comments in the header files now + explain how the unknown handling works. + Allow fine grain control of unknown chunk APIs. This change allows + png_set_keep_unknown_chunks() to be turned off if not required and causes + both read and write to behave appropriately (on read this is only possible + if the user callback is used to handle unknown chunks). The change + also removes the support for storing unknown chunks in the info_struct + if the only unknown handling enabled is via the callback, allowing libpng + to be configured with callback reading and none of the unnecessary code. + Corrected fix for unknown handling in pngtest. This reinstates the + libpng handling of unknown chunks other than vpAg and sTER (including + unsafe-to-copy chunks which were dropped before) and eliminates the + repositioning of vpAg and sTER in pngtest.png by changing pngtest.png + (so the chunks are where libpng would put them). + Added "tunknown" test and corrected a logic error in png_handle_unknown() + when SAVE support is absent. Moved the shell test scripts for + contrib/libtests from the libpng top directory to contrib/libtests. + png_handle_unknown() must always read or skip the chunk, if + SAVE_UNKNOWN_CHUNKS is turned off *and* the application does not set + a user callback an unknown chunk will not be read, leading to a read + error, which was revealed by the "tunknown" test. + Cleaned up and corrected ICC profile handling. + contrib/libtests/makepng: corrected 'rgb' and 'gray' cases. profile_error + messages could be truncated; made a correct buffer size calculation and + adjusted pngerror.c appropriately. png_icc_check_* checking improved; + changed the functions to receive the correct color type of the PNG on read + or write and check that it matches the color space of the profile (despite + what the comments said before, there is danger in assuming the app will + cope correctly with an RGB profile on a grayscale image and, since it + violates the PNG spec, allowing it is certain to produce inconsistent + app behavior and might even cause app crashes.) Check that profiles + contain the tags needed to process the PNG (tags all required by the ICC + spec). Removed unused PNG_STATIC from pngpriv.h. + +Version 1.6.0beta29 [September 4, 2012] + Fixed the simplified API example programs to add the *colormap parameter + to several of he API and improved the error message if the version field + is not set. + Added contrib/examples/* to the *.zip and *.7z distributions. + Updated simplified API synopses and description of the png_image structure + in the manual. + Made makepng and pngtest produce identical PNGs, add "--relaxed" option + to pngtest. The "--relaxed" option turns off the benign errors that are + enabled by default in pre-RC builds. makepng can now write ICC profiles + where the length has not been extended to a multiple of 4, and pngtest + now intercepts all libpng errors, allowing the previously-introduced + "--strict test" on no warnings to actually work. + Improved ICC profile handling including cHRM chunk generation and fixed + Cygwin+MSVC build errors. The ICC profile handling now includes more + checking. Several errors that caused rejection of the profile are now + handled with a warning in such a way that the invalid profiles will be + read by default in release (but not pre-RC) builds but will not be + written by default. The easy part of handling the cHRM chunk is written, + where the ICC profile contains the required data. The more difficult + part plus guessing a gAMA value requires code to pass selected RGB values + through the profile. + +Version 1.6.0beta30 [October 24, 2012] + Changed ICC profile matrix/vector types to not depend on array type rules. + By the ANSI-C standard the new types should be identical to the previous + versions, and all known versions of gcc tested with the previous versions + except for GCC-4.2.1 work with this version. The change makes the ANSI-C + rule that const applied to an array of elements applies instead to the + elements in the array moot by explicitly applying const to the base + elements of the png_icc_matrix and png_icc_vector types. The accidental + (harmless) 'const' previously applied to the parameters of two of the + functions have also been removed. + Added a work around for GCC 4.2 optimization bug. + Marked the broken (bad white point) original HP sRGB profiles correctly and + correct comments. + Added -DZ_SOLO to contrib/pngminim/*/makefile to work with zlib-1.2.7 + Use /MDd for vstudio debug builds. Also added pngunkown to the vstudio + builds, fixed build errors and corrected a minor exit code error in + pngvalid if the 'touch' file name is invalid. + Add updated WARNING file to projects/vstudio from libpng 1.5/vstudio + Fixed build when using #define PNG_NO_READ_GAMMA in png_do_compose() in + pngrtran.c (Domani Hannes). + +Version 1.6.0beta31 [November 1, 2012] + Undid the erroneous change to vstudio/pngvalid build in libpng-1.6.0beta30. + Made pngvalid so that it will build outside the libpng source tree. + Made builds -DPNG_NO_READ_GAMMA compile (the unit tests still fail). + Made PNG_NO_READ_GAMMA switch off interfaces that depend on READ_GAMMA. + Prior to 1.6.0 switching off READ_GAMMA did unpredictable things to the + interfaces that use it (specifically, png_do_background in 1.4 would + simply display composite for grayscale images but do composition + with the incorrect arithmetic for color ones). In 1.6 the semantic + of -DPNG_NO_READ_GAMMA is changed to simply disable any interface that + depends on it; this obliges people who set it to consider whether they + really want it off if they happen to use any of the interfaces in + question (typically most users who disable it won't). + Fixed GUIDs in projects/vstudio. Some were duplicated or missing, + resulting in VS2010 having to update the files. + Removed non-working ICC profile support code that was mostly added to + libpng-1.6.0beta29 and beta30. There was too much code for too little + gain; implementing full ICC color correction may be desireable but is left + up to applications. + +Version 1.6.0beta32 [November 25, 2012] + Fixed an intermittent SEGV in pngstest due to an uninitialized array element. + Added the ability for contrib/libtests/makepng.c to make a PNG with just one + color. This is useful for debugging pngstest color inaccuracy reports. + Fixed error checking in the simplified write API (Olaf van der Spek) + Made png_user_version_check() ok to use with libpng version 1.10.x and later. + +Version 1.6.0beta33 [December 15, 2012] + Fixed typo in png.c (PNG_SET_CHUNK_MALLOC_MAX should be PNG_CHUNK_MALLOC_MAX) + that causes the MALLOC_MAX limit not to work (John Bowler) + Change png_warning() to png_app_error() in pngwrite.c and comment the + fall-through condition. + Change png_warning() to png_app_warning() in png_write_tRNS(). + Rearranged the ARM-NEON optimizations: Isolated the machine specific code + to the hardware subdirectory and added comments to pngrutil.c so that + implementors of other optimizations know what to do. + Fixed cases of unquoted DESTDIR in Makefile.am + Rebuilt Makefile.in, etc., with autoconf-2.69 and automake-1.12.5. + +Version 1.6.0beta34 [December 19, 2012] + Cleaned up whitespace in the synopsis portion of the manpage "libpng.3" + Disassembled the version number in scripts/options.awk (necessary for + building on SunOs). + +Version 1.6.0beta35 [December 23, 2012] + Made default Zlib compression settings be configurable. This adds #defines to + pnglibconf.h to control the defaults. + Fixed Windows build issues, enabled ARM compilation. Various warnings issued + by earlier versions of GCC fixed for Cygwin and Min/GW (which both use old + GCCs.) ARM support is enabled by default in zlib.props (unsupported by + Microsoft) and ARM compilation is made possible by deleting the check for + x86. The test programs cannot be run because they are not signed. + +Version 1.6.0beta36 [January 2, 2013] + Discontinued distributing libpng-1.x.x.tar.bz2. + Discontinued distributing libpng-1.7.0-1.6.0-diff.txt and similar. + Rebuilt configure with autoconf-2.69 (inadvertently not done in beta33) + Fixed 'make distcheck' on SUN OS - libpng.so was not being removed + +Version 1.6.0beta37 [January 10, 2013] + Fixed conceivable but difficult to repro overflow. Also added two test + programs to generate and test a PNG which should have the problem. + +Version 1.6.0beta39 [January 19, 2013] + Again corrected attempt at overflow detection in png_set_unknown_chunks() + (CVE-2013-7353). Added overflow detection in png_set_sPLT() and + png_set_text_2() (CVE-2013-7354). + +Version 1.6.0beta40 [January 20, 2013] + Use consistent handling of overflows in text, sPLT and unknown png_set_* APIs + +Version 1.6.0rc01 [January 26, 2013] + No changes. + +Version 1.6.0rc02 [February 4, 2013] + Added png_get_palette_max() function. + +Version 1.6.0rc03 [February 5, 2013] + Fixed the png_get_palette_max API. + +Version 1.6.0rc04 [February 7, 2013] + Turn serial tests back on (recently turned off by autotools upgrade). + +Version 1.6.0rc05 [February 8, 2013] + Update manual about png_get_palette_max(). + +Version 1.6.0rc06 [February 9, 2013] + Fixed missing dependency in --prefix builds The intermediate + internal 'prefix.h' file can only be generated correctly after + pnglibconf.h, however the dependency was not in Makefile.am. The + symptoms are unpredictable depending on the order make chooses to + build pngprefix.h and pnglibconf.h, often the error goes unnoticed + because there is a system pnglibconf.h to use instead. + +Version 1.6.0rc07 [February 10, 2013] + Enclosed the new png_get_palette_max in #ifdef PNG_GET_PALETTE_MAX_SUPPORTED + block, and revised pnglibconf.h and pnglibconf.h.prebuilt accordingly. + +Version 1.6.0rc08 [February 10, 2013] + Fix typo in png.h #ifdef + +Version 1.6.0 [February 14, 2013] + No changes. + +Version 1.6.1beta01 [February 16, 2013] + Made symbol prefixing work with the ARM neon optimizations. Also allow + pngpriv.h to be included for preprocessor definitions only, so it can + be used in non-C/C++ files. Back ported from libpng 1.7. + Made sRGB check numbers consistent. + Ported libpng 1.5 options.awk/dfn file handling to 1.6, fixed one bug. + Removed cc -E workround, corrected png_get_palette_max API Tested on + SUN OS cc 5.9, which demonstrates the tokenization problem previously + avoided by using /lib/cpp. Since all .dfn output is now protected in + double quotes unless it is to be macro substituted the fix should + work everywhere. + Enabled parallel tests - back ported from libpng-1.7. + scripts/pnglibconf.dfa formatting improvements back ported from libpng17. + Fixed a race condition in the creation of the build 'scripts' directory + while building with a parallel make. + Use approved/supported Android method to check for NEON, use Linux/POSIX + 1003.1 API to check /proc/self/auxv avoiding buffer allocation and other + library calls (ported from libpng15). + +Version 1.6.1beta02 [February 19, 2013] + Use parentheses more consistently in "#if defined(MACRO)" tests. + Folded long lines. + Reenabled code to allow zero length PLTE chunks for MNG. + +Version 1.6.1beta03 [February 22, 2013] + Fixed ALIGNED_MEMORY support. + Allow run-time ARM NEON checking to be disabled. A new configure option: + --enable-arm-neon=always will stop the run-time checks. New checks + within arm/arm_init.c will cause the code not to be compiled unless + __ARM_NEON__ is set. This should make it fail safe (if someone asks + for it on then the build will fail if it can't be done.) + Updated the INSTALL document. + +Version 1.6.1beta04 [February 27, 2013] + Revised INSTALL to recommend using CPPFLAGS instead of INCLUDES. + Revised scripts/makefile.freebsd to respect ZLIBLIB and ZLIBINC. + Revised scripts/dfn.awk to work with the buggy MSYS awk that has trouble + with CRLF line endings. + +Version 1.6.1beta05 [March 1, 2013] + Avoid a possible memory leak in contrib/gregbook/readpng.c + +Version 1.6.1beta06 [March 4, 2013] + Better documentation of unknown handling API interactions. + Corrected Android builds and corrected libpng.vers with symbol + prefixing. This adds an API to set optimization options externally, + providing an alternative and general solution for the non-portable + run-time tests used by the ARM Neon code. It also makes those tests + compile and link on Android. + The order of settings vs options in pnglibconf.h is reversed to allow + settings to depend on options and options can now set (or override) the + defaults for settings. + +Version 1.6.1beta07 [March 7, 2013] + Corrected simplified API default gamma for color-mapped output, added + a flag to change default. In 1.6.0 when the simplified API was used + to produce color-mapped output from an input image with no gamma + information the gamma assumed for the input could be different from + that assumed for non-color-mapped output. In particular 16-bit depth + input files were assumed to be sRGB encoded, whereas in the 'direct' + case they were assumed to have linear data. This was an error. The + fix makes the simplified API treat all input files the same way and + adds a new flag to the png_image::flags member to allow the + application/user to specify that 16-bit files contain sRGB data + rather than the default linear. + Fixed bugs in the pngpixel and makepng test programs. + +Version 1.6.1beta08 [March 7, 2013] + Fixed CMakelists.txt to allow building a single variant of the library + (Claudio Bley): + Introduced a PNG_LIB_TARGETS variable that lists all activated library + targets. It is an error if this variable ends up empty, ie. you have + to build at least one library variant. + Made the *_COPY targets only depend on library targets actually being build. + Use PNG_LIB_TARGETS to unify a code path. + Changed the CREATE_SYMLINK macro to expect the full path to a file as the + first argument. When symlinking the filename component of that path is + determined and used as the link target. + Use copy_if_different in the CREATE_SYMLINK macro. + +Version 1.6.1beta09 [March 13, 2013] + Eliminated two warnings from the Intel C compiler. The warnings are + technically valid, although a reasonable treatment of division would + show it to be incorrect. + +Version 1.6.1rc01 [March 21, 2013] + No changes. + +Version 1.6.1 [March 28, 2013] + No changes. + +Version 1.6.2beta01 [April 14, 2013] + Updated documentation of 1.5.x to 1.6.x changes in iCCP chunk handling. + Fixed incorrect warning of excess deflate data. End condition - the + warning would be produced if the end of the deflate stream wasn't read + in the last row. The warning is harmless. + Corrected the test on user transform changes on read. It was in the + png_set of the transform function, but that doesn't matter unless the + transform function changes the rowbuf size, and that is only valid if + transform_info is called. + Corrected a misplaced closing bracket in contrib/libtests/pngvalid.c + (Flavio Medeiros). + Corrected length written to uncompressed iTXt chunks (Samuli Suominen). + Bug was introduced in libpng-1.6.0. + +Version 1.6.2rc01 [April 18, 2013] + Added contrib/tools/fixitxt.c, to repair the erroneous iTXt chunk length + written by libpng-1.6.0 and 1.6.1. + Disallow storing sRGB information when the sRGB is not supported. + +Version 1.6.2rc02 [April 18, 2013] + Merge pngtest.c with libpng-1.7.0 + +Version 1.6.2rc03 [April 22, 2013] + Trivial spelling cleanup. + +Version 1.6.2rc04 and 1.6.2rc05 [omitted] + +Version 1.6.2rc06 [April 24, 2013] + Reverted to version 1.6.2rc03. Recent changes to arm/neon support + have been ported to libpng-1.7.0beta09 and will reappear in version + 1.6.3beta01. + +Version 1.6.2 [April 25, 2013] + No changes. + +Version 1.6.3beta01 [April 25, 2013] + Revised stack marking in arm/filter_neon.S and configure.ac. + Ensure that NEON filter stuff is completely disabled when switched 'off'. + Previously the ARM NEON specific files were still built if the option + was switched 'off' as opposed to being explicitly disabled. + +Version 1.6.3beta02 [April 26, 2013] + Test for 'arm*' not just 'arm' in the host_cpu configure variable. + Rebuilt the configure scripts. + +Version 1.6.3beta03 [April 30, 2013] + Expanded manual paragraph about writing private chunks, particularly + the need to call png_set_keep_unknown_chunks() when writing them. + Avoid dereferencing NULL pointer possibly returned from + png_create_write_struct() (Andrew Church). + +Version 1.6.3beta05 [May 9, 2013] + Calculate our own zlib windowBits when decoding rather than trusting the + CMF bytes in the PNG datastream. + Added an option to force maximum window size for inflating, which was + the behavior of libpng15 and earlier. + Added png-fix-itxt and png-fix-too-far-back to the built programs and + removed warnings from the source code and timepng that are revealed as + a result. + Detect wrong libpng versions linked to png-fix-too-far-back, which currently + only works with libpng versions that can be made to reliably fail when + the deflate data contains an out-of-window reference. This means only + 1.6 and later. + Fixed gnu issues: g++ needs a static_cast, gcc 4.4.7 has a broken warning + message which it is easier to work round than ignore. + Updated contrib/pngminus/pnm2png.c (Paul Stewart): + Check for EOF + Ignore "#" delimited comments in input file to pnm2png.c. + Fixed whitespace handling + Added a call to png_set_packing() + Initialize dimension values so if sscanf fails at least we have known + invalid values. + Attempt to detect configuration issues with png-fix-too-far-back, which + requires both the correct libpng and the correct zlib to function + correctly. + Check ZLIB_VERNUM for mismatches, enclose #error in quotes + Added information in the documentation about problems with and fixes for + the bad CRC and bad iTXt chunk situations. + +Version 1.6.3beta06 [May 12, 2013] + Allow contrib/pngminus/pnm2png.c to compile without WRITE_INVERT and + WRITE_PACK supported (writes error message that it can't read P1 or + P4 PBM files). + Improved png-fix-too-far-back usage message, added --suffix option. + Revised contrib/pngminim/*/makefile to generate pnglibconf.h with the + right zlib header files. + Separated CPPFLAGS and CFLAGS in contrib/pngminim/*/makefile + +Version 1.6.3beta07 [June 8, 2013] + Removed a redundant test in png_set_IHDR(). + Added set(CMAKE_CONFIGURATION_TYPES ...) to CMakeLists.txt (Andrew Hundt) + Deleted set(CMAKE_BUILD_TYPE) block from CMakeLists.txt + Enclose the prototypes for the simplified write API in + #ifdef PNG_STDIO_SUPPORTED/#endif + Make ARM NEON support work at compile time (not just configure time). + This moves the test on __ARM_NEON__ into pngconf.h to avoid issues when + using a compiler that compiles for multiple architectures at one time. + Removed PNG_FILTER_OPTIMIZATIONS and PNG_ARM_NEON_SUPPORTED from + pnglibconf.h, allowing more of the decisions to be made internally + (pngpriv.h) during the compile. Without this, symbol prefixing is broken + under certain circumstances on ARM platforms. Now only the API parts of + the optimizations ('check' vs 'api') are exposed in the public header files + except that the new setting PNG_ARM_NEON_OPT documents how libpng makes the + decision about whether or not to use the optimizations. + Protect symbol prefixing against CC/CPPFLAGS/CFLAGS useage. + Previous iOS/Xcode fixes for the ARM NEON optimizations moved the test + on __ARM_NEON__ from configure time to compile time. This breaks symbol + prefixing because the definition of the special png_init_filter_functions + call was hidden at configure time if the relevant compiler arguments are + passed in CFLAGS as opposed to CC. This change attempts to avoid all + the confusion that would result by declaring the init function even when + it is not used, so that it will always get prefixed. + +Version 1.6.3beta08 [June 18, 2013] + Revised libpng.3 so that "doclifter" can process it. + +Version 1.6.3beta09 [June 27, 2013] + Revised example.c to illustrate use of PNG_DEFAULT_sRGB and PNG_GAMMA_MAC_18 + as parameters for png_set_gamma(). These have been available since + libpng-1.5.4. + Renamed contrib/tools/png-fix-too-far-back.c to pngfix.c and revised it + to check all compressed chunks known to libpng. + +Version 1.6.3beta10 [July 5, 2013] + Updated documentation to show default behavior of benign errors correctly. + Only compile ARM code when PNG_READ_SUPPORTED is defined. + Fixed undefined behavior in contrib/tools/pngfix.c and added new strip + option. pngfix relied on undefined behavior and even a simple change from + gcc to g++ caused it to fail. The new strip option 'unsafe' has been + implemented and is the default if --max is given. Option names have + been clarified, with --strip=transform now stripping the bKGD chunk, + which was stripped previously with --strip=unused. + Added all documented chunk types to pngpriv.h + Unified pngfix.c source with libpng17. + +Version 1.6.3rc01 [July 11, 2013] + No changes. + +Version 1.6.3 [July 18, 2013] + Revised manual about changes in iTXt chunk handling made in libpng-1.6.0. + Added "/* SAFE */" comments in pngrutil.c and pngrtran.c where warnings + may be erroneously issued by code-checking applications. + +Version 1.6.4beta01 [August 21, 2013] + Added information about png_set_options() to the manual. + Delay calling png_init_filter_functions() until a row with nonzero filter + is found. + +Version 1.6.4beta02 [August 30, 2013] + Fixed inconsistent conditional compilation of png_chunk_unknown_handling() + prototype, definition, and usage. Made it depend on + PNG_HANDLE_AS_UNKNOWN_SUPPORTED everywhere. + +Version 1.6.4rc01 [September 5, 2013] + No changes. + +Version 1.6.4 [September 12, 2013] + No changes. + +Version 1.6.5 [September 14, 2013] + Removed two stray lines of code from arm/arm_init.c. + +Version 1.6.6 [September 16, 2013] + Removed two stray lines of code from arm/arm_init.c, again. + +Version 1.6.7beta01 [September 30, 2013] + Revised unknown chunk code to correct several bugs in the NO_SAVE_/NO_WRITE + combination + Allow HANDLE_AS_UNKNOWN to work when other options are configured off. Also + fixed the pngminim makefiles to work when $(MAKEFLAGS) contains stuff + which terminates the make options (as by default in recent versions of + Gentoo). + Avoid up-cast warnings in pngvalid.c. On ARM the alignment requirements of + png_modifier are greater than that of png_store and as a consequence + compilation of pngvalid.c results in a warning about increased alignment + requirements because of the bare cast to (png_modifier*). The code is safe, + because the pointer is known to point to a stack allocated png_modifier, + but this change avoids the warning. + Fixed default behavior of ARM_NEON_API. If the ARM NEON API option was + compiled without the CHECK option it defaulted to on, not off. + Check user callback behavior in pngunknown.c. Previous versions compiled + if SAVE_UNKNOWN was not available but did nothing since the callback + was never implemented. + Merged pngunknown.c with 1.7 version and back ported 1.7 improvements/fixes + +Version 1.6.7beta02 [October 12, 2013] + Made changes for compatibility with automake 1.14: + 1) Added the 'compile' program to the list of programs that must be cleaned + in autogen.sh + 2) Added 'subdir-objects' which causes .c files in sub-directories to be + compiled such that the corresponding .o files are also in the + sub-directory. This is because automake 1.14 warns that the + current behavior of compiling to the top level directory may be removed + in the future. + 3) Updated dependencies on pnglibconf.h to match the new .o locations and + added all the files in contrib/libtests and contrib/tools that depend + on pnglibconf.h + 4) Added 'BUILD_SOURCES = pnglibconf.h'; this is the automake recommended + way of handling the dependencies of sources that are machine generated; + unfortunately it only works if the user does 'make all' or 'make check', + so the dependencies (3) are still required. + Cleaned up (char*) casts of zlib messages. The latest version of the Intel C + compiler complains about casting a string literal as (char*), so copied the + treatment of z_const from the library code into pngfix.c + Simplified error message code in pngunknown. The simplification has the + useful side effect of avoiding a bogus warning generated by the latest + version of the Intel C compiler (it objects to + condition ? string-literal : string-literal). + Make autogen.sh work with automake 1.13 as well as 1.14. Do this by always + removing the 1.14 'compile' script but never checking for it. + +Version 1.6.7beta03 [October 19, 2013] + Added ARMv8 support (James Yu ). Added file + arm/filter_neon_intrinsics.c; enable with -mfpu=neon. + Revised pngvalid to generate size images with as many filters as it can + manage, limited by the number of rows. + Cleaned up ARM NEON compilation handling. The tests are now in pngpriv.h + and detect the broken GCC compilers. + +Version 1.6.7beta04 [October 26, 2013] + Allow clang derived from older GCC versions to use ARM intrinsics. This + causes all clang builds that use -mfpu=neon to use the intrinsics code, + not the assembler code. This has only been tested on iOS 7. It may be + necessary to exclude some earlier clang versions but this seems unlikely. + Changed NEON implementation selection mechanism. This allows assembler + or intrinsics to be turned on at compile time during the build by defining + PNG_ARM_NEON_IMPLEMENTATION to the correct value (2 or 1). This macro + is undefined by default and the build type is selected in pngpriv.h. + +Version 1.6.7rc01 [November 2, 2013] + No changes. + +Version 1.6.7rc02 [November 7, 2013] + Fixed #include in filter_neon_intrinsics.c and ctype macros. The ctype char + checking macros take an unsigned char argument, not a signed char. + +Version 1.6.7 [November 14, 2013] + No changes. + +Version 1.6.8beta01 [November 24, 2013] + Moved prototype for png_handle_unknown() in pngpriv.h outside of + the #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED/#endif block. + Added "-Wall" to CFLAGS in contrib/pngminim/*/makefile + Conditionally compile some unused functions reported by -Wall in + pngminim. + Fixed 'minimal' builds. Various obviously useful minimal configurations + don't build because of missing contrib/libtests test programs and + overly complex dependencies in scripts/pnglibconf.dfa. This change + adds contrib/conftest/*.dfa files that can be used in automatic build + scripts to ensure that these configurations continue to build. + Enabled WRITE_INVERT and WRITE_PACK in contrib/pngminim/encoder. + Fixed pngvalid 'fail' function declaration on the Intel C Compiler. + This reverts to the previous 'static' implementation and works round + the 'unused static function' warning by using PNG_UNUSED(). + +Version 1.6.8beta02 [November 30, 2013] + Removed or marked PNG_UNUSED some harmless "dead assignments" reported + by clang scan-build. + Changed tabs to 3 spaces in png_debug macros and changed '"%s"m' + to '"%s" m' to improve portability among compilers. + Changed png_free_default() to free() in pngtest.c + +Version 1.6.8rc01 [December 12, 2013] + Tidied up pngfix inits and fixed pngtest no-write builds. + +Version 1.6.8rc02 [December 14, 2013] + Handle zero-length PLTE chunk or NULL palette with png_error() + instead of png_chunk_report(), which by default issues a warning + rather than an error, leading to later reading from a NULL pointer + (png_ptr->palette) in png_do_expand_palette(). This is CVE-2013-6954 + and VU#650142. Libpng-1.6.1 through 1.6.7 are vulnerable. + Libpng-1.6.0 and earlier do not have this bug. + +Version 1.6.8 [December 19, 2013] + No changes. + +Version 1.6.9beta01 [December 26, 2013] + Bookkeeping: Moved functions around (no changes). Moved transform + function definitions before the place where they are called so that + they can be made static. Move the intrapixel functions and the + grayscale palette builder out of the png?tran.c files. The latter + isn't a transform function and is no longer used internally, and the + former MNG specific functions are better placed in pngread/pngwrite.c + Made transform implementation functions static. This makes the internal + functions called by png_do_{read|write}_transformations static. On an + x86-64 DLL build (Gentoo Linux) this reduces the size of the text + segment of the DLL by 1208 bytes, about 0.6%. It also simplifies + maintenance by removing the declarations from pngpriv.h and allowing + easier changes to the internal interfaces. + Rebuilt configure scripts with automake-1.14.1 and autoconf-2.69 + in the tar distributions. + +Version 1.6.9beta02 [January 1, 2014] + Added checks for libpng 1.5 to pngvalid.c. This supports the use of + this version of pngvalid in libpng 1.5 + Merged with pngvalid.c from libpng-1.7 changes to create a single + pngvalid.c + Removed #error macro from contrib/tools/pngfix.c (Thomas Klausner). + Merged pngrio.c, pngtrans.c, pngwio.c, and pngerror.c with libpng-1.7.0 + Merged libpng-1.7.0 changes to make no-interlace configurations work + with test programs. + Revised pngvalid.c to support libpng 1.5, which does not support the + PNG_MAXIMUM_INFLATE_WINDOW option, so #define it out when appropriate in + pngvalid.c + Allow unversioned links created on install to be disabled in configure. + In configure builds 'make install' changes/adds links like png.h + and libpng.a to point to the newly installed, versioned, files (e.g. + libpng17/png.h and libpng17.a). Three new configure options and some + rearrangement of Makefile.am allow creation of these links to be disabled. + +Version 1.6.9beta03 [January 10, 2014] + Removed potentially misleading warning from png_check_IHDR(). + +Version 1.6.9beta04 [January 20, 2014] + Updated scripts/makefile.* to use CPPFLAGS (Cosmin). + Added clang attribute support (Cosmin). + +Version 1.6.9rc01 [January 28, 2014] + No changes. + +Version 1.6.9rc02 [January 30, 2014] + Quiet an uninitialized memory warning from VC2013 in png_get_png(). + +Version 1.6.9 [February 6, 2014] + +Version 1.6.10beta01 [February 9, 2014] + Backported changes from libpng-1.7.0beta30 and beta31: + Fixed a large number of instances where PNGCBAPI was omitted from + function definitions. + Added pngimage test program for png_read_png() and png_write_png() + with two new test scripts. + Removed dependence on !PNG_READ_EXPAND_SUPPORTED for calling + png_set_packing() in png_read_png(). + Fixed combination of ~alpha with shift. On read invert alpha, processing + occurred after shift processing, which causes the final values to be + outside the range that should be produced by the shift. Reversing the + order on read makes the two transforms work together correctly and mirrors + the order used on write. + Do not read invalid sBIT chunks. Previously libpng only checked sBIT + values on write, so a malicious PNG writer could therefore cause + the read code to return an invalid sBIT chunk, which might lead to + application errors or crashes. Such chunks are now skipped (with + chunk_benign_error). + Make png_read_png() and png_write_png() prototypes in png.h depend + upon PNG_READ_SUPPORTED and PNG_WRITE_SUPPORTED. + Support builds with unsupported PNG_TRANSFORM_* values. All of the + PNG_TRANSFORM_* values are always defined in png.h and, because they + are used for both read and write in some cases, it is not reliable + to #if out ones that are totally unsupported. This change adds error + detection in png_read_image() and png_write_image() to do a + png_app_error() if the app requests something that cannot be done + and it adds corresponding code to pngimage.c to handle such options + by not attempting to test them. + +Version 1.6.10beta02 [February 23, 2014] + Moved redefines of png_error(), png_warning(), png_chunk_error(), + and png_chunk_warning() from pngpriv.h to png.h to make them visible + to libpng-calling applications. + Moved OS dependent code from arm/arm_init.c, to allow the included + implementation of the ARM NEON discovery function to be set at + build-time and provide sample implementations from the current code in the + contrib/arm-neon subdirectory. The __linux__ code has also been changed to + compile and link on Android by using /proc/cpuinfo, and the old linux code + is in contrib/arm-neon/linux-auxv.c. The new code avoids POSIX and Linux + dependencies apart from opening /proc/cpuinfo and is C90 compliant. + Check for info_ptr == NULL early in png_read_end() so we don't need to + run all the png_handle_*() and depend on them to return if info_ptr == NULL. + This improves the performance of png_read_end(png_ptr, NULL) and makes + it more robust against future programming errors. + Check for __has_extension before using it in pngconf.h, to + support older Clang versions (Jeremy Sequoia). + Treat CRC error handling with png_set_crc_action(), instead of with + png_set_benign_errors(), which has been the case since libpng-1.6.0beta18. + Use a user warning handler in contrib/gregbook/readpng2.c instead of default, + so warnings will be put on stderr even if libpng has CONSOLE_IO disabled. + Added png_ptr->process_mode = PNG_READ_IDAT_MODE in png_push_read_chunk + after recognizing the IDAT chunk, which avoids an infinite loop while + reading a datastream whose first IDAT chunk is of zero-length. + This fixes CERT VU#684412 and CVE-2014-0333. + Don't recognize known sRGB profiles as sRGB if they have been hacked, + but don't reject them and don't issue a copyright violation warning. + +Version 1.6.10beta03 [February 25, 2014] + Moved some documentation from png.h to libpng.3 and libpng-manual.txt + Minor editing of contrib/arm-neon/README and contrib/examples/*.c + +Version 1.6.10rc01 [February 27, 2014] + Fixed typos in the manual and in scripts/pnglibconf.dfa (CFLAGS -> CPPFLAGS + and PNG_USR_CONFIG -> PNG_USER_CONFIG). + +Version 1.6.10rc02 [February 28, 2014] + Removed unreachable return statement after png_chunk_error() + in pngrutil.c + +Version 1.6.10rc03 [March 4, 2014] + Un-deprecated png_data_freer(). + +Version 1.6.10 [March 6, 2014] + No changes. + +Version 1.6.11beta01 [March 17, 2014] + Use "if (value != 0)" instead of "if (value)" consistently. + Changed ZlibSrcDir from 1.2.5 to 1.2.8 in projects/vstudio. + Moved configuration information from the manual to the INSTALL file. + +Version 1.6.11beta02 [April 6, 2014] + Removed #if/#else/#endif from inside two pow() calls in pngvalid.c because + they were handled improperly by Portland Group's PGI-14.1 - PGI-14.3 + when using its "__builtin_pow()" function. + Silence 'unused parameter' build warnings (Cosmin Truta). + $(CP) is now used alongside $(RM_F). Also, use 'copy' instead of 'cp' + where applicable, and applied other minor makefile changes (Cosmin). + Don't warn about invalid dimensions exceeding user limits (Cosmin). + Allow an easy replacement of the default pre-built configuration + header with a custom header, via the make PNGLIBCONF_H_PREBUILT + macro (Cosmin). + +Version 1.6.11beta03 [April 6, 2014] + Fixed a typo in pngrutil.c, introduced in libpng-1.5.6, that interferes + with "blocky" expansion of sub-8-bit interlaced PNG files (Eric Huss). + Optionally use __builtin_bswap16() in png_do_swap(). + +Version 1.6.11beta04 [April 19, 2014] + Made progressive reading of interlaced images consistent with the + behavior of the sequential reader and consistent with the manual, by + moving some code out of the PNG_READ_INTERLACING_SUPPORTED blocks. The + row_callback now receives the proper pass number and unexpanded rows, when + png_combine_row() isn't built or used, and png_set_interlace_handling() + is not called. + Allow PNG_sRGB_PROFILE_CHECKING = (-1) to mean no sRGB profile checking. + +Version 1.6.11beta05 [April 26, 2014] + Do not reject ICC V2 profiles that lack padding (Kai-Uwe Behrmann). + Relocated closing bracket of the sRGB profile test loop to avoid getting + "Not recognizing known sRGB profile that has been edited" warning for + ICC V2 profiles that lack the MD5 signature in the profile header. + +Version 1.6.11beta06 [May 19, 2014] + Added PNG_SKIP_sRGB_CHECK_PROFILE choice for png_set_option(). + +Version 1.6.11rc01 [May 27, 2014] + No changes. + +Version 1.6.11rc02 [June 3, 2014] + Test ZLIB_VERNUM instead of PNG_ZLIB_VERNUM in contrib/tools/pngfix.c + +Version 1.6.11 [June 5, 2014] + No changes. + +Version 1.6.12rc01 [June 6, 2014] + Relocated new code from 1.6.11beta06 in png.c to a point after the + declarations (Max Stepin). + +Version 1.6.12rc02 [June 7, 2014] + Changed file permissions of contrib/tools/intgamma.sh, + test-driver, and compile from 0644 to 0755 (Cosmin). + +Version 1.6.12rc03 [June 8, 2014] + Ensure "__has_attribute()" macro exists before trying to use it with + old clang compilers (MacPorts Ticket #43939). + +Version 1.6.12 [June 12, 2014] + No changes. + +Version 1.6.13beta01 [July 4, 2014] + Quieted -Wsign-compare and -Wclobber compiler warnings in + contrib/pngminus/*.c + Added "(void) png_ptr;" where needed in contrib/gregbook to quiet + compiler complaints about unused pointers. + Split a long output string in contrib/gregbook/rpng2-x.c. + Added "PNG_SET_OPTION" requirement for sRGB chunk support to pnglibconf.dfa, + Needed for write-only support (John Bowler). + Changed "if defined(__ARM_NEON__)" to + "if (defined(__ARM_NEON__) || defined(__ARM_NEON))" (James Wu). + Fixed clang no-warning builds: png_digit was defined but never used. + +Version 1.6.13beta02 [July 21, 2014] + Fixed an incorrect separator ("/" should be "\") in scripts/makefile.vcwin32 + (bug report from Wolfgang S. Kechel). Bug was introduced in libpng-1.6.11. + Also fixed makefile.bc32, makefile.bor, makefile.msc, makefile.intel, and + makefile.tc3 similarly. + +Version 1.6.13beta03 [August 3, 2014] + Removed scripts/makefile.elf. It has not worked since libpng-1.5.0beta14 + due to elimination of the PNG_FUNCTION_EXPORT and PNG_DATA_EXPORT + definitions from pngconf.h. + Ensure that CMakeLists.txt makes the target "lib" directory before making + symbolic link into it (SourceForge bug report #226 by Rolf Timmermans). + +Version 1.6.13beta04 [August 8, 2014] + Added opinion that the ECCN (Export Control Classification Number) for + libpng is EAR99 to the README file. + Eliminated use of "$<" in makefile explicit rules, when copying + $PNGLIBCONF_H_PREBUILT. This does not work on some versions of make; + bug introduced in libpng version 1.6.11. + +Version 1.6.13rc01 [August 14, 2014] + Made "ccopts" agree with "CFLAGS" in scripts/makefile.hp* and makefile.*sunu + +Version 1.6.13 [August 21, 2014] + No changes. + +Version 1.6.14beta01 [September 14, 2014] + Guard usage of png_ptr->options with #ifdef PNG_SET_OPTION_SUPPORTED. + Do not build contrib/tools/pngfix.c when PNG_SETJMP_NOT_SUPPORTED, + to allow "make" to complete without setjmp support (bug report by + Claudio Fontana) + Add "#include " to contrib/tools/pngfix.c (John Bowler) + +Version 1.6.14beta02 [September 18, 2014] + Use nanosleep() instead of usleep() in contrib/gregbook/rpng2-x.c + because usleep() is deprecated. + Define usleep() in contrib/gregbook/rpng2-x.c if not already defined + in unistd.h and nanosleep() is not available; fixes error introduced + in libpng-1.6.13. + Disable floating point exception handling in pngvalid.c when + PNG_FLOATING_ARITHMETIC is not supported (bug report by "zootus + at users.sourceforge.net"). + +Version 1.6.14beta03 [September 19, 2014] + Define FE_DIVBYZERO, FE_INVALID, and FE_OVERFLOW in pngvalid.c if not + already defined. Revert floating point exception handling in pngvalid.c + to version 1.6.14beta01 behavior. + +Version 1.6.14beta04 [September 27, 2014] + Fixed incorrect handling of the iTXt compression flag in pngrutil.c + (bug report by Shunsaku Hirata). Bug was introduced in libpng-1.6.0. + +Version 1.6.14beta05 [October 1, 2014] + Added "option READ_iCCP enables READ_COMPRESSED_TEXT" to pnglibconf.dfa + +Version 1.6.14beta06 [October 5, 2014] + Removed unused "text_len" parameter from private function png_write_zTXt(). + Conditionally compile some code in png_deflate_claim(), when + PNG_WARNINGS_SUPPORTED and PNG_ERROR_TEXT_SUPPORTED are disabled. + Replaced repeated code in pngpread.c with PNG_PUSH_SAVE_BUFFER_IF_FULL. + Added "chunk iTXt enables TEXT" and "chunk zTXt enables TEXT" + to pnglibconf.dfa. + Removed "option READ_COMPRESSED_TEXT enables READ_TEXT" from pnglibconf.dfa, + to make it possible to configure a libpng that supports iCCP but not TEXT. + +Version 1.6.14beta07 [October 7, 2014] + Removed "option WRITE_COMPRESSED_TEXT enables WRITE_TEXT" from pnglibconf.dfa + Only mark text chunks as written after successfully writing them. + +Version 1.6.14rc01 [October 15, 2014] + Fixed some typos in comments. + +Version 1.6.14rc02 [October 17, 2014] + Changed png_convert_to_rfc_1123() to png_convert_to_rfc_1123_buffer() + in the manual, to reflect the change made in libpng-1.6.0. + Updated README file to explain that direct access to the png_struct + and info_struct members has not been permitted since libpng-1.5.0. + +Version 1.6.14 [October 23, 2014] + No changes. + +Version 1.6.15beta01 [October 29, 2014] + Changed "if (!x)" to "if (x == 0)" and "if (x)" to "if (x != 0)" + Simplified png_free_data(). + Added missing "ptr = NULL" after some instances of png_free(). + +Version 1.6.15beta02 [November 1, 2014] + Changed remaining "if (!x)" to "if (x == 0)" and "if (x)" to "if (x != 0)" + +Version 1.6.15beta03 [November 3, 2014] + Added PNG_USE_ARM_NEON configuration flag (Marcin Juszkiewicz). + +Version 1.6.15beta04 [November 4, 2014] + Removed new PNG_USE_ARM_NEON configuration flag and made a one-line + revision to configure.ac to support ARM on aarch64 instead (John Bowler). + +Version 1.6.15beta05 [November 5, 2014] + Use png_get_libpng_ver(NULL) instead of PNG_LIBPNG_VER_STRING in + example.c, pngtest.c, and applications in the contrib directory. + Avoid out-of-bounds memory access in png_user_version_check(). + Simplified and future-proofed png_user_version_check(). + Fixed GCC unsigned int->float warnings. Various versions of GCC + seem to generate warnings when an unsigned value is implicitly + converted to double. This is probably a GCC bug but this change + avoids the issue by explicitly converting to (int) where safe. + Free all allocated memory in pngimage. The file buffer cache was left + allocated at the end of the program, harmless but it causes memory + leak reports from clang. + Fixed array size calculations to avoid warnings. At various points + in the code the number of elements in an array is calculated using + sizeof. This generates a compile time constant of type (size_t) which + is then typically assigned to an (unsigned int) or (int). Some versions + of GCC on 64-bit systems warn about the apparent narrowing, even though + the same compiler does apparently generate the correct, in-range, + numeric constant. This adds appropriate, safe, casts to make the + warnings go away. + +Version 1.6.15beta06 [November 6, 2014] + Reverted use png_get_libpng_ver(NULL) instead of PNG_LIBPNG_VER_STRING + in the manual, example.c, pngtest.c, and applications in the contrib + directory. It was incorrect advice. + +Version 1.6.15beta07 [November 7, 2014] + Removed #ifdef PNG_16BIT_SUPPORTED/#endif around png_product2(); it is + needed by png_reciprocal2(). + Added #ifdef PNG_16BIT_SUPPORTED/#endif around png_log16bit() and + png_do_swap(). + Changed all "#endif /* PNG_FEATURE_SUPPORTED */" to "#endif /* FEATURE */" + +Version 1.6.15beta08 [November 8, 2014] + More housecleaning in *.h + +Version 1.6.15rc01 [November 13, 2014] + +Version 1.6.15rc02 [November 14, 2014] + The macros passed in the command line to Borland make were ignored if + similarly-named macros were already defined in makefiles. This behavior + is different from POSIX make and other make programs. Surround the + macro definitions with ifndef guards (Cosmin). + +Version 1.6.15rc03 [November 16, 2014] + Added "-D_CRT_SECURE_NO_WARNINGS" to CFLAGS in scripts/makefile.vcwin32. + Removed the obsolete $ARCH variable from scripts/makefile.darwin. + +Version 1.6.15 [November 20, 2014] + No changes. + +Version 1.6.16beta01 [December 14, 2014] + Added ".align 2" to arm/filter_neon.S to support old GAS assemblers that + don't do alignment correctly. + Revised Makefile.am and scripts/symbols.dfn to work with MinGW/MSYS + (Bob Friesenhahn). + +Version 1.6.16beta02 [December 15, 2014] + Revised Makefile.am and scripts/*.dfn again to work with MinGW/MSYS; + renamed scripts/*.dfn to scripts/*.c (John Bowler). + +Version 1.6.16beta03 [December 21, 2014] + Quiet a "comparison always true" warning in pngstest.c (John Bowler). + +Version 1.6.16rc01 [December 21, 2014] + Restored a test on width that was removed from png.c at libpng-1.6.9 + (Bug report by Alex Eubanks, CVE-2015-0973). + +Version 1.6.16rc02 [December 21, 2014] + Undid the update to pngrutil.c in 1.6.16rc01. + +Version 1.6.16rc03 [December 21, 2014] + Fixed an overflow in png_combine_row() with very wide interlaced images + (Bug report and fix by John Bowler, CVE-2014-9495). + +Version 1.6.16 [December 22, 2014] + No changes. + +Version 1.6.17beta01 [January 29, 2015] + Removed duplicate PNG_SAFE_LIMITS_SUPPORTED handling from pngconf.h + Corrected the width limit calculation in png_check_IHDR(). + Removed user limits from pngfix. Also pass NULL pointers to + png_read_row to skip the unnecessary row de-interlace stuff. + Added testing of png_set_packing() to pngvalid.c + Regenerated configure scripts in the *.tar distributions with libtool-2.4.4 + Implement previously untested cases of libpng transforms in pngvalid.c + Fixed byte order in 2-byte filler, in png_do_read_filler(). + Made the check for out-of-range values in png_set_tRNS() detect + values that are exactly 2^bit_depth, and work on 16-bit platforms. + Merged some parts of libpng-1.6.17beta01 and libpng-1.7.0beta47. + Added #ifndef __COVERITY__ where needed in png.c, pngrutil.c and + pngset.c to avoid warnings about dead code. + Added "& 0xff" to many instances of expressions that are typecast + to (png_byte), to avoid Coverity gripes. + +Version 1.6.17beta02 [February 7, 2015] + Work around one more Coverity-scan dead-code warning. + Do not build png_product2() when it is unused. + +Version 1.6.17beta03 [February 17, 2015] + Display user limits in the output from pngtest. + Eliminated the PNG_SAFE_LIMITS macro and restored the 1-million-column + and 1-million-row default limits in pnglibconf.dfa, that can be reset + by the user at build time or run time. This provides a more robust + defense against DOS and as-yet undiscovered overflows. + +Version 1.6.17beta04 [February 21, 2015] + Added PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED macro, on by default. + Allow user to call png_get_IHDR() with NULL arguments (Reuben Hawkins). + Rebuilt configure scripts with automake-1.15 and libtool-2.4.6 + +Version 1.6.17beta05 [February 25, 2015] + Restored compiling of png_reciprocal2 with PNG_NO_16BIT. + +Version 1.6.17beta06 [February 27, 2015] + Moved png_set_filter() prototype into a PNG_WRITE_SUPPORTED block + of png.h. + Avoid runtime checks when converting integer to png_byte with + Visual Studio (Sergey Kosarevsky) + +Version 1.6.17rc01 [March 4, 2015] + No changes. + +Version 1.6.17rc02 [March 9, 2015] + Removed some comments that the configure script did not handle + properly from scripts/pnglibconf.dfa and pnglibconf.h.prebuilt. + Free the unknown_chunks structure even when it contains no data. + +Version 1.6.17rc03 [March 12, 2015] + Updated CMakeLists.txt to add OSX framework, change YES/NO to ON/OFF + for consistency, and remove some useless tests (Alexey Petruchik). + +Version 1.6.17rc04 [March 16, 2015] + Remove pnglibconf.h, pnglibconf.c, and pnglibconf.out instead of + pnglibconf.* in "make clean" (Cosmin). + Fix bug in calculation of maxbits, in png_write_sBIT, introduced + in libpng-1.6.17beta01 (John Bowler). + +Version 1.6.17rc05 [March 21, 2015] + Define PNG_FILTER_* and PNG_FILTER_VALUE_* in png.h even when WRITE + is not supported (John Bowler). This fixes an error introduced in + libpng-1.6.17beta06. + Reverted "& 0xff" additions of version 1.6.17beta01. Libpng passes + the Coverity scan without them. + +Version 1.6.17rc06 [March 23, 2015] + Remove pnglibconf.dfn and pnglibconf.pre with "make clean". + Reformatted some "&0xff" instances to "& 0xff". + Fixed simplified 8-bit-linear to sRGB alpha. The calculated alpha + value was wrong. It's not clear if this affected the final stored + value; in the obvious code path the upper and lower 8-bits of the + alpha value were identical and the alpha was truncated to 8-bits + rather than dividing by 257 (John Bowler). + +Version 1.6.17 [March 26, 2015] + No changes. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit @@ -3861,4 +5212,3 @@ to subscribe) or to glennrp at users.sourceforge.net Glenn R-P -#endif diff --git a/src/3rdparty/libpng/INSTALL b/src/3rdparty/libpng/INSTALL index e6979c6fb0..a294ffe633 100644 --- a/src/3rdparty/libpng/INSTALL +++ b/src/3rdparty/libpng/INSTALL @@ -1,32 +1,69 @@ Installing libpng +Contents + + I. Simple installation + II. Rebuilding the configure scripts + III. Using scripts/makefile* + IV. Using cmake + V. Directory structure + VI. Building with project files + VII. Building with makefiles +VIII. Configuring libpng for 16-bit platforms + IX. Configuring for DOS + X. Configuring for Medium Model + XI. Prepending a prefix to exported symbols + XII. Configuring for compiler xxx: +XIII. Removing unwanted object code + XIV. Changes to the build and configuration of libpng in libpng-1.5.x + XV. Setjmp/longjmp issues + XVI. Other sources of information about libpng + +I. Simple installation + On Unix/Linux and similar systems, you can simply type ./configure [--prefix=/path] make check make install -and ignore the rest of this document. +and ignore the rest of this document. "/path" is the path to the directory +where you want to install the libpng "lib", "include", and "bin" +subdirectories. + +If you downloaded a GIT clone, you will need to run ./autogen.sh before +running ./configure, to create "configure" and "Makefile.in" which are +not included in the GIT repository. + +Note that "configure" is only included in the "*.tar" distributions and not +in the "*.zip" or "*.7z" distributions. If you downloaded one of those +distributions, see "Building with project files" or "Building with makefiles", +below. -If configure does not work on your system and you have a reasonably -up-to-date set of tools, running ./autogen.sh before running ./configure -may fix the problem. You can also run the individual commands in -autogen.sh with the --force option, if supported by your version of -the tools. To be really sure that you aren't using any of the included -pre-built scripts, you can do this: +II. Rebuilding the configure scripts + +If configure does not work on your system, or if you have a need to +change configure.ac or Makefile.am, and you have a reasonably +up-to-date set of tools, running ./autogen.sh in a git clone before +running ./configure may fix the problem. To be really sure that you +aren't using any of the included pre-built scripts, you can do this: ./configure --enable-maintainer-mode make maintainer-clean - ./autogen.sh + ./autogen.sh --maintainer --clean + ./autogen.sh --maintainer ./configure [--prefix=/path] [other options] make make install make check +III. Using scripts/makefile* + Instead, you can use one of the custom-built makefiles in the "scripts" directory + cp scripts/pnglibconf.h.prebuilt pnglibconf.h cp scripts/makefile.system makefile make test make install @@ -38,8 +75,28 @@ Or you can use one of the "projects" in the "projects" directory. Before installing libpng, you must first install zlib, if it is not already on your system. zlib can usually be found -wherever you got libpng. zlib can be placed in another directory, -at the same level as libpng. +wherever you got libpng; otherwise go to http://zlib.net. You can place +zlib in in the same directory as libpng or in another directory. + +If your system already has a preinstalled zlib you will still need +to have access to the zlib.h and zconf.h include files that +correspond to the version of zlib that's installed. + +If you wish to test with a particular zlib that is not first in the +standard library search path, put ZLIBLIB, ZLIBINC, CPPFLAGS, LDFLAGS, +and LD_LIBRARY_PATH in your environment before running "make test" +or "make distcheck": + +ZLIBLIB=/path/to/lib export ZLIBLIB +ZLIBINC=/path/to/include export ZLIBINC +CPPFLAGS="-I$ZLIBINC" export CPPFLAGS +LDFLAGS="-L$ZLIBLIB" export LDFLAGS +LD_LIBRARY_PATH="$ZLIBLIB:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH + +If you are using one of the makefile scripts, put ZLIBLIB and ZLIBINC +in your environment and type "make ZLIBLIB=$ZLIBLIB ZLIBINC=$ZLIBINC test". + +IV. Using cmake If you want to use "cmake" (see www.cmake.org), type @@ -47,13 +104,15 @@ If you want to use "cmake" (see www.cmake.org), type make make install -If your system already has a preinstalled zlib you will still need -to have access to the zlib.h and zconf.h include files that -correspond to the version of zlib that's installed. +As when using the simple configure method described above, "/path" points to +the installation directory where you want to put the libpng "lib", "include", +and "bin" subdirectories. + +V. Directory structure You can rename the directories that you downloaded (they -might be called "libpng-x.y.z" or "libpngNN" and "zlib-1.2.5" -or "zlib125") so that you have directories called "zlib" and "libpng". +might be called "libpng-x.y.z" or "libpngNN" and "zlib-1.2.8" +or "zlib128") so that you have directories called "zlib" and "libpng". Your directory structure should look like this: @@ -61,8 +120,7 @@ Your directory structure should look like this: libpng (this directory) INSTALL (this file) README - *.h - *.c + *.h, *.c => libpng source files CMakeLists.txt => "cmake" script configuration files: configure.ac, configure, Makefile.am, Makefile.in, @@ -70,14 +128,10 @@ Your directory structure should look like this: libpng-config.in, aclocal.m4, config.h.in, config.sub, depcomp, install-sh, mkinstalldirs, test-pngtest.sh contrib - gregbook - pngminim - pngminus - pngsuite - visupng + arm-neon, conftest, examples, gregbook, libtests, pngminim, + pngminus, pngsuite, tools, visupng projects - visualc71 - vstudio + cbuilder5, owatcom, visualc71, vstudio, xcode scripts makefile.* *.def (module definition files) @@ -85,29 +139,31 @@ Your directory structure should look like this: pngtest.png etc. zlib - README - *.h - *.c - contrib - etc. + README, *.h, *.c contrib, etc. If the line endings in the files look funny, you may wish to get the other distribution of libpng. It is available in both tar.gz (UNIX style line endings) and zip (DOS style line endings) formats. +VI. Building with project files + If you are building libpng with MSVC, you can enter the -libpng projects\visualc6 or visualc71 directory and follow the instructions +libpng projects\visualc71 or vstudio directory and follow the instructions in README.txt. Otherwise enter the zlib directory and follow the instructions in zlib/README, then come back here and run "configure" or choose the appropriate makefile.sys in the scripts directory. +VII. Building with makefiles + Copy the file (or files) that you need from the scripts directory into this directory, for example MSDOS example: copy scripts\makefile.msc makefile - UNIX example: cp scripts/makefile.std makefile + copy scripts\pnglibconf.h.prebuilt pnglibconf.h + UNIX example: cp scripts/makefile.std makefile + cp scripts/pnglibconf.h.prebuilt pnglibconf.h Read the makefile to see if you need to change any source or target directories to match your preferences. @@ -130,6 +186,202 @@ do that, run "make install" in the zlib directory first if necessary). Some also allow you to run "make test-installed" after you have run "make install". +VIII. Configuring libpng for 16-bit platforms + +You will want to look into zconf.h to tell zlib (and thus libpng) that +it cannot allocate more than 64K at a time. Even if you can, the memory +won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. + +IX. Configuring for DOS + +For DOS users who only have access to the lower 640K, you will +have to limit zlib's memory usage via a png_set_compression_mem_level() +call. See zlib.h or zconf.h in the zlib library for more information. + +X. Configuring for Medium Model + +Libpng's support for medium model has been tested on most of the popular +compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets +defined, and FAR gets defined to far in pngconf.h, and you should be +all set. Everything in the library (except for zlib's structure) is +expecting far data. You must use the typedefs with the p or pp on +the end for pointers (or at least look at them and be careful). Make +note that the rows of data are defined as png_bytepp, which is +an "unsigned char far * far *". + +XI. Prepending a prefix to exported symbols + +Starting with libpng-1.6.0, you can configure libpng (when using the +"configure" script) to prefix all exported symbols by means of the +configuration option "--with-libpng-prefix=FOO_", where FOO_ can be any +string beginning with a letter and containing only uppercase +and lowercase letters, digits, and the underscore (i.e., a C language +identifier). This creates a set of macros in pnglibconf.h, so this is +transparent to applications; their function calls get transformed by +the macros to use the modified names. + +XII. Configuring for compiler xxx: + +All includes for libpng are in pngconf.h. If you need to add, change +or delete an include, this is the place to do it. +The includes that are not needed outside libpng are placed in pngpriv.h, +which is only used by the routines inside libpng itself. +The files in libpng proper only include pngpriv.h and png.h, which +in turn includes pngconf.h and, as of libpng-1.5.0, pnglibconf.h. +As of libpng-1.5.0, pngpriv.h also includes three other private header +files, pngstruct.h, pnginfo.h, and pngdebug.h, which contain material +that previously appeared in the public headers. + +XIII. Removing unwanted object code + +There are a bunch of #define's in pngconf.h that control what parts of +libpng are compiled. All the defines end in _SUPPORTED. If you are +never going to use a capability, you can change the #define to #undef +before recompiling libpng and save yourself code and data space, or +you can turn off individual capabilities with defines that begin with +PNG_NO_. + +In libpng-1.5.0 and later, the #define's are in pnglibconf.h instead. + +You can also turn all of the transforms and ancillary chunk capabilities +off en masse with compiler directives that define +PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, +or all four, along with directives to turn on any of the capabilities that +you do want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable the +extra transformations but still leave the library fully capable of reading +and writing PNG files with all known public chunks. Use of the +PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive produces a library +that is incapable of reading or writing ancillary chunks. If you are +not using the progressive reading capability, you can turn that off +with PNG_NO_PROGRESSIVE_READ (don't confuse this with the INTERLACING +capability, which you'll still have). + +All the reading and writing specific code are in separate files, so the +linker should only grab the files it needs. However, if you want to +make sure, or if you are building a stand alone library, all the +reading files start with "pngr" and all the writing files start with "pngw". +The files that don't match either (like png.c, pngtrans.c, etc.) +are used for both reading and writing, and always need to be included. +The progressive reader is in pngpread.c + +If you are creating or distributing a dynamically linked library (a .so +or DLL file), you should not remove or disable any parts of the library, +as this will cause applications linked with different versions of the +library to fail if they call functions not available in your library. +The size of the library itself should not be an issue, because only +those sections that are actually used will be loaded into memory. + +XIV. Changes to the build and configuration of libpng in libpng-1.5.x + +Details of internal changes to the library code can be found in the CHANGES +file and in the GIT repository logs. These will be of no concern to the vast +majority of library users or builders; however, the few who configure libpng +to a non-default feature set may need to change how this is done. + +There should be no need for library builders to alter build scripts if +these use the distributed build support - configure or the makefiles - +however, users of the makefiles may care to update their build scripts +to build pnglibconf.h where the corresponding makefile does not do so. + +Building libpng with a non-default configuration has changed completely. +The old method using pngusr.h should still work correctly even though the +way pngusr.h is used in the build has been changed; however, library +builders will probably want to examine the changes to take advantage of +new capabilities and to simplify their build system. + +A. Specific changes to library configuration capabilities + +The exact mechanism used to control attributes of API functions has +changed. A single set of operating system independent macro definitions +is used and operating system specific directives are defined in +pnglibconf.h + +As part of this the mechanism used to choose procedure call standards on +those systems that allow a choice has been changed. At present this only +affects certain Microsoft (DOS, Windows) and IBM (OS/2) operating systems +running on Intel processors. As before, PNGAPI is defined where required +to control the exported API functions; however, two new macros, PNGCBAPI +and PNGCAPI, are used instead for callback functions (PNGCBAPI) and +(PNGCAPI) for functions that must match a C library prototype (currently +only png_longjmp_ptr, which must match the C longjmp function.) The new +approach is documented in pngconf.h + +Despite these changes, libpng 1.5.0 only supports the native C function +calling standard on those platforms tested so far (__cdecl on Microsoft +Windows). This is because the support requirements for alternative +calling conventions seem to no longer exist. Developers who find it +necessary to set PNG_API_RULE to 1 should advise the mailing list +(png-mng-implement) of this and library builders who use Openwatcom and +therefore set PNG_API_RULE to 2 should also contact the mailing list. + +B. Changes to the configuration mechanism + +Prior to libpng-1.5.0 library builders who needed to configure libpng +had either to modify the exported pngconf.h header file to add system +specific configuration or had to write feature selection macros into +pngusr.h and cause this to be included into pngconf.h by defining +PNG_USER_CONFIG. The latter mechanism had the disadvantage that an +application built without PNG_USER_CONFIG defined would see the +unmodified, default, libpng API and thus would probably fail to link. + +These mechanisms still work in the configure build and in any makefile +build that builds pnglibconf.h, although the feature selection macros +have changed somewhat as described above. In 1.5.0, however, pngusr.h is +processed only once, at the time the exported header file pnglibconf.h is +built. pngconf.h no longer includes pngusr.h; therefore, pngusr.h is ignored +after the build of pnglibconf.h and it is never included in an application +build. + +The formerly used alternative of adding a list of feature macros to the +CPPFLAGS setting in the build also still works; however, the macros will be +copied to pnglibconf.h and this may produce macro redefinition warnings +when the individual C files are compiled. + +All configuration now only works if pnglibconf.h is built from +scripts/pnglibconf.dfa. This requires the program awk. Brian Kernighan +(the original author of awk) maintains C source code of that awk and this +and all known later implementations (often called by subtly different +names - nawk and gawk for example) are adequate to build pnglibconf.h. +The Sun Microsystems (now Oracle) program 'awk' is an earlier version +and does not work; this may also apply to other systems that have a +functioning awk called 'nawk'. + +Configuration options are now documented in scripts/pnglibconf.dfa. This +file also includes dependency information that ensures a configuration is +consistent; that is, if a feature is switched off, dependent features are +also switched off. As a recommended alternative to using feature macros in +pngusr.h a system builder may also define equivalent options in pngusr.dfa +(or, indeed, any file) and add that to the configuration by setting +DFA_XTRA to the file name. The makefiles in contrib/pngminim illustrate +how to do this, and also illustrate a case where pngusr.h is still required. + +After you have built libpng, the definitions that were recorded in +pnglibconf.h are available to your application (pnglibconf.h is included +in png.h and gets installed alongside png.h and pngconf.h in your +$PREFIX/include directory). Do not edit pnglibconf.h after you have built +libpng, because than the settings would not accurately reflect the settings +that were used to build libpng. + +XV. Setjmp/longjmp issues + +Libpng uses setjmp()/longjmp() for error handling. Unfortunately setjmp() +is known to be not thread-safe on some platforms and we don't know of +any platform where it is guaranteed to be thread-safe. Therefore, if +your application is going to be using multiple threads, you should +configure libpng with PNG_NO_SETJMP in your pngusr.dfa file, with +-DPNG_NO_SETJMP on your compile line, or with + + #undef PNG_SETJMP_SUPPORTED + +in your pnglibconf.h or pngusr.h. + +Starting with libpng-1.6.0, the library included a "simplified API". +This requires setjmp/longjmp, so you must either build the library +with PNG_SETJMP_SUPPORTED defined, or with PNG_SIMPLIFIED_READ_SUPPORTED +and PNG_SIMPLIFIED_WRITE_SUPPORTED undefined. + +XVI. Other sources of information about libpng: + Further information can be found in the README and libpng-manual.txt files, in the individual makefiles, in png.h, and the manual pages libpng.3 and png.5. @@ -147,7 +399,7 @@ CFLAGS="-Wall -O -funroll-loops \ --with-pkgconfigdir=/usr/lib/pkgconfig --includedir=/usr/include You can alternatively specify --includedir=/usr/include, /usr/local/include, -/usr/include/libpng%NN%, or whatever. +/usr/include/libpng16, or whatever. If you find that the configure script is out-of-date or is not supporting your platform properly, try running autogen.sh to regenerate "configure", diff --git a/src/3rdparty/libpng/LICENSE b/src/3rdparty/libpng/LICENSE index b72d1258e3..eb4a9a9da4 100644 --- a/src/3rdparty/libpng/LICENSE +++ b/src/3rdparty/libpng/LICENSE @@ -10,8 +10,8 @@ this sentence. This code is released under the libpng license. -libpng versions 1.2.6, August 15, 2004, through 1.5.10, March 29, 2012, are -Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are +libpng versions 1.2.6, August 15, 2004, through 1.6.17, March 26, 2015, are +Copyright (c) 2004, 2006-2015 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.2.5 with the following individual added to the list of Contributing Authors @@ -108,4 +108,4 @@ certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net -March 29, 2012 +March 26, 2015 diff --git a/src/3rdparty/libpng/README b/src/3rdparty/libpng/README index e821ee4c87..a158ea8a77 100644 --- a/src/3rdparty/libpng/README +++ b/src/3rdparty/libpng/README @@ -1,11 +1,11 @@ -README for libpng version 1.5.10 - March 29, 2012 (shared library 15.0) +README for libpng version 1.6.17 - March 26, 2015 (shared library 16.0) See the note about version numbers near the top of png.h See INSTALL for instructions on how to install libpng. -Libpng comes in several distribution formats. Get libpng-*.tar.gz, -libpng-*.tar.xz or libpng-*.tar.bz2 if you want UNIX-style line endings -in the text files, or lpng*.zip if you want DOS-style line endings. +Libpng comes in several distribution formats. Get libpng-*.tar.gz or +libpng-*.tar.xz or if you want UNIX-style line endings in the text files, +or lpng*.7z or lpng*.zip if you want DOS-style line endings. Version 0.89 was the first official release of libpng. Don't let the fact that it's the first release fool you. The libpng library has been in @@ -23,18 +23,25 @@ earlier versions if you are using a shared library. The type of the png_uint_32, which will affect shared-library applications that use this function. -To avoid problems with changes to the internals of png_info_struct, +To avoid problems with changes to the internals of png info_struct, new APIs have been made available in 0.95 to avoid direct application access to info_ptr. These functions are the png_set_ and png_get_ functions. These functions should be used when accessing/storing the info_struct data, rather than manipulating it directly, to avoid such problems in the future. -It is important to note that the APIs do not make current programs +It is important to note that the APIs did not make current programs that access the info struct directly incompatible with the new -library. However, it is strongly suggested that new programs use -the new APIs (as shown in example.c and pngtest.c), and older programs -be converted to the new format, to facilitate upgrades in the future. +library, through libpng-1.2.x. In libpng-1.4.x, which was meant to +be a transitional release, members of the png_struct and the +info_struct can still be accessed, but the compiler will issue a +warning about deprecated usage. Since libpng-1.5.0, direct access +to these structs is not allowed, and the definitions of the structs +reside in private pngstruct.h and pnginfo.h header files that are not +accessible to applications. It is strongly suggested that new +programs use the new APIs (as shown in example.c and pngtest.c), and +older programs be converted to the new format, to facilitate upgrades +in the future. **** Additions since 0.90 include the ability to compile libpng as a @@ -77,17 +84,21 @@ compression library that is useful for more things than just PNG files. You can use zlib as a drop-in replacement for fread() and fwrite() if you are so inclined. -zlib should be available at the same place that libpng is, or at. -ftp://ftp.info-zip.org/pub/infozip/zlib +zlib should be available at the same place that libpng is, or at zlib.net. You may also want a copy of the PNG specification. It is available as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find these at http://www.libpng.org/pub/png/documents/ This code is currently being archived at libpng.sf.net in the -[DOWNLOAD] area, and on CompuServe, Lib 20 (PNG SUPPORT) -at GO GRAPHSUP. If you can't find it in any of those places, -e-mail me, and I'll help you find it. +[DOWNLOAD] area, and at ftp://ftp.simplesystems.org. If you can't find it +in any of those places, e-mail me, and I'll help you find it. + +I am not a lawyer, but I believe that the Export Control Classification +Number (ECCN) for libpng is EAR99, which means not subject to export +controls or International Traffic in Arms Regulations (ITAR) because it +is open source, publicly available software, that does not contain any +encryption software. See the EAR, paragraphs 734.3(b)(3) and 734.7(b). If you have any code changes, requests, problems, etc., please e-mail them to me. Also, I'd appreciate any make files or project files, @@ -105,7 +116,7 @@ based in a large way on Guy's and Andreas' earlier work), and the PNG development group. Send comments/corrections/commendations to png-mng-implement at -lists.sourceforge.net (subscription required; visit +lists.sourceforge.net (subscription required; visit https://lists.sourceforge.net/lists/listinfo/png-mng-implement to subscribe) or to glennrp at users.sourceforge.net @@ -123,7 +134,7 @@ and ...". If in doubt, send questions to me. I'll bounce them to others, if necessary. Please do not send suggestions on how to change PNG. We have -been discussing PNG for sixteen years now, and it is official and +been discussing PNG for nineteen years now, and it is official and finished. If you have suggestions for libpng, however, I'll gladly listen. Even if your suggestion is not used immediately, it may be used later. @@ -167,23 +178,25 @@ Files in this distribution: pngwrite.c => High-level write functions pngwtran.c => Write data transformations pngwutil.c => Write utility functions + arm => Contains optimized code for the ARM platform contrib => Contributions + examples => Example programs gregbook => source code for PNG reading and writing, from Greg Roelofs' "PNG: The Definitive Guide", O'Reilly, 1999 - msvctest => Builds and runs pngtest using a MSVC workspace - pngminus => Simple pnm2png and png2pnm programs - pngsuite => Test images - visupng => Contains a MSVC workspace for VisualPng + libtests => Test programs + pngminim => Minimal decoder, encoder, and progressive decoder + programs demonstrating use of pngusr.dfa + pngminus => Simple pnm2png and png2pnm programs + pngsuite => Test images + tools => Various tools + visupng => Contains a MSVC workspace for VisualPng projects => Contains project files and workspaces for building a DLL - cbuilder5 => Contains a Borland workspace for building - libpng and zlib - visualc6 => Contains a Microsoft Visual C++ (MSVC) - workspace for building libpng and zlib + owatcom => Contains a WATCOM project for building libpng visualc71 => Contains a Microsoft Visual C++ (MSVC) workspace for building libpng and zlib - xcode => Contains an Apple xcode + vstudio => Contains a Microsoft Visual C++ (MSVC) workspace for building libpng and zlib scripts => Directory containing scripts for building libpng: (see scripts/README.txt for the list of scripts) diff --git a/src/3rdparty/libpng/libpng-manual.txt b/src/3rdparty/libpng/libpng-manual.txt index d55e80a009..f0dae987f9 100644 --- a/src/3rdparty/libpng/libpng-manual.txt +++ b/src/3rdparty/libpng/libpng-manual.txt @@ -1,9 +1,9 @@ libpng-manual.txt - A description on how to use and modify libpng - libpng version 1.5.10 - March 29, 2012 + libpng version 1.6.17 - March 26, 2015 Updated and distributed by Glenn Randers-Pehrson - Copyright (c) 1998-2011 Glenn Randers-Pehrson + Copyright (c) 1998-2015 Glenn Randers-Pehrson This document is released under the libpng license. For conditions of distribution and use, see the disclaimer @@ -11,15 +11,15 @@ libpng-manual.txt - A description on how to use and modify libpng Based on: - libpng versions 0.97, January 1998, through 1.5.10 - March 29, 2012 + libpng versions 0.97, January 1998, through 1.6.17 - March 26, 2015 Updated and distributed by Glenn Randers-Pehrson - Copyright (c) 1998-2011 Glenn Randers-Pehrson + Copyright (c) 1998-2015 Glenn Randers-Pehrson - libpng 1.0 beta 6 version 0.96 May 28, 1997 + libpng 1.0 beta 6 - version 0.96 - May 28, 1997 Updated and distributed by Andreas Dilger Copyright (c) 1996, 1997 Andreas Dilger - libpng 1.0 beta 2 - version 0.88 January 26, 1996 + libpng 1.0 beta 2 - version 0.88 - January 26, 1996 For conditions of distribution and use, see copyright notice in png.h. Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. @@ -28,16 +28,33 @@ libpng-manual.txt - A description on how to use and modify libpng Copyright (c) 1995, 1996 Frank J. T. Wojcik December 18, 1995 & January 20, 1996 + TABLE OF CONTENTS + + I. Introduction + II. Structures + III. Reading + IV. Writing + V. Simplified API + VI. Modifying/Customizing libpng + VII. MNG support + VIII. Changes to Libpng from version 0.88 + IX. Changes to Libpng from version 1.0.x to 1.2.x + X. Changes to Libpng from version 1.0.x/1.2.x to 1.4.x + XI. Changes to Libpng from version 1.4.x to 1.5.x + XII. Changes to Libpng from version 1.5.x to 1.6.x + XIII. Detecting libpng + XIV. Source code repository + XV. Coding style + XVI. Y2K Compliance in libpng + I. Introduction This file describes how to use and modify the PNG reference library -(known as libpng) for your own use. There are five sections to this -file: introduction, structures, reading, writing, and modification and -configuration notes for various special platforms. In addition to this +(known as libpng) for your own use. In addition to this file, example.c is a good starting point for using the library, as it is heavily commented and should include everything most people will need. We assume that libpng is already installed; see the -INSTALL file for instructions on how to install libpng. +INSTALL file for instructions on how to configure and install libpng. For examples of libpng usage, see the files "example.c", "pngtest.c", and the files in the "contrib" directory, all of which are included in @@ -48,7 +65,7 @@ of reducing the amount of time and effort it takes to support the PNG file format in application programs. The PNG specification (second edition), November 2003, is available as -a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at +a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2004 (E)) at = 10504 - png_set_alpha_mode(png_ptr, mode, screen_gamma); -#else - png_set_gamma(png_ptr, screen_gamma, 1.0/screen_gamma); -#endif + #if PNG_LIBPNG_VER >= 10504 + png_set_alpha_mode(png_ptr, mode, screen_gamma); + #else + png_set_gamma(png_ptr, screen_gamma, 1.0/screen_gamma); + #endif The screen_gamma value is the same as the argument to png_set_gamma; however, how it affects the output depends on the mode. png_set_alpha_mode() sets the @@ -738,11 +831,11 @@ by png_set_alpha_mode(). The mode is as follows: - PNG_ALPHA_PNG: The data is encoded according to the PNG specification. Red, -green and blue, or gray, components are gamma encoded color -values and are not premultiplied by the alpha value. The -alpha value is a linear measure of the contribution of the -pixel to the corresponding final output pixel. + PNG_ALPHA_PNG: The data is encoded according to the PNG +specification. Red, green and blue, or gray, components are +gamma encoded color values and are not premultiplied by the +alpha value. The alpha value is a linear measure of the +contribution of the pixel to the corresponding final output pixel. You should normally use this format if you intend to perform color correction on the color values; most, maybe all, color @@ -759,11 +852,35 @@ be used! The remaining modes assume you don't need to do any further color correction or that if you do, your color correction software knows all about alpha (it -probably doesn't!) - - PNG_ALPHA_STANDARD: The data libpng produces -is encoded in the standard way -assumed by most correctly written graphics software. +probably doesn't!). They 'associate' the alpha with the color information by +storing color channel values that have been scaled by the alpha. The +advantage is that the color channels can be resampled (the image can be +scaled) in this form. The disadvantage is that normal practice is to store +linear, not (gamma) encoded, values and this requires 16-bit channels for +still images rather than the 8-bit channels that are just about sufficient if +gamma encoding is used. In addition all non-transparent pixel values, +including completely opaque ones, must be gamma encoded to produce the final +image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes +described below (the latter being the two common names for associated alpha +color channels). Note that PNG files always contain non-associated color +channels; png_set_alpha_mode() with one of the modes causes the decoder to +convert the pixels to an associated form before returning them to your +application. + +Since it is not necessary to perform arithmetic on opaque color values so +long as they are not to be resampled and are in the final color space it is +possible to optimize the handling of alpha by storing the opaque pixels in +the PNG format (adjusted for the output color space) while storing partially +opaque pixels in the standard, linear, format. The accuracy required for +standard alpha composition is relatively low, because the pixels are +isolated, therefore typically the accuracy loss in storing 8-bit linear +values is acceptable. (This is not true if the alpha channel is used to +simulate transparency over large areas - use 16 bits or the PNG mode in +this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is +treated as opaque only if the alpha value is equal to the maximum value. + + PNG_ALPHA_STANDARD: The data libpng produces is encoded in the +standard way assumed by most correctly written graphics software. The gamma encoding will be removed by libpng and the linear component values will be pre-multiplied by the alpha channel. @@ -792,14 +909,13 @@ dynamic range. To avoid problems, and if your software supports it, use png_set_expand_16() to force all components to 16 bits. - PNG_ALPHA_OPTIMIZED: This mode is the same -as PNG_ALPHA_STANDARD except that -completely opaque pixels are gamma encoded according to + PNG_ALPHA_OPTIMIZED: This mode is the same as PNG_ALPHA_STANDARD +except that completely opaque pixels are gamma encoded according to the screen_gamma value. Pixels with alpha less than 1.0 will still have linear components. Use this format if you have control over your -compositing software and do don't do other arithmetic +compositing software and so don't do other arithmetic (such as scaling) on the data you get from libpng. Your compositing software can simply copy opaque pixels to the output but still has linear values for the @@ -813,18 +929,16 @@ representation of non-opaque pixels are irrelevant. You can also try this format if your software is broken; it might look better. - PNG_ALPHA_BROKEN: This is PNG_ALPHA_STANDARD; -however, all component values, -including the alpha channel are gamma encoded. This is -an appropriate format to try if your software, or more -likely hardware, is totally broken, i.e., if it performs -linear arithmetic directly on gamma encoded values. - -In most cases of broken software or hardware the bug in the final display -manifests as a subtle halo around composited parts of the image. You may not -even perceive this as a halo; the composited part of the image may simply appear -separate from the background, as though it had been cut out of paper and pasted -on afterward. + PNG_ALPHA_BROKEN: This is PNG_ALPHA_STANDARD; however, all component +values, including the alpha channel are gamma encoded. This is +broken because, in practice, no implementation that uses this choice +correctly undoes the encoding before handling alpha composition. Use this +choice only if other serious errors in the software or hardware you use +mandate it. In most cases of broken software or hardware the bug in the +final display manifests as a subtle halo around composited parts of the +image. You may not even perceive this as a halo; the composited part of +the image may simply appear separate from the background, as though it had +been cut out of paper and pasted on afterward. If you don't have to deal with bugs in software or hardware, or if you can fix them, there are three recommended ways of using png_set_alpha_mode(): @@ -855,6 +969,89 @@ All you can do is compose the result onto a matching output. Since this mode is libpng-specific you also need to write your own composition software. +The following are examples of calls to png_set_alpha_mode to achieve the +required overall gamma correction and, where necessary, alpha +premultiplication. + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + +This is the default libpng handling of the alpha channel - it is not +pre-multiplied into the color components. In addition the call states +that the output is for a sRGB system and causes all PNG files without gAMA +chunks to be assumed to be encoded using sRGB. + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + +In this case the output is assumed to be something like an sRGB conformant +display preceeded by a power-law lookup table of power 1.45. This is how +early Mac systems behaved. + + png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + +This is the classic Jim Blinn approach and will work in academic +environments where everything is done by the book. It has the shortcoming +of assuming that input PNG data with no gamma information is linear - this +is unlikely to be correct unless the PNG files where generated locally. +Most of the time the output precision will be so low as to show +significant banding in dark areas of the image. + + png_set_expand_16(pp); + png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + +This is a somewhat more realistic Jim Blinn inspired approach. PNG files +are assumed to have the sRGB encoding if not marked with a gamma value and +the output is always 16 bits per component. This permits accurate scaling +and processing of the data. If you know that your input PNG files were +generated locally you might need to replace PNG_DEFAULT_sRGB with the +correct value for your system. + + png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + +If you just need to composite the PNG image onto an existing background +and if you control the code that does this you can use the optimization +setting. In this case you just copy completely opaque pixels to the +output. For pixels that are not completely transparent (you just skip +those) you do the composition math using png_composite or png_composite_16 +below then encode the resultant 8-bit or 16-bit values to match the output +encoding. + + Other cases + +If neither the PNG nor the standard linear encoding work for you because +of the software or hardware you use then you have a big problem. The PNG +case will probably result in halos around the image. The linear encoding +will probably result in a washed out, too bright, image (it's actually too +contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably +substantially reduce the halos. Alternatively try: + + png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + +This option will also reduce the halos, but there will be slight dark +halos round the opaque parts of the image where the background is light. +In the OPTIMIZED mode the halos will be light halos where the background +is dark. Take your pick - the halos are unavoidable unless you can get +your hardware/software fixed! (The OPTIMIZED approach is slightly +faster.) + +When the default gamma of PNG files doesn't match the output gamma. +If you have PNG files with no gamma information png_set_alpha_mode allows +you to provide a default gamma, but it also sets the ouput gamma to the +matching value. If you know your PNG files have a gamma that doesn't +match the output you can take advantage of the fact that +png_set_alpha_mode always sets the output gamma but only sets the PNG +default if it is not already set: + + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + +The first call sets both the default and the output gamma values, the +second call overrides the output gamma without changing the default. This +is easier than achieving the same effect with png_set_gamma. You must use +PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will +fire if more than one call to png_set_alpha_mode and png_set_background is +made in the same read operation, however multiple calls with PNG_ALPHA_PNG +are ignored. + If you don't need, or can't handle, the alpha channel you can call png_set_background() to remove it by compositing against a fixed color. Don't call png_set_strip_alpha() to do this - it will leave spurious pixel values in @@ -962,7 +1159,7 @@ where row_pointers is an array of pointers to the pixel data for each row: If you know your image size and pixel size ahead of time, you can allocate row_pointers prior to calling png_read_png() with - if (height > PNG_UINT_32_MAX/png_sizeof(png_byte)) + if (height > PNG_UINT_32_MAX/(sizeof (png_byte))) png_error (png_ptr, "Image is too tall to process in memory"); @@ -971,7 +1168,7 @@ row_pointers prior to calling png_read_png() with "Image is too wide to process in memory"); row_pointers = png_malloc(png_ptr, - height*png_sizeof(png_bytep)); + height*(sizeof (png_bytep))); for (int i=0; i are set directly if they are simple data types, or a pointer into the info_ptr is returned for any complex types. +The colorspace data from gAMA, cHRM, sRGB, iCCP, and sBIT chunks +is simply returned to give the application information about how the +image was encoded. Libpng itself only does transformations using the file +gamma when combining semitransparent pixels with the background color, and, +since libpng-1.6.0, when converting between 8-bit sRGB and 16-bit linear pixels +within the simplified API. Libpng also uses the file gamma when converting +RGB to gray, beginning with libpng-1.0.5, if the application calls +png_set_rgb_to_gray()). + png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); @@ -1147,31 +1353,36 @@ pointer into the info_ptr is returned for any complex types. int_file_gamma - 100,000 times the gamma at which the file is written - png_get_cHRM(png_ptr, info_ptr, &white_x, &white_y, &red_x, &red_y, - &green_x, &green_y, &blue_x, &blue_y) - png_get_cHRM_XYZ(png_ptr, info_ptr, &red_X, &red_Y, &red_Z, &green_X, - &green_Y, &green_Z, &blue_X, &blue_Y, &blue_Z) - png_get_cHRM_fixed(png_ptr, info_ptr, &int_white_x, &int_white_y, - &int_red_x, &int_red_y, &int_green_x, &int_green_y, - &int_blue_x, &int_blue_y) + png_get_cHRM(png_ptr, info_ptr, &white_x, &white_y, &red_x, + &red_y, &green_x, &green_y, &blue_x, &blue_y) + png_get_cHRM_XYZ(png_ptr, info_ptr, &red_X, &red_Y, &red_Z, + &green_X, &green_Y, &green_Z, &blue_X, &blue_Y, + &blue_Z) + png_get_cHRM_fixed(png_ptr, info_ptr, &int_white_x, + &int_white_y, &int_red_x, &int_red_y, + &int_green_x, &int_green_y, &int_blue_x, + &int_blue_y) png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &int_red_X, &int_red_Y, - &int_red_Z, &int_green_X, &int_green_Y, &int_green_Z, - &int_blue_X, &int_blue_Y, &int_blue_Z) + &int_red_Z, &int_green_X, &int_green_Y, + &int_green_Z, &int_blue_X, &int_blue_Y, + &int_blue_Z) {white,red,green,blue}_{x,y} - A color space encoding specified using the chromaticities - of the end points and the white point. (PNG_INFO_cHRM) + A color space encoding specified using the + chromaticities of the end points and the + white point. (PNG_INFO_cHRM) {red,green,blue}_{X,Y,Z} - A color space encoding specified using the encoding end - points - the CIE tristimulus specification of the intended - color of the red, green and blue channels in the PNG RGB - data. The white point is simply the sum of the three end - points. (PNG_INFO_cHRM) + A color space encoding specified using the + encoding end points - the CIE tristimulus + specification of the intended color of the red, + green and blue channels in the PNG RGB data. + The white point is simply the sum of the three + end points. (PNG_INFO_cHRM) png_get_sRGB(png_ptr, info_ptr, &srgb_intent); - file_srgb_intent - the rendering intent (PNG_INFO_sRGB) + srgb_intent - the rendering intent (PNG_INFO_sRGB) The presence of the sRGB chunk means that the pixel data is in the sRGB color space. This chunk also @@ -1571,17 +1782,19 @@ Within the matrix, "A" means the transformation is obtained by png_set_add_alpha(). "X" means the transformation is obtained by png_set_expand(). "1" means the transformation is obtained by - png_set_expand_gray_1_2_4_to_8() (and by png_set_expand() if there - is no transparency in the original or the final format). + png_set_expand_gray_1_2_4_to_8() (and by png_set_expand() + if there is no transparency in the original or the final + format). "C" means the transformation is obtained by png_set_gray_to_rgb(). "G" means the transformation is obtained by png_set_rgb_to_gray(). "P" means the transformation is obtained by png_set_expand_palette_to_rgb(). "p" means the transformation is obtained by png_set_packing(). "Q" means the transformation is obtained by png_set_quantize(). - "T" means the transformation is obtained by png_set_tRNS_to_alpha(). - "B" means the transformation is obtained by png_set_background(), or - png_strip_alpha(). + "T" means the transformation is obtained by + png_set_tRNS_to_alpha(). + "B" means the transformation is obtained by + png_set_background(), or png_strip_alpha(). When an entry has multiple transforms listed all are required to cause the right overall transformation. When two transforms are separated by a comma @@ -1666,8 +1879,8 @@ with alpha. if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_rgb_to_gray(png_ptr, error_action, double red_weight, - double green_weight); + png_set_rgb_to_gray(png_ptr, error_action, + double red_weight, double green_weight); error_action = 1: silently do the conversion @@ -1689,7 +1902,8 @@ with alpha. In the corresponding fixed point API the red_weight and green_weight values are simply scaled by 100,000: - png_set_rgb_to_gray(png_ptr, error_action, png_fixed_point red_weight, + png_set_rgb_to_gray(png_ptr, error_action, + png_fixed_point red_weight, png_fixed_point green_weight); If you have set error_action = 1 or 2, you can @@ -1733,7 +1947,7 @@ the current display (e.g., the background color from a web page). You need to tell libpng how the color is represented, both the format of the component values in the color (the number of bits) and the gamma encoding of the color. The function takes two arguments, background_gamma_mode and need_expand -to convey this information, however only two combinations are likely to be +to convey this information; however, only two combinations are likely to be useful: png_color_16 my_background; @@ -1780,7 +1994,7 @@ value when you call it in this position: png_set_gamma(png_ptr, screen_gamma, 0.45455); If you need to reduce an RGB file to a paletted file, or if a paletted -file has more entries then will fit on your screen, png_set_quantize() +file has more entries than will fit on your screen, png_set_quantize() will do that. Note that this is a simple match quantization that merely finds the closest color available. This should work fairly well with optimized palettes, but fairly badly with linear color cubes. If you @@ -2027,7 +2241,7 @@ the second parameter NULL. If you don't want libpng to handle the interlacing details, just call png_read_rows() PNG_INTERLACE_ADAM7_PASSES times to read in all the images. -Each of the images is a valid image by itself, however you will almost +Each of the images is a valid image by itself; however, you will almost certainly need to distribute the pixels from each sub-image to the correct place. This is where everything gets very tricky. @@ -2118,10 +2332,15 @@ how pngvalid.c does it. Finishing a sequential read After you are finished reading the image through the -low-level interface, you can finish reading the file. If you are -interested in comments or time, which may be stored either before or -after the image data, you should pass the separate png_info struct if -you want to keep the comments from before and after the image +low-level interface, you can finish reading the file. + +If you want to use a different crc action for handling CRC errors in +chunks after the image data, you can call png_set_crc_action() +again at this point. + +If you are interested in comments or time, which may be stored either +before or after the image data, you should pass the separate png_info +struct if you want to keep the comments from before and after the image separate. png_infop end_info = png_create_info_struct(png_ptr); @@ -2137,6 +2356,9 @@ separate. If you are not interested, you should still call png_read_end() but you can pass NULL, avoiding the need to create an end_info structure. +If you do this, libpng will not process any chunks after IDAT other than +skipping over them and perhaps (depending on whether you have called +png_set_crc_action) checking their CRCs while looking for the IEND chunk. png_read_end(png_ptr, (png_infop)NULL); @@ -2184,7 +2406,7 @@ sPLT, only the n'th item in the structure is freed, where n is "seq". The default behavior is only to free data that was allocated internally by libpng. This can be changed, so that libpng will not free the data, or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with +or png_calloc() and passed in via a png_set_*() function, with png_data_freer(png_ptr, info_ptr, freer, mask) @@ -2205,7 +2427,7 @@ or png_destroy_*() is supposed to free the data. When the user assumes responsibility for libpng-allocated data, the application must use png_free() to free it, and when the user transfers responsibility to libpng for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. +or png_calloc() to allocate it. If you allocated your row_pointers in a single block, as suggested above in the description of the high level read interface, you must not transfer @@ -2241,7 +2463,7 @@ For a more compact example of reading a PNG image, see the file example.c. Reading PNG files progressively -The progressive reader is slightly different then the non-progressive +The progressive reader is slightly different from the non-progressive reader. Instead of calling png_read_info(), png_read_rows(), and png_read_end(), you make one call to png_process_data(), which calls callbacks when it has the info, a row, or the end of the image. You @@ -2325,7 +2547,7 @@ png_infop info_ptr; 64K. The library seems to run fine with sizes of 4K. Although you can give it much less if necessary (I assume you can give it chunks of - 1 byte, I haven't tried less then 256 bytes + 1 byte, I haven't tried less than 256 bytes yet). When this function returns, you may want to display any rows that were generated in the row callback if you don't already do @@ -2412,7 +2634,7 @@ png_infop info_ptr; png_progressive_combine_row(png_ptr, old_row, new_row); - /* where old_row is what was displayed for + /* where old_row is what was displayed previously for the row. Note that the first pass (pass == 0, really) will completely cover the old row, so the rows do not have to be @@ -2521,6 +2743,20 @@ You can #define PNG_ABORT() to a function that does something more useful than abort(), as long as your function does not return. +Checking for invalid palette index on write was added at libpng +1.5.10. If a pixel contains an invalid (out-of-range) index libpng issues +a benign error. This is enabled by default because this condition is an +error according to the PNG specification, Clause 11.3.2, but the error can +be ignored in each png_ptr with + + png_set_check_for_invalid_index(png_ptr, 0); + +If the error is ignored, or if png_benign_error() treats it as a warning, +any invalid pixels are written as-is by the encoder, resulting in an +invalid PNG datastream as output. In this case the application is +responsible for ensuring that the pixel indexes are in range when it writes +a PLTE chunk with fewer entries than the bit depth would allow. + Now you need to set up the output code. The default for libpng is to use the C function fwrite(). If you use this, you will need to pass a valid FILE * in the function png_init_io(). Be sure that the file is @@ -3023,18 +3259,53 @@ tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"), although this isn't a requirement. Unlike the tIME chunk, the "Creation Time" tEXt chunk is not expected to be automatically changed by the software. To facilitate the use of RFC 1123 dates, a function -png_convert_to_rfc1123(png_timep) is provided to convert from PNG -time to an RFC 1123 format string. +png_convert_to_rfc1123_buffer(buffer, png_timep) is provided to +convert from PNG time to an RFC 1123 format string. The caller must provide +a writeable buffer of at least 29 bytes. Writing unknown chunks -You can use the png_set_unknown_chunks function to queue up chunks -for writing. You give it a chunk name, raw data, and a size; that's -all there is to it. The chunks will be written by the next following -png_write_info_before_PLTE, png_write_info, or png_write_end function. -Any chunks previously read into the info structure's unknown-chunk -list will also be written out in a sequence that satisfies the PNG -specification's ordering rules. +You can use the png_set_unknown_chunks function to queue up private chunks +for writing. You give it a chunk name, location, raw data, and a size. You +also must use png_set_keep_unknown_chunks() to ensure that libpng will +handle them. That's all there is to it. The chunks will be written by the +next following png_write_info_before_PLTE, png_write_info, or png_write_end +function, depending upon the specified location. Any chunks previously +read into the info structure's unknown-chunk list will also be written out +in a sequence that satisfies the PNG specification's ordering rules. + +Here is an example of writing two private chunks, prVt and miNE: + + #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + /* Set unknown chunk data */ + png_unknown_chunk unk_chunk[2]; + strcpy((char *) unk_chunk[0].name, "prVt"; + unk_chunk[0].data = (unsigned char *) "PRIVATE DATA"; + unk_chunk[0].size = strlen(unk_chunk[0].data)+1; + unk_chunk[0].location = PNG_HAVE_IHDR; + strcpy((char *) unk_chunk[1].name, "miNE"; + unk_chunk[1].data = (unsigned char *) "MY CHUNK DATA"; + unk_chunk[1].size = strlen(unk_chunk[0].data)+1; + unk_chunk[1].location = PNG_AFTER_IDAT; + png_set_unknown_chunks(write_ptr, write_info_ptr, + unk_chunk, 2); + /* Needed because miNE is not safe-to-copy */ + png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, + (png_bytep) "miNE", 1); + # if PNG_LIBPNG_VER < 10600 + /* Deal with unknown chunk location bug in 1.5.x and earlier */ + png_set_unknown_chunk_location(png, info, 0, PNG_HAVE_IHDR); + png_set_unknown_chunk_location(png, info, 1, PNG_AFTER_IDAT); + # endif + # if PNG_LIBPNG_VER < 10500 + /* PNG_AFTER_IDAT writes two copies of the chunk prior to libpng-1.5.0, + * one before IDAT and another after IDAT, so don't use it; only use + * PNG_HAVE_IHDR location. This call resets the location previously + * set by assignment and png_set_unknown_chunk_location() for chunk 1. + */ + png_set_unknown_chunk_location(png, info, 1, PNG_HAVE_IHDR); + # endif + #endif The high-level write interface @@ -3386,7 +3657,7 @@ png_destroy_write_struct(). The default behavior is only to free data that was allocated internally by libpng. This can be changed, so that libpng will not free the data, or so that it will free data that was allocated by the user with png_malloc() -or png_zalloc() and passed in via a png_set_*() function, with +or png_calloc() and passed in via a png_set_*() function, with png_data_freer(png_ptr, info_ptr, freer, mask) @@ -3422,7 +3693,7 @@ When the user assumes responsibility for libpng-allocated data, the application must use png_free() to free it, and when the user transfers responsibility to libpng for data that the user has allocated, the user must have used png_malloc() -or png_zalloc() to allocate it. +or png_calloc() to allocate it. If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword separately, do not transfer responsibility for freeing text_ptr to libpng, @@ -3432,7 +3703,374 @@ if you transfer responsibility for free'ing text_ptr from libpng to your application, your application must not separately free those members. For a more compact example of writing a PNG image, see the file example.c. -V. Modifying/Customizing libpng: +V. Simplified API + +The simplified API, which became available in libpng-1.6.0, hides the details +of both libpng and the PNG file format itself. +It allows PNG files to be read into a very limited number of +in-memory bitmap formats or to be written from the same formats. If these +formats do not accommodate your needs then you can, and should, use the more +sophisticated APIs above - these support a wide variety of in-memory formats +and a wide variety of sophisticated transformations to those formats as well +as a wide variety of APIs to manipulate ancilliary information. + +To read a PNG file using the simplified API: + + 1) Declare a 'png_image' structure (see below) on the + stack and memset() it to all zero. + + 2) Call the appropriate png_image_begin_read... function. + + 3) Set the png_image 'format' member to the required + format and allocate a buffer for the image. + + 4) Call png_image_finish_read to read the image into + your buffer. + +There are no restrictions on the format of the PNG input itself; all valid +color types, bit depths, and interlace methods are acceptable, and the +input image is transformed as necessary to the requested in-memory format +during the png_image_finish_read() step. + +To write a PNG file using the simplified API: + + 1) Declare a 'png_image' structure on the stack and memset() + it to all zero. + + 2) Initialize the members of the structure that describe the + image, setting the 'format' member to the format of the + image in memory. + + 3) Call the appropriate png_image_write... function with a + pointer to the image to write the PNG data. + +png_image is a structure that describes the in-memory format of an image +when it is being read or define the in-memory format of an image that you +need to write. The "png_image" structure contains the following members: + + png_uint_32 version Set to PNG_IMAGE_VERSION + png_uint_32 width Image width in pixels (columns) + png_uint_32 height Image height in pixels (rows) + png_uint_32 format Image format as defined below + png_uint_32 flags A bit mask containing informational flags + png_controlp opaque Initialize to NULL, free with png_image_free + png_uint_32 colormap_entries; Number of entries in the color-map + png_uint_32 warning_or_error; + char message[64]; + +In the event of an error or warning the following field warning_or_error +field will be set to a non-zero value and the 'message' field will contain +a '\0' terminated string with the libpng error or warning message. If both +warnings and an error were encountered, only the error is recorded. If there +are multiple warnings, only the first one is recorded. + +The upper 30 bits of this value are reserved; the low two bits contain +a two bit code such that a value more than 1 indicates a failure in the API +just called: + + 0 - no warning or error + 1 - warning + 2 - error + 3 - error preceded by warning + +The pixels (samples) of the image have one to four channels whose components +have original values in the range 0 to 1.0: + + 1: A single gray or luminance channel (G). + 2: A gray/luminance channel and an alpha channel (GA). + 3: Three red, green, blue color channels (RGB). + 4: Three color channels and an alpha channel (RGBA). + +The channels are encoded in one of two ways: + + a) As a small integer, value 0..255, contained in a single byte. For the +alpha channel the original value is simply value/255. For the color or +luminance channels the value is encoded according to the sRGB specification +and matches the 8-bit format expected by typical display devices. + +The color/gray channels are not scaled (pre-multiplied) by the alpha +channel and are suitable for passing to color management software. + + b) As a value in the range 0..65535, contained in a 2-byte integer, in +the native byte order of the platform on which the application is running. +All channels can be converted to the original value by dividing by 65535; all +channels are linear. Color channels use the RGB encoding (RGB end-points) of +the sRGB specification. This encoding is identified by the +PNG_FORMAT_FLAG_LINEAR flag below. + +When an alpha channel is present it is expected to denote pixel coverage +of the color or luminance channels and is returned as an associated alpha +channel: the color/gray channels are scaled (pre-multiplied) by the alpha +value. + +When a color-mapped image is used as a result of calling +png_image_read_colormap or png_image_write_colormap the channels are encoded +in the color-map and the descriptions above apply to the color-map entries. +The image data is encoded as small integers, value 0..255, that index the +entries in the color-map. One integer (one byte) is stored for each pixel. + +PNG_FORMAT_* + +The #defines to be used in png_image::format. Each #define identifies a +particular layout of channel data and, if present, alpha values. There are +separate defines for each of the two channel encodings. + +A format is built up using single bit flag values. Not all combinations are +valid: use the bit flag values below for testing a format returned by the +read APIs, but set formats from the derived values. + +When reading or writing color-mapped images the format should be set to the +format of the entries in the color-map then png_image_{read,write}_colormap +called to read or write the color-map and set the format correctly for the +image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + +NOTE: libpng can be built with particular features disabled, if you see +compiler errors because the definition of one of the following flags has been +compiled out it is because libpng does not have the required support. It is +possible, however, for the libpng configuration to enable the format on just +read or just write; in that case you may see an error at run time. You can +guard against this by checking for the definition of: + + PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + + PNG_FORMAT_FLAG_ALPHA 0x01 format with an alpha channel + PNG_FORMAT_FLAG_COLOR 0x02 color format: otherwise grayscale + PNG_FORMAT_FLAG_LINEAR 0x04 png_uint_16 channels else png_byte + PNG_FORMAT_FLAG_COLORMAP 0x08 libpng use only + PNG_FORMAT_FLAG_BGR 0x10 BGR colors, else order is RGB + PNG_FORMAT_FLAG_AFIRST 0x20 alpha channel comes first + +Supported formats are as follows. Future versions of libpng may support more +formats; for compatibility with older versions simply check if the format +macro is defined using #ifdef. These defines describe the in-memory layout +of the components of the pixels of the image. + +First the single byte formats: + + PNG_FORMAT_GRAY 0 + PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA + PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) + PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR + PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) + PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) + PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) + PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) + PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) + +Then the linear 2-byte formats. When naming these "Y" is used to +indicate a luminance (gray) channel. The component order within the pixel +is always the same - there is no provision for swapping the order of the +components in the linear format. The components are 16-bit integers in +the native byte order for your platform, and there is no provision for +swapping the bytes to a different endian condition. + + PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR + PNG_FORMAT_LINEAR_Y_ALPHA + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) + PNG_FORMAT_LINEAR_RGB + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) + PNG_FORMAT_LINEAR_RGB_ALPHA + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR| + PNG_FORMAT_FLAG_ALPHA) + +Color-mapped formats are obtained by calling png_image_{read,write}_colormap, +as appropriate after setting png_image::format to the format of the color-map +to be read or written. Applications may check the value of +PNG_FORMAT_FLAG_COLORMAP to see if they have called the colormap API. The +format of the color-map may be extracted using the following macro. + + PNG_FORMAT_OF_COLORMAP(fmt) ((fmt) & ~PNG_FORMAT_FLAG_COLORMAP) + +PNG_IMAGE macros + +These are convenience macros to derive information from a png_image +structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the +actual image sample values - either the entries in the color-map or the +pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values +for the pixels and will always return 1 after a call to +png_image_{read,write}_colormap. The remaining macros return information +about the rows in the image and the complete image. + +NOTE: All the macros that take a png_image::format parameter are compile time +constants if the format parameter is, itself, a constant. Therefore these +macros can be used in array declarations and case labels where required. +Similarly the macros are also pre-processor constants (sizeof is not used) so +they can be used in #if tests. + +First the information about the samples. + + PNG_IMAGE_SAMPLE_CHANNELS(fmt) + Returns the total number of channels in a given format: 1..4 + + PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt) + Returns the size in bytes of a single component of a pixel or color-map + entry (as appropriate) in the image. + + PNG_IMAGE_SAMPLE_SIZE(fmt) + This is the size of the sample data for one sample. If the image is + color-mapped it is the size of one color-map entry (and image pixels are + one byte in size), otherwise it is the size of one image pixel. + + PNG_IMAGE_COLORMAP_SIZE(fmt) + The size of the color-map required by the format; this is the size of the + color-map buffer passed to the png_image_{read,write}_colormap APIs, it is + a fixed number determined by the format so can easily be allocated on the + stack if necessary. + +#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) + /* The maximum size of the color-map required by the format expressed in a + * count of components. This can be used to compile-time allocate a + * color-map: + * + * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + * + * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + * + * Alternatively, use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + * information from one of the png_image_begin_read_ APIs and dynamically + * allocate the required memory. + */ + + +Corresponding information about the pixels + + PNG_IMAGE_PIXEL_(test,fmt) + + PNG_IMAGE_PIXEL_CHANNELS(fmt) + The number of separate channels (components) in a pixel; 1 for a + color-mapped image. + + PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + The size, in bytes, of each component in a pixel; 1 for a color-mapped + image. + + PNG_IMAGE_PIXEL_SIZE(fmt) + The size, in bytes, of a complete pixel; 1 for a color-mapped image. + +Information about the whole row, or whole image + + PNG_IMAGE_ROW_STRIDE(image) + Returns the total number of components in a single row of the image; this + is the minimum 'row stride', the minimum count of components between each + row. For a color-mapped image this is the minimum number of bytes in a + row. + + If you need the stride measured in bytes, row_stride_bytes is + PNG_IMAGE_ROW_STRIDE(image) * PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt) + plus any padding bytes that your application might need, for example + to start the next row on a 4-byte boundary. + + PNG_IMAGE_BUFFER_SIZE(image, row_stride) + Returns the size, in bytes, of an image buffer given a png_image and a row + stride - the number of components to leave space for in each row. This + macro takes care of multiplying row_stride by PNG_IMAGE_PIXEL_COMONENT_SIZE + when the image has 2-byte components. + + PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB == 0x01 + This indicates the the RGB values of the in-memory bitmap do not + correspond to the red, green and blue end-points defined by sRGB. + + PNG_IMAGE_FLAG_COLORMAP == 0x02 + The PNG is color-mapped. If this flag is set png_image_read_colormap + can be used without further loss of image information. If it is not set + png_image_read_colormap will cause significant loss if the image has any + +READ APIs + + The png_image passed to the read APIs must have been initialized by setting + the png_controlp field 'opaque' to NULL (or, better, memset the whole thing.) + + int png_image_begin_read_from_file( png_imagep image, + const char *file_name) + + The named file is opened for read and the image header + is filled in from the PNG header in the file. + + int png_image_begin_read_from_stdio (png_imagep image, + FILE* file) + + The PNG header is read from the stdio FILE object. + + int png_image_begin_read_from_memory(png_imagep image, + png_const_voidp memory, png_size_t size) + + The PNG header is read from the given memory buffer. + + int png_image_finish_read(png_imagep image, + png_colorp background, void *buffer, + png_int_32 row_stride, void *colormap)); + + Finish reading the image into the supplied buffer and + clean up the png_image structure. + + row_stride is the step, in png_byte or png_uint_16 units + as appropriate, between adjacent rows. A positive stride + indicates that the top-most row is first in the buffer - + the normal top-down arrangement. A negative stride + indicates that the bottom-most row is first in the buffer. + + background need only be supplied if an alpha channel must + be removed from a png_byte format and the removal is to be + done by compositing on a solid color; otherwise it may be + NULL and any composition will be done directly onto the + buffer. The value is an sRGB color to use for the + background, for grayscale output the green channel is used. + + For linear output removing the alpha channel is always done + by compositing on black. + + void png_image_free(png_imagep image) + + Free any data allocated by libpng in image->opaque, + setting the pointer to NULL. May be called at any time + after the structure is initialized. + +When the simplified API needs to convert between sRGB and linear colorspaces, +the actual sRGB transfer curve defined in the sRGB specification (see the +article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 +approximation used elsewhere in libpng. + +WRITE APIS + +For write you must initialize a png_image structure to describe the image to +be written: + + version: must be set to PNG_IMAGE_VERSION + opaque: must be initialized to NULL + width: image width in pixels + height: image height in rows + format: the format of the data you wish to write + flags: set to 0 unless one of the defined flags applies; set + PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images + where the RGB values do not correspond to the colors in sRGB. + colormap_entries: set to the number of entries in the color-map (0 to 256) + + int png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + + Write the image to the named file. + + int png_image_write_to_stdio(png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, + png_int_32 row_stride, const void *colormap) + + Write the image to the given (FILE*). + +With all write APIs if image is in one of the linear formats with +(png_uint_16) data then setting convert_to_8_bit will cause the output to be +a (png_byte) PNG gamma encoded according to the sRGB specification, otherwise +a 16-bit linear encoded PNG file is written. + +With all APIs row_stride is handled as in the read APIs - it is the spacing +from one row to the next in component sized units (float) and if negative +indicates a bottom-up row layout in the buffer. + +Note that the write API does not support interlacing, sub-8-bit pixels, +and indexed (paletted) images. + +VI. Modifying/Customizing libpng There are two issues here. The first is changing how libpng does standard things like memory allocation, input/output, and error handling. @@ -3450,19 +4088,17 @@ in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change these functions, call the appropriate png_set_*_fn() function. Memory allocation is done through the functions png_malloc(), png_calloc(), -and png_free(). These currently just call the standard C functions. -png_calloc() calls png_malloc() and then clears the newly -allocated memory to zero. There is limited support for certain systems -with segmented memory architectures and the types of pointers declared by -png.h match this; you will have to use appropriate pointers in your -application. Since it is -unlikely that the method of handling memory allocation on a platform -will change between applications, these functions must be modified in -the library at compile time. If you prefer to use a different method -of allocating and freeing data, you can use png_create_read_struct_2() or -png_create_write_struct_2() to register your own functions as described -above. These functions also provide a void pointer that can be retrieved -via +and png_free(). The png_malloc() and png_free() functions currently just +call the standard C functions and png_calloc() calls png_malloc() and then +clears the newly allocated memory to zero; note that png_calloc(png_ptr, size) +is not the same as the calloc(number, size) function provided by stdlib.h. +There is limited support for certain systems with segmented memory +architectures and the types of pointers declared by png.h match this; you +will have to use appropriate pointers in your application. If you prefer +to use a different method of allocating and freeing data, you can use +png_create_read_struct_2() or png_create_write_struct_2() to register your +own functions as described above. These functions also provide a void +pointer that can be retrieved via mem_ptr=png_get_mem_ptr(png_ptr); @@ -3565,6 +4201,18 @@ compiler documentation for more details. For an alternative approach, you may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net), which is illustrated in pngvalid.c and in contrib/visupng. +Beginning in libpng-1.4.0, the png_set_benign_errors() API became available. +You can use this to handle certain errors (normally handled as errors) +as warnings. + + png_set_benign_errors (png_ptr, int allowed); + + allowed: 0: treat png_benign_error() as an error. + 1: treat png_benign_error() as a warning. + +As of libpng-1.6.0, the default condition is to treat benign errors as +warnings while reading and as errors while writing. + Custom chunks If you need to read or write custom chunks, you may need to get deeper @@ -3593,29 +4241,6 @@ the simpler ones to get an idea of how they work. Try to find a similar transformation to the one you want to add and copy off of it. More details can be found in the comments inside the code itself. -Configuring for 16-bit platforms - -You will want to look into zconf.h to tell zlib (and thus libpng) that -it cannot allocate more then 64K at a time. Even if you can, the memory -won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K. - -Configuring for DOS - -For DOS users who only have access to the lower 640K, you will -have to limit zlib's memory usage via a png_set_compression_mem_level() -call. See zlib.h or zconf.h in the zlib library for more information. - -Configuring for Medium Model - -Libpng's support for medium model has been tested on most of the popular -compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets -defined, and FAR gets defined to far in pngconf.h, and you should be -all set. Everything in the library (except for zlib's structure) is -expecting far data. You must use the typedefs with the p or pp on -the end for pointers (or at least look at them and be careful). Make -note that the rows of data are defined as png_bytepp, which is -an "unsigned char far * far *". - Configuring for gui/windowing platforms: You will need to write new error and warning functions that use the GUI @@ -3625,18 +4250,6 @@ in order to have them available during the structure initialization. They can be changed later via png_set_error_fn(). On some compilers, you may also have to change the memory allocators (png_malloc, etc.). -Configuring for compiler xxx: - -All includes for libpng are in pngconf.h. If you need to add, change -or delete an include, this is the place to do it. -The includes that are not needed outside libpng are placed in pngpriv.h, -which is only used by the routines inside libpng itself. -The files in libpng proper only include pngpriv.h and png.h, which -in turn includes pngconf.h and, as of libpng-1.5.0, pnglibconf.h. -As of libpng-1.5.0, pngpriv.h also includes three other private header -files, pngstruct.h, pnginfo.h, and pngdebug.h, which contain material -that previously appeared in the public headers. - Configuring zlib: There are special functions to configure the compression. Perhaps the @@ -3678,6 +4291,8 @@ zlib.h for more information on what these mean. png_set_compression_method(png_ptr, method); +This controls the size of the IDAT chunks (default 8192): + png_set_compression_buffer_size(png_ptr, size); As of libpng version 1.5.4, additional APIs became @@ -3685,7 +4300,7 @@ available to set these separately for non-IDAT compressed chunks such as zTXt, iTXt, and iCCP: #include zlib.h - #if PNG_LIBPNG_VER <= 10504 + #if PNG_LIBPNG_VER >= 10504 png_set_text_compression_level(png_ptr, level); png_set_text_compression_mem_level(png_ptr, level); @@ -3776,46 +4391,6 @@ Note that the numbers above were invented purely for this example and are given only to help explain the function usage. Little testing has been done to find optimum values for either the costs or the weights. -Removing unwanted object code - -There are a bunch of #define's in pngconf.h that control what parts of -libpng are compiled. All the defines end in _SUPPORTED. If you are -never going to use a capability, you can change the #define to #undef -before recompiling libpng and save yourself code and data space, or -you can turn off individual capabilities with defines that begin with -PNG_NO_. - -In libpng-1.5.0 and later, the #define's are in pnglibconf.h instead. - -You can also turn all of the transforms and ancillary chunk capabilities -off en masse with compiler directives that define -PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS, -or all four, -along with directives to turn on any of the capabilities that you do -want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable the extra -transformations but still leave the library fully capable of reading -and writing PNG files with all known public chunks. Use of the -PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive produces a library -that is incapable of reading or writing ancillary chunks. If you are -not using the progressive reading capability, you can turn that off -with PNG_NO_PROGRESSIVE_READ (don't confuse this with the INTERLACING -capability, which you'll still have). - -All the reading and writing specific code are in separate files, so the -linker should only grab the files it needs. However, if you want to -make sure, or if you are building a stand alone library, all the -reading files start with "pngr" and all the writing files start with "pngw". -The files that don't match either (like png.c, pngtrans.c, etc.) -are used for both reading and writing, and always need to be included. -The progressive reader is in pngpread.c - -If you are creating or distributing a dynamically linked library (a .so -or DLL file), you should not remove or disable any parts of the library, -as this will cause applications linked with different versions of the -library to fail if they call functions not available in your library. -The size of the library itself should not be an issue, because only -those sections that are actually used will be loaded into memory. - Requesting debug printout The macro definition PNG_DEBUG can be used to request debugging @@ -3835,7 +4410,7 @@ the message, "message" is the formatted string to be printed, and p1 and p2 are parameters that are to be embedded in the string according to printf-style formatting directives. For example, - png_debug1(2, "foo=%d\n", foo); + png_debug1(2, "foo=%d", foo); is expanded to @@ -3853,7 +4428,7 @@ When PNG_DEBUG = 1, the macros are defined, but only png_debug statements having level = 0 will be printed. There aren't any such statements in this version of libpng, but if you insert some they will be printed. -VI. MNG support +VII. MNG support The MNG specification (available at http://www.libpng.org/pub/mng) allows certain extensions to PNG for PNG images that are embedded in MNG datastreams. @@ -3880,7 +4455,7 @@ or any other MNG chunks; your application must provide its own support for them. You may wish to consider using libmng (available at http://www.libmng.com) instead. -VII. Changes to Libpng from version 0.88 +VIII. Changes to Libpng from version 0.88 It should be noted that versions of libpng later than 0.96 are not distributed by the original libpng author, Guy Schalnat, nor by @@ -3915,6 +4490,9 @@ png_set_error_fn(), which is essentially the same function, but with a new name to force compilation errors with applications that try to use the old method. +Support for the sCAL, iCCP, iTXt, and sPLT chunks was added at libpng-1.0.6; +however, iTXt support was not enabled by default. + Starting with version 1.0.7, you can find out which version of the library you are using at run-time: @@ -3932,7 +4510,7 @@ application: png_uint_32 application_vn = PNG_LIBPNG_VER; -VIII. Changes to Libpng from version 1.0.x to 1.2.x +IX. Changes to Libpng from version 1.0.x to 1.2.x Support for user memory management was enabled by default. To accomplish this, the functions png_create_read_struct_2(), @@ -4029,7 +4607,7 @@ which also expands tRNS to alpha was replaced with png_set_expand_gray_1_2_4_to_8() which does not. It has been deprecated since libpng-1.0.18 and 1.2.9. -IX. Changes to Libpng from version 1.0.x/1.2.x to 1.4.x +X. Changes to Libpng from version 1.0.x/1.2.x to 1.4.x Private libpng prototypes and macro definitions were moved from png.h and pngconf.h into a new pngpriv.h header file. @@ -4122,14 +4700,16 @@ png_set_strip_error_numbers() was removed from the library by default. The png_zalloc() and png_zfree() functions are no longer exported. The png_zalloc() function no longer zeroes out the memory that it -allocates. +allocates. Applications that called png_zalloc(png_ptr, number, size) +can call png_calloc(png_ptr, number*size) instead, and can call +png_free() instead of png_zfree(). Support for dithering was disabled by default in libpng-1.4.0, because it has not been well tested and doesn't actually "dither". The code was not removed, however, and could be enabled by building libpng with PNG_READ_DITHER_SUPPORTED defined. In libpng-1.4.2, this support -was reenabled, but the function was renamed png_set_quantize() to +was re-enabled, but the function was renamed png_set_quantize() to reflect more accurately what it actually does. At the same time, the PNG_DITHER_[RED,GREEN_BLUE]_BITS macros were also renamed to PNG_QUANTIZE_[RED,GREEN,BLUE]_BITS, and PNG_READ_DITHER_SUPPORTED @@ -4137,37 +4717,61 @@ was renamed to PNG_READ_QUANTIZE_SUPPORTED. We removed the trailing '.' from the warning and error messages. -X. Changes to Libpng from version 1.4.x to 1.5.x +XI. Changes to Libpng from version 1.4.x to 1.5.x From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the function) incorrectly returned a value of type png_uint_32. +The incorrect macro was removed from libpng-1.4.5. -Checking for invalid palette index on read or write was added at libpng -1.5.10. When an invalid index is found, libpng issues a benign error. -This is enabled by default but can be disabled in each png_ptr with +Checking for invalid palette index on write was added at libpng +1.5.10. If a pixel contains an invalid (out-of-range) index libpng issues +a benign error. This is enabled by default because this condition is an +error according to the PNG specification, Clause 11.3.2, but the error can +be ignored in each png_ptr with png_set_check_for_invalid_index(png_ptr, allowed); allowed - one of - 0: disable - 1: enable + 0: disable benign error (accept the + invalid data without warning). + 1: enable benign error (treat the + invalid data as an error or a + warning). + +If the error is ignored, or if png_benign_error() treats it as a warning, +any invalid pixels are decoded as opaque black by the decoder and written +as-is by the encoder. + +Retrieving the maximum palette index found was added at libpng-1.5.15. +This statement must appear after png_read_png() or png_read_image() while +reading, and after png_write_png() or png_write_image() while writing. + + int max_palette = png_get_palette_max(png_ptr, info_ptr); -A. Changes that affect users of libpng +This will return the maximum palette index found in the image, or "-1" if +the palette was not checked, or "0" if no palette was found. Note that this +does not account for any palette index used by ancillary chunks such as the +bKGD chunk; you must check those separately to determine the maximum +palette index actually used. There are no substantial API changes between the non-deprecated parts of -the 1.4.5 API and the 1.5.0 API, however the ability to directly access -the main libpng control structures, png_struct and png_info, deprecated -in earlier versions of libpng, has been completely removed from +the 1.4.5 API and the 1.5.0 API; however, the ability to directly access +members of the main libpng control structures, png_struct and png_info, +deprecated in earlier versions of libpng, has been completely removed from libpng 1.5. -We no longer include zlib.h in png.h. Applications that need access -to information in zlib.h will need to add the '#include "zlib.h"' -directive. It does not matter whether it is placed prior to or after +We no longer include zlib.h in png.h. The include statement has been moved +to pngstruct.h, where it is not accessible by applications. Applications that +need access to information in zlib.h will need to add the '#include "zlib.h"' +directive. It does not matter whether this is placed prior to or after the '"#include png.h"' directive. -We moved the png_strcpy(), png_strncpy(), png_strlen(), png_memcpy(), -png_memcmp(), png_sprintf, and png_memcpy() macros into a private -header file (pngpriv.h) that is not accessible to applications. +The png_sprintf(), png_strcpy(), and png_strncpy() macros are no longer used +and were removed. + +We moved the png_strlen(), png_memcpy(), png_memset(), and png_memcmp() +macros into a private header file (pngpriv.h) that is not accessible to +applications. In png_get_iCCP, the type of "profile" was changed from png_charpp to png_bytepp, and in png_set_iCCP, from png_charp to png_const_bytep. @@ -4220,7 +4824,10 @@ and the accuracy of PNG fixed point values is insufficient for representation of these values. Consequently a "string" API (png_get_sCAL_s and png_set_sCAL_s) is the only reliable way of reading arbitrary sCAL chunks in the absence of either the floating point API or -internal floating point calculations. +internal floating point calculations. Starting with libpng-1.5.0, both +of these functions are present when PNG_sCAL_SUPPORTED is defined. Prior +to libpng-1.5.0, their presence also depended upon PNG_FIXED_POINT_SUPPORTED +being defined and PNG_FLOATING_POINT_SUPPORTED not being defined. Applications no longer need to include the optional distribution header file pngusr.h or define the corresponding macros during application @@ -4240,15 +4847,10 @@ reset by pngusr.h or by explicit settings on the compiler command line. These settings may produce compiler warnings or errors in 1.5.0 because of macro redefinition. -From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the -function) incorrectly returned a value of type png_uint_32. libpng 1.5.0 -is consistent with the implementation in 1.4.5 and 1.2.x (where the macro -did not exist.) - Applications can now choose whether to use these macros or to call the corresponding function by defining PNG_USE_READ_MACROS or PNG_NO_USE_READ_MACROS before including png.h. Notice that this is -only supported from 1.5.0 -defining PNG_NO_USE_READ_MACROS prior to 1.5.0 +only supported from 1.5.0; defining PNG_NO_USE_READ_MACROS prior to 1.5.0 will lead to a link failure. Prior to libpng-1.5.4, the zlib compressor used the same set of parameters @@ -4262,7 +4864,10 @@ option was off by default, and slightly inaccurate scaling occurred. This option can no longer be turned off, and the choice of accurate or inaccurate 16-to-8 scaling is by using the new png_set_scale_16_to_8() API for accurate scaling or the old png_set_strip_16_to_8() API for simple -chopping. +chopping. In libpng-1.5.4, the PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +macro became PNG_READ_SCALE_16_TO_8_SUPPORTED, and the PNG_READ_16_TO_8 +macro became PNG_READ_STRIP_16_TO_8_SUPPORTED, to enable the two +png_set_*_16_to_8() functions separately. Prior to libpng-1.5.4, the png_set_user_limits() function could only be used to reduce the width and height limits from the value of @@ -4284,25 +4889,8 @@ limits are now png_user_chunk_cache_max 0 (unlimited) 128 png_user_chunk_malloc_max 0 (unlimited) 8,000,000 -B. Changes to the build and configuration of libpng - -Details of internal changes to the library code can be found in the CHANGES -file and in the GIT repository logs. These will be of no concern to the vast -majority of library users or builders, however the few who configure libpng -to a non-default feature set may need to change how this is done. - -There should be no need for library builders to alter build scripts if -these use the distributed build support - configure or the makefiles - -however users of the makefiles may care to update their build scripts -to build pnglibconf.h where the corresponding makefile does not do so. - -Building libpng with a non-default configuration has changed completely. -The old method using pngusr.h should still work correctly even though the -way pngusr.h is used in the build has been changed; however, library -builders will probably want to examine the changes to take advantage of -new capabilities and to simplify their build system. - -B.1 Specific changes to library configuration capabilities +The png_set_option() function (and the "options" member of the png struct) was +added to libpng-1.5.15. The library now supports a complete fixed point implementation and can thus be used on systems that have no floating point support or very @@ -4314,27 +4902,7 @@ independent of the choice of fixed versus floating point APIs and all the missing fixed point APIs have been implemented. The exact mechanism used to control attributes of API functions has -changed. A single set of operating system independent macro definitions -is used and operating system specific directives are defined in -pnglibconf.h - -As part of this the mechanism used to choose procedure call standards on -those systems that allow a choice has been changed. At present this only -affects certain Microsoft (DOS, Windows) and IBM (OS/2) operating systems -running on Intel processors. As before, PNGAPI is defined where required -to control the exported API functions; however, two new macros, PNGCBAPI -and PNGCAPI, are used instead for callback functions (PNGCBAPI) and -(PNGCAPI) for functions that must match a C library prototype (currently -only png_longjmp_ptr, which must match the C longjmp function.) The new -approach is documented in pngconf.h - -Despite these changes, libpng 1.5.0 only supports the native C function -calling standard on those platforms tested so far (__cdecl on Microsoft -Windows). This is because the support requirements for alternative -calling conventions seem to no longer exist. Developers who find it -necessary to set PNG_API_RULE to 1 should advise the mailing list -(png-mng-implement) of this and library builders who use Openwatcom and -therefore set PNG_API_RULE to 2 should also contact the mailing list. +changed, as described in the INSTALL file. A new test program, pngvalid, is provided in addition to pngtest. pngvalid validates the arithmetic accuracy of the gamma correction @@ -4399,7 +4967,7 @@ merely stops the function from being exported. PNG_FLOATING_ARITHMETIC_SUPPORTED chooses between the internal floating point implementation or the fixed point one. Typically the fixed point implementation is larger and slower than the floating point implementation -on a system that supports floating point, however it may be faster on a +on a system that supports floating point; however, it may be faster on a system which lacks floating point hardware and therefore uses a software emulation. @@ -4410,47 +4978,138 @@ even though the default is to use the macros - this allows applications to choose at app buildtime whether or not to use macros (previously impossible because the functions weren't in the default build.) -B.2 Changes to the configuration mechanism - -Prior to libpng-1.5.0 library builders who needed to configure libpng -had either to modify the exported pngconf.h header file to add system -specific configuration or had to write feature selection macros into -pngusr.h and cause this to be included into pngconf.h by defining -PNG_USER_CONFIG. The latter mechanism had the disadvantage that an -application built without PNG_USER_CONFIG defined would see the -unmodified, default, libpng API and thus would probably fail to link. - -These mechanisms still work in the configure build and in any makefile -build that builds pnglibconf.h, although the feature selection macros -have changed somewhat as described above. In 1.5.0, however, pngusr.h is -processed only once, when the exported header file pnglibconf.h is built. -pngconf.h no longer includes pngusr.h, therefore pngusr.h is ignored after the -build of pnglibconf.h and it is never included in an application build. - -The rarely used alternative of adding a list of feature macros to the -CFLAGS setting in the build also still works, however the macros will be -copied to pnglibconf.h and this may produce macro redefinition warnings -when the individual C files are compiled. - -All configuration now only works if pnglibconf.h is built from -scripts/pnglibconf.dfa. This requires the program awk. Brian Kernighan -(the original author of awk) maintains C source code of that awk and this -and all known later implementations (often called by subtly different -names - nawk and gawk for example) are adequate to build pnglibconf.h. -The Sun Microsystems (now Oracle) program 'awk' is an earlier version -and does not work; this may also apply to other systems that have a -functioning awk called 'nawk'. - -Configuration options are now documented in scripts/pnglibconf.dfa. This -file also includes dependency information that ensures a configuration is -consistent; that is, if a feature is switched off dependent features are -also removed. As a recommended alternative to using feature macros in -pngusr.h a system builder may also define equivalent options in pngusr.dfa -(or, indeed, any file) and add that to the configuration by setting -DFA_XTRA to the file name. The makefiles in contrib/pngminim illustrate -how to do this, and a case where pngusr.h is still required. - -XI. Detecting libpng +XII. Changes to Libpng from version 1.5.x to 1.6.x + +A "simplified API" has been added (see documentation in png.h and a simple +example in contrib/examples/pngtopng.c). The new publicly visible API +includes the following: + + macros: + PNG_FORMAT_* + PNG_IMAGE_* + structures: + png_control + png_image + read functions + png_image_begin_read_from_file() + png_image_begin_read_from_stdio() + png_image_begin_read_from_memory() + png_image_finish_read() + png_image_free() + write functions + png_image_write_to_file() + png_image_write_to_stdio() + +Starting with libpng-1.6.0, you can configure libpng to prefix all exported +symbols, using the PNG_PREFIX macro. + +We no longer include string.h in png.h. The include statement has been moved +to pngpriv.h, where it is not accessible by applications. Applications that +need access to information in string.h must add an '#include ' +directive. It does not matter whether this is placed prior to or after +the '#include "png.h"' directive. + +The following API are now DEPRECATED: + png_info_init_3() + png_convert_to_rfc1123() which has been replaced + with png_convert_to_rfc1123_buffer() + png_malloc_default() + png_free_default() + png_reset_zstream() + +The following have been removed: + png_get_io_chunk_name(), which has been replaced + with png_get_io_chunk_type(). The new + function returns a 32-bit integer instead of + a string. + The png_sizeof(), png_strlen(), png_memcpy(), png_memcmp(), and + png_memset() macros are no longer used in the libpng sources and + have been removed. These had already been made invisible to applications + (i.e., defined in the private pngpriv.h header file) since libpng-1.5.0. + +The signatures of many exported functions were changed, such that + png_structp became png_structrp or png_const_structrp + png_infop became png_inforp or png_const_inforp +where "rp" indicates a "restricted pointer". + +The support for FAR/far types has been eliminated and the definition of +png_alloc_size_t is now controlled by a flag so that 'small size_t' systems +can select it if necessary. + +Error detection in some chunks has improved; in particular the iCCP chunk +reader now does pretty complete validation of the basic format. Some bad +profiles that were previously accepted are now accepted with a warning or +rejected, depending upon the png_set_benign_errors() setting, in particular +the very old broken Microsoft/HP 3144-byte sRGB profile. Starting with +libpng-1.6.11, recognizing and checking sRGB profiles can be avoided by +means of + + #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && \ + defined(PNG_SET_OPTION_SUPPORTED) + png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE, + PNG_OPTION_ON); + #endif + +It's not a good idea to do this if you are using the "simplified API", +which needs to be able to recognize sRGB profiles conveyed via the iCCP +chunk. + +The PNG spec requirement that only grayscale profiles may appear in images +with color type 0 or 4 and that even if the image only contains gray pixels, +only RGB profiles may appear in images with color type 2, 3, or 6, is now +enforced. The sRGB chunk is allowed to appear in images with any color type +and is interpreted by libpng to convey a one-tracer-curve gray profile or a +three-tracer-curve RGB profile as appropriate. + +Prior to libpng-1.6.0 a warning would be issued if the iTXt chunk contained +an empty language field or an empty translated keyword. Both of these +are allowed by the PNG specification, so these warnings are no longer issued. + +The library now issues an error if the application attempts to set a +transform after it calls png_read_update_info() or if it attempts to call +both png_read_update_info() and png_start_read_image() or to call either +of them more than once. + +The default condition for benign_errors is now to treat benign errors as +warnings while reading and as errors while writing. + +The library now issues a warning if both background processing and RGB to +gray are used when gamma correction happens. As with previous versions of +the library the results are numerically very incorrect in this case. + +There are some minor arithmetic changes in some transforms such as +png_set_background(), that might be detected by certain regression tests. + +Unknown chunk handling has been improved internally, without any API change. +This adds more correct option control of the unknown handling, corrects +a pre-existing bug where the per-chunk 'keep' setting is ignored, and makes +it possible to skip IDAT chunks in the sequential reader. + +The machine-generated configure files are no longer included in branches +libpng16 and later of the GIT repository. They continue to be included +in the tarball releases, however. + +Libpng-1.6.0 through 1.6.2 used the CMF bytes at the beginning of the IDAT +stream to set the size of the sliding window for reading instead of using the +default 32-kbyte sliding window size. It was discovered that there are +hundreds of PNG files in the wild that have incorrect CMF bytes that caused +zlib to issue the "invalid distance too far back" error and reject the file. +Libpng-1.6.3 and later calculate their own safe CMF from the image dimensions, +provide a way to revert to the libpng-1.5.x behavior (ignoring the CMF bytes +and using a 32-kbyte sliding window), by using + + png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, + PNG_OPTION_ON); + +and provide a tool (contrib/tools/pngfix) for rewriting a PNG file while +optimizing the CMF bytes in its IDAT chunk correctly. + +Libpng-1.6.0 and libpng-1.6.1 wrote uncompressed iTXt chunks with the wrong +length, which resulted in PNG files that cannot be read beyond the bad iTXt +chunk. This error was fixed in libpng-1.6.3, and a tool (called +contrib/tools/png-fix-itxt) has been added to the libpng distribution. + +XIII. Detecting libpng The png_get_io_ptr() function has been present since libpng-0.88, has never changed, and is unaffected by conditional compilation macros. It is the @@ -4459,18 +5118,18 @@ libpng version since 0.88. In an autoconf "configure.in" you could use AC_CHECK_LIB(png, png_get_io_ptr, ... -XII. Source code repository +XV. Source code repository Since about February 2009, version 1.2.34, libpng has been under "git" source control. The git repository was built from old libpng-x.y.z.tar.gz files going back to version 0.70. You can access the git repository (read only) at - git://libpng.git.sourceforge.net/gitroot/libpng + git://git.code.sf.net/p/libpng/code -or you can browse it via "gitweb" at +or you can browse it with a web browser by selecting the "code" button at - http://libpng.git.sourceforge.net/git/gitweb.cgi?p=libpng + https://sourceforge.net/projects/libpng Patches can be sent to glennrp at users.sourceforge.net or to png-mng-implement at lists.sourceforge.net or you can upload them to @@ -4483,9 +5142,10 @@ simple verbal discriptions of bug fixes, reported either to the SourceForge bug tracker, to the png-mng-implement at lists.sf.net mailing list, or directly to glennrp. -XIII. Coding style +XV. Coding style -Our coding style is similar to the "Allman" style, with curly +Our coding style is similar to the "Allman" style +(See http://en.wikipedia.org/wiki/Indent_style#Allman_style), with curly braces on separate lines: if (condition) @@ -4548,6 +5208,9 @@ exported functions are marked with PNGAPI: body; } +The return type and decorations are placed on a separate line +ahead of the function name, as illustrated above. + The prototypes for all exported functions appear in png.h, above the comment that says @@ -4562,17 +5225,29 @@ We mark all non-exported functions with "/* PRIVATE */"": } The prototypes for non-exported functions (except for those in -pngtest) appear in -pngpriv.h -above the comment that says +pngtest) appear in pngpriv.h above the comment that says - /* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ + /* Maintainer: Put new private prototypes here ^ */ To avoid polluting the global namespace, the names of all exported functions and variables begin with "png_", and all publicly visible C preprocessor macros begin with "PNG". We request that applications that use libpng *not* begin any of their own symbols with either of these strings. +We put a space after the "sizeof" operator and we omit the +optional parentheses around its argument when the argument +is an expression, not a type name, and we always enclose the +sizeof operator, with its argument, in parentheses: + + (sizeof (png_uint_32)) + (sizeof array) + +Prior to libpng-1.6.0 we used a "png_sizeof()" macro, formatted as +though it were a function. + +Control keywords if, for, while, and switch are always followed by a space +to distinguish them from function calls, which have no trailing space. + We put a space after each comma and after each semicolon in "for" statements, and we put spaces before and after each C binary operator and after "for" or "while", and before @@ -4583,44 +5258,52 @@ left parenthesis that follows it: for (i = 2; i > 0; --i) y[i] = a(x) + (int)b; -We prefer #ifdef and #ifndef to #if defined() and if !defined() -when there is only one macro being tested. +We prefer #ifdef and #ifndef to #if defined() and #if !defined() +when there is only one macro being tested. We always use parentheses +with "defined". We prefer to express integers that are used as bit masks in hex format, with an even number of lower-case hex digits (e.g., 0x00, 0xff, 0x0100). +We prefer to use underscores in variable names rather than camelCase, except +for a few type names that we inherit from zlib.h. + +We prefer "if (something != 0)" and "if (something == 0)" +over "if (something)" and if "(!something)", respectively. + We do not use the TAB character for indentation in the C sources. Lines do not exceed 80 characters. Other rules can be inferred by inspecting the libpng source. -XIV. Y2K Compliance in libpng +XVI. Y2K Compliance in libpng -March 29, 2012 +March 26, 2015 Since the PNG Development group is an ad-hoc body, we can't make an official declaration. This is your unofficial assurance that libpng from version 0.71 and -upward through 1.5.10 are Y2K compliant. It is my belief that earlier +upward through 1.6.17 are Y2K compliant. It is my belief that earlier versions were also Y2K compliant. -Libpng only has three year fields. One is a 2-byte unsigned integer that -will hold years up to 65535. The other two hold the date in text -format, and will hold years up to 9999. +Libpng only has two year fields. One is a 2-byte unsigned integer +that will hold years up to 65535. The other, which is deprecated, +holds the date in text format, and will hold years up to 9999. The integer is "png_uint_16 year" in png_time_struct. -The strings are - "png_charp time_buffer" in png_struct and - "near_time_buffer", which is a local character string in png.c. +The string is + "char time_buffer[29]" in png_struct. This is no longer used +in libpng-1.6.x and will be removed from libpng-1.7.0. There are seven time-related functions: - png_convert_to_rfc_1123() in png.c - (formerly png_convert_to_rfc_1152() in error) + png_convert_to_rfc_1123_buffer() in png.c + (formerly png_convert_to_rfc_1152() in error, and + also formerly png_convert_to_rfc_1123()) png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c png_convert_from_time_t() in pngwrite.c diff --git a/src/3rdparty/libpng/png.c b/src/3rdparty/libpng/png.c index cba18ba915..7575ede97b 100644 --- a/src/3rdparty/libpng/png.c +++ b/src/3rdparty/libpng/png.c @@ -1,8 +1,8 @@ /* png.c - location for general purpose libpng functions * - * Last changed in libpng 1.5.10 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -14,7 +14,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_5_10 Your_png_h_is_not_version_1_5_10; +typedef png_libpng_version_1_6_17 Your_png_h_is_not_version_1_6_17; /* Tells libpng that we have already handled the first "num_bytes" bytes * of the PNG file signature. If the PNG data is embedded into another @@ -24,7 +24,7 @@ typedef png_libpng_version_1_5_10 Your_png_h_is_not_version_1_5_10; #ifdef PNG_READ_SUPPORTED void PNGAPI -png_set_sig_bytes(png_structp png_ptr, int num_bytes) +png_set_sig_bytes(png_structrp png_ptr, int num_bytes) { png_debug(1, "in png_set_sig_bytes"); @@ -34,7 +34,7 @@ png_set_sig_bytes(png_structp png_ptr, int num_bytes) if (num_bytes > 8) png_error(png_ptr, "Too many bytes for PNG signature"); - png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); + png_ptr->sig_bytes = (png_byte)((num_bytes < 0 ? 0 : num_bytes) & 0xff); } /* Checks whether the supplied bytes match the PNG signature. We allow @@ -62,50 +62,44 @@ png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check) if (start + num_to_check > 8) num_to_check = 8 - start; - return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check))); + return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check))); } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) /* Function to allocate memory for zlib */ PNG_FUNCTION(voidpf /* PRIVATE */, png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED) { - png_voidp ptr; - png_structp p=(png_structp)png_ptr; - png_uint_32 save_flags=p->flags; - png_alloc_size_t num_bytes; + png_alloc_size_t num_bytes = size; if (png_ptr == NULL) - return (NULL); + return NULL; - if (items > PNG_UINT_32_MAX/size) + if (items >= (~(png_alloc_size_t)0)/size) { - png_warning (p, "Potential overflow in png_zalloc()"); - return (NULL); + png_warning (png_voidcast(png_structrp, png_ptr), + "Potential overflow in png_zalloc()"); + return NULL; } - num_bytes = (png_alloc_size_t)items * size; - - p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; - ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes); - p->flags=save_flags; - return ((voidpf)ptr); + num_bytes *= items; + return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes); } /* Function to free memory for zlib */ void /* PRIVATE */ png_zfree(voidpf png_ptr, voidpf ptr) { - png_free((png_structp)png_ptr, (png_voidp)ptr); + png_free(png_voidcast(png_const_structrp,png_ptr), ptr); } /* Reset the CRC variable to 32 bits of 1's. Care must be taken * in case CRC is > 32 bits to leave the top bits 0. */ void /* PRIVATE */ -png_reset_crc(png_structp png_ptr) +png_reset_crc(png_structrp png_ptr) { /* The cast is safe because the crc is a 32 bit value. */ png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); @@ -117,11 +111,11 @@ png_reset_crc(png_structp png_ptr) * trouble of calculating it. */ void /* PRIVATE */ -png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length) +png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length) { int need_crc = 1; - if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name)) + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) @@ -130,33 +124,35 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length) else /* critical */ { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) need_crc = 0; } - /* 'uLong' is defined as unsigned long, this means that on some systems it is - * a 64 bit value. crc32, however, returns 32 bits so the following cast is - * safe. 'uInt' may be no more than 16 bits, so it is necessary to perform a - * loop here. + /* 'uLong' is defined in zlib.h as unsigned long; this means that on some + * systems it is a 64 bit value. crc32, however, returns 32 bits so the + * following cast is safe. 'uInt' may be no more than 16 bits, so it is + * necessary to perform a loop here. */ - if (need_crc && length > 0) + if (need_crc != 0 && length > 0) { uLong crc = png_ptr->crc; /* Should never issue a warning */ do { - uInt safeLength = (uInt)length; - if (safeLength == 0) - safeLength = (uInt)-1; /* evil, but safe */ + uInt safe_length = (uInt)length; +#ifndef __COVERITY__ + if (safe_length == 0) + safe_length = (uInt)-1; /* evil, but safe */ +#endif - crc = crc32(crc, ptr, safeLength); + crc = crc32(crc, ptr, safe_length); - /* The following should never issue compiler warnings, if they do the + /* The following should never issue compiler warnings; if they do the * target system has characteristics that will probably violate other * assumptions within the libpng code. */ - ptr += safeLength; - length -= safeLength; + ptr += safe_length; + length -= safe_length; } while (length > 0); @@ -166,97 +162,205 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length) } /* Check a user supplied version number, called from both read and write - * functions that create a png_struct + * functions that create a png_struct. */ int -png_user_version_check(png_structp png_ptr, png_const_charp user_png_ver) +png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) { - if (user_png_ver) + /* Libpng versions 1.0.0 and later are binary compatible if the version + * string matches through the second '.'; we must recompile any + * applications that use any older library version. + */ + + if (user_png_ver != NULL) { - int i = 0; + int i = -1; + int found_dots = 0; do { - if (user_png_ver[i] != png_libpng_ver[i]) + i++; + if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i]) png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); + if (user_png_ver[i] == '.') + found_dots++; + } while (found_dots < 2 && user_png_ver[i] != 0 && + PNG_LIBPNG_VER_STRING[i] != 0); } else png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0) { - /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so - * we must recompile any applications that use any older library version. - * For versions after libpng 1.0, we will be compatible, so we need - * only check the first digit. - */ - if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || - (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || - (user_png_ver[0] == '0' && user_png_ver[2] < '9')) - { #ifdef PNG_WARNINGS_SUPPORTED - size_t pos = 0; - char m[128]; + size_t pos = 0; + char m[128]; - pos = png_safecat(m, sizeof m, pos, "Application built with libpng-"); - pos = png_safecat(m, sizeof m, pos, user_png_ver); - pos = png_safecat(m, sizeof m, pos, " but running with "); - pos = png_safecat(m, sizeof m, pos, png_libpng_ver); + pos = png_safecat(m, (sizeof m), pos, + "Application built with libpng-"); + pos = png_safecat(m, (sizeof m), pos, user_png_ver); + pos = png_safecat(m, (sizeof m), pos, " but running with "); + pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING); + PNG_UNUSED(pos) - png_warning(png_ptr, m); + png_warning(png_ptr, m); #endif #ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; + png_ptr->flags = 0; #endif - return 0; - } + return 0; } /* Success return. */ return 1; } -/* Allocate the memory for an info_struct for the application. We don't - * really need the png_ptr, but it could potentially be useful in the - * future. This should be used in favour of malloc(png_sizeof(png_info)) - * and png_info_init() so that applications that want to use a shared - * libpng don't have to be recompiled if png_info changes size. +/* Generic function to create a png_struct for either read or write - this + * contains the common initialization. */ +PNG_FUNCTION(png_structp /* PRIVATE */, +png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) +{ + png_struct create_struct; +# ifdef PNG_SETJMP_SUPPORTED + jmp_buf create_jmp_buf; +# endif + + /* This temporary stack-allocated structure is used to provide a place to + * build enough context to allow the user provided memory allocator (if any) + * to be called. + */ + memset(&create_struct, 0, (sizeof create_struct)); + + /* Added at libpng-1.2.6 */ +# ifdef PNG_USER_LIMITS_SUPPORTED + create_struct.user_width_max = PNG_USER_WIDTH_MAX; + create_struct.user_height_max = PNG_USER_HEIGHT_MAX; + +# ifdef PNG_USER_CHUNK_CACHE_MAX + /* Added at libpng-1.2.43 and 1.4.0 */ + create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; +# endif + +# ifdef PNG_USER_CHUNK_MALLOC_MAX + /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists + * in png_struct regardless. + */ + create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; +# endif +# endif + + /* The following two API calls simply set fields in png_struct, so it is safe + * to do them now even though error handling is not yet set up. + */ +# ifdef PNG_USER_MEM_SUPPORTED + png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn); +# else + PNG_UNUSED(mem_ptr) + PNG_UNUSED(malloc_fn) + PNG_UNUSED(free_fn) +# endif + + /* (*error_fn) can return control to the caller after the error_ptr is set, + * this will result in a memory leak unless the error_fn does something + * extremely sophisticated. The design lacks merit but is implicit in the + * API. + */ + png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn); + +# ifdef PNG_SETJMP_SUPPORTED + if (!setjmp(create_jmp_buf)) + { + /* Temporarily fake out the longjmp information until we have + * successfully completed this function. This only works if we have + * setjmp() support compiled in, but it is safe - this stuff should + * never happen. + */ + create_struct.jmp_buf_ptr = &create_jmp_buf; + create_struct.jmp_buf_size = 0; /*stack allocation*/ + create_struct.longjmp_fn = longjmp; +# else + { +# endif + /* Call the general version checker (shared with read and write code): + */ + if (png_user_version_check(&create_struct, user_png_ver) != 0) + { + png_structrp png_ptr = png_voidcast(png_structrp, + png_malloc_warn(&create_struct, (sizeof *png_ptr))); + + if (png_ptr != NULL) + { + /* png_ptr->zstream holds a back-pointer to the png_struct, so + * this can only be done now: + */ + create_struct.zstream.zalloc = png_zalloc; + create_struct.zstream.zfree = png_zfree; + create_struct.zstream.opaque = png_ptr; + +# ifdef PNG_SETJMP_SUPPORTED + /* Eliminate the local error handling: */ + create_struct.jmp_buf_ptr = NULL; + create_struct.jmp_buf_size = 0; + create_struct.longjmp_fn = 0; +# endif + + *png_ptr = create_struct; + + /* This is the successful return point */ + return png_ptr; + } + } + } + + /* A longjmp because of a bug in the application storage allocator or a + * simple failure to allocate the png_struct. + */ + return NULL; +} + +/* Allocate the memory for an info_struct for the application. */ PNG_FUNCTION(png_infop,PNGAPI -png_create_info_struct,(png_structp png_ptr),PNG_ALLOCATED) +png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED) { - png_infop info_ptr; + png_inforp info_ptr; png_debug(1, "in png_create_info_struct"); if (png_ptr == NULL) - return (NULL); + return NULL; + + /* Use the internal API that does not (or at least should not) error out, so + * that this call always returns ok. The application typically sets up the + * error handling *after* creating the info_struct because this is the way it + * has always been done in 'example.c'. + */ + info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr, + (sizeof *info_ptr))); -#ifdef PNG_USER_MEM_SUPPORTED - info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO, - png_ptr->malloc_fn, png_ptr->mem_ptr); -#else - info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); -#endif if (info_ptr != NULL) - png_info_init_3(&info_ptr, png_sizeof(png_info)); + memset(info_ptr, 0, (sizeof *info_ptr)); - return (info_ptr); + return info_ptr; } /* This function frees the memory associated with a single info struct. * Normally, one would use either png_destroy_read_struct() or * png_destroy_write_struct() to free an info struct, but this may be - * useful for some applications. + * useful for some applications. From libpng 1.6.0 this function is also used + * internally to implement the png_info release part of the 'struct' destroy + * APIs. This ensures that all possible approaches free the same data (all of + * it). */ void PNGAPI -png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) +png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr) { - png_infop info_ptr = NULL; + png_inforp info_ptr = NULL; png_debug(1, "in png_destroy_info_struct"); @@ -268,46 +372,57 @@ png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr) if (info_ptr != NULL) { - png_info_destroy(png_ptr, info_ptr); - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn, - png_ptr->mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif + /* Do this first in case of an error below; if the app implements its own + * memory management this can lead to png_free calling png_error, which + * will abort this routine and return control to the app error handler. + * An infinite loop may result if it then tries to free the same info + * ptr. + */ *info_ptr_ptr = NULL; + + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + memset(info_ptr, 0, (sizeof *info_ptr)); + png_free(png_ptr, info_ptr); } } /* Initialize the info structure. This is now an internal function (0.89) * and applications using it are urged to use png_create_info_struct() - * instead. + * instead. Use deprecated in 1.6.0, internal use removed (used internally it + * is just a memset). + * + * NOTE: it is almost inconceivable that this API is used because it bypasses + * the user-memory mechanism and the user error handling/warning mechanisms in + * those cases where it does anything other than a memset. */ - -void PNGAPI -png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size) +PNG_FUNCTION(void,PNGAPI +png_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size), + PNG_DEPRECATED) { - png_infop info_ptr = *ptr_ptr; + png_inforp info_ptr = *ptr_ptr; png_debug(1, "in png_info_init_3"); if (info_ptr == NULL) return; - if (png_sizeof(png_info) > png_info_struct_size) + if ((sizeof (png_info)) > png_info_struct_size) { - png_destroy_struct(info_ptr); - info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO); + *ptr_ptr = NULL; + /* The following line is why this API should not be used: */ + free(info_ptr); + info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL, + (sizeof *info_ptr))); *ptr_ptr = info_ptr; } /* Set everything to 0 */ - png_memset(info_ptr, 0, png_sizeof(png_info)); + memset(info_ptr, 0, (sizeof *info_ptr)); } +/* The following API is not called internally */ void PNGAPI -png_data_freer(png_structp png_ptr, png_infop info_ptr, +png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, int freer, png_uint_32 mask) { png_debug(1, "in png_data_freer"); @@ -322,12 +437,11 @@ png_data_freer(png_structp png_ptr, png_infop info_ptr, info_ptr->free_me &= ~mask; else - png_warning(png_ptr, - "Unknown freer parameter in png_data_freer"); + png_error(png_ptr, "Unknown freer parameter in png_data_freer"); } void PNGAPI -png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, +png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, int num) { png_debug(1, "in png_free_data"); @@ -337,42 +451,43 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #ifdef PNG_TEXT_SUPPORTED /* Free text item num or (if num == -1) all text items */ - if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) + if (info_ptr->text != 0 && + ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0) { if (num != -1) { - if (info_ptr->text && info_ptr->text[num].key) - { - png_free(png_ptr, info_ptr->text[num].key); - info_ptr->text[num].key = NULL; - } + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; } else { int i; + for (i = 0; i < info_ptr->num_text; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); + png_free(png_ptr, info_ptr->text[i].key); + png_free(png_ptr, info_ptr->text); info_ptr->text = NULL; - info_ptr->num_text=0; + info_ptr->num_text = 0; } } #endif #ifdef PNG_tRNS_SUPPORTED /* Free any tRNS entry */ - if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) + if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0) { + info_ptr->valid &= ~PNG_INFO_tRNS; png_free(png_ptr, info_ptr->trans_alpha); info_ptr->trans_alpha = NULL; - info_ptr->valid &= ~PNG_INFO_tRNS; + info_ptr->num_trans = 0; } #endif #ifdef PNG_sCAL_SUPPORTED /* Free any sCAL entry */ - if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) + if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->scal_s_width); png_free(png_ptr, info_ptr->scal_s_height); @@ -384,20 +499,20 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #ifdef PNG_pCAL_SUPPORTED /* Free any pCAL entry */ - if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) + if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->pcal_purpose); png_free(png_ptr, info_ptr->pcal_units); info_ptr->pcal_purpose = NULL; info_ptr->pcal_units = NULL; + if (info_ptr->pcal_params != NULL) { int i; - for (i = 0; i < (int)info_ptr->pcal_nparams; i++) - { + + for (i = 0; i < info_ptr->pcal_nparams; i++) png_free(png_ptr, info_ptr->pcal_params[i]); - info_ptr->pcal_params[i] = NULL; - } + png_free(png_ptr, info_ptr->pcal_params); info_ptr->pcal_params = NULL; } @@ -406,8 +521,8 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #endif #ifdef PNG_iCCP_SUPPORTED - /* Free any iCCP entry */ - if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) + /* Free any profile entry */ + if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->iccp_name); png_free(png_ptr, info_ptr->iccp_profile); @@ -419,74 +534,62 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #ifdef PNG_sPLT_SUPPORTED /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ - if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) + if (info_ptr->splt_palettes != 0 && + ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0) { if (num != -1) { - if (info_ptr->splt_palettes) - { - png_free(png_ptr, info_ptr->splt_palettes[num].name); - png_free(png_ptr, info_ptr->splt_palettes[num].entries); - info_ptr->splt_palettes[num].name = NULL; - info_ptr->splt_palettes[num].entries = NULL; - } + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; } else { - if (info_ptr->splt_palettes_num) - { - int i; - for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i); + int i; - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = NULL; - info_ptr->splt_palettes_num = 0; + for (i = 0; i < info_ptr->splt_palettes_num; i++) + { + png_free(png_ptr, info_ptr->splt_palettes[i].name); + png_free(png_ptr, info_ptr->splt_palettes[i].entries); } + + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; info_ptr->valid &= ~PNG_INFO_sPLT; } } #endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - if (png_ptr->unknown_chunk.data) - { - png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - - if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + if (info_ptr->unknown_chunks != 0 && + ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0) { if (num != -1) { - if (info_ptr->unknown_chunks) - { - png_free(png_ptr, info_ptr->unknown_chunks[num].data); - info_ptr->unknown_chunks[num].data = NULL; - } + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; } else { int i; - if (info_ptr->unknown_chunks_num) - { - for (i = 0; i < info_ptr->unknown_chunks_num; i++) - png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i); + for (i = 0; i < info_ptr->unknown_chunks_num; i++) + png_free(png_ptr, info_ptr->unknown_chunks[i].data); - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - info_ptr->unknown_chunks_num = 0; - } + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; } } #endif #ifdef PNG_hIST_SUPPORTED /* Free any hIST entry */ - if ((mask & PNG_FREE_HIST) & info_ptr->free_me) + if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->hist); info_ptr->hist = NULL; @@ -495,9 +598,9 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #endif /* Free any PLTE entry that was internally allocated */ - if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) + if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0) { - png_zfree(png_ptr, info_ptr->palette); + png_free(png_ptr, info_ptr->palette); info_ptr->palette = NULL; info_ptr->valid &= ~PNG_INFO_PLTE; info_ptr->num_palette = 0; @@ -505,16 +608,14 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, #ifdef PNG_INFO_IMAGE_SUPPORTED /* Free any image bits attached to the info structure */ - if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) + if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0) { - if (info_ptr->row_pointers) + if (info_ptr->row_pointers != 0) { - int row; - for (row = 0; row < (int)info_ptr->height; row++) - { + png_uint_32 row; + for (row = 0; row < info_ptr->height; row++) png_free(png_ptr, info_ptr->row_pointers[row]); - info_ptr->row_pointers[row] = NULL; - } + png_free(png_ptr, info_ptr->row_pointers); info_ptr->row_pointers = NULL; } @@ -527,37 +628,14 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, info_ptr->free_me &= ~mask; } - -/* This is an internal routine to free any memory that the info struct is - * pointing to before re-using it or freeing the struct itself. Recall - * that png_free() checks for NULL pointers for us. - */ -void /* PRIVATE */ -png_info_destroy(png_structp png_ptr, png_infop info_ptr) -{ - png_debug(1, "in png_info_destroy"); - - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_ptr->num_chunk_list) - { - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list = NULL; - png_ptr->num_chunk_list = 0; - } -#endif - - png_info_init_3(&info_ptr, png_sizeof(png_info)); -} -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ +#endif /* READ || WRITE */ /* This function returns a pointer to the io_ptr associated with the user * functions. The application should free any memory associated with this * pointer before png_write_destroy() or png_read_destroy() are called. */ png_voidp PNGAPI -png_get_io_ptr(png_structp png_ptr) +png_get_io_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); @@ -574,7 +652,7 @@ png_get_io_ptr(png_structp png_ptr) * function of your own because "FILE *" isn't necessarily available. */ void PNGAPI -png_init_io(png_structp png_ptr, png_FILE_p fp) +png_init_io(png_structrp png_ptr, png_FILE_p fp) { png_debug(1, "in png_init_io"); @@ -585,42 +663,52 @@ png_init_io(png_structp png_ptr, png_FILE_p fp) } # endif +# ifdef PNG_SAVE_INT_32_SUPPORTED +/* The png_save_int_32 function assumes integers are stored in two's + * complement format. If this isn't the case, then this routine needs to + * be modified to write data in two's complement format. Note that, + * the following works correctly even if png_int_32 has more than 32 bits + * (compare the more complex code required on read for sign extension.) + */ +void PNGAPI +png_save_int_32(png_bytep buf, png_int_32 i) +{ + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); +} +# endif + # ifdef PNG_TIME_RFC1123_SUPPORTED /* Convert the supplied time into an RFC 1123 string suitable for use in * a "Creation Time" or other text-based time string. */ -png_const_charp PNGAPI -png_convert_to_rfc1123(png_structp png_ptr, png_const_timep ptime) +int PNGAPI +png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) { static PNG_CONST char short_months[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - if (png_ptr == NULL) - return (NULL); + if (out == NULL) + return 0; if (ptime->year > 9999 /* RFC1123 limitation */ || ptime->month == 0 || ptime->month > 12 || ptime->day == 0 || ptime->day > 31 || ptime->hour > 23 || ptime->minute > 59 || ptime->second > 60) - { - png_warning(png_ptr, "Ignoring invalid time value"); - return (NULL); - } + return 0; { size_t pos = 0; char number_buf[5]; /* enough for a four-digit year */ -# define APPEND_STRING(string)\ - pos = png_safecat(png_ptr->time_buffer, sizeof png_ptr->time_buffer,\ - pos, (string)) +# define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string)) # define APPEND_NUMBER(format, value)\ APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value))) -# define APPEND(ch)\ - if (pos < (sizeof png_ptr->time_buffer)-1)\ - png_ptr->time_buffer[pos++] = (ch) +# define APPEND(ch) if (pos < 28) out[pos++] = (ch) APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day); APPEND(' '); @@ -640,14 +728,37 @@ png_convert_to_rfc1123(png_structp png_ptr, png_const_timep ptime) # undef APPEND_STRING } - return png_ptr->time_buffer; + return 1; +} + +# if PNG_LIBPNG_VER < 10700 +/* To do: remove the following from libpng-1.7 */ +/* Original API that uses a private buffer in png_struct. + * Deprecated because it causes png_struct to carry a spurious temporary + * buffer (png_struct::time_buffer), better to have the caller pass this in. + */ +png_const_charp PNGAPI +png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) +{ + if (png_ptr != NULL) + { + /* The only failure above if png_ptr != NULL is from an invalid ptime */ + if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0) + png_warning(png_ptr, "Ignoring invalid time value"); + + else + return png_ptr->time_buffer; + } + + return NULL; } -# endif /* PNG_TIME_RFC1123_SUPPORTED */ +# endif /* LIBPNG_VER < 10700 */ +# endif /* TIME_RFC1123 */ -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ +#endif /* READ || WRITE */ png_const_charp PNGAPI -png_get_copyright(png_const_structp png_ptr) +png_get_copyright(png_const_structrp png_ptr) { PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ #ifdef PNG_STRING_COPYRIGHT @@ -655,14 +766,14 @@ png_get_copyright(png_const_structp png_ptr) #else # ifdef __STDC__ return PNG_STRING_NEWLINE \ - "libpng version 1.5.10 - March 29, 2012" PNG_STRING_NEWLINE \ - "Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ + "libpng version 1.6.17 - March 26, 2015" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2015 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ PNG_STRING_NEWLINE; # else - return "libpng version 1.5.10 - March 29, 2012\ - Copyright (c) 1998-2011 Glenn Randers-Pehrson\ + return "libpng version 1.6.17 - March 26, 2015\ + Copyright (c) 1998-2015 Glenn Randers-Pehrson\ Copyright (c) 1996-1997 Andreas Dilger\ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; # endif @@ -678,14 +789,14 @@ png_get_copyright(png_const_structp png_ptr) * it is guaranteed that png.c uses the correct version of png.h. */ png_const_charp PNGAPI -png_get_libpng_ver(png_const_structp png_ptr) +png_get_libpng_ver(png_const_structrp png_ptr) { /* Version of *.c files used when building libpng */ return png_get_header_ver(png_ptr); } png_const_charp PNGAPI -png_get_header_ver(png_const_structp png_ptr) +png_get_header_ver(png_const_structrp png_ptr) { /* Version of *.h files used when building libpng */ PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ @@ -693,7 +804,7 @@ png_get_header_ver(png_const_structp png_ptr) } png_const_charp PNGAPI -png_get_header_version(png_const_structp png_ptr) +png_get_header_version(png_const_structrp png_ptr) { /* Returns longer string containing both version and date */ PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ @@ -708,55 +819,122 @@ png_get_header_version(png_const_structp png_ptr) #endif } -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +/* NOTE: this routine is not used internally! */ +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. This API is not used internally. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette"); + + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + + case 2: + num_palette = 4; + color_inc = 0x55; + break; + + case 4: + num_palette = 16; + color_inc = 0x11; + break; + + case 8: + num_palette = 256; + color_inc = 1; + break; + + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)(v & 0xff); + palette[i].green = (png_byte)(v & 0xff); + palette[i].blue = (png_byte)(v & 0xff); + } +} +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED int PNGAPI -png_handle_as_unknown(png_structp png_ptr, png_const_bytep chunk_name) +png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) { /* Check chunk_name and return "keep" value if it's on the list, else 0 */ png_const_bytep p, p_end; - if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list <= 0) + if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0) return PNG_HANDLE_CHUNK_AS_DEFAULT; p_end = png_ptr->chunk_list; p = p_end + png_ptr->num_chunk_list*5; /* beyond end */ /* The code is the fifth byte after each four byte string. Historically this - * code was always searched from the end of the list, so it should continue - * to do so in case there are duplicated entries. + * code was always searched from the end of the list, this is no longer + * necessary because the 'set' routine handles duplicate entries correcty. */ do /* num_chunk_list > 0, so at least one */ { p -= 5; - if (!png_memcmp(chunk_name, p, 4)) + + if (memcmp(chunk_name, p, 4) == 0) return p[4]; } while (p > p_end); + /* This means that known chunks should be processed and unknown chunks should + * be handled according to the value of png_ptr->unknown_default; this can be + * confusing because, as a result, there are two levels of defaulting for + * unknown chunks. + */ return PNG_HANDLE_CHUNK_AS_DEFAULT; } +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) int /* PRIVATE */ -png_chunk_unknown_handling(png_structp png_ptr, png_uint_32 chunk_name) +png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) { png_byte chunk_string[5]; PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name); return png_handle_as_unknown(png_ptr, chunk_string); } -#endif +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ +#endif /* SET_UNKNOWN_CHUNKS */ #ifdef PNG_READ_SUPPORTED /* This function, added to libpng-1.0.6g, is untested. */ int PNGAPI -png_reset_zstream(png_structp png_ptr) +png_reset_zstream(png_structrp png_ptr) { if (png_ptr == NULL) return Z_STREAM_ERROR; + /* WARNING: this resets the window bits to the maximum! */ return (inflateReset(&png_ptr->zstream)); } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ /* This function was added to libpng-1.0.7 */ png_uint_32 PNGAPI @@ -766,126 +944,291 @@ png_access_version_number(void) return((png_uint_32)PNG_LIBPNG_VER); } +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) +/* Ensure that png_ptr->zstream.msg holds some appropriate error message string. + * If it doesn't 'ret' is used to set it to something appropriate, even in cases + * like Z_OK or Z_STREAM_END where the error code is apparently a success code. + */ +void /* PRIVATE */ +png_zstream_error(png_structrp png_ptr, int ret) +{ + /* Translate 'ret' into an appropriate error string, priority is given to the + * one in zstream if set. This always returns a string, even in cases like + * Z_OK or Z_STREAM_END where the error code is a success code. + */ + if (png_ptr->zstream.msg == NULL) switch (ret) + { + default: + case Z_OK: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); + break; + + case Z_STREAM_END: + /* Normal exit */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); + break; + + case Z_NEED_DICT: + /* This means the deflate stream did not have a dictionary; this + * indicates a bogus PNG. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); + break; + case Z_ERRNO: + /* gz APIs only: should not happen */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error"); + break; + + case Z_STREAM_ERROR: + /* internal libpng error */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib"); + break; + + case Z_DATA_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); + break; + + case Z_MEM_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); + break; + + case Z_BUF_ERROR: + /* End of input or output; not a problem if the caller is doing + * incremental read or write. + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); + break; + + case Z_VERSION_ERROR: + png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); + break; + + case PNG_UNEXPECTED_ZLIB_RETURN: + /* Compile errors here mean that zlib now uses the value co-opted in + * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above + * and change pngpriv.h. Note that this message is "... return", + * whereas the default/Z_OK one is "... return code". + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return"); + break; + } +} -#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) /* png_convert_size: a PNGAPI but no longer in png.h, so deleted * at libpng 1.5.5! */ /* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ -# ifdef PNG_CHECK_cHRM_SUPPORTED - -int /* PRIVATE */ -png_check_cHRM_fixed(png_structp png_ptr, - png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, - png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, - png_fixed_point blue_x, png_fixed_point blue_y) +#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */ +static int +png_colorspace_check_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA, int from) + /* This is called to check a new gamma value against an existing one. The + * routine returns false if the new gamma value should not be written. + * + * 'from' says where the new gamma value comes from: + * + * 0: the new gamma value is the libpng estimate for an ICC profile + * 1: the new gamma value comes from a gAMA chunk + * 2: the new gamma value comes from an sRGB chunk + */ { - int ret = 1; - unsigned long xy_hi,xy_lo,yx_hi,yx_lo; + png_fixed_point gtest; + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + (png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0 || + png_gamma_significant(gtest) != 0)) + { + /* Either this is an sRGB image, in which case the calculated gamma + * approximation should match, or this is an image with a profile and the + * value libpng calculates for the gamma of the profile does not match the + * value recorded in the file. The former, sRGB, case is an error, the + * latter is just a warning. + */ + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2) + { + png_chunk_report(png_ptr, "gamma value does not match sRGB", + PNG_CHUNK_ERROR); + /* Do not overwrite an sRGB value */ + return from == 2; + } - png_debug(1, "in function png_check_cHRM_fixed"); + else /* sRGB tag not involved */ + { + png_chunk_report(png_ptr, "gamma value does not match libpng estimate", + PNG_CHUNK_WARNING); + return from == 1; + } + } - if (png_ptr == NULL) - return 0; + return 1; +} - /* (x,y,z) values are first limited to 0..100000 (PNG_FP_1), the white - * y must also be greater than 0. To test for the upper limit calculate - * (PNG_FP_1-y) - x must be <= to this for z to be >= 0 (and the expression - * cannot overflow.) At this point we know x and y are >= 0 and (x+y) is - * <= PNG_FP_1. The previous test on PNG_MAX_UINT_31 is removed because it - * pointless (and it produces compiler warnings!) +void /* PRIVATE */ +png_colorspace_set_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA) +{ + /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't + * occur. Since the fixed point representation is asymetrical it is + * possible for 1/gamma to overflow the limit of 21474 and this means the + * gamma value must be at least 5/100000 and hence at most 20000.0. For + * safety the limits here are a little narrower. The values are 0.00016 to + * 6250.0, which are truly ridiculous gamma values (and will produce + * displays that are all black or all white.) + * + * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk + * handling code, which only required the value to be >0. */ - if (white_x < 0 || white_y <= 0 || - red_x < 0 || red_y < 0 || - green_x < 0 || green_y < 0 || - blue_x < 0 || blue_y < 0) - { - png_warning(png_ptr, - "Ignoring attempt to set negative chromaticity value"); - ret = 0; - } - /* And (x+y) must be <= PNG_FP_1 (so z is >= 0) */ - if (white_x > PNG_FP_1 - white_y) - { - png_warning(png_ptr, "Invalid cHRM white point"); - ret = 0; - } + png_const_charp errmsg; - if (red_x > PNG_FP_1 - red_y) + if (gAMA < 16 || gAMA > 625000000) + errmsg = "gamma value out of range"; + +# ifdef PNG_READ_gAMA_SUPPORTED + /* Allow the application to set the gamma value more than once */ + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0) + errmsg = "duplicate"; +# endif + + /* Do nothing if the colorspace is already invalid */ + else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return; + + else { - png_warning(png_ptr, "Invalid cHRM red point"); - ret = 0; + if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, + 1/*from gAMA*/) != 0) + { + /* Store this gamma value. */ + colorspace->gamma = gAMA; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA); + } + + /* At present if the check_gamma test fails the gamma of the colorspace is + * not updated however the colorspace is not invalidated. This + * corresponds to the case where the existing gamma comes from an sRGB + * chunk or profile. An error message has already been output. + */ + return; } - if (green_x > PNG_FP_1 - green_y) + /* Error exit - errmsg has been set. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR); +} + +void /* PRIVATE */ +png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) { - png_warning(png_ptr, "Invalid cHRM green point"); - ret = 0; + /* Everything is invalid */ + info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB| + PNG_INFO_iCCP); + +# ifdef PNG_COLORSPACE_SUPPORTED + /* Clean up the iCCP profile now if it won't be used. */ + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/); +# else + PNG_UNUSED(png_ptr) +# endif } - if (blue_x > PNG_FP_1 - blue_y) + else { - png_warning(png_ptr, "Invalid cHRM blue point"); - ret = 0; - } +# ifdef PNG_COLORSPACE_SUPPORTED + /* Leave the INFO_iCCP flag set if the pngset.c code has already set + * it; this allows a PNG to contain a profile which matches sRGB and + * yet still have that profile retrievable by the application. + */ + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0) + info_ptr->valid |= PNG_INFO_sRGB; + + else + info_ptr->valid &= ~PNG_INFO_sRGB; - png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo); - png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo); + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + info_ptr->valid |= PNG_INFO_cHRM; - if (xy_hi == yx_hi && xy_lo == yx_lo) - { - png_warning(png_ptr, - "Ignoring attempt to set cHRM RGB triangle with zero area"); - ret = 0; + else + info_ptr->valid &= ~PNG_INFO_cHRM; +# endif + + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0) + info_ptr->valid |= PNG_INFO_gAMA; + + else + info_ptr->valid &= ~PNG_INFO_gAMA; } +} + +#ifdef PNG_READ_SUPPORTED +void /* PRIVATE */ +png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if (info_ptr == NULL) /* reduce code size; check here not in the caller */ + return; - return ret; + info_ptr->colorspace = png_ptr->colorspace; + png_colorspace_sync_info(png_ptr, info_ptr); } -# endif /* PNG_CHECK_cHRM_SUPPORTED */ +#endif +#endif /* GAMMA */ -#ifdef PNG_cHRM_SUPPORTED +#ifdef PNG_COLORSPACE_SUPPORTED /* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for * cHRM, as opposed to using chromaticities. These internal APIs return * non-zero on a parameter error. The X, Y and Z values are required to be * positive and less than 1.0. */ -int png_xy_from_XYZ(png_xy *xy, png_XYZ XYZ) +static int +png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) { png_int_32 d, dwhite, whiteX, whiteY; - d = XYZ.redX + XYZ.redY + XYZ.redZ; - if (!png_muldiv(&xy->redx, XYZ.redX, PNG_FP_1, d)) return 1; - if (!png_muldiv(&xy->redy, XYZ.redY, PNG_FP_1, d)) return 1; + d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z; + if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0) + return 1; dwhite = d; - whiteX = XYZ.redX; - whiteY = XYZ.redY; + whiteX = XYZ->red_X; + whiteY = XYZ->red_Y; - d = XYZ.greenX + XYZ.greenY + XYZ.greenZ; - if (!png_muldiv(&xy->greenx, XYZ.greenX, PNG_FP_1, d)) return 1; - if (!png_muldiv(&xy->greeny, XYZ.greenY, PNG_FP_1, d)) return 1; + d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z; + if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0) + return 1; dwhite += d; - whiteX += XYZ.greenX; - whiteY += XYZ.greenY; + whiteX += XYZ->green_X; + whiteY += XYZ->green_Y; - d = XYZ.blueX + XYZ.blueY + XYZ.blueZ; - if (!png_muldiv(&xy->bluex, XYZ.blueX, PNG_FP_1, d)) return 1; - if (!png_muldiv(&xy->bluey, XYZ.blueY, PNG_FP_1, d)) return 1; + d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z; + if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0) + return 1; + if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0) + return 1; dwhite += d; - whiteX += XYZ.blueX; - whiteY += XYZ.blueY; + whiteX += XYZ->blue_X; + whiteY += XYZ->blue_Y; - /* The reference white is simply the same of the end-point (X,Y,Z) vectors, + /* The reference white is simply the sum of the end-point (X,Y,Z) vectors, * thus: */ - if (!png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite)) return 1; - if (!png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite)) return 1; + if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0) + return 1; + if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0) + return 1; return 0; } -int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy) +static int +png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) { png_fixed_point red_inverse, green_inverse, blue_scale; png_fixed_point left, right, denominator; @@ -894,14 +1237,14 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy) * have end points with 0 tristimulus values (these are impossible end * points, but they are used to cover the possible colors.) */ - if (xy.redx < 0 || xy.redx > PNG_FP_1) return 1; - if (xy.redy < 0 || xy.redy > PNG_FP_1-xy.redx) return 1; - if (xy.greenx < 0 || xy.greenx > PNG_FP_1) return 1; - if (xy.greeny < 0 || xy.greeny > PNG_FP_1-xy.greenx) return 1; - if (xy.bluex < 0 || xy.bluex > PNG_FP_1) return 1; - if (xy.bluey < 0 || xy.bluey > PNG_FP_1-xy.bluex) return 1; - if (xy.whitex < 0 || xy.whitex > PNG_FP_1) return 1; - if (xy.whitey < 0 || xy.whitey > PNG_FP_1-xy.whitex) return 1; + if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1; + if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1; + if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1; + if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1; + if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1; + if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1; + if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1; + if (xy->whitey < 0 || xy->whitey > PNG_FP_1-xy->whitex) return 1; /* The reverse calculation is more difficult because the original tristimulus * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 @@ -969,14 +1312,14 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy) * and it is certain that it becomes unstable where the end points are close * together. * - * So this code uses the perhaps slighly less optimal but more understandable - * and totally obvious approach of calculating color-scale. + * So this code uses the perhaps slightly less optimal but more + * understandable and totally obvious approach of calculating color-scale. * * This algorithm depends on the precision in white-scale and that is * (1/white-y), so we can immediately see that as white-y approaches 0 the * accuracy inherent in the cHRM chunk drops off substantially. * - * libpng arithmetic: a simple invertion of the above equations + * libpng arithmetic: a simple inversion of the above equations * ------------------------------------------------------------ * * white_scale = 1/white-y @@ -1082,91 +1425,1050 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy) /* By the argument, above overflow should be impossible here. The return * value of 2 indicates an internal error to the caller. */ - if (!png_muldiv(&left, xy.greenx-xy.bluex, xy.redy - xy.bluey, 7)) return 2; - if (!png_muldiv(&right, xy.greeny-xy.bluey, xy.redx - xy.bluex, 7)) return 2; + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0) + return 2; denominator = left - right; /* Now find the red numerator. */ - if (!png_muldiv(&left, xy.greenx-xy.bluex, xy.whitey-xy.bluey, 7)) return 2; - if (!png_muldiv(&right, xy.greeny-xy.bluey, xy.whitex-xy.bluex, 7)) return 2; + if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0) + return 2; + + /* Overflow is possible here and it indicates an extreme set of PNG cHRM + * chunk values. This calculation actually returns the reciprocal of the + * scale value because this allows us to delay the multiplication of white-y + * into the denominator, which tends to produce a small number. + */ + if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 || + red_inverse <= xy->whitey /* r+g+b scales = white scale */) + return 1; + + /* Similarly for green_inverse: */ + if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0) + return 2; + if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) + return 2; + if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 || + green_inverse <= xy->whitey) + return 1; + + /* And the blue scale, the checks above guarantee this can't overflow but it + * can still produce 0 for extreme cHRM values. + */ + blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) - + png_reciprocal(green_inverse); + if (blue_scale <= 0) + return 1; + + + /* And fill in the png_XYZ: */ + if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, + red_inverse) == 0) + return 1; + + if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0) + return 1; + if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, + green_inverse) == 0) + return 1; + + if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, + PNG_FP_1) == 0) + return 1; + + return 0; /*success*/ +} + +static int +png_XYZ_normalize(png_XYZ *XYZ) +{ + png_int_32 Y; + + if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 || + XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 || + XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0) + return 1; + + /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. + * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore + * relying on addition of two positive values producing a negative one is not + * safe. + */ + Y = XYZ->red_Y; + if (0x7fffffff - Y < XYZ->green_X) + return 1; + Y += XYZ->green_Y; + if (0x7fffffff - Y < XYZ->blue_X) + return 1; + Y += XYZ->blue_Y; + + if (Y != PNG_FP_1) + { + if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0) + return 1; + + if (png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0) + return 1; + + if (png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0) + return 1; + if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0) + return 1; + } + + return 0; +} + +static int +png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta) +{ + /* Allow an error of +/-0.01 (absolute value) on each chromaticity */ + if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) || + PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) || + PNG_OUT_OF_RANGE(xy1->redx, xy2->redx, delta) || + PNG_OUT_OF_RANGE(xy1->redy, xy2->redy, delta) || + PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) || + PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) || + PNG_OUT_OF_RANGE(xy1->bluex, xy2->bluex, delta) || + PNG_OUT_OF_RANGE(xy1->bluey, xy2->bluey, delta)) + return 0; + return 1; +} + +/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM + * chunk chromaticities. Earlier checks used to simply look for the overflow + * condition (where the determinant of the matrix to solve for XYZ ends up zero + * because the chromaticity values are not all distinct.) Despite this it is + * theoretically possible to produce chromaticities that are apparently valid + * but that rapidly degrade to invalid, potentially crashing, sets because of + * arithmetic inaccuracies when calculations are performed on them. The new + * check is to round-trip xy -> XYZ -> xy and then check that the result is + * within a small percentage of the original. + */ +static int +png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy) +{ + int result; + png_xy xy_test; + + /* As a side-effect this routine also returns the XYZ endpoints. */ + result = png_XYZ_from_xy(XYZ, xy); + if (result != 0) + return result; + + result = png_xy_from_XYZ(&xy_test, XYZ); + if (result != 0) + return result; + + if (png_colorspace_endpoints_match(xy, &xy_test, + 5/*actually, the math is pretty accurate*/) != 0) + return 0; + + /* Too much slip */ + return 1; +} + +/* This is the check going the other way. The XYZ is modified to normalize it + * (another side-effect) and the xy chromaticities are returned. + */ +static int +png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ) +{ + int result; + png_XYZ XYZtemp; + + result = png_XYZ_normalize(XYZ); + if (result != 0) + return result; + + result = png_xy_from_XYZ(xy, XYZ); + if (result != 0) + return result; + + XYZtemp = *XYZ; + return png_colorspace_check_xy(&XYZtemp, xy); +} + +/* Used to check for an endpoint match against sRGB */ +static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ +{ + /* color x y */ + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000, + /* white */ 31270, 32900 +}; + +static int +png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ, + int preferred) +{ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return 0; + + /* The consistency check is performed on the chromaticities; this factors out + * variations because of the normalization (or not) of the end point Y + * values. + */ + if (preferred < 2 && + (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + /* The end points must be reasonably close to any we already have. The + * following allows an error of up to +/-.001 + */ + if (png_colorspace_endpoints_match(xy, &colorspace->end_points_xy, + 100) == 0) + { + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "inconsistent chromaticities"); + return 0; /* failed */ + } + + /* Only overwrite with preferred values */ + if (preferred == 0) + return 1; /* ok, but no change */ + } + + colorspace->end_points_xy = *xy; + colorspace->end_points_XYZ = *XYZ; + colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS; + + /* The end points are normally quoted to two decimal digits, so allow +/-0.01 + * on this test. + */ + if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000) != 0) + colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB; + + else + colorspace->flags &= PNG_COLORSPACE_CANCEL( + PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + return 2; /* ok and changed */ +} + +int /* PRIVATE */ +png_colorspace_set_chromaticities(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, int preferred) +{ + /* We must check the end points to ensure they are reasonable - in the past + * color management systems have crashed as a result of getting bogus + * colorant values, while this isn't the fault of libpng it is the + * responsibility of libpng because PNG carries the bomb and libpng is in a + * position to protect against it. + */ + png_XYZ XYZ; + + switch (png_colorspace_check_xy(&XYZ, xy)) + { + case 0: /* success */ + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ, + preferred); + + case 1: + /* We can't invert the chromaticities so we can't produce value XYZ + * values. Likely as not a color management system will fail too. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid chromaticities"); + break; + + default: + /* libpng is broken; this should be a warning but if it happens we + * want error reports so for the moment it is an error. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + break; + } + + return 0; /* failed */ +} + +int /* PRIVATE */ +png_colorspace_set_endpoints(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred) +{ + png_XYZ XYZ = *XYZ_in; + png_xy xy; + + switch (png_colorspace_check_XYZ(&xy, &XYZ)) + { + case 0: + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ, + preferred); + + case 1: + /* End points are invalid. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid end points"); + break; + + default: + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + break; + } + + return 0; /* failed */ +} + +#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED) +/* Error message generation */ +static char +png_icc_tag_char(png_uint_32 byte) +{ + byte &= 0xff; + if (byte >= 32 && byte <= 126) + return (char)byte; + else + return '?'; +} + +static void +png_icc_tag_name(char *name, png_uint_32 tag) +{ + name[0] = '\''; + name[1] = png_icc_tag_char(tag >> 24); + name[2] = png_icc_tag_char(tag >> 16); + name[3] = png_icc_tag_char(tag >> 8); + name[4] = png_icc_tag_char(tag ); + name[5] = '\''; +} + +static int +is_ICC_signature_char(png_alloc_size_t it) +{ + return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) || + (it >= 97 && it <= 122); +} + +static int +is_ICC_signature(png_alloc_size_t it) +{ + return is_ICC_signature_char(it >> 24) /* checks all the top bits */ && + is_ICC_signature_char((it >> 16) & 0xff) && + is_ICC_signature_char((it >> 8) & 0xff) && + is_ICC_signature_char(it & 0xff); +} + +static int +png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_alloc_size_t value, png_const_charp reason) +{ + size_t pos; + char message[196]; /* see below for calculation */ + + if (colorspace != NULL) + colorspace->flags |= PNG_COLORSPACE_INVALID; + + pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */ + pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */ + pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */ + if (is_ICC_signature(value) != 0) + { + /* So 'value' is at most 4 bytes and the following cast is safe */ + png_icc_tag_name(message+pos, (png_uint_32)value); + pos += 6; /* total +8; less than the else clause */ + message[pos++] = ':'; + message[pos++] = ' '; + } +# ifdef PNG_WARNINGS_SUPPORTED + else + { + char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/ + + pos = png_safecat(message, (sizeof message), pos, + png_format_number(number, number+(sizeof number), + PNG_NUMBER_FORMAT_x, value)); + pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/ + } +# endif + /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ + pos = png_safecat(message, (sizeof message), pos, reason); + PNG_UNUSED(pos) + + /* This is recoverable, but make it unconditionally an app_error on write to + * avoid writing invalid ICC profiles into PNG files (i.e., we handle them + * on read, with a warning, but on write unless the app turns off + * application errors the PNG won't be written.) + */ + png_chunk_report(png_ptr, message, + (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR); + + return 0; +} +#endif /* sRGB || iCCP */ + +#ifdef PNG_sRGB_SUPPORTED +int /* PRIVATE */ +png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, + int intent) +{ + /* sRGB sets known gamma, end points and (from the chunk) intent. */ + /* IMPORTANT: these are not necessarily the values found in an ICC profile + * because ICC profiles store values adapted to a D50 environment; it is + * expected that the ICC profile mediaWhitePointTag will be D50; see the + * checks and code elsewhere to understand this better. + * + * These XYZ values, which are accurate to 5dp, produce rgb to gray + * coefficients of (6968,23435,2366), which are reduced (because they add up + * to 32769 not 32768) to (6968,23434,2366). These are the values that + * libpng has traditionally used (and are the best values given the 15bit + * algorithm used by the rgb to gray code.) + */ + static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */ + { + /* color X Y Z */ + /* red */ 41239, 21264, 1933, + /* green */ 35758, 71517, 11919, + /* blue */ 18048, 7219, 95053 + }; + + /* Do nothing if the colorspace is already invalidated. */ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return 0; + + /* Check the intent, then check for existing settings. It is valid for the + * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must + * be consistent with the correct values. If, however, this function is + * called below because an iCCP chunk matches sRGB then it is quite + * conceivable that an older app recorded incorrect gAMA and cHRM because of + * an incorrect calculation based on the values in the profile - this does + * *not* invalidate the profile (though it still produces an error, which can + * be ignored.) + */ + if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "invalid sRGB rendering intent"); + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 && + colorspace->rendering_intent != intent) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "inconsistent rendering intents"); + + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0) + { + png_benign_error(png_ptr, "duplicate sRGB information ignored"); + return 0; + } + + /* If the standard sRGB cHRM chunk does not match the one from the PNG file + * warn but overwrite the value with the correct one. + */ + if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 && + !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy, + 100)) + png_chunk_report(png_ptr, "cHRM chunk does not match sRGB", + PNG_CHUNK_ERROR); + + /* This check is just done for the error reporting - the routine always + * returns true when the 'from' argument corresponds to sRGB (2). + */ + (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE, + 2/*from sRGB*/); + + /* intent: bugs in GCC force 'int' to be used as the parameter type. */ + colorspace->rendering_intent = (png_uint_16)intent; + colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT; + + /* endpoints */ + colorspace->end_points_xy = sRGB_xy; + colorspace->end_points_XYZ = sRGB_XYZ; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + /* gamma */ + colorspace->gamma = PNG_GAMMA_sRGB_INVERSE; + colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Finally record that we have an sRGB profile */ + colorspace->flags |= + (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB); + + return 1; /* set */ +} +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +/* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value + * is XYZ(0.9642,1.0,0.8249), which scales to: + * + * (63189.8112, 65536, 54060.6464) + */ +static const png_byte D50_nCIEXYZ[12] = + { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d }; + +int /* PRIVATE */ +png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length) +{ + if (profile_length < 132) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "too short"); + + return 1; +} + +int /* PRIVATE */ +png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile/* first 132 bytes only */, int color_type) +{ + png_uint_32 temp; + + /* Length check; this cannot be ignored in this code because profile_length + * is used later to check the tag table, so even if the profile seems over + * long profile_length from the caller must be correct. The caller can fix + * this up on read or write by just passing in the profile header length. + */ + temp = png_get_uint_32(profile); + if (temp != profile_length) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "length does not match profile"); + + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_length & 3)) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "invalid length"); + + temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */ + if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */ + profile_length < 132+12*temp) /* truncated tag table */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "tag count too large"); + + /* The 'intent' must be valid or we can't store it, ICC limits the intent to + * 16 bits. + */ + temp = png_get_uint_32(profile+64); + if (temp >= 0xffff) /* The ICC limit */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid rendering intent"); + + /* This is just a warning because the profile may be valid in future + * versions. + */ + if (temp >= PNG_sRGB_INTENT_LAST) + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "intent outside defined range"); + + /* At this point the tag table can't be checked because it hasn't necessarily + * been loaded; however, various header fields can be checked. These checks + * are for values permitted by the PNG spec in an ICC profile; the PNG spec + * restricts the profiles that can be passed in an iCCP chunk (they must be + * appropriate to processing PNG data!) + */ + + /* Data checks (could be skipped). These checks must be independent of the + * version number; however, the version number doesn't accomodate changes in + * the header fields (just the known tags and the interpretation of the + * data.) + */ + temp = png_get_uint_32(profile+36); /* signature 'ascp' */ + if (temp != 0x61637370) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid signature"); + + /* Currently the PCS illuminant/adopted white point (the computational + * white point) are required to be D50, + * however the profile contains a record of the illuminant so perhaps ICC + * expects to be able to change this in the future (despite the rationale in + * the introduction for using a fixed PCS adopted white.) Consequently the + * following is just a warning. + */ + if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0) + (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/, + "PCS illuminant is not D50"); + + /* The PNG spec requires this: + * "If the iCCP chunk is present, the image samples conform to the colour + * space represented by the embedded ICC profile as defined by the + * International Color Consortium [ICC]. The colour space of the ICC profile + * shall be an RGB colour space for colour images (PNG colour types 2, 3, and + * 6), or a greyscale colour space for greyscale images (PNG colour types 0 + * and 4)." + * + * This checking code ensures the embedded profile (on either read or write) + * conforms to the specification requirements. Notice that an ICC 'gray' + * color-space profile contains the information to transform the monochrome + * data to XYZ or L*a*b (according to which PCS the profile uses) and this + * should be used in preference to the standard libpng K channel replication + * into R, G and B channels. + * + * Previously it was suggested that an RGB profile on grayscale data could be + * handled. However it it is clear that using an RGB profile in this context + * must be an error - there is no specification of what it means. Thus it is + * almost certainly more correct to ignore the profile. + */ + temp = png_get_uint_32(profile+16); /* data colour space field */ + switch (temp) + { + case 0x52474220: /* 'RGB ' */ + if ((color_type & PNG_COLOR_MASK_COLOR) == 0) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "RGB color space not permitted on grayscale PNG"); + break; + + case 0x47524159: /* 'GRAY' */ + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "Gray color space not permitted on RGB PNG"); + break; + + default: + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid ICC profile color space"); + } + + /* It is up to the application to check that the profile class matches the + * application requirements; the spec provides no guidance, but it's pretty + * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer + * ('prtr') or 'spac' (for generic color spaces). Issue a warning in these + * cases. Issue an error for device link or abstract profiles - these don't + * contain the records necessary to transform the color-space to anything + * other than the target device (and not even that for an abstract profile). + * Profiles of these classes may not be embedded in images. + */ + temp = png_get_uint_32(profile+12); /* profile/device class */ + switch (temp) + { + case 0x73636E72: /* 'scnr' */ + case 0x6D6E7472: /* 'mntr' */ + case 0x70727472: /* 'prtr' */ + case 0x73706163: /* 'spac' */ + /* All supported */ + break; + + case 0x61627374: /* 'abst' */ + /* May not be embedded in an image */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid embedded Abstract ICC profile"); + + case 0x6C696E6B: /* 'link' */ + /* DeviceLink profiles cannot be interpreted in a non-device specific + * fashion, if an app uses the AToB0Tag in the profile the results are + * undefined unless the result is sent to the intended device, + * therefore a DeviceLink profile should not be found embedded in a + * PNG. + */ + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected DeviceLink ICC profile class"); + + case 0x6E6D636C: /* 'nmcl' */ + /* A NamedColor profile is also device specific, however it doesn't + * contain an AToB0 tag that is open to misinterpretation. Almost + * certainly it will fail the tests below. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unexpected NamedColor ICC profile class"); + break; + + default: + /* To allow for future enhancements to the profile accept unrecognized + * profile classes with a warning, these then hit the test below on the + * tag content to ensure they are backward compatible with one of the + * understood profiles. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unrecognized ICC profile class"); + break; + } + + /* For any profile other than a device link one the PCS must be encoded + * either in XYZ or Lab. + */ + temp = png_get_uint_32(profile+20); + switch (temp) + { + case 0x58595A20: /* 'XYZ ' */ + case 0x4C616220: /* 'Lab ' */ + break; + + default: + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected ICC PCS encoding"); + } + + return 1; +} + +int /* PRIVATE */ +png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */) +{ + png_uint_32 tag_count = png_get_uint_32(profile+128); + png_uint_32 itag; + png_const_bytep tag = profile+132; /* The first tag */ + + /* First scan all the tags in the table and add bits to the icc_info value + * (temporarily in 'tags'). + */ + for (itag=0; itag < tag_count; ++itag, tag += 12) + { + png_uint_32 tag_id = png_get_uint_32(tag+0); + png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */ + png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */ + + /* The ICC specification does not exclude zero length tags, therefore the + * start might actually be anywhere if there is no data, but this would be + * a clear abuse of the intent of the standard so the start is checked for + * being in range. All defined tag types have an 8 byte header - a 4 byte + * type signature then 0. + */ + if ((tag_start & 3) != 0) + { + /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is + * only a warning here because libpng does not care about the + * alignment. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, tag_id, + "ICC profile tag start not a multiple of 4"); + } + + /* This is a hard error; potentially it can cause read outside the + * profile. + */ + if (tag_start > profile_length || tag_length > profile_length - tag_start) + return png_icc_profile_error(png_ptr, colorspace, name, tag_id, + "ICC profile tag outside profile"); + } + + return 1; /* success, maybe with warnings */ +} + +#ifdef PNG_sRGB_SUPPORTED +#if PNG_sRGB_PROFILE_CHECKS >= 0 +/* Information about the known ICC sRGB profiles */ +static const struct +{ + png_uint_32 adler, crc, length; + png_uint_32 md5[4]; + png_byte have_md5; + png_byte is_broken; + png_uint_16 intent; + +# define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0) +# define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\ + { adler, crc, length, md5, broke, intent }, + +} png_sRGB_checks[] = +{ + /* This data comes from contrib/tools/checksum-icc run on downloads of + * all four ICC sRGB profiles from www.color.org. + */ + /* adler32, crc32, MD5[4], intent, date, length, file-name */ + PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9, + PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0, + "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc") + + /* ICC sRGB v2 perceptual no black-compensation: */ + PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21, + PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0, + "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc") + + PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae, + PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0, + "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc") + + /* ICC sRGB v4 perceptual */ + PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812, + PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0, + "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc") + + /* The following profiles have no known MD5 checksum. If there is a match + * on the (empty) MD5 the other fields are used to attempt a match and + * a warning is produced. The first two of these profiles have a 'cprt' tag + * which suggests that they were also made by Hewlett Packard. + */ + PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0, + "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc") + + /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not + * match the D50 PCS illuminant in the header (it is in fact the D65 values, + * so the white point is recorded as the un-adapted value.) The profiles + * below only differ in one byte - the intent - and are basically the same as + * the previous profile except for the mediaWhitePointTag error and a missing + * chromaticAdaptationTag. + */ + PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual") + + PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative") +}; + +static int +png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, + png_const_bytep profile, uLong adler) +{ + /* The quick check is to verify just the MD5 signature and trust the + * rest of the data. Because the profile has already been verified for + * correctness this is safe. png_colorspace_set_sRGB will check the 'intent' + * field too, so if the profile has been edited with an intent not defined + * by sRGB (but maybe defined by a later ICC specification) the read of + * the profile will fail at that point. + */ + + png_uint_32 length = 0; + png_uint_32 intent = 0x10000; /* invalid */ +#if PNG_sRGB_PROFILE_CHECKS > 1 + uLong crc = 0; /* the value for 0 length data */ +#endif + unsigned int i; + +#ifdef PNG_SET_OPTION_SUPPORTED + /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */ + if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) == + PNG_OPTION_ON) + return 0; +#endif + + for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i) + { + if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] && + png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] && + png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] && + png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3]) + { + /* This may be one of the old HP profiles without an MD5, in that + * case we can only use the length and Adler32 (note that these + * are not used by default if there is an MD5!) + */ +# if PNG_sRGB_PROFILE_CHECKS == 0 + if (png_sRGB_checks[i].have_md5 != 0) + return 1+png_sRGB_checks[i].is_broken; +# endif + + /* Profile is unsigned or more checks have been configured in. */ + if (length == 0) + { + length = png_get_uint_32(profile); + intent = png_get_uint_32(profile+64); + } + + /* Length *and* intent must match */ + if (length == png_sRGB_checks[i].length && + intent == png_sRGB_checks[i].intent) + { + /* Now calculate the adler32 if not done already. */ + if (adler == 0) + { + adler = adler32(0, NULL, 0); + adler = adler32(adler, profile, length); + } + + if (adler == png_sRGB_checks[i].adler) + { + /* These basic checks suggest that the data has not been + * modified, but if the check level is more than 1 perform + * our own crc32 checksum on the data. + */ +# if PNG_sRGB_PROFILE_CHECKS > 1 + if (crc == 0) + { + crc = crc32(0, NULL, 0); + crc = crc32(crc, profile, length); + } + + /* So this check must pass for the 'return' below to happen. + */ + if (crc == png_sRGB_checks[i].crc) +# endif + { + if (png_sRGB_checks[i].is_broken != 0) + { + /* These profiles are known to have bad data that may cause + * problems if they are used, therefore attempt to + * discourage their use, skip the 'have_md5' warning below, + * which is made irrelevant by this error. + */ + png_chunk_report(png_ptr, "known incorrect sRGB profile", + PNG_CHUNK_ERROR); + } - /* Overflow is possible here and it indicates an extreme set of PNG cHRM - * chunk values. This calculation actually returns the reciprocal of the - * scale value because this allows us to delay the multiplication of white-y - * into the denominator, which tends to produce a small number. - */ - if (!png_muldiv(&red_inverse, xy.whitey, denominator, left-right) || - red_inverse <= xy.whitey /* r+g+b scales = white scale */) - return 1; + /* Warn that this being done; this isn't even an error since + * the profile is perfectly valid, but it would be nice if + * people used the up-to-date ones. + */ + else if (png_sRGB_checks[i].have_md5 == 0) + { + png_chunk_report(png_ptr, + "out-of-date sRGB profile with no signature", + PNG_CHUNK_WARNING); + } - /* Similarly for green_inverse: */ - if (!png_muldiv(&left, xy.redy-xy.bluey, xy.whitex-xy.bluex, 7)) return 2; - if (!png_muldiv(&right, xy.redx-xy.bluex, xy.whitey-xy.bluey, 7)) return 2; - if (!png_muldiv(&green_inverse, xy.whitey, denominator, left-right) || - green_inverse <= xy.whitey) - return 1; + return 1+png_sRGB_checks[i].is_broken; + } + } - /* And the blue scale, the checks above guarantee this can't overflow but it - * can still produce 0 for extreme cHRM values. - */ - blue_scale = png_reciprocal(xy.whitey) - png_reciprocal(red_inverse) - - png_reciprocal(green_inverse); - if (blue_scale <= 0) return 1; +# if PNG_sRGB_PROFILE_CHECKS > 0 + /* The signature matched, but the profile had been changed in some + * way. This probably indicates a data error or uninformed hacking. + * Fall through to "no match". + */ + png_chunk_report(png_ptr, + "Not recognizing known sRGB profile that has been edited", + PNG_CHUNK_WARNING); + break; +# endif + } + } + } + return 0; /* no match */ +} +#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */ - /* And fill in the png_XYZ: */ - if (!png_muldiv(&XYZ->redX, xy.redx, PNG_FP_1, red_inverse)) return 1; - if (!png_muldiv(&XYZ->redY, xy.redy, PNG_FP_1, red_inverse)) return 1; - if (!png_muldiv(&XYZ->redZ, PNG_FP_1 - xy.redx - xy.redy, PNG_FP_1, - red_inverse)) - return 1; +void /* PRIVATE */ +png_icc_set_sRGB(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_bytep profile, uLong adler) +{ + /* Is this profile one of the known ICC sRGB profiles? If it is, just set + * the sRGB information. + */ +#if PNG_sRGB_PROFILE_CHECKS >= 0 + if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0) +#endif + (void)png_colorspace_set_sRGB(png_ptr, colorspace, + (int)/*already checked*/png_get_uint_32(profile+64)); +} +#endif /* sRGB */ - if (!png_muldiv(&XYZ->greenX, xy.greenx, PNG_FP_1, green_inverse)) return 1; - if (!png_muldiv(&XYZ->greenY, xy.greeny, PNG_FP_1, green_inverse)) return 1; - if (!png_muldiv(&XYZ->greenZ, PNG_FP_1 - xy.greenx - xy.greeny, PNG_FP_1, - green_inverse)) - return 1; +int /* PRIVATE */ +png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, png_const_bytep profile, + int color_type) +{ + if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) + return 0; - if (!png_muldiv(&XYZ->blueX, xy.bluex, blue_scale, PNG_FP_1)) return 1; - if (!png_muldiv(&XYZ->blueY, xy.bluey, blue_scale, PNG_FP_1)) return 1; - if (!png_muldiv(&XYZ->blueZ, PNG_FP_1 - xy.bluex - xy.bluey, blue_scale, - PNG_FP_1)) + if (png_icc_check_length(png_ptr, colorspace, name, profile_length) != 0 && + png_icc_check_header(png_ptr, colorspace, name, profile_length, profile, + color_type) != 0 && + png_icc_check_tag_table(png_ptr, colorspace, name, profile_length, + profile) != 0) + { +# ifdef PNG_sRGB_SUPPORTED + /* If no sRGB support, don't try storing sRGB information */ + png_icc_set_sRGB(png_ptr, colorspace, profile, 0); +# endif return 1; + } - return 0; /*success*/ + /* Failure case */ + return 0; } +#endif /* iCCP */ -int png_XYZ_from_xy_checked(png_structp png_ptr, png_XYZ *XYZ, png_xy xy) +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void /* PRIVATE */ +png_colorspace_set_rgb_coefficients(png_structrp png_ptr) { - switch (png_XYZ_from_xy(XYZ, xy)) + /* Set the rgb_to_gray coefficients from the colorspace. */ + if (png_ptr->rgb_to_gray_coefficients_set == 0 && + (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { - case 0: /* success */ - return 1; - - case 1: - /* The chunk may be technically valid, but we got png_fixed_point - * overflow while trying to get XYZ values out of it. This is - * entirely benign - the cHRM chunk is pretty extreme. + /* png_set_background has not been called, get the coefficients from the Y + * values of the colorspace colorants. + */ + png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y; + png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y; + png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y; + png_fixed_point total = r+g+b; + + if (total > 0 && + r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && + g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && + b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && + r+g+b <= 32769) + { + /* We allow 0 coefficients here. r+g+b may be 32769 if two or + * all of the coefficients were rounded up. Handle this by + * reducing the *largest* coefficient by 1; this matches the + * approach used for the default coefficients in pngrtran.c */ - png_warning(png_ptr, - "extreme cHRM chunk cannot be converted to tristimulus values"); - break; + int add = 0; - default: - /* libpng is broken; this should be a warning but if it happens we - * want error reports so for the moment it is an error. - */ - png_error(png_ptr, "internal error in png_XYZ_from_xy"); - break; + if (r+g+b > 32768) + add = -1; + else if (r+g+b < 32768) + add = 1; + + if (add != 0) + { + if (g >= r && g >= b) + g += add; + else if (r >= g && r >= b) + r += add; + else + b += add; + } + + /* Check for an internal error. */ + if (r+g+b != 32768) + png_error(png_ptr, + "internal error handling cHRM coefficients"); + + else + { + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; + } + } + + /* This is a png_error at present even though it could be ignored - + * it should never happen, but it is important that if it does, the + * bug is fixed. + */ + else + png_error(png_ptr, "internal error handling cHRM->XYZ"); } +} +#endif /* READ_RGB_TO_GRAY */ - /* ERROR RETURN */ - return 0; +#endif /* COLORSPACE */ + +#ifdef __GNUC__ +/* This exists solely to work round a warning from GNU C. */ +static int /* PRIVATE */ +png_gt(size_t a, size_t b) +{ + return a > b; } +#else +# define png_gt(a,b) ((a) > (b)) #endif void /* PRIVATE */ -png_check_IHDR(png_structp png_ptr, +png_check_IHDR(png_const_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, int filter_type) @@ -1180,36 +2482,47 @@ png_check_IHDR(png_structp png_ptr, error = 1; } - if (height == 0) + if (width > PNG_UINT_31_MAX) { - png_warning(png_ptr, "Image height is zero in IHDR"); + png_warning(png_ptr, "Invalid image width in IHDR"); error = 1; } -# ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (width > png_ptr->user_width_max) - -# else - if (width > PNG_USER_WIDTH_MAX) -# endif + if (png_gt(((width + 7) & (~7)), + ((PNG_SIZE_MAX + - 48 /* big_row_buf hack */ + - 1) /* filter byte */ + / 8) /* 8-byte RGBA pixels */ + - 1)) /* extra max_pixel_depth pad */ { - png_warning(png_ptr, "Image width exceeds user limit in IHDR"); + /* The size of the row must be within the limits of this architecture. + * Because the read code can perform arbitrary transformations the + * maximum size is checked here. Because the code in png_read_start_row + * adds extra space "for safety's sake" in several places a conservative + * limit is used here. + * + * NOTE: it would be far better to check the size that is actually used, + * but the effect in the real world is minor and the changes are more + * extensive, therefore much more dangerous and much more difficult to + * write in a way that avoids compiler warnings. + */ + png_warning(png_ptr, "Image width is too large for this architecture"); error = 1; } -# ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (height > png_ptr->user_height_max) -# else - if (height > PNG_USER_HEIGHT_MAX) -# endif +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (width > png_ptr->user_width_max) +#else + if (width > PNG_USER_WIDTH_MAX) +#endif { - png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + png_warning(png_ptr, "Image width exceeds user limit in IHDR"); error = 1; } - if (width > PNG_UINT_31_MAX) + if (height == 0) { - png_warning(png_ptr, "Invalid image width in IHDR"); + png_warning(png_ptr, "Image height is zero in IHDR"); error = 1; } @@ -1219,13 +2532,15 @@ png_check_IHDR(png_structp png_ptr, error = 1; } - if (width > (PNG_UINT_32_MAX - >> 3) /* 8-byte RGBA pixels */ - - 48 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - png_warning(png_ptr, "Width is too large for libpng to process pixels"); +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (height > png_ptr->user_height_max) +#else + if (height > PNG_USER_HEIGHT_MAX) +#endif + { + png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + error = 1; + } /* Check other values */ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && @@ -1263,7 +2578,7 @@ png_check_IHDR(png_structp png_ptr, error = 1; } -# ifdef PNG_MNG_FEATURES_SUPPORTED +#ifdef PNG_MNG_FEATURES_SUPPORTED /* Accept filter_method 64 (intrapixel differencing) only if * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and * 2. Libpng did not read a PNG signature (this filter_method is only @@ -1273,13 +2588,13 @@ png_check_IHDR(png_structp png_ptr, * 4. The filter_method is 64 and * 5. The color_type is RGB or RGBA */ - if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) && - png_ptr->mng_features_permitted) + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && + png_ptr->mng_features_permitted != 0) png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); if (filter_type != PNG_FILTER_TYPE_BASE) { - if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && (color_type == PNG_COLOR_TYPE_RGB || @@ -1289,20 +2604,20 @@ png_check_IHDR(png_structp png_ptr, error = 1; } - if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0) { png_warning(png_ptr, "Invalid filter method in IHDR"); error = 1; } } -# else +#else if (filter_type != PNG_FILTER_TYPE_BASE) { png_warning(png_ptr, "Unknown filter method in IHDR"); error = 1; } -# endif +#endif if (error == 1) png_error(png_ptr, "Invalid IHDR data"); @@ -1349,7 +2664,7 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) { case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: - if (state & PNG_FP_SAW_ANY) + if ((state & PNG_FP_SAW_ANY) != 0) goto PNG_FP_End; /* not a part of the number */ png_fp_add(state, type); @@ -1357,10 +2672,10 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, case PNG_FP_INTEGER + PNG_FP_SAW_DOT: /* Ok as trailer, ok as lead of fraction. */ - if (state & PNG_FP_SAW_DOT) /* two dots */ + if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */ goto PNG_FP_End; - else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */ + else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */ png_fp_add(state, type); else @@ -1369,7 +2684,7 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, break; case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: - if (state & PNG_FP_SAW_DOT) /* delayed fraction */ + if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */ png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); png_fp_add(state, type | PNG_FP_WAS_VALID); @@ -1407,7 +2722,7 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, break; case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: - if (state & PNG_FP_SAW_ANY) + if ((state & PNG_FP_SAW_ANY) != 0) goto PNG_FP_End; /* not a part of the number */ png_fp_add(state, PNG_FP_SAW_SIGN); @@ -1450,15 +2765,15 @@ png_check_fp_string(png_const_charp string, png_size_t size) int state=0; png_size_t char_index=0; - if (png_check_fp_number(string, size, &state, &char_index) && + if (png_check_fp_number(string, size, &state, &char_index) != 0 && (char_index == size || string[char_index] == 0)) return state /* must be non-zero - see above */; return 0; /* i.e. fail */ } -#endif /* pCAL or sCAL */ +#endif /* pCAL || sCAL */ -#ifdef PNG_READ_sCAL_SUPPORTED +#ifdef PNG_sCAL_SUPPORTED # ifdef PNG_FLOATING_POINT_SUPPORTED /* Utility used below - a simple accurate power of ten from an integral * exponent. @@ -1467,7 +2782,7 @@ static double png_pow10(int power) { int recip = 0; - double d = 1.0; + double d = 1; /* Handle negative exponent with a reciprocal at the end because * 10 is exact whereas .1 is inexact in base 2 @@ -1481,7 +2796,7 @@ png_pow10(int power) if (power > 0) { /* Decompose power bitwise. */ - double mult = 10.0; + double mult = 10; do { if (power & 1) d *= mult; @@ -1490,7 +2805,7 @@ png_pow10(int power) } while (power > 0); - if (recip) d = 1/d; + if (recip != 0) d = 1/d; } /* else power is 0 and d is 1 */ @@ -1501,7 +2816,7 @@ png_pow10(int power) * precision. */ void /* PRIVATE */ -png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, +png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, double fp, unsigned int precision) { /* We use standard functions from math.h, but not printf because @@ -1600,8 +2915,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, { double d; - fp *= 10.0; - + fp *= 10; /* Use modf here, not floor and subtract, so that * the separation is done in one step. At the end * of the loop don't break the number into parts so @@ -1614,7 +2928,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, { d = floor(fp + .5); - if (d > 9.0) + if (d > 9) { /* Rounding up to 10, handle that here. */ if (czero > 0) @@ -1622,10 +2936,9 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, --czero, d = 1; if (cdigits == 0) --clead; } - else { - while (cdigits > 0 && d > 9.0) + while (cdigits > 0 && d > 9) { int ch = *--ascii; @@ -1650,7 +2963,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, * exponent but take into account the leading * decimal point. */ - if (d > 9.0) /* cdigits == 0 */ + if (d > 9) /* cdigits == 0 */ { if (exp_b10 == (-1)) { @@ -1671,19 +2984,18 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, ++exp_b10; /* In all cases we output a '1' */ - d = 1.0; + d = 1; } } } fp = 0; /* Guarantees termination below. */ } - if (d == 0.0) + if (d == 0) { ++czero; if (cdigits == 0) ++clead; } - else { /* Included embedded zeros in the digit count. */ @@ -1707,11 +3019,11 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, if (exp_b10 != (-1)) { - if (exp_b10 == 0) *ascii++ = 46, --size; /* counted - above */ + if (exp_b10 == 0) + *ascii++ = 46, --size; /* counted above */ + --exp_b10; } - *ascii++ = (char)(48 + (int)d), ++cdigits; } } @@ -1722,7 +3034,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, /* Check for an exponent, if we don't need one we are * done and just need to terminate the string. At * this point exp_b10==(-1) is effectively if flag - it got - * to '-1' because of the decrement after outputing + * to '-1' because of the decrement after outputting * the decimal point above (the exponent required is * *not* -1!) */ @@ -1730,7 +3042,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, { /* The following only happens if we didn't output the * leading zeros above for negative exponent, so this - * doest add to the digit requirement. Note that the + * doesn't add to the digit requirement. Note that the * two zeros here can only be output if the two leading * zeros were *not* output, so this doesn't increase * the output count. @@ -1819,8 +3131,8 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, /* Function to format a fixed point value in ASCII. */ void /* PRIVATE */ -png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size, - png_fixed_point fp) +png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, + png_size_t size, png_fixed_point fp) { /* Require space for 10 decimal digits, a decimal point, a minus sign and a * trailing \0, 13 characters: @@ -1887,24 +3199,33 @@ png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size, png_error(png_ptr, "ASCII conversion buffer too small"); } # endif /* FIXED_POINT */ -#endif /* READ_SCAL */ +#endif /* SCAL */ #if defined(PNG_FLOATING_POINT_SUPPORTED) && \ - !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) png_fixed_point -png_fixed(png_structp png_ptr, double fp, png_const_charp text) +png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) { double r = floor(100000 * fp + .5); if (r > 2147483647. || r < -2147483648.) png_fixed_error(png_ptr, text); +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(text) +# endif + return (png_fixed_point)r; } #endif -#if defined(PNG_READ_GAMMA_SUPPORTED) || \ - defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG__READ_pHYs_SUPPORTED) +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) /* muldiv functions */ /* This API takes signed arguments and rounds the result to the nearest * integer (or, for a fixed point number - the standard argument - to @@ -2008,11 +3329,12 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, if (s00 >= (D >> 1)) ++result; - if (negative) + if (negative != 0) result = -result; /* Check for overflow. */ - if ((negative && result <= 0) || (!negative && result >= 0)) + if ((negative != 0 && result <= 0) || + (negative == 0 && result >= 0)) { *res = result; return 1; @@ -2031,12 +3353,12 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, * result. */ png_fixed_point -png_muldiv_warn(png_structp png_ptr, png_fixed_point a, png_int_32 times, +png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times, png_int_32 divisor) { png_fixed_point result; - if (png_muldiv(&result, a, times, divisor)) + if (png_muldiv(&result, a, times, divisor) != 0) return result; png_warning(png_ptr, "fixed point overflow ignored"); @@ -2044,7 +3366,7 @@ png_muldiv_warn(png_structp png_ptr, png_fixed_point a, png_int_32 times, } #endif -#ifdef PNG_READ_GAMMA_SUPPORTED /* more fixed point functions for gammma */ +#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */ /* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ png_fixed_point png_reciprocal(png_fixed_point a) @@ -2057,13 +3379,26 @@ png_reciprocal(png_fixed_point a) #else png_fixed_point res; - if (png_muldiv(&res, 100000, 100000, a)) + if (png_muldiv(&res, 100000, 100000, a) != 0) return res; #endif return 0; /* error/overflow */ } +/* This is the shared test on whether a gamma value is 'significant' - whether + * it is worth doing gamma correction. + */ +int /* PRIVATE */ +png_gamma_significant(png_fixed_point gamma_val) +{ + return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || + gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; +} +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +#ifdef PNG_16BIT_SUPPORTED /* A local convenience routine. */ static png_fixed_point png_product2(png_fixed_point a, png_fixed_point b) @@ -2079,12 +3414,13 @@ png_product2(png_fixed_point a, png_fixed_point b) #else png_fixed_point res; - if (png_muldiv(&res, a, b, 100000)) + if (png_muldiv(&res, a, b, 100000) != 0) return res; #endif return 0; /* overflow */ } +#endif /* 16BIT */ /* The inverse of the above. */ png_fixed_point @@ -2092,12 +3428,15 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b) { /* The required result is 1/a * 1/b; the following preserves accuracy. */ #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = 1E15/a; - r /= b; - r = floor(r+.5); + if (a != 0 && b != 0) + { + double r = 1E15/a; + r /= b; + r = floor(r+.5); - if (r <= 2147483647. && r >= -2147483648.) - return (png_fixed_point)r; + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; + } #else /* This may overflow because the range of png_fixed_point isn't symmetric, * but this API is only used for the product of file and screen gamma so it @@ -2114,73 +3453,28 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b) } #endif /* READ_GAMMA */ -#ifdef PNG_CHECK_cHRM_SUPPORTED -/* Added at libpng version 1.2.34 (Dec 8, 2008) and 1.4.0 (Jan 2, - * 2010: moved from pngset.c) */ -/* - * Multiply two 32-bit numbers, V1 and V2, using 32-bit - * arithmetic, to produce a 64-bit result in the HI/LO words. - * - * A B - * x C D - * ------ - * AD || BD - * AC || CB || 0 - * - * where A and B are the high and low 16-bit words of V1, - * C and D are the 16-bit words of V2, AD is the product of - * A and D, and X || Y is (X << 16) + Y. -*/ - -void /* PRIVATE */ -png_64bit_product (long v1, long v2, unsigned long *hi_product, - unsigned long *lo_product) -{ - int a, b, c, d; - long lo, hi, x, y; - - a = (v1 >> 16) & 0xffff; - b = v1 & 0xffff; - c = (v2 >> 16) & 0xffff; - d = v2 & 0xffff; - - lo = b * d; /* BD */ - x = a * d + c * b; /* AD + CB */ - y = ((lo >> 16) & 0xffff) + x; - - lo = (lo & 0xffff) | ((y & 0xffff) << 16); - hi = (y >> 16) & 0xffff; - - hi += a * c; /* AC */ - - *hi_product = (unsigned long)hi; - *lo_product = (unsigned long)lo; -} -#endif /* CHECK_cHRM */ - #ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */ #ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Fixed point gamma. + * + * The code to calculate the tables used below can be found in the shell script + * contrib/tools/intgamma.sh * * To calculate gamma this code implements fast log() and exp() calls using only * fixed point arithmetic. This code has sufficient precision for either 8-bit * or 16-bit sample values. * * The tables used here were calculated using simple 'bc' programs, but C double - * precision floating point arithmetic would work fine. The programs are given - * at the head of each table. + * precision floating point arithmetic would work fine. * * 8-bit log table * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to * 255, so it's the base 2 logarithm of a normalized 8-bit floating point * mantissa. The numbers are 32-bit fractions. */ -static png_uint_32 +static const png_uint_32 png_8bit_l2[128] = { -# ifdef PNG_DO_BC - for (i=128;i<256;++i) { .5 - l(i/255)/l(2)*65536*65536; } -# else 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U, 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U, 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U, @@ -2203,7 +3497,6 @@ png_8bit_l2[128] = 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U, 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, 24347096U, 0U -# endif #if 0 /* The following are the values for 16-bit tables - these work fine for the @@ -2226,18 +3519,18 @@ png_8bit_l2[128] = #endif }; -PNG_STATIC png_int_32 +static png_int_32 png_log8bit(unsigned int x) { unsigned int lg2 = 0; /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log, * because the log is actually negate that means adding 1. The final * returned value thus has the range 0 (for 255 input) to 7.994 (for 1 - * input), return 7.99998 for the overflow (log 0) case - so the result is + * input), return -1 for the overflow (log 0) case, - so the result is * always at most 19 bits. */ if ((x &= 0xff) == 0) - return 0xffffffff; + return -1; if ((x & 0xf0) == 0) lg2 = 4, x <<= 4; @@ -2282,14 +3575,15 @@ png_log8bit(unsigned int x) * Zero (257): 0 * End (258): 23499 */ -PNG_STATIC png_int_32 +#ifdef PNG_16BIT_SUPPORTED +static png_int_32 png_log16bit(png_uint_32 x) { unsigned int lg2 = 0; /* As above, but now the input has 16 bits. */ if ((x &= 0xffff) == 0) - return 0xffffffff; + return -1; if ((x & 0xff00) == 0) lg2 = 8, x <<= 8; @@ -2332,13 +3626,14 @@ png_log16bit(png_uint_32 x) /* Safe, because the result can't have more than 20 bits: */ return (png_int_32)((lg2 + 2048) >> 12); } +#endif /* 16BIT */ /* The 'exp()' case must invert the above, taking a 20-bit fixed point * logarithmic value and returning a 16 or 8-bit number as appropriate. In * each case only the low 16 bits are relevant - the fraction - since the * integer bits (the top 4) simply determine a shift. * - * The worst case is the 16-bit distinction between 65535 and 65534, this + * The worst case is the 16-bit distinction between 65535 and 65534. This * requires perhaps spurious accuracy in the decoding of the logarithm to * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance * of getting this accuracy in practice. @@ -2347,21 +3642,17 @@ png_log16bit(png_uint_32 x) * frational part of the logarithm by using an accurate 32-bit value from the * top four fractional bits then multiplying in the remaining bits. */ -static png_uint_32 +static const png_uint_32 png_32bit_exp[16] = { -# ifdef PNG_DO_BC - for (i=0;i<16;++i) { .5 + e(-i/16*l(2))*2^32; } -# else /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, 2553802834U, 2445529972U, 2341847524U, 2242560872U -# endif }; /* Adjustment table; provided to explain the numbers in the code below. */ -#ifdef PNG_DO_BC +#if 0 for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} 11 44937.64284865548751208448 10 45180.98734845585101160448 @@ -2377,7 +3668,7 @@ for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} 0 45425.85339951654943850496 #endif -PNG_STATIC png_uint_32 +static png_uint_32 png_exp(png_fixed_point x) { if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ @@ -2425,21 +3716,22 @@ png_exp(png_fixed_point x) return 0; } -PNG_STATIC png_byte +static png_byte png_exp8bit(png_fixed_point lg2) { /* Get a 32-bit value: */ png_uint_32 x = png_exp(lg2); - /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the + /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the * second, rounding, step can't overflow because of the first, subtraction, * step. */ x -= x >> 8; - return (png_byte)((x + 0x7fffffU) >> 24); + return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff); } -PNG_STATIC png_uint_16 +#ifdef PNG_16BIT_SUPPORTED +static png_uint_16 png_exp16bit(png_fixed_point lg2) { /* Get a 32-bit value: */ @@ -2449,6 +3741,7 @@ png_exp16bit(png_fixed_point lg2) x -= x >> 16; return (png_uint_16)((x + 32767U) >> 16); } +#endif /* 16BIT */ #endif /* FLOATING_ARITHMETIC */ png_byte @@ -2457,13 +3750,37 @@ png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) if (value > 0 && value < 255) { # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = floor(255*pow(value/255.,gamma_val*.00001)+.5); + /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly + * convert this to a floating point value. This includes values that + * would overflow if 'value' were to be converted to 'int'. + * + * Apparently GCC, however, does an intermediate conversion to (int) + * on some (ARM) but not all (x86) platforms, possibly because of + * hardware FP limitations. (E.g. if the hardware conversion always + * assumes the integer register contains a signed value.) This results + * in ANSI-C undefined behavior for large values. + * + * Other implementations on the same machine might actually be ANSI-C90 + * conformant and therefore compile spurious extra code for the large + * values. + * + * We can be reasonably sure that an unsigned to float conversion + * won't be faster than an int to float one. Therefore this code + * assumes responsibility for the undefined behavior, which it knows + * can't happen because of the check above. + * + * Note the argument to this routine is an (unsigned int) because, on + * 16-bit platforms, it is assigned a value which might be out of + * range for an (int); that would result in undefined behavior in the + * caller if the *argument* ('value') were to be declared (int). + */ + double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5); return (png_byte)r; # else png_int_32 lg2 = png_log8bit(value); png_fixed_point res; - if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) return png_exp8bit(res); /* Overflow. */ @@ -2471,22 +3788,29 @@ png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) # endif } - return (png_byte)value; + return (png_byte)(value & 0xff); } +#ifdef PNG_16BIT_SUPPORTED png_uint_16 png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) { if (value > 0 && value < 65535) { # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5); + /* The same (unsigned int)->(double) constraints apply here as above, + * however in this case the (unsigned int) to (int) conversion can + * overflow on an ANSI-C90 compliant system so the cast needs to ensure + * that this is not possible. + */ + double r = floor(65535*pow((png_int_32)value/65535., + gamma_val*.00001)+.5); return (png_uint_16)r; # else png_int_32 lg2 = png_log16bit(value); png_fixed_point res; - if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) return png_exp16bit(res); /* Overflow. */ @@ -2496,6 +3820,7 @@ png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) return (png_uint_16)value; } +#endif /* 16BIT */ /* This does the right thing based on the bit_depth field of the * png_struct, interpreting values as 8-bit or 16-bit. While the result @@ -2503,28 +3828,24 @@ png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) * 8-bit (as are the arguments.) */ png_uint_16 /* PRIVATE */ -png_gamma_correct(png_structp png_ptr, unsigned int value, +png_gamma_correct(png_structrp png_ptr, unsigned int value, png_fixed_point gamma_val) { if (png_ptr->bit_depth == 8) return png_gamma_8bit_correct(value, gamma_val); +#ifdef PNG_16BIT_SUPPORTED else return png_gamma_16bit_correct(value, gamma_val); +#else + /* should not reach this */ + return 0; +#endif /* 16BIT */ } -/* This is the shared test on whether a gamma value is 'significant' - whether - * it is worth doing gamma correction. - */ -int /* PRIVATE */ -png_gamma_significant(png_fixed_point gamma_val) -{ - return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || - gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; -} - +#ifdef PNG_16BIT_SUPPORTED /* Internal function to build a single 16-bit table - the table consists of - * 'num' 256-entry subtables, where 'num' is determined by 'shift' - the amount + * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount * to shift the input values right (or 16-number_of_signifiant_bits). * * The caller is responsible for ensuring that the table gets cleaned up on @@ -2532,27 +3853,33 @@ png_gamma_significant(png_fixed_point gamma_val) * should be somewhere that will be cleaned. */ static void -png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable, +png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) { /* Various values derived from 'shift': */ PNG_CONST unsigned int num = 1U << (8U - shift); +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + /* CSE the division and work round wacky GCC warnings (see the comments + * in png_gamma_8bit_correct for where these come from.) + */ + PNG_CONST double fmax = 1./(((png_int_32)1 << (16U - shift))-1); +#endif PNG_CONST unsigned int max = (1U << (16U - shift))-1U; PNG_CONST unsigned int max_by_2 = 1U << (15U-shift); unsigned int i; png_uint_16pp table = *ptable = - (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p)); + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); for (i = 0; i < num; i++) { png_uint_16p sub_table = table[i] = - (png_uint_16p)png_malloc(png_ptr, 256 * png_sizeof(png_uint_16)); + (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16))); /* The 'threshold' test is repeated here because it can arise for one of * the 16-bit tables even if the others don't hit it. */ - if (png_gamma_significant(gamma_val)) + if (png_gamma_significant(gamma_val) != 0) { /* The old code would overflow at the end and this would cause the * 'pow' function to return a result >1, resulting in an @@ -2568,10 +3895,13 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable, png_uint_32 ig = (j << (8-shift)) + i; # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Inline the 'max' scaling operation: */ - double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5); + /* See png_gamma_8bit_correct for why the cast to (int) is + * required here. + */ + double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5); sub_table[j] = (png_uint_16)d; # else - if (shift) + if (shift != 0) ig = (ig * 65535U + max_by_2)/max; sub_table[j] = png_gamma_16bit_correct(ig, gamma_val); @@ -2587,7 +3917,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable, { png_uint_32 ig = (j << (8-shift)) + i; - if (shift) + if (shift != 0) ig = (ig * 65535U + max_by_2)/max; sub_table[j] = (png_uint_16)ig; @@ -2600,7 +3930,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable, * required. */ static void -png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable, +png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) { PNG_CONST unsigned int num = 1U << (8U - shift); @@ -2609,15 +3939,15 @@ png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable, png_uint_32 last; png_uint_16pp table = *ptable = - (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p)); + (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); - /* 'num' is the number of tables and also the number of low bits of the - * input 16-bit value used to select a table. Each table is itself indexed - * by the high 8 bits of the value. + /* 'num' is the number of tables and also the number of low bits of low + * bits of the input 16-bit value used to select a table. Each table is + * itself indexed by the high 8 bits of the value. */ for (i = 0; i < num; i++) table[i] = (png_uint_16p)png_malloc(png_ptr, - 256 * png_sizeof(png_uint_16)); + 256 * (sizeof (png_uint_16))); /* 'gamma_val' is set to the reciprocal of the value calculated above, so * pow(out,g) is an *input* value. 'last' is the last input value set. @@ -2661,34 +3991,38 @@ png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable, last++; } } +#endif /* 16BIT */ /* Build a single 8-bit table: same as the 16-bit case but much simpler (and * typically much faster). Note that libpng currently does no sBIT processing * (apparently contrary to the spec) so a 256-entry table is always generated. */ static void -png_build_8bit_table(png_structp png_ptr, png_bytepp ptable, +png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, PNG_CONST png_fixed_point gamma_val) { unsigned int i; png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256); - if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++) - table[i] = png_gamma_8bit_correct(i, gamma_val); + if (png_gamma_significant(gamma_val) != 0) + for (i=0; i<256; i++) + table[i] = png_gamma_8bit_correct(i, gamma_val); - else for (i=0; i<256; ++i) - table[i] = (png_byte)i; + else + for (i=0; i<256; ++i) + table[i] = (png_byte)(i & 0xff); } /* Used from png_read_destroy and below to release the memory used by the gamma * tables. */ void /* PRIVATE */ -png_destroy_gamma_table(png_structp png_ptr) +png_destroy_gamma_table(png_structrp png_ptr) { png_free(png_ptr, png_ptr->gamma_table); png_ptr->gamma_table = NULL; +#ifdef PNG_16BIT_SUPPORTED if (png_ptr->gamma_16_table != NULL) { int i; @@ -2700,6 +4034,7 @@ png_destroy_gamma_table(png_structp png_ptr) png_free(png_ptr, png_ptr->gamma_16_table); png_ptr->gamma_16_table = NULL; } +#endif /* 16BIT */ #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ @@ -2709,6 +4044,7 @@ png_destroy_gamma_table(png_structp png_ptr) png_free(png_ptr, png_ptr->gamma_to_1); png_ptr->gamma_to_1 = NULL; +#ifdef PNG_16BIT_SUPPORTED if (png_ptr->gamma_16_from_1 != NULL) { int i; @@ -2731,6 +4067,7 @@ png_destroy_gamma_table(png_structp png_ptr) png_free(png_ptr, png_ptr->gamma_16_to_1); png_ptr->gamma_16_to_1 = NULL; } +#endif /* 16BIT */ #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } @@ -2740,7 +4077,7 @@ png_destroy_gamma_table(png_structp png_ptr) * we don't need to allocate > 64K chunks for a full 16-bit table. */ void /* PRIVATE */ -png_build_gamma_table(png_structp png_ptr, int bit_depth) +png_build_gamma_table(png_structrp png_ptr, int bit_depth) { png_debug(1, "in png_build_gamma_table"); @@ -2759,28 +4096,29 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) if (bit_depth <= 8) { png_build_8bit_table(png_ptr, &png_ptr->gamma_table, - png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma) : PNG_FP_1); #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) + if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) { png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, - png_reciprocal(png_ptr->gamma)); + png_reciprocal(png_ptr->colorspace.gamma)); png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : - png_ptr->gamma/* Probably doing rgb_to_gray */); + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); } #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } +#ifdef PNG_16BIT_SUPPORTED else { png_byte shift, sig_bit; - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) { sig_bit = png_ptr->sig_bit.red; @@ -2812,12 +4150,13 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) * */ if (sig_bit > 0 && sig_bit < 16U) - shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */ + /* shift == insignificant bits */ + shift = (png_byte)((16U - sig_bit) & 0xff); else shift = 0; /* keep all 16 bits */ - if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) + if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) { /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively * the significant bits in the *input* when the output will @@ -2832,32 +4171,28 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) png_ptr->gamma_shift = shift; -#ifdef PNG_16BIT_SUPPORTED /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now * PNG_COMPOSE). This effectively smashed the background calculation for * 16-bit output because the 8-bit table assumes the result will be reduced * to 8 bits. */ - if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) -#endif + if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, - png_ptr->screen_gamma > 0 ? png_product2(png_ptr->gamma, + png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma, png_ptr->screen_gamma) : PNG_FP_1); -#ifdef PNG_16BIT_SUPPORTED else png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift, - png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma) : PNG_FP_1); -#endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) + if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) { png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, - png_reciprocal(png_ptr->gamma)); + png_reciprocal(png_ptr->colorspace.gamma)); /* Notice that the '16 from 1' table should be full precision, however * the lookup on this table still uses gamma_shift, so it can't be. @@ -2865,10 +4200,291 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) */ png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : - png_ptr->gamma/* Probably doing rgb_to_gray */); + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); } #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } +#endif /* 16BIT */ } #endif /* READ_GAMMA */ -#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ + +/* HARDWARE OR SOFTWARE OPTION SUPPORT */ +#ifdef PNG_SET_OPTION_SUPPORTED +int PNGAPI +png_set_option(png_structrp png_ptr, int option, int onoff) +{ + if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && + (option & 1) == 0) + { + int mask = 3 << option; + int setting = (2 + (onoff != 0)) << option; + int current = png_ptr->options; + + png_ptr->options = (png_byte)(((current & ~mask) | setting) & 0xff); + + return (current & mask) >> option; + } + + return PNG_OPTION_INVALID; +} +#endif + +/* sRGB support */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* sRGB conversion tables; these are machine generated with the code in + * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the + * specification (see the article at http://en.wikipedia.org/wiki/SRGB) + * is used, not the gamma=1/2.2 approximation use elsewhere in libpng. + * The sRGB to linear table is exact (to the nearest 16 bit linear fraction). + * The inverse (linear to sRGB) table has accuracies as follows: + * + * For all possible (255*65535+1) input values: + * + * error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact + * + * For the input values corresponding to the 65536 16-bit values: + * + * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact + * + * In all cases the inexact readings are only off by one. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* The convert-to-sRGB table is only currently required for read. */ +const png_uint_16 png_sRGB_table[256] = +{ + 0,20,40,60,80,99,119,139, + 159,179,199,219,241,264,288,313, + 340,367,396,427,458,491,526,562, + 599,637,677,718,761,805,851,898, + 947,997,1048,1101,1156,1212,1270,1330, + 1391,1453,1517,1583,1651,1720,1790,1863, + 1937,2013,2090,2170,2250,2333,2418,2504, + 2592,2681,2773,2866,2961,3058,3157,3258, + 3360,3464,3570,3678,3788,3900,4014,4129, + 4247,4366,4488,4611,4736,4864,4993,5124, + 5257,5392,5530,5669,5810,5953,6099,6246, + 6395,6547,6700,6856,7014,7174,7335,7500, + 7666,7834,8004,8177,8352,8528,8708,8889, + 9072,9258,9445,9635,9828,10022,10219,10417, + 10619,10822,11028,11235,11446,11658,11873,12090, + 12309,12530,12754,12980,13209,13440,13673,13909, + 14146,14387,14629,14874,15122,15371,15623,15878, + 16135,16394,16656,16920,17187,17456,17727,18001, + 18277,18556,18837,19121,19407,19696,19987,20281, + 20577,20876,21177,21481,21787,22096,22407,22721, + 23038,23357,23678,24002,24329,24658,24990,25325, + 25662,26001,26344,26688,27036,27386,27739,28094, + 28452,28813,29176,29542,29911,30282,30656,31033, + 31412,31794,32179,32567,32957,33350,33745,34143, + 34544,34948,35355,35764,36176,36591,37008,37429, + 37852,38278,38706,39138,39572,40009,40449,40891, + 41337,41785,42236,42690,43147,43606,44069,44534, + 45002,45473,45947,46423,46903,47385,47871,48359, + 48850,49344,49841,50341,50844,51349,51858,52369, + 52884,53401,53921,54445,54971,55500,56032,56567, + 57105,57646,58190,58737,59287,59840,60396,60955, + 61517,62082,62650,63221,63795,64372,64952,65535 +}; +#endif /* SIMPLIFIED_READ */ + +/* The base/delta tables are required for both read and write (but currently + * only the simplified versions.) + */ +const png_uint_16 png_sRGB_base[512] = +{ + 128,1782,3383,4644,5675,6564,7357,8074, + 8732,9346,9921,10463,10977,11466,11935,12384, + 12816,13233,13634,14024,14402,14769,15125,15473, + 15812,16142,16466,16781,17090,17393,17690,17981, + 18266,18546,18822,19093,19359,19621,19879,20133, + 20383,20630,20873,21113,21349,21583,21813,22041, + 22265,22487,22707,22923,23138,23350,23559,23767, + 23972,24175,24376,24575,24772,24967,25160,25352, + 25542,25730,25916,26101,26284,26465,26645,26823, + 27000,27176,27350,27523,27695,27865,28034,28201, + 28368,28533,28697,28860,29021,29182,29341,29500, + 29657,29813,29969,30123,30276,30429,30580,30730, + 30880,31028,31176,31323,31469,31614,31758,31902, + 32045,32186,32327,32468,32607,32746,32884,33021, + 33158,33294,33429,33564,33697,33831,33963,34095, + 34226,34357,34486,34616,34744,34873,35000,35127, + 35253,35379,35504,35629,35753,35876,35999,36122, + 36244,36365,36486,36606,36726,36845,36964,37083, + 37201,37318,37435,37551,37668,37783,37898,38013, + 38127,38241,38354,38467,38580,38692,38803,38915, + 39026,39136,39246,39356,39465,39574,39682,39790, + 39898,40005,40112,40219,40325,40431,40537,40642, + 40747,40851,40955,41059,41163,41266,41369,41471, + 41573,41675,41777,41878,41979,42079,42179,42279, + 42379,42478,42577,42676,42775,42873,42971,43068, + 43165,43262,43359,43456,43552,43648,43743,43839, + 43934,44028,44123,44217,44311,44405,44499,44592, + 44685,44778,44870,44962,45054,45146,45238,45329, + 45420,45511,45601,45692,45782,45872,45961,46051, + 46140,46229,46318,46406,46494,46583,46670,46758, + 46846,46933,47020,47107,47193,47280,47366,47452, + 47538,47623,47709,47794,47879,47964,48048,48133, + 48217,48301,48385,48468,48552,48635,48718,48801, + 48884,48966,49048,49131,49213,49294,49376,49458, + 49539,49620,49701,49782,49862,49943,50023,50103, + 50183,50263,50342,50422,50501,50580,50659,50738, + 50816,50895,50973,51051,51129,51207,51285,51362, + 51439,51517,51594,51671,51747,51824,51900,51977, + 52053,52129,52205,52280,52356,52432,52507,52582, + 52657,52732,52807,52881,52956,53030,53104,53178, + 53252,53326,53400,53473,53546,53620,53693,53766, + 53839,53911,53984,54056,54129,54201,54273,54345, + 54417,54489,54560,54632,54703,54774,54845,54916, + 54987,55058,55129,55199,55269,55340,55410,55480, + 55550,55620,55689,55759,55828,55898,55967,56036, + 56105,56174,56243,56311,56380,56448,56517,56585, + 56653,56721,56789,56857,56924,56992,57059,57127, + 57194,57261,57328,57395,57462,57529,57595,57662, + 57728,57795,57861,57927,57993,58059,58125,58191, + 58256,58322,58387,58453,58518,58583,58648,58713, + 58778,58843,58908,58972,59037,59101,59165,59230, + 59294,59358,59422,59486,59549,59613,59677,59740, + 59804,59867,59930,59993,60056,60119,60182,60245, + 60308,60370,60433,60495,60558,60620,60682,60744, + 60806,60868,60930,60992,61054,61115,61177,61238, + 61300,61361,61422,61483,61544,61605,61666,61727, + 61788,61848,61909,61969,62030,62090,62150,62211, + 62271,62331,62391,62450,62510,62570,62630,62689, + 62749,62808,62867,62927,62986,63045,63104,63163, + 63222,63281,63340,63398,63457,63515,63574,63632, + 63691,63749,63807,63865,63923,63981,64039,64097, + 64155,64212,64270,64328,64385,64443,64500,64557, + 64614,64672,64729,64786,64843,64900,64956,65013, + 65070,65126,65183,65239,65296,65352,65409,65465 +}; + +const png_byte png_sRGB_delta[512] = +{ + 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54, + 52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36, + 35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28, + 28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24, + 23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21, + 21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19, + 19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17, + 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; +#endif /* SIMPLIFIED READ/WRITE sRGB support */ + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +static int +png_image_free_function(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_controlp cp = image->opaque; + png_control c; + + /* Double check that we have a png_ptr - it should be impossible to get here + * without one. + */ + if (cp->png_ptr == NULL) + return 0; + + /* First free any data held in the control structure. */ +# ifdef PNG_STDIO_SUPPORTED + if (cp->owned_file != 0) + { + FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr); + cp->owned_file = 0; + + /* Ignore errors here. */ + if (fp != NULL) + { + cp->png_ptr->io_ptr = NULL; + (void)fclose(fp); + } + } +# endif + + /* Copy the control structure so that the original, allocated, version can be + * safely freed. Notice that a png_error here stops the remainder of the + * cleanup, but this is probably fine because that would indicate bad memory + * problems anyway. + */ + c = *cp; + image->opaque = &c; + png_free(c.png_ptr, cp); + + /* Then the structures, calling the correct API. */ + if (c.for_write != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED + png_destroy_write_struct(&c.png_ptr, &c.info_ptr); +# else + png_error(c.png_ptr, "simplified write not supported"); +# endif + } + else + { +# ifdef PNG_SIMPLIFIED_READ_SUPPORTED + png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL); +# else + png_error(c.png_ptr, "simplified read not supported"); +# endif + } + + /* Success. */ + return 1; +} + +void PNGAPI +png_image_free(png_imagep image) +{ + /* Safely call the real function, but only if doing so is safe at this point + * (if not inside an error handling context). Otherwise assume + * png_safe_execute will call this API after the return. + */ + if (image != NULL && image->opaque != NULL && + image->opaque->error_buf == NULL) + { + /* Ignore errors here: */ + (void)png_safe_execute(image, png_image_free_function, image); + image->opaque = NULL; + } +} + +int /* PRIVATE */ +png_image_error(png_imagep image, png_const_charp error_message) +{ + /* Utility to log an error. */ + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + png_image_free(image); + return 0; +} + +#endif /* SIMPLIFIED READ/WRITE */ +#endif /* READ || WRITE */ diff --git a/src/3rdparty/libpng/png.h b/src/3rdparty/libpng/png.h index 4e0dee1793..372599bfb4 100644 --- a/src/3rdparty/libpng/png.h +++ b/src/3rdparty/libpng/png.h @@ -1,8 +1,9 @@ /* png.h - header file for PNG reference library * - * libpng version 1.5.10 - March 29, 2012 - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * libpng version 1.6.17, March 26, 2015 + * + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -11,7 +12,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.5.10 - March 29, 2012: Glenn + * libpng versions 0.97, January 1998, through 1.6.17, March 26, 2015: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -166,14 +167,55 @@ * 1.5.7beta01-05 15 10507 15.so.15.7[.0] * 1.5.7rc01-03 15 10507 15.so.15.7[.0] * 1.5.7 15 10507 15.so.15.7[.0] - * 1.5.8beta01 15 10508 15.so.15.8[.0] - * 1.5.8rc01 15 10508 15.so.15.8[.0] - * 1.5.8 15 10508 15.so.15.8[.0] - * 1.5.9beta01-02 15 10509 15.so.15.9[.0] - * 1.5.9rc01 15 10509 15.so.15.9[.0] - * 1.5.9 15 10509 15.so.15.9[.0] - * 1.5.10beta01-05 15 10510 15.so.15.10[.0] - * 1.5.10 15 10510 15.so.15.10[.0] + * 1.6.0beta01-40 16 10600 16.so.16.0[.0] + * 1.6.0rc01-08 16 10600 16.so.16.0[.0] + * 1.6.0 16 10600 16.so.16.0[.0] + * 1.6.1beta01-09 16 10601 16.so.16.1[.0] + * 1.6.1rc01 16 10601 16.so.16.1[.0] + * 1.6.1 16 10601 16.so.16.1[.0] + * 1.6.2beta01 16 10602 16.so.16.2[.0] + * 1.6.2rc01-06 16 10602 16.so.16.2[.0] + * 1.6.2 16 10602 16.so.16.2[.0] + * 1.6.3beta01-11 16 10603 16.so.16.3[.0] + * 1.6.3rc01 16 10603 16.so.16.3[.0] + * 1.6.3 16 10603 16.so.16.3[.0] + * 1.6.4beta01-02 16 10604 16.so.16.4[.0] + * 1.6.4rc01 16 10604 16.so.16.4[.0] + * 1.6.4 16 10604 16.so.16.4[.0] + * 1.6.5 16 10605 16.so.16.5[.0] + * 1.6.6 16 10606 16.so.16.6[.0] + * 1.6.7beta01-04 16 10607 16.so.16.7[.0] + * 1.6.7rc01-03 16 10607 16.so.16.7[.0] + * 1.6.7 16 10607 16.so.16.7[.0] + * 1.6.8beta01-02 16 10608 16.so.16.8[.0] + * 1.6.8rc01-02 16 10608 16.so.16.8[.0] + * 1.6.8 16 10608 16.so.16.8[.0] + * 1.6.9beta01-04 16 10609 16.so.16.9[.0] + * 1.6.9rc01-02 16 10609 16.so.16.9[.0] + * 1.6.9 16 10609 16.so.16.9[.0] + * 1.6.10beta01-03 16 10610 16.so.16.10[.0] + * 1.6.10rc01-03 16 10610 16.so.16.10[.0] + * 1.6.10 16 10610 16.so.16.10[.0] + * 1.6.11beta01-06 16 10611 16.so.16.11[.0] + * 1.6.11rc01-02 16 10611 16.so.16.11[.0] + * 1.6.11 16 10611 16.so.16.11[.0] + * 1.6.12rc01-03 16 10612 16.so.16.12[.0] + * 1.6.12 16 10612 16.so.16.12[.0] + * 1.6.13beta01-04 16 10613 16.so.16.13[.0] + * 1.6.13rc01-02 16 10613 16.so.16.13[.0] + * 1.6.13 16 10613 16.so.16.13[.0] + * 1.6.14beta01-07 16 10614 16.so.16.14[.0] + * 1.6.14rc01-02 16 10614 16.so.16.14[.0] + * 1.6.14 16 10614 16.so.16.14[.0] + * 1.6.15beta01-08 16 10615 16.so.16.15[.0] + * 1.6.15rc01-03 16 10615 16.so.16.15[.0] + * 1.6.15 16 10615 16.so.16.15[.0] + * 1.6.16beta01-03 16 10616 16.so.16.16[.0] + * 1.6.16rc01-02 16 10616 16.so.16.16[.0] + * 1.6.16 16 10616 16.so.16.16[.0] + * 1.6.17beta01-06 16 10617 16.so.16.17[.0] + * 1.6.17rc01-06 16 10617 16.so.16.17[.0] + * 1.6.17 16 10617 16.so.16.17[.0] * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be @@ -205,8 +247,8 @@ * * This code is released under the libpng license. * - * libpng versions 1.2.6, August 15, 2004, through 1.5.10, March 29, 2012, are - * Copyright (c) 2004, 2006-2012 Glenn Randers-Pehrson, and are + * libpng versions 1.2.6, August 15, 2004, through 1.6.17, March 26, 2015, are + * Copyright (c) 2004, 2006-2015 Glenn Randers-Pehrson, and are * distributed according to the same disclaimer and license as libpng-1.2.5 * with the following individual added to the list of Contributing Authors: * @@ -317,28 +359,30 @@ * Y2K compliance in libpng: * ========================= * - * March 29, 2012 + * March 26, 2015 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. * * This is your unofficial assurance that libpng from version 0.71 and - * upward through 1.5.10 are Y2K compliant. It is my belief that + * upward through 1.6.17 are Y2K compliant. It is my belief that * earlier versions were also Y2K compliant. * * Libpng only has two year fields. One is a 2-byte unsigned integer - * that will hold years up to 65535. The other holds the date in text - * format, and will hold years up to 9999. + * that will hold years up to 65535. The other, which is deprecated, + * holds the date in text format, and will hold years up to 9999. * * The integer is * "png_uint_16 year" in png_time_struct. * * The string is - * "png_char time_buffer" in png_struct + * "char time_buffer[29]" in png_struct. This is no longer used + * in libpng-1.6.x and will be removed from libpng-1.7.0. * * There are seven time-related functions: - * png.c: png_convert_to_rfc_1123() in png.c - * (formerly png_convert_to_rfc_1152() in error) + * png.c: png_convert_to_rfc_1123_buffer() in png.c + * (formerly png_convert_to_rfc_1123() prior to libpng-1.5.x and + * png_convert_to_rfc_1152() in error prior to libpng-0.98) * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c * png_convert_from_time_t() in pngwrite.c * png_get_tIME() in pngget.c @@ -349,8 +393,8 @@ * All handle dates properly in a Y2K environment. The * png_convert_from_time_t() function calls gmtime() to convert from system * clock time, which returns (year - 1900), which we properly convert to - * the full 4-digit year. There is a possibility that applications using - * libpng are not passing 4-digit years into the png_convert_to_rfc_1123() + * the full 4-digit year. There is a possibility that libpng applications + * are not passing 4-digit years into the png_convert_to_rfc_1123_buffer() * function, or that they are incorrectly passing only a 2-digit year * instead of "year - 1900" into the png_convert_from_struct_tm() function, * but this is not under our control. The libpng documentation has always @@ -374,24 +418,26 @@ /* This is not the place to learn how to use libpng. The file libpng-manual.txt * describes how to use libpng, and the file example.c summarizes it * with some code on which to build. This file is useful for looking - * at the actual function definitions and structure components. + * at the actual function definitions and structure components. If that + * file has been stripped from your copy of libpng, you can find it at + * * * If you just need to read a PNG file and don't want to read the documentation * skip to the end of this file and read the section entitled 'simplified API'. */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.5.10" +#define PNG_LIBPNG_VER_STRING "1.6.17" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.5.10 - March 29, 2012\n" + " libpng version 1.6.17 - March 26, 2015\n" -#define PNG_LIBPNG_VER_SONUM 15 -#define PNG_LIBPNG_VER_DLLNUM 15 +#define PNG_LIBPNG_VER_SONUM 16 +#define PNG_LIBPNG_VER_DLLNUM 16 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 -#define PNG_LIBPNG_VER_MINOR 5 -#define PNG_LIBPNG_VER_RELEASE 10 +#define PNG_LIBPNG_VER_MINOR 6 +#define PNG_LIBPNG_VER_RELEASE 17 /* This should match the numeric part of the final component of * PNG_LIBPNG_VER_STRING, omitting any leading zero: @@ -422,7 +468,7 @@ * version 1.0.0 was mis-numbered 100 instead of 10000). From * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ -#define PNG_LIBPNG_VER 10510 /* 1.5.10 */ +#define PNG_LIBPNG_VER 10617 /* 1.6.17 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -435,25 +481,7 @@ #endif #ifndef PNG_VERSION_INFO_ONLY -# ifndef PNG_BUILDING_SYMBOL_TABLE - /* - * Standard header files (not needed for the version info or while - * building symbol table -- see scripts/pnglibconf.dfa) - */ -# ifdef PNG_SETJMP_SUPPORTED -# include -# endif - - /* Need the time information for converting tIME chunks, it - * defines struct tm: - */ -# ifdef PNG_CONVERT_tIME_SUPPORTED - /* "time.h" functions are not supported on all operating systems */ -# include -# endif -# endif - -/* Machine specific configuration. */ + /* Machine specific configuration. */ # include "pngconf.h" #endif @@ -502,6 +530,7 @@ extern "C" { * 2. Type definitions (base types are defined in pngconf.h), structure * definitions. * 3. Exported library functions. + * 4. Simplified API. * * The library source code has additional files (principally pngpriv.h) that * allow configuration of the library. @@ -544,7 +573,48 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char* png_libpng_version_1_5_10; +typedef char* png_libpng_version_1_6_17; + +/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. + * + * png_struct is the cache of information used while reading or writing a single + * PNG file. One of these is always required, although the simplified API + * (below) hides the creation and destruction of it. + */ +typedef struct png_struct_def png_struct; +typedef const png_struct * png_const_structp; +typedef png_struct * png_structp; +typedef png_struct * * png_structpp; + +/* png_info contains information read from or to be written to a PNG file. One + * or more of these must exist while reading or creating a PNG file. The + * information is not used by libpng during read but is used to control what + * gets written when a PNG file is created. "png_get_" function calls read + * information during read and "png_set_" functions calls write information + * when creating a PNG. + * been moved into a separate header file that is not accessible to + * applications. Read libpng-manual.txt or libpng.3 for more info. + */ +typedef struct png_info_def png_info; +typedef png_info * png_infop; +typedef const png_info * png_const_infop; +typedef png_info * * png_infopp; + +/* Types with names ending 'p' are pointer types. The corresponding types with + * names ending 'rp' are identical pointer types except that the pointer is + * marked 'restrict', which means that it is the only pointer to the object + * passed to the function. Applications should not use the 'restrict' types; + * it is always valid to pass 'p' to a pointer with a function argument of the + * corresponding 'rp' type. Different compilers have different rules with + * regard to type matching in the presence of 'restrict'. For backward + * compatibility libpng callbacks never have 'restrict' in their parameters and, + * consequentially, writing portable application code is extremely difficult if + * an attempt is made to use 'restrict'. + */ +typedef png_struct * PNG_RESTRICT png_structrp; +typedef const png_struct * PNG_RESTRICT png_const_structrp; +typedef png_info * PNG_RESTRICT png_inforp; +typedef const png_info * PNG_RESTRICT png_const_inforp; /* Three color definitions. The order of the red, green, and blue, (and the * exact size) is not important, although the size of the fields need to @@ -556,9 +626,9 @@ typedef struct png_color_struct png_byte green; png_byte blue; } png_color; -typedef png_color FAR * png_colorp; -typedef PNG_CONST png_color FAR * png_const_colorp; -typedef png_color FAR * FAR * png_colorpp; +typedef png_color * png_colorp; +typedef const png_color * png_const_colorp; +typedef png_color * * png_colorpp; typedef struct png_color_16_struct { @@ -568,9 +638,9 @@ typedef struct png_color_16_struct png_uint_16 blue; png_uint_16 gray; /* for use in grayscale files */ } png_color_16; -typedef png_color_16 FAR * png_color_16p; -typedef PNG_CONST png_color_16 FAR * png_const_color_16p; -typedef png_color_16 FAR * FAR * png_color_16pp; +typedef png_color_16 * png_color_16p; +typedef const png_color_16 * png_const_color_16p; +typedef png_color_16 * * png_color_16pp; typedef struct png_color_8_struct { @@ -580,9 +650,9 @@ typedef struct png_color_8_struct png_byte gray; /* for use in grayscale files */ png_byte alpha; /* for alpha channel files */ } png_color_8; -typedef png_color_8 FAR * png_color_8p; -typedef PNG_CONST png_color_8 FAR * png_const_color_8p; -typedef png_color_8 FAR * FAR * png_color_8pp; +typedef png_color_8 * png_color_8p; +typedef const png_color_8 * png_const_color_8p; +typedef png_color_8 * * png_color_8pp; /* * The following two structures are used for the in-core representation @@ -596,9 +666,9 @@ typedef struct png_sPLT_entry_struct png_uint_16 alpha; png_uint_16 frequency; } png_sPLT_entry; -typedef png_sPLT_entry FAR * png_sPLT_entryp; -typedef PNG_CONST png_sPLT_entry FAR * png_const_sPLT_entryp; -typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp; +typedef png_sPLT_entry * png_sPLT_entryp; +typedef const png_sPLT_entry * png_const_sPLT_entryp; +typedef png_sPLT_entry * * png_sPLT_entrypp; /* When the depth of the sPLT palette is 8 bits, the color and alpha samples * occupy the LSB of their respective members, and the MSB of each member @@ -612,9 +682,9 @@ typedef struct png_sPLT_struct png_sPLT_entryp entries; /* palette entries */ png_int_32 nentries; /* number of palette entries */ } png_sPLT_t; -typedef png_sPLT_t FAR * png_sPLT_tp; -typedef PNG_CONST png_sPLT_t FAR * png_const_sPLT_tp; -typedef png_sPLT_t FAR * FAR * png_sPLT_tpp; +typedef png_sPLT_t * png_sPLT_tp; +typedef const png_sPLT_t * png_const_sPLT_tp; +typedef png_sPLT_t * * png_sPLT_tpp; #ifdef PNG_TEXT_SUPPORTED /* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, @@ -651,9 +721,9 @@ typedef struct png_text_struct png_charp lang_key; /* keyword translated UTF-8 string, 0 or more chars or a NULL pointer */ } png_text; -typedef png_text FAR * png_textp; -typedef PNG_CONST png_text FAR * png_const_textp; -typedef png_text FAR * FAR * png_textpp; +typedef png_text * png_textp; +typedef const png_text * png_const_textp; +typedef png_text * * png_textpp; #endif /* Supported compression types for text in PNG files (tEXt, and zTXt). @@ -681,49 +751,45 @@ typedef struct png_time_struct png_byte minute; /* minute of hour, 0 - 59 */ png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ } png_time; -typedef png_time FAR * png_timep; -typedef PNG_CONST png_time FAR * png_const_timep; -typedef png_time FAR * FAR * png_timepp; +typedef png_time * png_timep; +typedef const png_time * png_const_timep; +typedef png_time * * png_timepp; -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) || \ - defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_USER_CHUNKS_SUPPORTED) /* png_unknown_chunk is a structure to hold queued chunks for which there is * no specific support. The idea is that we can use this to queue * up private chunks for output even though the library doesn't actually * know about their semantics. + * + * The data in the structure is set by libpng on read and used on write. */ typedef struct png_unknown_chunk_t { - png_byte name[5]; - png_byte *data; + png_byte name[5]; /* Textual chunk name with '\0' terminator */ + png_byte *data; /* Data, should not be modified on read! */ png_size_t size; - /* libpng-using applications should NOT directly modify this byte. */ + /* On write 'location' must be set using the flag values listed below. + * Notice that on read it is set by libpng however the values stored have + * more bits set than are listed below. Always treat the value as a + * bitmask. On write set only one bit - setting multiple bits may cause the + * chunk to be written in multiple places. + */ png_byte location; /* mode of operation at read time */ } - - png_unknown_chunk; -typedef png_unknown_chunk FAR * png_unknown_chunkp; -typedef PNG_CONST png_unknown_chunk FAR * png_const_unknown_chunkp; -typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; -#endif -/* Values for the unknown chunk location byte */ +typedef png_unknown_chunk * png_unknown_chunkp; +typedef const png_unknown_chunk * png_const_unknown_chunkp; +typedef png_unknown_chunk * * png_unknown_chunkpp; +#endif +/* Flag values for the unknown chunk location byte. */ #define PNG_HAVE_IHDR 0x01 #define PNG_HAVE_PLTE 0x02 #define PNG_AFTER_IDAT 0x08 -/* The complete definition of png_info has, as of libpng-1.5.0, - * been moved into a separate header file that is not accessible to - * applications. Read libpng-manual.txt or libpng.3 for more info. - */ -typedef struct png_info_def png_info; -typedef png_info FAR * png_infop; -typedef PNG_CONST png_info FAR * png_const_infop; -typedef png_info FAR * FAR * png_infopp; - /* Maximum positive integer used in PNG is (2^31)-1 */ #define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) #define PNG_UINT_32_MAX ((png_uint_32)(-1)) @@ -839,16 +905,8 @@ typedef struct png_row_info_struct png_byte pixel_depth; /* bits per pixel (depth * channels) */ } png_row_info; -typedef png_row_info FAR * png_row_infop; -typedef png_row_info FAR * FAR * png_row_infopp; - -/* The complete definition of png_struct has, as of libpng-1.5.0, - * been moved into a separate header file that is not accessible to - * applications. Read libpng-manual.txt or libpng.3 for more info. - */ -typedef struct png_struct_def png_struct; -typedef PNG_CONST png_struct FAR * png_const_structp; -typedef png_struct FAR * png_structp; +typedef png_row_info * png_row_infop; +typedef png_row_info * * png_row_infopp; /* These are the function types for the I/O functions and for the functions * that allow the user to override the default I/O functions with his or her @@ -895,7 +953,8 @@ typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, png_unknown_chunkp)); #endif #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); +/* not used anywhere */ +/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */ #endif #ifdef PNG_SETJMP_SUPPORTED @@ -951,8 +1010,6 @@ typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, png_alloc_size_t)); typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); -typedef png_struct FAR * FAR * png_structpp; - /* Section 3: exported functions * Here are the function definitions most commonly used. This is not * the place to find out how to use libpng. See libpng-manual.txt for the @@ -988,7 +1045,7 @@ PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); /* Tell lib we have already handled the first magic bytes. * Handling more than 8 bytes from the beginning of the file is an error. */ -PNG_EXPORT(2, void, png_set_sig_bytes, (png_structp png_ptr, int num_bytes)); +PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes)); /* Check sig[start] through sig[start + num_to_check - 1] to see if it's a * PNG file. Returns zero if the supplied bytes match the 8-byte PNG @@ -1016,9 +1073,9 @@ PNG_EXPORTA(5, png_structp, png_create_write_struct, PNG_ALLOCATED); PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); -PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structp png_ptr, +PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, png_size_t size)); /* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp @@ -1032,10 +1089,10 @@ PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structp png_ptr, * allocated by the library - the call will return NULL on a mismatch * indicating an ABI mismatch. */ -PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structp png_ptr, +PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); # define png_jmpbuf(png_ptr) \ - (*png_set_longjmp_fn((png_ptr), longjmp, sizeof (jmp_buf))) + (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) #else # define png_jmpbuf(png_ptr) \ (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) @@ -1045,12 +1102,12 @@ PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structp png_ptr, * will use it; otherwise it will call PNG_ABORT(). This function was * added in libpng-1.5.0. */ -PNG_EXPORTA(9, void, png_longjmp, (png_structp png_ptr, int val), +PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), PNG_NORETURN); #ifdef PNG_READ_SUPPORTED /* Reset the compression stream */ -PNG_EXPORT(10, int, png_reset_zstream, (png_structp png_ptr)); +PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); #endif /* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ @@ -1068,81 +1125,92 @@ PNG_EXPORTA(12, png_structp, png_create_write_struct_2, #endif /* Write the PNG file signature. */ -PNG_EXPORT(13, void, png_write_sig, (png_structp png_ptr)); +PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); /* Write a PNG chunk - size, type, (optional) data, CRC. */ -PNG_EXPORT(14, void, png_write_chunk, (png_structp png_ptr, png_const_bytep +PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep chunk_name, png_const_bytep data, png_size_t length)); /* Write the start of a PNG chunk - length and chunk name. */ -PNG_EXPORT(15, void, png_write_chunk_start, (png_structp png_ptr, +PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, png_const_bytep chunk_name, png_uint_32 length)); /* Write the data of a PNG chunk started with png_write_chunk_start(). */ -PNG_EXPORT(16, void, png_write_chunk_data, (png_structp png_ptr, +PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, png_const_bytep data, png_size_t length)); /* Finish a chunk started with png_write_chunk_start() (includes CRC). */ -PNG_EXPORT(17, void, png_write_chunk_end, (png_structp png_ptr)); +PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); /* Allocate and initialize the info structure */ -PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_structp png_ptr), +PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), PNG_ALLOCATED); -PNG_EXPORT(19, void, png_info_init_3, (png_infopp info_ptr, - png_size_t png_info_struct_size)); +/* DEPRECATED: this function allowed init structures to be created using the + * default allocation method (typically malloc). Use is deprecated in 1.6.0 and + * the API will be removed in the future. + */ +PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, + png_size_t png_info_struct_size), PNG_DEPRECATED); /* Writes all the PNG information before the image. */ PNG_EXPORT(20, void, png_write_info_before_PLTE, - (png_structp png_ptr, png_infop info_ptr)); + (png_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(21, void, png_write_info, - (png_structp png_ptr, png_infop info_ptr)); + (png_structrp png_ptr, png_const_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the information before the actual image data. */ PNG_EXPORT(22, void, png_read_info, - (png_structp png_ptr, png_infop info_ptr)); + (png_structrp png_ptr, png_inforp info_ptr)); #endif #ifdef PNG_TIME_RFC1123_SUPPORTED -PNG_EXPORT(23, png_const_charp, png_convert_to_rfc1123, - (png_structp png_ptr, + /* Convert to a US string format: there is no localization support in this + * routine. The original implementation used a 29 character buffer in + * png_struct, this will be removed in future versions. + */ +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ +PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, + png_const_timep ptime),PNG_DEPRECATED); +#endif +PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], png_const_timep ptime)); #endif #ifdef PNG_CONVERT_tIME_SUPPORTED /* Convert from a struct tm to png_time */ PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, - PNG_CONST struct tm FAR * ttime)); + const struct tm * ttime)); /* Convert from time_t to png_time. Uses gmtime() */ -PNG_EXPORT(25, void, png_convert_from_time_t, - (png_timep ptime, time_t ttime)); -#endif /* PNG_CONVERT_tIME_SUPPORTED */ +PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); +#endif /* CONVERT_tIME */ #ifdef PNG_READ_EXPAND_SUPPORTED /* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ -PNG_EXPORT(26, void, png_set_expand, (png_structp png_ptr)); -PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structp png_ptr)); -PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structp png_ptr)); -PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structp png_ptr)); +PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); +PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); +PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); +PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED /* Expand to 16-bit channels, forces conversion of palette to RGB and expansion * of a tRNS chunk if present. */ -PNG_EXPORT(221, void, png_set_expand_16, (png_structp png_ptr)); +PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Use blue, green, red order for pixels. */ -PNG_EXPORT(30, void, png_set_bgr, (png_structp png_ptr)); +PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand the grayscale to 24-bit RGB if necessary. */ -PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structp png_ptr)); +PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED @@ -1152,12 +1220,12 @@ PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structp png_ptr)); #define PNG_ERROR_ACTION_ERROR 3 #define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ -PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structp png_ptr, - int error_action, double red, double green)); -PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structp png_ptr, - int error_action, png_fixed_point red, png_fixed_point green)); +PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, + int error_action, double red, double green)) +PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green)) -PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structp +PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp png_ptr)); #endif @@ -1167,9 +1235,9 @@ PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, #endif #ifdef PNG_READ_ALPHA_MODE_SUPPORTED -/* How the alpha channel is interpreted - this affects how the color channels of - * a PNG file are returned when an alpha channel, or tRNS chunk in a palette - * file, is present. +/* How the alpha channel is interpreted - this affects how the color channels + * of a PNG file are returned to the calling application when an alpha channel, + * or a tRNS chunk in a palette file, is present. * * This has no effect on the way pixels are written into a PNG output * datastream. The color samples in a PNG datastream are never premultiplied @@ -1177,33 +1245,19 @@ PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, * * The default is to return data according to the PNG specification: the alpha * channel is a linear measure of the contribution of the pixel to the - * corresponding composited pixel. The gamma encoded color channels must be - * scaled according to the contribution and to do this it is necessary to undo + * corresponding composited pixel, and the color channels are unassociated + * (not premultiplied). The gamma encoded color channels must be scaled + * according to the contribution and to do this it is necessary to undo * the encoding, scale the color values, perform the composition and reencode * the values. This is the 'PNG' mode. * * The alternative is to 'associate' the alpha with the color information by - * storing color channel values that have been scaled by the alpha. The - * advantage is that the color channels can be resampled (the image can be - * scaled) in this form. The disadvantage is that normal practice is to store - * linear, not (gamma) encoded, values and this requires 16-bit channels for - * still images rather than the 8-bit channels that are just about sufficient if - * gamma encoding is used. In addition all non-transparent pixel values, - * including completely opaque ones, must be gamma encoded to produce the final - * image. This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the - * latter being the two common names for associated alpha color channels.) - * - * Since it is not necessary to perform arithmetic on opaque color values so - * long as they are not to be resampled and are in the final color space it is - * possible to optimize the handling of alpha by storing the opaque pixels in - * the PNG format (adjusted for the output color space) while storing partially - * opaque pixels in the standard, linear, format. The accuracy required for - * standard alpha composition is relatively low, because the pixels are - * isolated, therefore typically the accuracy loss in storing 8-bit linear - * values is acceptable. (This is not true if the alpha channel is used to - * simulate transparency over large areas - use 16 bits or the PNG mode in - * this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is - * treated as opaque only if the alpha value is equal to the maximum value. + * storing color channel values that have been scaled by the alpha. + * image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes + * (the latter being the two common names for associated alpha color channels). + * + * For the 'OPTIMIZED' mode, a pixel is treated as opaque only if the alpha + * value is equal to the maximum value. * * The final choice is to gamma encode the alpha channel as well. This is * broken because, in practice, no implementation that uses this choice @@ -1222,76 +1276,15 @@ PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, #define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ #define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ -PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structp png_ptr, int mode, - double output_gamma)); -PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structp png_ptr, - int mode, png_fixed_point output_gamma)); +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, + double output_gamma)) +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, + int mode, png_fixed_point output_gamma)) #endif -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* The output_gamma value is a screen gamma in libpng terminology: it expresses - * how to decode the output values, not how they are encoded. The values used - * correspond to the normal numbers used to describe the overall gamma of a - * computer display system; for example 2.2 for an sRGB conformant system. The - * values are scaled by 100000 in the _fixed version of the API (so 220000 for - * sRGB.) - * - * The inverse of the value is always used to provide a default for the PNG file - * encoding if it has no gAMA chunk and if png_set_gamma() has not been called - * to override the PNG gamma information. - * - * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode - * opaque pixels however pixels with lower alpha values are not encoded, - * regardless of the output gamma setting. - * - * When the standard Porter Duff handling is requested with mode 1 the output - * encoding is set to be linear and the output_gamma value is only relevant - * as a default for input data that has no gamma information. The linear output - * encoding will be overridden if png_set_gamma() is called - the results may be - * highly unexpected! - * - * The following numbers are derived from the sRGB standard and the research - * behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of - * 0.45455 (1/2.2) for PNG. The value implicitly includes any viewing - * correction required to take account of any differences in the color - * environment of the original scene and the intended display environment; the - * value expresses how to *decode* the image for display, not how the original - * data was *encoded*. - * - * sRGB provides a peg for the PNG standard by defining a viewing environment. - * sRGB itself, and earlier TV standards, actually use a more complex transform - * (a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is - * limited to simple power laws.) By saying that an image for direct display on - * an sRGB conformant system should be stored with a gAMA chunk value of 45455 - * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification - * makes it possible to derive values for other display systems and - * environments. - * - * The Mac value is deduced from the sRGB based on an assumption that the actual - * extra viewing correction used in early Mac display systems was implemented as - * a power 1.45 lookup table. - * - * Any system where a programmable lookup table is used or where the behavior of - * the final display device characteristics can be changed requires system - * specific code to obtain the current characteristic. However this can be - * difficult and most PNG gamma correction only requires an approximate value. - * - * By default, if png_set_alpha_mode() is not called, libpng assumes that all - * values are unencoded, linear, values and that the output device also has a - * linear characteristic. This is only very rarely correct - it is invariably - * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the - * default if you don't know what the right answer is! - * - * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS - * 10.6) which used a correction table to implement a somewhat lower gamma on an - * otherwise sRGB system. - * - * Both these values are reserved (not simple gamma values) in order to allow - * more precise correction internally in the future. - * - * NOTE: the following values can be passed to either the fixed or floating - * point APIs, but the floating point API will also accept floating point - * values. + * how to decode the output values, not how they are encoded. */ #define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ #define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ @@ -1376,51 +1369,50 @@ PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structp png_ptr, */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED -PNG_EXPORT(36, void, png_set_strip_alpha, (png_structp png_ptr)); +PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -PNG_EXPORT(37, void, png_set_swap_alpha, (png_structp png_ptr)); +PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -PNG_EXPORT(38, void, png_set_invert_alpha, (png_structp png_ptr)); +PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) /* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ -PNG_EXPORT(39, void, png_set_filler, (png_structp png_ptr, png_uint_32 filler, +PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler, int flags)); /* The values of the PNG_FILLER_ defines should NOT be changed */ # define PNG_FILLER_BEFORE 0 # define PNG_FILLER_AFTER 1 /* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ -PNG_EXPORT(40, void, png_set_add_alpha, - (png_structp png_ptr, png_uint_32 filler, - int flags)); -#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ +PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, + png_uint_32 filler, int flags)); +#endif /* READ_FILLER || WRITE_FILLER */ #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Swap bytes in 16-bit depth files. */ -PNG_EXPORT(41, void, png_set_swap, (png_structp png_ptr)); +PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr)); #endif #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) /* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ -PNG_EXPORT(42, void, png_set_packing, (png_structp png_ptr)); +PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ defined(PNG_WRITE_PACKSWAP_SUPPORTED) /* Swap packing order of pixels in bytes. */ -PNG_EXPORT(43, void, png_set_packswap, (png_structp png_ptr)); +PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) /* Converts files to legal bit depths. */ -PNG_EXPORT(44, void, png_set_shift, (png_structp png_ptr, png_const_color_8p +PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p true_bits)); #endif @@ -1432,12 +1424,12 @@ PNG_EXPORT(44, void, png_set_shift, (png_structp png_ptr, png_const_color_8p * necessary to call png_read_row or png_read_rows png_get_image_height * times for each pass. */ -PNG_EXPORT(45, int, png_set_interlace_handling, (png_structp png_ptr)); +PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) /* Invert monochrome files */ -PNG_EXPORT(46, void, png_set_invert_mono, (png_structp png_ptr)); +PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED @@ -1446,12 +1438,12 @@ PNG_EXPORT(46, void, png_set_invert_mono, (png_structp png_ptr)); * read. Doing so will result in unexpected behavior and possible warnings or * errors if the PNG file contains a bKGD chunk. */ -PNG_FP_EXPORT(47, void, png_set_background, (png_structp png_ptr, +PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, - int need_expand, double background_gamma)); -PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structp png_ptr, + int need_expand, double background_gamma)) +PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, - int need_expand, png_fixed_point background_gamma)); + int need_expand, png_fixed_point background_gamma)) #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED # define PNG_BACKGROUND_GAMMA_UNKNOWN 0 @@ -1462,23 +1454,22 @@ PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structp png_ptr, #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale a 16-bit depth file down to 8-bit, accurately. */ -PNG_EXPORT(229, void, png_set_scale_16, (png_structp png_ptr)); +PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED #define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */ /* Strip the second byte of information from a 16-bit depth file. */ -PNG_EXPORT(48, void, png_set_strip_16, (png_structp png_ptr)); +PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED /* Turn on quantizing, and reduce the palette to the number of colors * available. */ -PNG_EXPORT(49, void, png_set_quantize, - (png_structp png_ptr, png_colorp palette, - int num_palette, int maximum_colors, png_const_uint_16p histogram, - int full_quantize)); +PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_const_uint_16p histogram, int full_quantize)); #endif #ifdef PNG_READ_GAMMA_SUPPORTED @@ -1498,71 +1489,69 @@ PNG_EXPORT(49, void, png_set_quantize, * API (floating point or fixed.) Notice, however, that the 'file_gamma' value * is the inverse of a 'screen gamma' value. */ -PNG_FP_EXPORT(50, void, png_set_gamma, - (png_structp png_ptr, double screen_gamma, - double override_file_gamma)); -PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structp png_ptr, - png_fixed_point screen_gamma, png_fixed_point override_file_gamma)); +PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, + double screen_gamma, double override_file_gamma)) +PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, + png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) #endif #ifdef PNG_WRITE_FLUSH_SUPPORTED /* Set how many lines between output flushes - 0 for no flushing */ -PNG_EXPORT(51, void, png_set_flush, (png_structp png_ptr, int nrows)); +PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); /* Flush the current PNG output buffer */ -PNG_EXPORT(52, void, png_write_flush, (png_structp png_ptr)); +PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); #endif /* Optional update palette with requested transformations */ -PNG_EXPORT(53, void, png_start_read_image, (png_structp png_ptr)); +PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); /* Optional call to update the users info structure */ -PNG_EXPORT(54, void, png_read_update_info, - (png_structp png_ptr, png_infop info_ptr)); +PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, + png_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. */ -PNG_EXPORT(55, void, png_read_rows, (png_structp png_ptr, png_bytepp row, +PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read a row of data. */ -PNG_EXPORT(56, void, png_read_row, (png_structp png_ptr, png_bytep row, +PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, png_bytep display_row)); #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the whole image into memory at once. */ -PNG_EXPORT(57, void, png_read_image, (png_structp png_ptr, png_bytepp image)); +PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); #endif /* Write a row of image data */ -PNG_EXPORT(58, void, png_write_row, - (png_structp png_ptr, png_const_bytep row)); +PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, + png_const_bytep row)); /* Write a few rows of image data: (*row) is not written; however, the type * is declared as writeable to maintain compatibility with previous versions * of libpng and to allow the 'display_row' array from read_rows to be passed * unchanged to write_rows. */ -PNG_EXPORT(59, void, png_write_rows, (png_structp png_ptr, png_bytepp row, +PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, png_uint_32 num_rows)); /* Write the image data */ -PNG_EXPORT(60, void, png_write_image, - (png_structp png_ptr, png_bytepp image)); +PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); /* Write the end of the PNG file. */ -PNG_EXPORT(61, void, png_write_end, - (png_structp png_ptr, png_infop info_ptr)); +PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, + png_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. */ -PNG_EXPORT(62, void, png_read_end, (png_structp png_ptr, png_infop info_ptr)); +PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); #endif /* Free any memory associated with the png_info_struct */ -PNG_EXPORT(63, void, png_destroy_info_struct, (png_structp png_ptr, +PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, png_infopp info_ptr_ptr)); /* Free any memory associated with the png_struct and the png_info_structs */ @@ -1574,8 +1563,8 @@ PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); /* Set the libpng method of handling chunk CRC errors */ -PNG_EXPORT(66, void, png_set_crc_action, - (png_structp png_ptr, int crit_action, int ancil_action)); +PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, + int ancil_action)); /* Values for png_set_crc_action() say how to handle CRC errors in * ancillary and critical chunks, and whether to use the data contained @@ -1593,6 +1582,7 @@ PNG_EXPORT(66, void, png_set_crc_action, #define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ #define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ +#ifdef PNG_WRITE_SUPPORTED /* These functions give the user control over the scan-line filtering in * libpng and the compression methods used by zlib. These functions are * mainly useful for testing, as the defaults should work with most users. @@ -1604,8 +1594,9 @@ PNG_EXPORT(66, void, png_set_crc_action, /* Set the filtering method(s) used by libpng. Currently, the only valid * value for "method" is 0. */ -PNG_EXPORT(67, void, png_set_filter, - (png_structp png_ptr, int method, int filters)); +PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, + int filters)); +#endif /* WRITE */ /* Flags for png_set_filter() to say which filters to use. The flags * are chosen so that they don't conflict with real filter types @@ -1631,6 +1622,7 @@ PNG_EXPORT(67, void, png_set_filter, #define PNG_FILTER_VALUE_PAETH 4 #define PNG_FILTER_VALUE_LAST 5 +#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ /* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ * defines, either the default (minimum-sum-of-absolute-differences), or @@ -1660,14 +1652,14 @@ PNG_EXPORT(67, void, png_set_filter, * the weights and costs are set to 1.0, this degenerates the WEIGHTED method * to the UNWEIGHTED method, but with added encoding time/computation. */ -PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structp png_ptr, +PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, int heuristic_method, int num_weights, png_const_doublep filter_weights, - png_const_doublep filter_costs)); + png_const_doublep filter_costs)) PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, - (png_structp png_ptr, - int heuristic_method, int num_weights, png_const_fixed_point_p - filter_weights, png_const_fixed_point_p filter_costs)); -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + (png_structrp png_ptr, int heuristic_method, int num_weights, + png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs)) +#endif /* WRITE_WEIGHTED_FILTER */ /* Heuristic used for row filter selection. These defines should NOT be * changed. @@ -1677,7 +1669,6 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, #define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ #define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ -#ifdef PNG_WRITE_SUPPORTED /* Set the library compression level. Currently, valid values range from * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 * (0 - no compression, 9 - "maximal" compression). Note that tests have @@ -1685,45 +1676,47 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, * for PNG images, and do considerably fewer caclulations. In the future, * these values may not correspond directly to the zlib compression levels. */ -PNG_EXPORT(69, void, png_set_compression_level, - (png_structp png_ptr, int level)); +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED +PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, + int level)); -PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structp png_ptr, +PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, int mem_level)); -PNG_EXPORT(71, void, png_set_compression_strategy, (png_structp png_ptr, +PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, int strategy)); /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a * smaller value of window_bits if it can do so safely. */ -PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structp png_ptr, +PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, int window_bits)); -PNG_EXPORT(73, void, png_set_compression_method, (png_structp png_ptr, +PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, int method)); -#endif +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED /* Also set zlib parameters for compressing non-IDAT chunks */ -PNG_EXPORT(222, void, png_set_text_compression_level, - (png_structp png_ptr, int level)); +PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, + int level)); -PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structp png_ptr, +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, int mem_level)); -PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structp png_ptr, +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, int strategy)); /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a * smaller value of window_bits if it can do so safely. */ -PNG_EXPORT(225, void, png_set_text_compression_window_bits, (png_structp - png_ptr, int window_bits)); +PNG_EXPORT(225, void, png_set_text_compression_window_bits, + (png_structrp png_ptr, int window_bits)); -PNG_EXPORT(226, void, png_set_text_compression_method, (png_structp png_ptr, +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, int method)); -#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +#endif /* WRITE */ /* These next functions are called for input/output, memory, and error * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, @@ -1736,7 +1729,7 @@ PNG_EXPORT(226, void, png_set_text_compression_method, (png_structp png_ptr, #ifdef PNG_STDIO_SUPPORTED /* Initialize the input/output for the PNG file to the default functions. */ -PNG_EXPORT(74, void, png_init_io, (png_structp png_ptr, png_FILE_p fp)); +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp)); #endif /* Replace the (error and abort), and warning functions with user @@ -1747,12 +1740,11 @@ PNG_EXPORT(74, void, png_init_io, (png_structp png_ptr, png_FILE_p fp)); * default function will be used. */ -PNG_EXPORT(75, void, png_set_error_fn, - (png_structp png_ptr, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warning_fn)); +PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); /* Return the user pointer associated with the error functions */ -PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structp png_ptr)); +PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr)); /* Replace the default data output functions with a user supplied one(s). * If buffered output is not used, then output_flush_fn can be set to NULL. @@ -1764,47 +1756,47 @@ PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structp png_ptr)); * default flush function, which uses the standard *FILE structure, will * be used. */ -PNG_EXPORT(77, void, png_set_write_fn, (png_structp png_ptr, png_voidp io_ptr, +PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); /* Replace the default data input function with a user supplied one. */ -PNG_EXPORT(78, void, png_set_read_fn, (png_structp png_ptr, png_voidp io_ptr, +PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn)); /* Return the user pointer associated with the I/O functions */ -PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_structp png_ptr)); +PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); -PNG_EXPORT(80, void, png_set_read_status_fn, (png_structp png_ptr, +PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, png_read_status_ptr read_row_fn)); -PNG_EXPORT(81, void, png_set_write_status_fn, (png_structp png_ptr, +PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr, png_write_status_ptr write_row_fn)); #ifdef PNG_USER_MEM_SUPPORTED /* Replace the default memory allocation functions with user supplied one(s). */ -PNG_EXPORT(82, void, png_set_mem_fn, (png_structp png_ptr, png_voidp mem_ptr, +PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); /* Return the user pointer associated with the memory functions */ -PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structp png_ptr)); +PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); #endif #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED -PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structp png_ptr, +PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, png_user_transform_ptr read_user_transform_fn)); #endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED -PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structp png_ptr, +PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn)); #endif #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED -PNG_EXPORT(86, void, png_set_user_transform_info, (png_structp png_ptr, +PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr, png_voidp user_transform_ptr, int user_transform_depth, int user_transform_channels)); /* Return the user pointer associated with the user transform functions */ PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); #endif #ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED @@ -1819,31 +1811,53 @@ PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, * find the output pixel (x,y) given an interlaced sub-image pixel * (row,col,pass). (See below for these macros.) */ -PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structp)); -PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structp)); +PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); +PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); #endif -#ifdef PNG_USER_CHUNKS_SUPPORTED -PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structp png_ptr, +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +/* This callback is called only for *unknown* chunks. If + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known + * chunks to be treated as unknown, however in this case the callback must do + * any processing required by the chunk (e.g. by calling the appropriate + * png_set_ APIs.) + * + * There is no write support - on write, by default, all the chunks in the + * 'unknown' list are written in the specified position. + * + * The integer return from the callback function is interpreted thus: + * + * negative: An error occurred; png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be saved. A critical + * chunk will cause an error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + * + * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about + * how this behavior will change in libpng 1.7 + */ +PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); -PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structp png_ptr)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr)); #endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED /* Sets the function callbacks for the push reader, and a pointer to a * user-defined structure available to the callback functions. */ -PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structp png_ptr, +PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr, png_voidp progressive_ptr, png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); /* Returns the user pointer associated with the push read functions */ -PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, (png_const_structp png_ptr)); +PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, + (png_const_structrp png_ptr)); /* Function to be called when data becomes available */ -PNG_EXPORT(92, void, png_process_data, - (png_structp png_ptr, png_infop info_ptr, - png_bytep buffer, png_size_t buffer_size)); +PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, + png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size)); /* A function which may be called *only* within png_process_data to stop the * processing of any more data. The function returns the number of bytes @@ -1852,7 +1866,7 @@ PNG_EXPORT(92, void, png_process_data, * 'save' is set to true the routine will first save all the pending data and * will always return 0. */ -PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structp, int save)); +PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save)); /* A function which may be called *only* outside (after) a call to * png_process_data. It returns the number of bytes of data to skip in the @@ -1860,42 +1874,43 @@ PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structp, int save)); * application must skip than number of bytes of input data and pass the * following data to the next call to png_process_data. */ -PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structp)); +PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); -#ifdef PNG_READ_INTERLACING_SUPPORTED /* Function that combines rows. 'new_row' is a flag that should come from * the callback and be non-NULL if anything needs to be done; the library * stores its own version of the new data internally and ignores the passed * in value. */ -PNG_EXPORT(93, void, png_progressive_combine_row, (png_structp png_ptr, +PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, png_bytep old_row, png_const_bytep new_row)); -#endif /* PNG_READ_INTERLACING_SUPPORTED */ -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PROGRESSIVE_READ */ -PNG_EXPORTA(94, png_voidp, png_malloc, - (png_structp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED); +PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); /* Added at libpng version 1.4.0 */ -PNG_EXPORTA(95, png_voidp, png_calloc, - (png_structp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED); +PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); /* Added at libpng version 1.2.4 */ -PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_structp png_ptr, +PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, png_alloc_size_t size), PNG_ALLOCATED); /* Frees a pointer allocated by png_malloc() */ -PNG_EXPORT(97, void, png_free, (png_structp png_ptr, png_voidp ptr)); +PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); /* Free data that was allocated internally */ -PNG_EXPORT(98, void, png_free_data, - (png_structp png_ptr, png_infop info_ptr, png_uint_32 free_me, int num)); +PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 free_me, int num)); /* Reassign responsibility for freeing existing data, whether allocated - * by libpng or by the application */ -PNG_EXPORT(99, void, png_data_freer, - (png_structp png_ptr, png_infop info_ptr, int freer, png_uint_32 mask)); + * by libpng or by the application; this works on the png_info structure passed + * in, it does not change the state for other png_info structures. + * + * It is unlikely that this function works correctly as of 1.6.0 and using it + * may result either in memory leaks or double free of allocated data. + */ +PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr, + png_inforp info_ptr, int freer, png_uint_32 mask)); /* Assignments for png_data_freer */ #define PNG_DESTROY_WILL_FREE_DATA 1 @@ -1908,8 +1923,10 @@ PNG_EXPORT(99, void, png_data_freer, #define PNG_FREE_ROWS 0x0040 #define PNG_FREE_PCAL 0x0080 #define PNG_FREE_SCAL 0x0100 -#define PNG_FREE_UNKN 0x0200 -#define PNG_FREE_LIST 0x0400 +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_FREE_UNKN 0x0200 +#endif +/* PNG_FREE_LIST 0x0400 removed in 1.6.0 because it is ignored */ #define PNG_FREE_PLTE 0x1000 #define PNG_FREE_TRNS 0x2000 #define PNG_FREE_TEXT 0x4000 @@ -1917,50 +1934,55 @@ PNG_EXPORT(99, void, png_data_freer, #define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ #ifdef PNG_USER_MEM_SUPPORTED -PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_structp png_ptr, - png_alloc_size_t size), PNG_ALLOCATED); -PNG_EXPORT(101, void, png_free_default, (png_structp png_ptr, png_voidp ptr)); +PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); +PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, + png_voidp ptr), PNG_DEPRECATED); #endif #ifdef PNG_ERROR_TEXT_SUPPORTED /* Fatal error in PNG image of libpng - can't continue */ -PNG_EXPORTA(102, void, png_error, - (png_structp png_ptr, png_const_charp error_message), - PNG_NORETURN); +PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); /* The same, but the chunk name is prepended to the error string. */ -PNG_EXPORTA(103, void, png_chunk_error, (png_structp png_ptr, +PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN); #else /* Fatal error in PNG image of libpng - can't continue */ -PNG_EXPORTA(104, void, png_err, (png_structp png_ptr), PNG_NORETURN); +PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); +# define png_error(s1,s2) png_err(s1) +# define png_chunk_error(s1,s2) png_err(s1) #endif #ifdef PNG_WARNINGS_SUPPORTED /* Non-fatal error in libpng. Can continue, but may have a problem. */ -PNG_EXPORT(105, void, png_warning, (png_structp png_ptr, +PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, png_const_charp warning_message)); /* Non-fatal error in libpng, chunk name is prepended to message. */ -PNG_EXPORT(106, void, png_chunk_warning, (png_structp png_ptr, +PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, png_const_charp warning_message)); +#else +# define png_warning(s1,s2) ((void)(s1)) +# define png_chunk_warning(s1,s2) ((void)(s1)) #endif #ifdef PNG_BENIGN_ERRORS_SUPPORTED /* Benign error in libpng. Can continue, but may have a problem. * User can choose whether to handle as a fatal error or as a warning. */ -# undef png_benign_error -PNG_EXPORT(107, void, png_benign_error, (png_structp png_ptr, +PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, png_const_charp warning_message)); -/* Same, chunk name is prepended to message. */ -# undef png_chunk_benign_error -PNG_EXPORT(108, void, png_chunk_benign_error, (png_structp png_ptr, +#ifdef PNG_READ_SUPPORTED +/* Same, chunk name is prepended to message (only during read) */ +PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, png_const_charp warning_message)); +#endif PNG_EXPORT(109, void, png_set_benign_errors, - (png_structp png_ptr, int allowed)); + (png_structrp png_ptr, int allowed)); #else # ifdef PNG_ALLOW_BENIGN_ERRORS # define png_benign_error png_warning @@ -1984,289 +2006,274 @@ PNG_EXPORT(109, void, png_set_benign_errors, * png_info_struct. */ /* Returns "flag" if chunk data is valid in info_ptr. */ -PNG_EXPORT(110, png_uint_32, png_get_valid, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_uint_32 flag)); +PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 flag)); /* Returns number of bytes needed to hold a transformed row. */ -PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structp png_ptr, - png_const_infop info_ptr)); +PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); #ifdef PNG_INFO_IMAGE_SUPPORTED /* Returns row_pointers, which is an array of pointers to scanlines that was * returned from png_read_png(). */ -PNG_EXPORT(112, png_bytepp, png_get_rows, - (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + /* Set row_pointers, which is an array of pointers to scanlines for use * by png_write_png(). */ -PNG_EXPORT(113, void, png_set_rows, (png_structp png_ptr, - png_infop info_ptr, png_bytepp row_pointers)); +PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytepp row_pointers)); #endif /* Returns number of color channels in image. */ -PNG_EXPORT(114, png_byte, png_get_channels, - (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); #ifdef PNG_EASY_ACCESS_SUPPORTED /* Returns image width in pixels. */ -PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structp png_ptr, - png_const_infop info_ptr)); +PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image height in pixels. */ -PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structp png_ptr, - png_const_infop info_ptr)); +PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image bit_depth. */ -PNG_EXPORT(117, png_byte, png_get_bit_depth, - (png_const_structp png_ptr, png_const_infop info_ptr)); +PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image color_type. */ -PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structp png_ptr, - png_const_infop info_ptr)); +PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image filter_type. */ -PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structp png_ptr, - png_const_infop info_ptr)); +PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image interlace_type. */ -PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structp png_ptr, - png_const_infop info_ptr)); +PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image compression_type. */ -PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structp png_ptr, - png_const_infop info_ptr)); +PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image resolution in pixels per meter, from pHYs chunk data. */ PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns pixel aspect ratio, computed from pHYs chunk data. */ PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)) PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)) /* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); -#endif /* PNG_EASY_ACCESS_SUPPORTED */ +#endif /* EASY_ACCESS */ +#ifdef PNG_READ_SUPPORTED /* Returns pointer to signature string read from PNG header */ -PNG_EXPORT(130, png_const_bytep, png_get_signature, - (png_const_structp png_ptr, png_infop info_ptr)); +PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); +#endif #ifdef PNG_bKGD_SUPPORTED -PNG_EXPORT(131, png_uint_32, png_get_bKGD, - (png_const_structp png_ptr, png_infop info_ptr, - png_color_16p *background)); +PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_16p *background)); #endif #ifdef PNG_bKGD_SUPPORTED -PNG_EXPORT(132, void, png_set_bKGD, (png_structp png_ptr, png_infop info_ptr, - png_const_color_16p background)); +PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_16p background)); #endif #ifdef PNG_cHRM_SUPPORTED -PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structp png_ptr, - png_const_infop info_ptr, double *white_x, double *white_y, double *red_x, +PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, double *red_y, double *green_x, double *green_y, double *blue_x, - double *blue_y)); -PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_structp png_ptr, - png_const_infop info_ptr, double *red_X, double *red_Y, double *red_Z, + double *blue_y)) +PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, double *green_X, double *green_Y, double *green_Z, double *blue_X, - double *blue_Y, double *blue_Z)); -#ifdef PNG_FIXED_POINT_SUPPORTED /* Otherwise not implemented */ + double *blue_Y, double *blue_Z)) PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, - (png_const_structp png_ptr, - png_const_infop info_ptr, png_fixed_point *int_white_x, - png_fixed_point *int_white_y, png_fixed_point *int_red_x, - png_fixed_point *int_red_y, png_fixed_point *int_green_x, - png_fixed_point *int_green_y, png_fixed_point *int_blue_x, - png_fixed_point *int_blue_y)); -#endif + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_white_x, png_fixed_point *int_white_y, + png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, + png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)) PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, - (png_structp png_ptr, png_const_infop info_ptr, + (png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_red_X, png_fixed_point *int_red_Y, png_fixed_point *int_red_Z, png_fixed_point *int_green_X, png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, - png_fixed_point *int_blue_Z)); + png_fixed_point *int_blue_Z)) #endif #ifdef PNG_cHRM_SUPPORTED -PNG_FP_EXPORT(135, void, png_set_cHRM, - (png_structp png_ptr, png_infop info_ptr, +PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, - double green_y, double blue_x, double blue_y)); -PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_structp png_ptr, - png_infop info_ptr, double red_X, double red_Y, double red_Z, + double green_y, double blue_x, double blue_y)) +PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, + png_inforp info_ptr, double red_X, double red_Y, double red_Z, double green_X, double green_Y, double green_Z, double blue_X, - double blue_Y, double blue_Z)); -PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_structp png_ptr, - png_infop info_ptr, png_fixed_point int_white_x, + double blue_Y, double blue_Z)) +PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); -PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_structp png_ptr, - png_infop info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_blue_y)) +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, png_fixed_point int_red_Z, png_fixed_point int_green_X, png_fixed_point int_green_Y, png_fixed_point int_green_Z, png_fixed_point int_blue_X, png_fixed_point int_blue_Y, - png_fixed_point int_blue_Z)); + png_fixed_point int_blue_Z)) #endif #ifdef PNG_gAMA_SUPPORTED -PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, - (png_const_structp png_ptr, png_const_infop info_ptr, - double *file_gamma)); +PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *file_gamma)) PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_fixed_point *int_file_gamma)); + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_file_gamma)) #endif #ifdef PNG_gAMA_SUPPORTED -PNG_FP_EXPORT(139, void, png_set_gAMA, (png_structp png_ptr, - png_infop info_ptr, double file_gamma)); -PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_structp png_ptr, - png_infop info_ptr, png_fixed_point int_file_gamma)); +PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, + png_inforp info_ptr, double file_gamma)) +PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_file_gamma)) #endif #ifdef PNG_hIST_SUPPORTED -PNG_EXPORT(141, png_uint_32, png_get_hIST, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_uint_16p *hist)); +PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_16p *hist)); #endif #ifdef PNG_hIST_SUPPORTED -PNG_EXPORT(142, void, png_set_hIST, (png_structp png_ptr, - png_infop info_ptr, png_const_uint_16p hist)); +PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_uint_16p hist)); #endif -PNG_EXPORT(143, png_uint_32, png_get_IHDR, - (png_structp png_ptr, png_infop info_ptr, - png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, - int *interlace_method, int *compression_method, int *filter_method)); +PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); -PNG_EXPORT(144, void, png_set_IHDR, - (png_structp png_ptr, png_infop info_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, - int interlace_method, int compression_method, int filter_method)); +PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); #ifdef PNG_oFFs_SUPPORTED -PNG_EXPORT(145, png_uint_32, png_get_oFFs, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)); +PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); #endif #ifdef PNG_oFFs_SUPPORTED -PNG_EXPORT(146, void, png_set_oFFs, - (png_structp png_ptr, png_infop info_ptr, - png_int_32 offset_x, png_int_32 offset_y, int unit_type)); +PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); #endif #ifdef PNG_pCAL_SUPPORTED -PNG_EXPORT(147, png_uint_32, png_get_pCAL, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, - int *nparams, - png_charp *units, png_charpp *params)); +PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, + png_int_32 *X1, int *type, int *nparams, png_charp *units, + png_charpp *params)); #endif #ifdef PNG_pCAL_SUPPORTED -PNG_EXPORT(148, void, png_set_pCAL, (png_structp png_ptr, - png_infop info_ptr, - png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, - int nparams, png_const_charp units, png_charpp params)); +PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_const_charp units, png_charpp params)); #endif #ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(149, png_uint_32, png_get_pHYs, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); #endif #ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(150, void, png_set_pHYs, - (png_structp png_ptr, png_infop info_ptr, - png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); #endif -PNG_EXPORT(151, png_uint_32, png_get_PLTE, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_colorp *palette, int *num_palette)); +PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, + png_inforp info_ptr, png_colorp *palette, int *num_palette)); -PNG_EXPORT(152, void, png_set_PLTE, - (png_structp png_ptr, png_infop info_ptr, - png_const_colorp palette, int num_palette)); +PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, + png_inforp info_ptr, png_const_colorp palette, int num_palette)); #ifdef PNG_sBIT_SUPPORTED -PNG_EXPORT(153, png_uint_32, png_get_sBIT, - (png_const_structp png_ptr, png_infop info_ptr, - png_color_8p *sig_bit)); +PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_8p *sig_bit)); #endif #ifdef PNG_sBIT_SUPPORTED -PNG_EXPORT(154, void, png_set_sBIT, - (png_structp png_ptr, png_infop info_ptr, png_const_color_8p sig_bit)); +PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_8p sig_bit)); #endif #ifdef PNG_sRGB_SUPPORTED -PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structp png_ptr, - png_const_infop info_ptr, int *file_srgb_intent)); +PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *file_srgb_intent)); #endif #ifdef PNG_sRGB_SUPPORTED -PNG_EXPORT(156, void, png_set_sRGB, - (png_structp png_ptr, png_infop info_ptr, int srgb_intent)); -PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_structp png_ptr, - png_infop info_ptr, int srgb_intent)); +PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); #endif #ifdef PNG_iCCP_SUPPORTED -PNG_EXPORT(158, png_uint_32, png_get_iCCP, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_charpp name, int *compression_type, png_bytepp profile, - png_uint_32 *proflen)); +PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen)); #endif #ifdef PNG_iCCP_SUPPORTED -PNG_EXPORT(159, void, png_set_iCCP, - (png_structp png_ptr, png_infop info_ptr, - png_const_charp name, int compression_type, png_const_bytep profile, - png_uint_32 proflen)); +PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen)); #endif #ifdef PNG_sPLT_SUPPORTED -PNG_EXPORT(160, png_uint_32, png_get_sPLT, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_sPLT_tpp entries)); +PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_sPLT_tpp entries)); #endif #ifdef PNG_sPLT_SUPPORTED -PNG_EXPORT(161, void, png_set_sPLT, - (png_structp png_ptr, png_infop info_ptr, - png_const_sPLT_tp entries, int nentries)); +PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); #endif #ifdef PNG_TEXT_SUPPORTED /* png_get_text also returns the number of text chunks in *num_text */ -PNG_EXPORT(162, png_uint_32, png_get_text, - (png_const_structp png_ptr, png_const_infop info_ptr, - png_textp *text_ptr, int *num_text)); +PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_textp *text_ptr, int *num_text)); #endif /* Note while png_set_text() will accept a structure whose text, @@ -2277,122 +2284,220 @@ PNG_EXPORT(162, png_uint_32, png_get_text, */ #ifdef PNG_TEXT_SUPPORTED -PNG_EXPORT(163, void, png_set_text, - (png_structp png_ptr, png_infop info_ptr, - png_const_textp text_ptr, int num_text)); +PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text)); #endif #ifdef PNG_tIME_SUPPORTED -PNG_EXPORT(164, png_uint_32, png_get_tIME, - (png_const_structp png_ptr, png_infop info_ptr, png_timep *mod_time)); +PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_timep *mod_time)); #endif #ifdef PNG_tIME_SUPPORTED -PNG_EXPORT(165, void, png_set_tIME, - (png_structp png_ptr, png_infop info_ptr, png_const_timep mod_time)); +PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_timep mod_time)); #endif #ifdef PNG_tRNS_SUPPORTED -PNG_EXPORT(166, png_uint_32, png_get_tRNS, - (png_const_structp png_ptr, png_infop info_ptr, - png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)); +PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, + png_color_16p *trans_color)); #endif #ifdef PNG_tRNS_SUPPORTED -PNG_EXPORT(167, void, png_set_tRNS, - (png_structp png_ptr, png_infop info_ptr, - png_const_bytep trans_alpha, int num_trans, +PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, + png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)); #endif #ifdef PNG_sCAL_SUPPORTED -PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, - (png_const_structp png_ptr, png_const_infop info_ptr, - int *unit, double *width, double *height)); -#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED +PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *unit, double *width, double *height)) +#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) /* NOTE: this API is currently implemented using floating point arithmetic, * consequently it can only be used on systems with floating point support. * In any case the range of values supported by png_fixed_point is small and it * is highly recommended that png_get_sCAL_s be used instead. */ PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, - (png_structp png_ptr, png_const_infop info_ptr, int *unit, - png_fixed_point *width, - png_fixed_point *height)); + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_fixed_point *width, png_fixed_point *height)) #endif PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, - (png_const_structp png_ptr, png_const_infop info_ptr, - int *unit, png_charpp swidth, png_charpp sheight)); - -PNG_FP_EXPORT(170, void, png_set_sCAL, - (png_structp png_ptr, png_infop info_ptr, - int unit, double width, double height)); -PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_structp png_ptr, - png_infop info_ptr, int unit, png_fixed_point width, - png_fixed_point height)); -PNG_EXPORT(171, void, png_set_sCAL_s, - (png_structp png_ptr, png_infop info_ptr, - int unit, png_const_charp swidth, png_const_charp sheight)); -#endif /* PNG_sCAL_SUPPORTED */ - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -/* Provide a list of chunks and how they are to be handled, if the built-in - handling or default unknown chunk handling is not desired. Any chunks not - listed will be handled in the default manner. The IHDR and IEND chunks - must not be listed. Because this turns off the default handling for chunks - that would otherwise be recognized the behavior of libpng transformations may - well become incorrect! - keep = 0: PNG_HANDLE_CHUNK_AS_DEFAULT: follow default behavior - = 1: PNG_HANDLE_CHUNK_NEVER: do not keep - = 2: PNG_HANDLE_CHUNK_IF_SAFE: keep only if safe-to-copy - = 3: PNG_HANDLE_CHUNK_ALWAYS: keep even if unsafe-to-copy -*/ -PNG_EXPORT(172, void, png_set_keep_unknown_chunks, - (png_structp png_ptr, int keep, - png_const_bytep chunk_list, int num_chunks)); - -/* The handling code is returned; the result is therefore true (non-zero) if - * special handling is required, false for the default handling. - */ -PNG_EXPORT(173, int, png_handle_as_unknown, (png_structp png_ptr, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_charpp swidth, png_charpp sheight)); + +PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, double width, double height)) +PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, png_fixed_point width, + png_fixed_point height)) +PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, + png_const_charp swidth, png_const_charp sheight)); +#endif /* sCAL */ + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +/* Provide the default handling for all unknown chunks or, optionally, for + * specific unknown chunks. + * + * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was + * ignored and the default was used, the per-chunk setting only had an effect on + * write. If you wish to have chunk-specific handling on read in code that must + * work on earlier versions you must use a user chunk callback to specify the + * desired handling (keep or discard.) + * + * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The + * parameter is interpreted as follows: + * + * READ: + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Known chunks: do normal libpng processing, do not keep the chunk (but + * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED) + * Unknown chunks: for a specific chunk use the global default, when used + * as the default discard the chunk data. + * PNG_HANDLE_CHUNK_NEVER: + * Discard the chunk data. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Keep the chunk data if the chunk is not critical else raise a chunk + * error. + * PNG_HANDLE_CHUNK_ALWAYS: + * Keep the chunk data. + * + * If the chunk data is saved it can be retrieved using png_get_unknown_chunks, + * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent + * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks + * it simply resets the behavior to the libpng default. + * + * INTERACTION WTIH USER CHUNK CALLBACKS: + * The per-chunk handling is always used when there is a png_user_chunk_ptr + * callback and the callback returns 0; the chunk is then always stored *unless* + * it is critical and the per-chunk setting is other than ALWAYS. Notice that + * the global default is *not* used in this case. (In effect the per-chunk + * value is incremented to at least IF_SAFE.) + * + * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and + * per-chunk defaults will be honored. If you want to preserve the current + * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE + * as the default - if you don't do this libpng 1.6 will issue a warning. + * + * If you want unhandled unknown chunks to be discarded in libpng 1.6 and + * earlier simply return '1' (handled). + * + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED: + * If this is *not* set known chunks will always be handled by libpng and + * will never be stored in the unknown chunk list. Known chunks listed to + * png_set_keep_unknown_chunks will have no effect. If it is set then known + * chunks listed with a keep other than AS_DEFAULT will *never* be processed + * by libpng, in addition critical chunks must either be processed by the + * callback or saved. + * + * The IHDR and IEND chunks must not be listed. Because this turns off the + * default handling for chunks that would otherwise be recognized the + * behavior of libpng transformations may well become incorrect! + * + * WRITE: + * When writing chunks the options only apply to the chunks specified by + * png_set_unknown_chunks (below), libpng will *always* write known chunks + * required by png_set_ calls and will always write the core critical chunks + * (as required for PLTE). + * + * Each chunk in the png_set_unknown_chunks list is looked up in the + * png_set_keep_unknown_chunks list to find the keep setting, this is then + * interpreted as follows: + * + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Write safe-to-copy chunks and write other chunks if the global + * default is set to _ALWAYS, otherwise don't write this chunk. + * PNG_HANDLE_CHUNK_NEVER: + * Do not write the chunk. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Write the chunk if it is safe-to-copy, otherwise do not write it. + * PNG_HANDLE_CHUNK_ALWAYS: + * Write the chunk. + * + * Note that the default behavior is effectively the opposite of the read case - + * in read unknown chunks are not stored by default, in write they are written + * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different + * - on write the safe-to-copy bit is checked, on read the critical bit is + * checked and on read if the chunk is critical an error will be raised. + * + * num_chunks: + * =========== + * If num_chunks is positive, then the "keep" parameter specifies the manner + * for handling only those chunks appearing in the chunk_list array, + * otherwise the chunk list array is ignored. + * + * If num_chunks is 0 the "keep" parameter specifies the default behavior for + * unknown chunks, as described above. + * + * If num_chunks is negative, then the "keep" parameter specifies the manner + * for handling all unknown chunks plus all chunks recognized by libpng + * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to + * be processed by libpng. + */ +PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, + int keep, png_const_bytep chunk_list, int num_chunks)); + +/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; + * the result is therefore true (non-zero) if special handling is required, + * false for the default handling. + */ +PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, png_const_bytep chunk_name)); #endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED -PNG_EXPORT(174, void, png_set_unknown_chunks, (png_structp png_ptr, - png_infop info_ptr, png_const_unknown_chunkp unknowns, + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)); + /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added + * unknowns to the location currently stored in the png_struct. This is + * invariably the wrong value on write. To fix this call the following API + * for each chunk in the list with the correct location. If you know your + * code won't be compiled on earlier versions you can rely on + * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing + * the correct thing. + */ + PNG_EXPORT(175, void, png_set_unknown_chunk_location, - (png_structp png_ptr, png_infop info_ptr, int chunk, int location)); -PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structp png_ptr, - png_const_infop info_ptr, png_unknown_chunkpp entries)); + (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); + +PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_unknown_chunkpp entries)); #endif /* Png_free_data() will turn off the "valid" flag for anything it frees. * If you need to turn it off for a chunk that your application has freed, * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */ -PNG_EXPORT(177, void, png_set_invalid, - (png_structp png_ptr, png_infop info_ptr, int mask)); +PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, + png_inforp info_ptr, int mask)); #ifdef PNG_INFO_IMAGE_SUPPORTED /* The "params" pointer is currently not used and is for future expansion. */ -PNG_EXPORT(178, void, png_read_png, (png_structp png_ptr, png_infop info_ptr, +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params)); -PNG_EXPORT(179, void, png_write_png, (png_structp png_ptr, png_infop info_ptr, +#endif +#ifdef PNG_WRITE_SUPPORTED +PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params)); #endif +#endif PNG_EXPORT(180, png_const_charp, png_get_copyright, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); PNG_EXPORT(181, png_const_charp, png_get_header_ver, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); PNG_EXPORT(182, png_const_charp, png_get_header_version, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); #ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structp png_ptr, +PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, png_uint_32 mng_features_permitted)); #endif @@ -2401,75 +2506,77 @@ PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structp png_ptr, #define PNG_HANDLE_CHUNK_NEVER 1 #define PNG_HANDLE_CHUNK_IF_SAFE 2 #define PNG_HANDLE_CHUNK_ALWAYS 3 +#define PNG_HANDLE_CHUNK_LAST 4 /* Strip the prepended error numbers ("#nnn ") from error and warning * messages before passing them to the error or warning handler. */ #ifdef PNG_ERROR_NUMBERS_SUPPORTED -PNG_EXPORT(185, void, png_set_strip_error_numbers, - (png_structp png_ptr, +PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, png_uint_32 strip_mode)); #endif /* Added in libpng-1.2.6 */ #ifdef PNG_SET_USER_LIMITS_SUPPORTED -PNG_EXPORT(186, void, png_set_user_limits, (png_structp png_ptr, +PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); PNG_EXPORT(187, png_uint_32, png_get_user_width_max, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); PNG_EXPORT(188, png_uint_32, png_get_user_height_max, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); /* Added in libpng-1.4.0 */ -PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structp png_ptr, +PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)); PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); /* Added in libpng-1.4.1 */ -PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structp png_ptr, +PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, png_alloc_size_t user_chunk_cache_max)); PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); #endif #if defined(PNG_INCH_CONVERSIONS_SUPPORTED) PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_FP_EXPORT(196, float, png_get_x_offset_inches, - (png_const_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)) #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, - (png_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)) #endif -PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structp png_ptr, - png_const_infop info_ptr)); +PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, + png_const_inforp info_ptr)) #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, - (png_structp png_ptr, png_const_infop info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)) #endif # ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structp png_ptr, - png_const_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, +PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); -# endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ +# endif /* pHYs */ +#endif /* INCH_CONVERSIONS */ /* Added in libpng-1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED -PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_structp png_ptr)); +PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); + +/* Removed from libpng 1.6; use png_get_io_chunk_type. */ +PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), + PNG_DEPRECATED) -PNG_EXPORTA(200, png_const_bytep, png_get_io_chunk_name, - (png_structp png_ptr), PNG_DEPRECATED); PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, - (png_const_structp png_ptr)); + (png_const_structrp png_ptr)); /* The flags returned by png_get_io_state() are the following: */ # define PNG_IO_NONE 0x0000 /* no I/O at this moment */ @@ -2481,7 +2588,7 @@ PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, # define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ # define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ # define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ -#endif /* ?PNG_IO_STATE_SUPPORTED */ +#endif /* IO_STATE */ /* Interlace support. The following macros are always defined so that if * libpng interlace handling is turned off the macros may be used to handle @@ -2525,10 +2632,10 @@ PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, * necessary to find the row in the output image given a row in an interlaced * image, so two more macros: */ -#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \ - (((yIn)<> 8)) >> 8); } + (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); } # define png_composite_16(composite, fg, alpha, bg) \ { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ * (png_uint_32)(alpha) \ + (png_uint_32)(bg)*(65535 \ - (png_uint_32)(alpha)) + 32768); \ - (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + (composite) = (png_uint_16)(0xffff & ((temp + (temp >> 16)) >> 16)); } #else /* Standard method using integer division */ -# define png_composite(composite, fg, alpha, bg) \ - (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ - (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ - 127) / 255) +# define png_composite(composite, fg, alpha, bg) \ + (composite) = \ + (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 127) / 255)) # define png_composite_16(composite, fg, alpha, bg) \ - (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ - (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ - 32767) / 65535) -#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + (composite) = \ + (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535)) +#endif /* READ_COMPOSITE_NODIV */ #ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); @@ -2593,7 +2702,7 @@ PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); #endif -PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_structp png_ptr, +PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, png_const_bytep buf)); /* No png_get_int_16 -- may be added if there's a real need for it. */ @@ -2619,7 +2728,7 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); * The png_get_int_32() routine assumes we are using two's complement * format for negative values, which is almost certainly true. */ -# define png_get_uint_32(buf) \ +# define PNG_get_uint_32(buf) \ (((png_uint_32)(*(buf)) << 24) + \ ((png_uint_32)(*((buf) + 1)) << 16) + \ ((png_uint_32)(*((buf) + 2)) << 8) + \ @@ -2628,33 +2737,550 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the * function) incorrectly returned a value of type png_uint_32. */ -# define png_get_uint_16(buf) \ +# define PNG_get_uint_16(buf) \ ((png_uint_16) \ (((unsigned int)(*(buf)) << 8) + \ ((unsigned int)(*((buf) + 1))))) -# define png_get_int_32(buf) \ +# define PNG_get_int_32(buf) \ ((png_int_32)((*(buf) & 0x80) \ ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \ : (png_int_32)png_get_uint_32(buf))) + + /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, + * but defining a macro name prefixed with PNG_PREFIX. + */ +# ifndef PNG_PREFIX +# define png_get_uint_32(buf) PNG_get_uint_32(buf) +# define png_get_uint_16(buf) PNG_get_uint_16(buf) +# define png_get_int_32(buf) PNG_get_int_32(buf) +# endif +#else +# ifdef PNG_PREFIX + /* No macros; revert to the (redefined) function */ +# define PNG_get_uint_32 (png_get_uint_32) +# define PNG_get_uint_16 (png_get_uint_16) +# define PNG_get_int_32 (png_get_int_32) +# endif #endif -#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ - defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) -PNG_EXPORT(234, void, png_set_check_for_invalid_index, (png_structp png_ptr, - int allowed)); +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/******************************************************************************* + * SIMPLIFIED API + ******************************************************************************* + * + * Please read the documentation in libpng-manual.txt (TODO: write said + * documentation) if you don't understand what follows. + * + * The simplified API hides the details of both libpng and the PNG file format + * itself. It allows PNG files to be read into a very limited number of + * in-memory bitmap formats or to be written from the same formats. If these + * formats do not accomodate your needs then you can, and should, use the more + * sophisticated APIs above - these support a wide variety of in-memory formats + * and a wide variety of sophisticated transformations to those formats as well + * as a wide variety of APIs to manipulate ancillary information. + * + * To read a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure (see below) on the stack and set the + * version field to PNG_IMAGE_VERSION. + * 2) Call the appropriate png_image_begin_read... function. + * 3) Set the png_image 'format' member to the required sample format. + * 4) Allocate a buffer for the image and, if required, the color-map. + * 5) Call png_image_finish_read to read the image and, if required, the + * color-map into your buffers. + * + * There are no restrictions on the format of the PNG input itself; all valid + * color types, bit depths, and interlace methods are acceptable, and the + * input image is transformed as necessary to the requested in-memory format + * during the png_image_finish_read() step. The only caveat is that if you + * request a color-mapped image from a PNG that is full-color or makes + * complex use of an alpha channel the transformation is extremely lossy and the + * result may look terrible. + * + * To write a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure on the stack and memset() it to all zero. + * 2) Initialize the members of the structure that describe the image, setting + * the 'format' member to the format of the image samples. + * 3) Call the appropriate png_image_write... function with a pointer to the + * image and, if necessary, the color-map to write the PNG data. + * + * png_image is a structure that describes the in-memory format of an image + * when it is being read or defines the in-memory format of an image that you + * need to write: + */ +#define PNG_IMAGE_VERSION 1 + +typedef struct png_control *png_controlp; +typedef struct +{ + png_controlp opaque; /* Initialize to NULL, free with png_image_free */ + png_uint_32 version; /* Set to PNG_IMAGE_VERSION */ + png_uint_32 width; /* Image width in pixels (columns) */ + png_uint_32 height; /* Image height in pixels (rows) */ + png_uint_32 format; /* Image format as defined below */ + png_uint_32 flags; /* A bit mask containing informational flags */ + png_uint_32 colormap_entries; + /* Number of entries in the color-map */ + + /* In the event of an error or warning the following field will be set to a + * non-zero value and the 'message' field will contain a '\0' terminated + * string with the libpng error or warning message. If both warnings and + * an error were encountered, only the error is recorded. If there + * are multiple warnings, only the first one is recorded. + * + * The upper 30 bits of this value are reserved, the low two bits contain + * a value as follows: + */ +# define PNG_IMAGE_WARNING 1 +# define PNG_IMAGE_ERROR 2 + /* + * The result is a two-bit code such that a value more than 1 indicates + * a failure in the API just called: + * + * 0 - no warning or error + * 1 - warning + * 2 - error + * 3 - error preceded by warning + */ +# define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1) + + png_uint_32 warning_or_error; + + char message[64]; +} png_image, *png_imagep; + +/* The samples of the image have one to four channels whose components have + * original values in the range 0 to 1.0: + * + * 1: A single gray or luminance channel (G). + * 2: A gray/luminance channel and an alpha channel (GA). + * 3: Three red, green, blue color channels (RGB). + * 4: Three color channels and an alpha channel (RGBA). + * + * The components are encoded in one of two ways: + * + * a) As a small integer, value 0..255, contained in a single byte. For the + * alpha channel the original value is simply value/255. For the color or + * luminance channels the value is encoded according to the sRGB specification + * and matches the 8-bit format expected by typical display devices. + * + * The color/gray channels are not scaled (pre-multiplied) by the alpha + * channel and are suitable for passing to color management software. + * + * b) As a value in the range 0..65535, contained in a 2-byte integer. All + * channels can be converted to the original value by dividing by 65535; all + * channels are linear. Color channels use the RGB encoding (RGB end-points) of + * the sRGB specification. This encoding is identified by the + * PNG_FORMAT_FLAG_LINEAR flag below. + * + * When the simplified API needs to convert between sRGB and linear colorspaces, + * the actual sRGB transfer curve defined in the sRGB specification (see the + * article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 + * approximation used elsewhere in libpng. + * + * When an alpha channel is present it is expected to denote pixel coverage + * of the color or luminance channels and is returned as an associated alpha + * channel: the color/gray channels are scaled (pre-multiplied) by the alpha + * value. + * + * The samples are either contained directly in the image data, between 1 and 8 + * bytes per pixel according to the encoding, or are held in a color-map indexed + * by bytes in the image data. In the case of a color-map the color-map entries + * are individual samples, encoded as above, and the image data has one byte per + * pixel to select the relevant sample from the color-map. + */ + +/* PNG_FORMAT_* + * + * #defines to be used in png_image::format. Each #define identifies a + * particular layout of sample data and, if present, alpha values. There are + * separate defines for each of the two component encodings. + * + * A format is built up using single bit flag values. All combinations are + * valid. Formats can be built up from the flag values or you can use one of + * the predefined values below. When testing formats always use the FORMAT_FLAG + * macros to test for individual features - future versions of the library may + * add new flags. + * + * When reading or writing color-mapped images the format should be set to the + * format of the entries in the color-map then png_image_{read,write}_colormap + * called to read or write the color-map and set the format correctly for the + * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + * + * NOTE: libpng can be built with particular features disabled, if you see + * compiler errors because the definition of one of the following flags has been + * compiled out it is because libpng does not have the required support. It is + * possible, however, for the libpng configuration to enable the format on just + * read or just write; in that case you may see an error at run time. You can + * guard against this by checking for the definition of the appropriate + * "_SUPPORTED" macro, one of: + * + * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + */ +#define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ +#define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ +#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2 byte channels else 1 byte */ +#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ + +#ifdef PNG_FORMAT_BGR_SUPPORTED +# define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */ +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ +#endif + +/* Commonly used formats have predefined macros. + * + * First the single byte (sRGB) formats: + */ +#define PNG_FORMAT_GRAY 0 +#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA +#define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR +#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) +#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) + +/* Then the linear 2-byte formats. When naming these "Y" is used to + * indicate a luminance (gray) channel. + */ +#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR +#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) +#define PNG_FORMAT_LINEAR_RGB_ALPHA \ + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA) + +/* With color-mapped formats the image data is one byte for each pixel, the byte + * is an index into the color-map which is formatted as above. To obtain a + * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP + * to one of the above definitions, or you can use one of the definitions below. + */ +#define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP) + +/* PNG_IMAGE macros + * + * These are convenience macros to derive information from a png_image + * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the + * actual image sample values - either the entries in the color-map or the + * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values + * for the pixels and will always return 1 for color-mapped formats. The + * remaining macros return information about the rows in the image and the + * complete image. + * + * NOTE: All the macros that take a png_image::format parameter are compile time + * constants if the format parameter is, itself, a constant. Therefore these + * macros can be used in array declarations and case labels where required. + * Similarly the macros are also pre-processor constants (sizeof is not used) so + * they can be used in #if tests. + * + * First the information about the samples. + */ +#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\ + (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1) + /* Return the total number of channels in a given format: 1..4 */ + +#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\ + ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1) + /* Return the size in bytes of a single component of a pixel or color-map + * entry (as appropriate) in the image: 1 or 2. + */ + +#define PNG_IMAGE_SAMPLE_SIZE(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)) + /* This is the size of the sample data for one sample. If the image is + * color-mapped it is the size of one color-map entry (and image pixels are + * one byte in size), otherwise it is the size of one image pixel. + */ + +#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) + /* The maximum size of the color-map required by the format expressed in a + * count of components. This can be used to compile-time allocate a + * color-map: + * + * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + * + * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + * + * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + * information from one of the png_image_begin_read_ APIs and dynamically + * allocate the required memory. + */ + +/* Corresponding information about the pixels */ +#define PNG_IMAGE_PIXEL_(test,fmt)\ + (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt)) + +#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt) + /* The number of separate channels (components) in a pixel; 1 for a + * color-mapped image. + */ + +#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt) + /* The size, in bytes, of each component in a pixel; 1 for a color-mapped + * image. + */ + +#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt) + /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */ + +/* Information about the whole row, or whole image */ +#define PNG_IMAGE_ROW_STRIDE(image)\ + (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) + /* Return the total number of components in a single row of the image; this + * is the minimum 'row stride', the minimum count of components between each + * row. For a color-mapped image this is the minimum number of bytes in a + * row. + */ + +#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ + (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) + /* Return the size, in bytes, of an image buffer given a png_image and a row + * stride - the number of components to leave space for in each row. + */ + +#define PNG_IMAGE_SIZE(image)\ + PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) + /* Return the size, in bytes, of the image in memory given just a png_image; + * the row stride is the minimum stride required for the image. + */ + +#define PNG_IMAGE_COLORMAP_SIZE(image)\ + (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries) + /* Return the size, in bytes, of the color-map of this image. If the image + * format is not a color-map format this will return a size sufficient for + * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if + * you don't want to allocate a color-map in this case. + */ + +/* PNG_IMAGE_FLAG_* + * + * Flags containing additional information about the image are held in the + * 'flags' field of png_image. + */ +#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 + /* This indicates the the RGB values of the in-memory bitmap do not + * correspond to the red, green and blue end-points defined by sRGB. + */ + +#define PNG_IMAGE_FLAG_FAST 0x02 + /* On write emphasise speed over compression; the resultant PNG file will be + * larger but will be produced significantly faster, particular for large + * images. Do not use this option for images which will be distributed, only + * used it when producing intermediate files that will be read back in + * repeatedly. For a typical 24-bit image the option will double the read + * speed at the cost of increasing the image size by 25%, however for many + * more compressible images the PNG file can be 10 times larger with only a + * slight speed gain. + */ + +#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 + /* On read if the image is a 16-bit per component image and there is no gAMA + * or sRGB chunk assume that the components are sRGB encoded. Notice that + * images output by the simplified API always have gamma information; setting + * this flag only affects the interpretation of 16-bit images from an + * external source. It is recommended that the application expose this flag + * to the user; the user can normally easily recognize the difference between + * linear and sRGB encoding. This flag has no effect on write - the data + * passed to the write APIs must have the correct encoding (as defined + * above.) + * + * If the flag is not set (the default) input 16-bit per component data is + * assumed to be linear. + * + * NOTE: the flag can only be set after the png_image_begin_read_ call, + * because that call initializes the 'flags' field. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* READ APIs + * --------- + * + * The png_image passed to the read APIs must have been initialized by setting + * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) + */ +#ifdef PNG_STDIO_SUPPORTED +PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, + const char *file_name)); + /* The named file is opened for read and the image header is filled in + * from the PNG header in the file. + */ + +PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, + FILE* file)); + /* The PNG header is read from the stdio FILE object. */ +#endif /* STDIO */ + +PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, + png_const_voidp memory, png_size_t size)); + /* The PNG header is read from the given memory buffer. */ + +PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, + png_const_colorp background, void *buffer, png_int_32 row_stride, + void *colormap)); + /* Finish reading the image into the supplied buffer and clean up the + * png_image structure. + * + * row_stride is the step, in byte or 2-byte units as appropriate, + * between adjacent rows. A positive stride indicates that the top-most row + * is first in the buffer - the normal top-down arrangement. A negative + * stride indicates that the bottom-most row is first in the buffer. + * + * background need only be supplied if an alpha channel must be removed from + * a png_byte format and the removal is to be done by compositing on a solid + * color; otherwise it may be NULL and any composition will be done directly + * onto the buffer. The value is an sRGB color to use for the background, + * for grayscale output the green channel is used. + * + * background must be supplied when an alpha channel must be removed from a + * single byte color-mapped output format, in other words if: + * + * 1) The original format from png_image_begin_read_from_* had + * PNG_FORMAT_FLAG_ALPHA set. + * 2) The format set by the application does not. + * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and + * PNG_FORMAT_FLAG_LINEAR *not* set. + * + * For linear output removing the alpha channel is always done by compositing + * on black and background is ignored. + * + * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must + * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. + * image->colormap_entries will be updated to the actual number of entries + * written to the colormap; this may be less than the original value. + */ + +PNG_EXPORT(238, void, png_image_free, (png_imagep image)); + /* Free any data allocated by libpng in image->opaque, setting the pointer to + * NULL. May be called at any time after the structure is initialized. + */ +#endif /* SIMPLIFIED_READ */ + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED +/* WRITE APIS + * ---------- + * For write you must initialize a png_image structure to describe the image to + * be written. To do this use memset to set the whole structure to 0 then + * initialize fields describing your image. + * + * version: must be set to PNG_IMAGE_VERSION + * opaque: must be initialized to NULL + * width: image width in pixels + * height: image height in rows + * format: the format of the data (image and color-map) you wish to write + * flags: set to 0 unless one of the defined flags applies; set + * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB + * values do not correspond to the colors in sRGB. + * colormap_entries: set to the number of entries in the color-map (0 to 256) + */ +PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + /* Write the image to the named file. */ + +PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, png_int_32 row_stride, + const void *colormap)); + /* Write the image to the given (FILE*). */ + +/* With both write APIs if image is in one of the linear formats with 16-bit + * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG + * gamma encoded according to the sRGB specification, otherwise a 16-bit linear + * encoded PNG file is written. + * + * With color-mapped data formats the colormap parameter point to a color-map + * with at least image->colormap_entries encoded in the specified format. If + * the format is linear the written PNG color-map will be converted to sRGB + * regardless of the convert_to_8_bit flag. + * + * With all APIs row_stride is handled as in the read APIs - it is the spacing + * from one row to the next in component sized units (1 or 2 bytes) and if + * negative indicates a bottom-up row layout in the buffer. + * + * Note that the write API does not support interlacing or sub-8-bit pixels. + */ +#endif /* STDIO */ +#endif /* SIMPLIFIED_WRITE */ +/******************************************************************************* + * END OF SIMPLIFIED API + ******************************************************************************/ +#endif /* SIMPLIFIED_{READ|WRITE} */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +PNG_EXPORT(242, void, png_set_check_for_invalid_index, + (png_structrp png_ptr, int allowed)); +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, + png_const_infop info_ptr)); +# endif +#endif /* CHECK_FOR_INVALID_INDEX */ + +/******************************************************************************* + * IMPLEMENTATION OPTIONS + ******************************************************************************* + * + * Support for arbitrary implementation-specific optimizations. The API allows + * particular options to be turned on or off. 'Option' is the number of the + * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given + * by the PNG_OPTION_ defines below. + * + * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, + * are detected at run time, however sometimes it may be impossible + * to do this in user mode, in which case it is necessary to discover + * the capabilities in an OS specific way. Such capabilities are + * listed here when libpng has support for them and must be turned + * ON by the application if present. + * + * SOFTWARE: sometimes software optimizations actually result in performance + * decrease on some architectures or systems, or with some sets of + * PNG images. 'Software' options allow such optimizations to be + * selected at run time. + */ +#ifdef PNG_SET_OPTION_SUPPORTED +#ifdef PNG_ARM_NEON_API_SUPPORTED +# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ #endif +#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ +#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */ +#define PNG_OPTION_NEXT 6 /* Next option - numbers must be even */ + +/* Return values: NOTE: there are four values and 'off' is *not* zero */ +#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ +#define PNG_OPTION_INVALID 1 /* Option number out of range */ +#define PNG_OPTION_OFF 2 +#define PNG_OPTION_ON 3 + +PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, + int onoff)); +#endif /* SET_OPTION */ + +/******************************************************************************* + * END OF HARDWARE AND SOFTWARE OPTIONS + ******************************************************************************/ -/* Maintainer: Put new public prototypes here ^, in libpng.3, and project - * defs +/* Maintainer: Put new public prototypes here ^, in libpng.3, in project + * defs, and in scripts/symbols.def. */ /* The last ordinal number (this is the *last* one already used; the next - * one to use is one more than this.) Maintainer, remember to add an entry to - * scripts/symbols.def as well. + * one to use is one more than this.) */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(234); + PNG_EXPORT_LAST_ORDINAL(244); #endif #ifdef __cplusplus diff --git a/src/3rdparty/libpng/pngconf.h b/src/3rdparty/libpng/pngconf.h index 89add405b6..3f9493e438 100644 --- a/src/3rdparty/libpng/pngconf.h +++ b/src/3rdparty/libpng/pngconf.h @@ -1,9 +1,9 @@ /* pngconf.h - machine configurable file for libpng * - * libpng version 1.5.10 - March 29, 2012 + * libpng version 1.6.17, March 26, 2015 * - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -11,9 +11,7 @@ * For conditions of distribution and use, see the disclaimer * and license in png.h * - */ - -/* Any machine specific code is near the front of this file, so if you + * Any machine specific code is near the front of this file, so if you * are configuring libpng for a machine, you may want to read the section * starting here down to where it starts to typedef png_color, png_text, * and png_info. @@ -22,33 +20,49 @@ #ifndef PNGCONF_H #define PNGCONF_H -#ifndef PNG_BUILDING_SYMBOL_TABLE -/* PNG_NO_LIMITS_H may be used to turn off the use of the standard C - * definition file for machine specific limits, this may impact the - * correctness of the definitons below (see uses of INT_MAX). - */ -# ifndef PNG_NO_LIMITS_H -# include -# endif +#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ -/* For the memory copy APIs (i.e. the standard definitions of these), - * because this file defines png_memcpy and so on the base APIs must - * be defined here. +/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C + * compiler for correct compilation. The following header files are required by + * the standard. If your compiler doesn't provide these header files, or they + * do not match the standard, you will need to provide/improve them. */ -# if defined(BSD) && !defined(VXWORKS) -# include -# else -# include -# endif - -/* For png_FILE_p - this provides the standard definition of a - * FILE +#include +#include + +/* Library header files. These header files are all defined by ISOC90; libpng + * expects conformant implementations, however, an ISOC90 conformant system need + * not provide these header files if the functionality cannot be implemented. + * In this case it will be necessary to disable the relevant parts of libpng in + * the build of pnglibconf.h. + * + * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not + * include this unnecessary header file. */ -# ifdef PNG_STDIO_SUPPORTED -# include -# endif + +#ifdef PNG_STDIO_SUPPORTED + /* Required for the definition of FILE: */ +# include +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Required for the definition of jmp_buf and the declaration of longjmp: */ +# include #endif +#ifdef PNG_CONVERT_tIME_SUPPORTED + /* Required for struct tm: */ +# include +#endif + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using + * PNG_NO_CONST; this is no longer supported except for data declarations which + * apparently still cause problems in 2011 on some compilers. + */ +#define PNG_CONST const /* backward compatibility only */ + /* This controls optimization of the reading of 16 and 32 bit values * from PNG files. It can be set on a per-app-file basis - it * just changes whether a macro is used when the function is called. @@ -72,28 +86,13 @@ * may be changed on a per-file basis when compiling against libpng. */ -/* The PNGARG macro protects us against machines that don't have function - * prototypes (ie K&R style headers). If your compiler does not handle - * function prototypes, define this macro and use the included ansi2knr. - * I've always been able to use _NO_PROTO as the indicator, but you may - * need to drag the empty declaration out in front of here, or change the - * ifdef to suit your own needs. +/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect + * against legacy (pre ISOC90) compilers that did not understand function + * prototypes. It is not required for modern C compilers. */ #ifndef PNGARG - -# ifdef OF /* zlib prototype munger */ -# define PNGARG(arglist) OF(arglist) -# else - -# ifdef _NO_PROTO -# define PNGARG(arglist) () -# else -# define PNGARG(arglist) arglist -# endif /* _NO_PROTO */ - -# endif /* OF */ - -#endif /* PNGARG */ +# define PNGARG(arglist) arglist +#endif /* Function calling conventions. * ============================= @@ -177,18 +176,16 @@ * ========================== * This code is used at build time to find PNG_IMPEXP, the API settings * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL - * import processing is possible. On Windows/x86 systems it also sets + * import processing is possible. On Windows systems it also sets * compiler-specific macros to the values required to change the calling * conventions of the various functions. */ -#if ( defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ - defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) ) &&\ - ( defined(_X86_) || defined(_X64_) || defined(_M_IX86) ||\ - defined(_M_X64) || defined(_M_IA64) ) - /* Windows system (DOS doesn't support DLLs) running on x86/x64. Includes - * builds under Cygwin or MinGW. Also includes Watcom builds but these need - * special treatment because they are not compatible with GCC or Visual C - * because of different calling conventions. +#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ + defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) + /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or + * MinGW on any architecture currently supported by Windows. Also includes + * Watcom builds but these need special treatment because they are not + * compatible with GCC or Visual C because of different calling conventions. */ # if PNG_API_RULE == 2 /* If this line results in an error, either because __watcall is not @@ -199,9 +196,12 @@ # define PNGCAPI __watcall # endif -# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) # define PNGCAPI __cdecl # if PNG_API_RULE == 1 + /* If this line results in an error __stdcall is not understood and + * PNG_API_RULE should not have been set to '1'. + */ # define PNGAPI __stdcall # endif # else @@ -216,10 +216,11 @@ # define PNGAPI _stdcall # endif # endif /* compiler/api */ + /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ # if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) - ERROR: PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed +# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" # endif # if (defined(_MSC_VER) && _MSC_VER < 800) ||\ @@ -239,7 +240,7 @@ # endif # endif /* compiler */ -#else /* !Windows/x86 */ +#else /* !Windows */ # if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) # define PNGAPI _System # else /* !Windows/x86 && !OS/2 */ @@ -333,40 +334,73 @@ #ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED /* Support for compiler specific function attributes. These are used - * so that where compiler support is available incorrect use of API + * so that where compiler support is available, incorrect use of API * functions in png.h will generate compiler warnings. Added at libpng - * version 1.2.41. + * version 1.2.41. Disabling these removes the warnings but may also produce + * less efficient code. */ -# if defined(__GNUC__) -# ifndef PNG_USE_RESULT +# if defined(__clang__) && defined(__has_attribute) + /* Clang defines both __clang__ and __GNUC__. Check __clang__ first. */ +# if !defined(PNG_USE_RESULT) && __has_attribute(__warn_unused_result__) # define PNG_USE_RESULT __attribute__((__warn_unused_result__)) # endif -# ifndef PNG_NORETURN -# define PNG_NORETURN __attribute__((__noreturn__)) +# if !defined(PNG_NORETURN) && __has_attribute(__noreturn__) +# define PNG_NORETURN __attribute__((__noreturn__)) # endif -# ifndef PNG_ALLOCATED -# define PNG_ALLOCATED __attribute__((__malloc__)) +# if !defined(PNG_ALLOCATED) && __has_attribute(__malloc__) +# define PNG_ALLOCATED __attribute__((__malloc__)) # endif -# ifndef PNG_DEPRECATED +# if !defined(PNG_DEPRECATED) && __has_attribute(__deprecated__) # define PNG_DEPRECATED __attribute__((__deprecated__)) # endif -# ifndef PNG_PRIVATE -# if 0 /* Doesn't work so we use deprecated instead*/ -# define PNG_PRIVATE \ - __attribute__((warning("This function is not exported by libpng."))) -# else -# define PNG_PRIVATE \ - __attribute__((__deprecated__)) +# if !defined(PNG_PRIVATE) +# ifdef __has_extension +# if __has_extension(attribute_unavailable_with_message) +# define PNG_PRIVATE __attribute__((__unavailable__(\ + "This function is not exported by libpng."))) +# endif # endif # endif -# endif /* __GNUC__ */ +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif -# if defined(_MSC_VER) && (_MSC_VER >= 1300) +# elif defined(__GNUC__) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if __GNUC__ >= 3 +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif +# if ((__GNUC__ > 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* __GNUC__.__GNUC_MINOR__ > 3.0 */ +# endif /* __GNUC__ >= 3 */ + +# elif defined(_MSC_VER) && (_MSC_VER >= 1300) # ifndef PNG_USE_RESULT # define PNG_USE_RESULT /* not supported */ # endif # ifndef PNG_NORETURN -# define PNG_NORETURN __declspec(noreturn) +# define PNG_NORETURN __declspec(noreturn) # endif # ifndef PNG_ALLOCATED # if (_MSC_VER >= 1400) @@ -379,7 +413,17 @@ # ifndef PNG_PRIVATE # define PNG_PRIVATE __declspec(deprecated) # endif -# endif /* _MSC_VER */ +# ifndef PNG_RESTRICT +# if (_MSC_VER >= 1400) +# define PNG_RESTRICT __restrict +# endif +# endif + +# elif defined(__WATCOMC__) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif #endif /* PNG_PEDANTIC_WARNINGS */ #ifndef PNG_DEPRECATED @@ -397,10 +441,14 @@ #ifndef PNG_PRIVATE # define PNG_PRIVATE /* This is a private libpng function */ #endif +#ifndef PNG_RESTRICT +# define PNG_RESTRICT /* The C99 "restrict" feature */ +#endif + #ifndef PNG_FP_EXPORT /* A floating point API. */ # ifdef PNG_FLOATING_POINT_SUPPORTED # define PNG_FP_EXPORT(ordinal, type, name, args)\ - PNG_EXPORT(ordinal, type, name, args) + PNG_EXPORT(ordinal, type, name, args); # else /* No floating point APIs */ # define PNG_FP_EXPORT(ordinal, type, name, args) # endif @@ -408,189 +456,167 @@ #ifndef PNG_FIXED_EXPORT /* A fixed point API. */ # ifdef PNG_FIXED_POINT_SUPPORTED # define PNG_FIXED_EXPORT(ordinal, type, name, args)\ - PNG_EXPORT(ordinal, type, name, args) + PNG_EXPORT(ordinal, type, name, args); # else /* No fixed point APIs */ # define PNG_FIXED_EXPORT(ordinal, type, name, args) # endif #endif -/* The following uses const char * instead of char * for error - * and warning message functions, so some compilers won't complain. - * If you do not want to use const, define PNG_NO_CONST here. +#ifndef PNG_BUILDING_SYMBOL_TABLE +/* Some typedefs to get us started. These should be safe on most of the common + * platforms. + * + * png_uint_32 and png_int_32 may, currently, be larger than required to hold a + * 32-bit value however this is not normally advisable. + * + * png_uint_16 and png_int_16 should always be two bytes in size - this is + * verified at library build time. + * + * png_byte must always be one byte in size. * - * This should not change how the APIs are called, so it can be done - * on a per-file basis in the application. + * The checks below use constants from limits.h, as defined by the ISOC90 + * standard. */ -#ifndef PNG_CONST -# ifndef PNG_NO_CONST -# define PNG_CONST const -# else -# define PNG_CONST -# endif +#if CHAR_BIT == 8 && UCHAR_MAX == 255 + typedef unsigned char png_byte; +#else +# error "libpng requires 8 bit bytes" #endif -/* Some typedefs to get us started. These should be safe on most of the - * common platforms. The typedefs should be at least as large as the - * numbers suggest (a png_uint_32 must be at least 32 bits long), but they - * don't have to be exactly that size. Some compilers dislike passing - * unsigned shorts as function parameters, so you may be better off using - * unsigned int for png_uint_16. - */ +#if INT_MIN == -32768 && INT_MAX == 32767 + typedef int png_int_16; +#elif SHRT_MIN == -32768 && SHRT_MAX == 32767 + typedef short png_int_16; +#else +# error "libpng requires a signed 16 bit type" +#endif -#if defined(INT_MAX) && (INT_MAX > 0x7ffffffeL) -typedef unsigned int png_uint_32; -typedef int png_int_32; +#if UINT_MAX == 65535 + typedef unsigned int png_uint_16; +#elif USHRT_MAX == 65535 + typedef unsigned short png_uint_16; #else -typedef unsigned long png_uint_32; -typedef long png_int_32; +# error "libpng requires an unsigned 16 bit type" #endif -typedef unsigned short png_uint_16; -typedef short png_int_16; -typedef unsigned char png_byte; -#ifdef PNG_NO_SIZE_T -typedef unsigned int png_size_t; +#if INT_MIN < -2147483646 && INT_MAX > 2147483646 + typedef int png_int_32; +#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 + typedef long int png_int_32; #else -typedef size_t png_size_t; +# error "libpng requires a signed 32 bit (or more) type" #endif -#define png_sizeof(x) (sizeof (x)) -/* The following is needed for medium model support. It cannot be in the - * pngpriv.h header. Needs modification for other compilers besides - * MSC. Model independent support declares all arrays and pointers to be - * large using the far keyword. The zlib version used must also support - * model independent data. As of version zlib 1.0.4, the necessary changes - * have been made in zlib. The USE_FAR_KEYWORD define triggers other - * changes that are needed. (Tim Wegner) - */ +#if UINT_MAX > 4294967294 + typedef unsigned int png_uint_32; +#elif ULONG_MAX > 4294967294 + typedef unsigned long int png_uint_32; +#else +# error "libpng requires an unsigned 32 bit (or more) type" +#endif -/* Separate compiler dependencies (problem here is that zlib.h always - * defines FAR. (SJT) - */ -#ifdef __BORLANDC__ -# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__) -# define LDATA 1 -# else -# define LDATA 0 -# endif - /* GRR: why is Cygwin in here? Cygwin is not Borland C... */ -# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__) -# define PNG_MAX_MALLOC_64K /* only used in build */ -# if (LDATA != 1) -# ifndef FAR -# define FAR __far -# endif -# define USE_FAR_KEYWORD -# endif /* LDATA != 1 */ - /* Possibly useful for moving data out of default segment. - * Uncomment it if you want. Could also define FARDATA as - * const if your compiler supports it. (SJT) -# define FARDATA FAR - */ -# endif /* __WIN32__, __FLAT__, __CYGWIN__ */ -#endif /* __BORLANDC__ */ - - -/* Suggest testing for specific compiler first before testing for - * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM, - * making reliance oncertain keywords suspect. (SJT) +/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, + * requires an ISOC90 compiler and relies on consistent behavior of sizeof. */ +typedef size_t png_size_t; +typedef ptrdiff_t png_ptrdiff_t; -/* MSC Medium model */ -#ifdef FAR -# ifdef M_I86MM -# define USE_FAR_KEYWORD -# define FARDATA FAR -# include +/* libpng needs to know the maximum value of 'size_t' and this controls the + * definition of png_alloc_size_t, below. This maximum value of size_t limits + * but does not control the maximum allocations the library makes - there is + * direct application control of this through png_set_user_limits(). + */ +#ifndef PNG_SMALL_SIZE_T + /* Compiler specific tests for systems where size_t is known to be less than + * 32 bits (some of these systems may no longer work because of the lack of + * 'far' support; see above.) + */ +# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ + (defined(_MSC_VER) && defined(MAXSEG_64K)) +# define PNG_SMALL_SIZE_T # endif #endif -/* SJT: default case */ -#ifndef FAR -# define FAR +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no + * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to + * png_alloc_size_t are not necessary; in fact, it is recommended not to use + * them at all so that the compiler can complain when something turns out to be + * problematic. + * + * Casts in the other direction (from png_alloc_size_t to png_size_t or + * png_uint_32) should be explicitly applied; however, we do not expect to + * encounter practical situations that require such conversions. + * + * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than + * 4294967295 - i.e. less than the maximum value of png_uint_32. + */ +#ifdef PNG_SMALL_SIZE_T + typedef png_uint_32 png_alloc_size_t; +#else + typedef png_size_t png_alloc_size_t; #endif -/* At this point FAR is always defined */ -#ifndef FARDATA -# define FARDATA -#endif +/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler + * implementations of Intel CPU specific support of user-mode segmented address + * spaces, where 16-bit pointers address more than 65536 bytes of memory using + * separate 'segment' registers. The implementation requires two different + * types of pointer (only one of which includes the segment value.) + * + * If required this support is available in version 1.2 of libpng and may be + * available in versions through 1.5, although the correctness of the code has + * not been verified recently. + */ -/* Typedef for floating-point numbers that are converted - * to fixed-point with a multiple of 100,000, e.g., gamma +/* Typedef for floating-point numbers that are converted to fixed-point with a + * multiple of 100,000, e.g., gamma */ typedef png_int_32 png_fixed_point; /* Add typedefs for pointers */ -typedef void FAR * png_voidp; -typedef PNG_CONST void FAR * png_const_voidp; -typedef png_byte FAR * png_bytep; -typedef PNG_CONST png_byte FAR * png_const_bytep; -typedef png_uint_32 FAR * png_uint_32p; -typedef PNG_CONST png_uint_32 FAR * png_const_uint_32p; -typedef png_int_32 FAR * png_int_32p; -typedef PNG_CONST png_int_32 FAR * png_const_int_32p; -typedef png_uint_16 FAR * png_uint_16p; -typedef PNG_CONST png_uint_16 FAR * png_const_uint_16p; -typedef png_int_16 FAR * png_int_16p; -typedef PNG_CONST png_int_16 FAR * png_const_int_16p; -typedef char FAR * png_charp; -typedef PNG_CONST char FAR * png_const_charp; -typedef png_fixed_point FAR * png_fixed_point_p; -typedef PNG_CONST png_fixed_point FAR * png_const_fixed_point_p; -typedef png_size_t FAR * png_size_tp; -typedef PNG_CONST png_size_t FAR * png_const_size_tp; +typedef void * png_voidp; +typedef const void * png_const_voidp; +typedef png_byte * png_bytep; +typedef const png_byte * png_const_bytep; +typedef png_uint_32 * png_uint_32p; +typedef const png_uint_32 * png_const_uint_32p; +typedef png_int_32 * png_int_32p; +typedef const png_int_32 * png_const_int_32p; +typedef png_uint_16 * png_uint_16p; +typedef const png_uint_16 * png_const_uint_16p; +typedef png_int_16 * png_int_16p; +typedef const png_int_16 * png_const_int_16p; +typedef char * png_charp; +typedef const char * png_const_charp; +typedef png_fixed_point * png_fixed_point_p; +typedef const png_fixed_point * png_const_fixed_point_p; +typedef png_size_t * png_size_tp; +typedef const png_size_t * png_const_size_tp; #ifdef PNG_STDIO_SUPPORTED typedef FILE * png_FILE_p; #endif #ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double FAR * png_doublep; -typedef PNG_CONST double FAR * png_const_doublep; +typedef double * png_doublep; +typedef const double * png_const_doublep; #endif /* Pointers to pointers; i.e. arrays */ -typedef png_byte FAR * FAR * png_bytepp; -typedef png_uint_32 FAR * FAR * png_uint_32pp; -typedef png_int_32 FAR * FAR * png_int_32pp; -typedef png_uint_16 FAR * FAR * png_uint_16pp; -typedef png_int_16 FAR * FAR * png_int_16pp; -typedef PNG_CONST char FAR * FAR * png_const_charpp; -typedef char FAR * FAR * png_charpp; -typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +typedef png_byte * * png_bytepp; +typedef png_uint_32 * * png_uint_32pp; +typedef png_int_32 * * png_int_32pp; +typedef png_uint_16 * * png_uint_16pp; +typedef png_int_16 * * png_int_16pp; +typedef const char * * png_const_charpp; +typedef char * * png_charpp; +typedef png_fixed_point * * png_fixed_point_pp; #ifdef PNG_FLOATING_POINT_SUPPORTED -typedef double FAR * FAR * png_doublepp; +typedef double * * png_doublepp; #endif /* Pointers to pointers to pointers; i.e., pointer to array */ -typedef char FAR * FAR * FAR * png_charppp; +typedef char * * * png_charppp; -/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, - * and no smaller than png_uint_32. Casts from png_size_t or png_uint_32 - * to png_alloc_size_t are not necessary; in fact, it is recommended - * not to use them at all so that the compiler can complain when something - * turns out to be problematic. - * Casts in the other direction (from png_alloc_size_t to png_size_t or - * png_uint_32) should be explicitly applied; however, we do not expect - * to encounter practical situations that require such conversions. - */ -#if defined(__TURBOC__) && !defined(__FLAT__) - typedef unsigned long png_alloc_size_t; -#else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - typedef unsigned long png_alloc_size_t; -# else - /* This is an attempt to detect an old Windows system where (int) is - * actually 16 bits, in that case png_malloc must have an argument with a - * bigger size to accomodate the requirements of the library. - */ -# if (defined(_Windows) || defined(_WINDOWS) || defined(_WINDOWS_)) && \ - (!defined(INT_MAX) || INT_MAX <= 0x7ffffffeL) - typedef DWORD png_alloc_size_t; -# else - typedef png_size_t png_alloc_size_t; -# endif -# endif -#endif +#endif /* PNG_BUILDING_SYMBOL_TABLE */ #endif /* PNGCONF_H */ diff --git a/src/3rdparty/libpng/pngdebug.h b/src/3rdparty/libpng/pngdebug.h index 4547b7d808..6a01b106ed 100644 --- a/src/3rdparty/libpng/pngdebug.h +++ b/src/3rdparty/libpng/pngdebug.h @@ -1,12 +1,11 @@ /* pngdebug.h - Debugging macros for libpng, also used in pngtest.c * - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.8 [December 19, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.0 [January 6, 2011] - * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h @@ -25,7 +24,7 @@ * (actually ((void)0)). * * level: level of detail of message, starting at 0. A level 'n' - * message is preceded by 'n' tab characters (not implemented + * message is preceded by 'n' 3-space indentations (not implemented * on Microsoft compilers unless PNG_DEBUG_FILE is also * defined, to allow debug DLL compilation with no standard IO). * message: a printf(3) style text string. A trailing '\n' is added @@ -77,32 +76,29 @@ # endif /* PNG_DEBUG_FILE */ # if (PNG_DEBUG > 1) -/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on - * non-ISO compilers - */ # ifdef __STDC__ # ifndef png_debug # define png_debug(l,m) \ do { \ int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : "")))); \ } while (0) # endif # ifndef png_debug1 # define png_debug1(l,m,p1) \ do { \ int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1); \ } while (0) # endif # ifndef png_debug2 # define png_debug2(l,m,p1,p2) \ do { \ int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ - (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ + fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ + (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1,p2);\ } while (0) # endif # else /* __STDC __ */ diff --git a/src/3rdparty/libpng/pngerror.c b/src/3rdparty/libpng/pngerror.c index 95002f84f7..0781866a89 100644 --- a/src/3rdparty/libpng/pngerror.c +++ b/src/3rdparty/libpng/pngerror.c @@ -1,8 +1,8 @@ /* pngerror.c - stub functions for i/o and memory allocation * - * Last changed in libpng 1.5.8 [February 1, 2011] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -20,14 +20,14 @@ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -static PNG_FUNCTION(void, png_default_error,PNGARG((png_structp png_ptr, +static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr, png_const_charp error_message)),PNG_NORETURN); #ifdef PNG_WARNINGS_SUPPORTED static void /* PRIVATE */ -png_default_warning PNGARG((png_structp png_ptr, +png_default_warning PNGARG((png_const_structrp png_ptr, png_const_charp warning_message)); -#endif /* PNG_WARNINGS_SUPPORTED */ +#endif /* WARNINGS */ /* This function is called whenever there is a fatal error. This function * should not be changed. If there is a need to handle errors differently, @@ -36,14 +36,15 @@ png_default_warning PNGARG((png_structp png_ptr, */ #ifdef PNG_ERROR_TEXT_SUPPORTED PNG_FUNCTION(void,PNGAPI -png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN) +png_error,(png_const_structrp png_ptr, png_const_charp error_message), + PNG_NORETURN) { #ifdef PNG_ERROR_NUMBERS_SUPPORTED char msg[16]; if (png_ptr != NULL) { - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + if ((png_ptr->flags & + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0 { if (*error_message == PNG_LITERAL_SHARP) { @@ -53,7 +54,7 @@ png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN) if (error_message[offset] == ' ') break; - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) { int i; for (i = 0; i < offset - 1; i++) @@ -68,7 +69,7 @@ png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN) else { - if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) { msg[0] = '0'; msg[1] = '\0'; @@ -79,7 +80,8 @@ png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN) } #endif if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, error_message); + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), + error_message); /* If the custom handler doesn't exist, or if it returns, use the default handler, which will not return. */ @@ -87,7 +89,7 @@ png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN) } #else PNG_FUNCTION(void,PNGAPI -png_err,(png_structp png_ptr),PNG_NORETURN) +png_err,(png_const_structrp png_ptr),PNG_NORETURN) { /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed * erroneously as '\0', instead of the empty string "". This was @@ -95,13 +97,13 @@ png_err,(png_structp png_ptr),PNG_NORETURN) * will crash in this case. */ if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, ""); + (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), ""); /* If the custom handler doesn't exist, or if it returns, use the default handler, which will not return. */ png_default_error(png_ptr, ""); } -#endif /* PNG_ERROR_TEXT_SUPPORTED */ +#endif /* ERROR_TEXT */ /* Utility to safely appends strings to a buffer. This never errors out so * error checking is not required in the caller. @@ -150,7 +152,7 @@ png_format_number(png_const_charp start, png_charp end, int format, case PNG_NUMBER_FORMAT_fixed: /* Needs five digits (the fraction) */ mincount = 5; - if (output || number % 10 != 0) + if (output != 0 || number % 10 != 0) { *--end = digits[number % 10]; output = 1; @@ -161,7 +163,7 @@ png_format_number(png_const_charp start, png_charp end, int format, case PNG_NUMBER_FORMAT_02u: /* Expects at least 2 digits. */ mincount = 2; - /* fall through */ + /* FALL THROUGH */ case PNG_NUMBER_FORMAT_u: *--end = digits[number % 10]; @@ -171,7 +173,7 @@ png_format_number(png_const_charp start, png_charp end, int format, case PNG_NUMBER_FORMAT_02x: /* This format expects at least two digits */ mincount = 2; - /* fall through */ + /* FALL THROUGH */ case PNG_NUMBER_FORMAT_x: *--end = digits[number & 0xf]; @@ -187,13 +189,13 @@ png_format_number(png_const_charp start, png_charp end, int format, ++count; /* Float a fixed number here: */ - if (format == PNG_NUMBER_FORMAT_fixed) if (count == 5) if (end > start) + if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start)) { /* End of the fraction, but maybe nothing was output? In that case * drop the decimal point. If the number is a true zero handle that * here. */ - if (output) + if (output != 0) *--end = '.'; else if (number == 0) /* and !output */ *--end = '0'; @@ -211,14 +213,14 @@ png_format_number(png_const_charp start, png_charp end, int format, * png_set_error_fn() to replace the warning function at run-time. */ void PNGAPI -png_warning(png_structp png_ptr, png_const_charp warning_message) +png_warning(png_const_structrp png_ptr, png_const_charp warning_message) { int offset = 0; if (png_ptr != NULL) { #ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (png_ptr->flags& - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + if ((png_ptr->flags & + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) #endif { if (*warning_message == PNG_LITERAL_SHARP) @@ -230,7 +232,8 @@ png_warning(png_structp png_ptr, png_const_charp warning_message) } } if (png_ptr != NULL && png_ptr->warning_fn != NULL) - (*(png_ptr->warning_fn))(png_ptr, warning_message + offset); + (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), + warning_message + offset); else png_default_warning(png_ptr, warning_message + offset); } @@ -278,7 +281,7 @@ png_warning_parameter_signed(png_warning_parameters p, int number, int format, } void -png_formatted_warning(png_structp png_ptr, png_warning_parameters p, +png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, png_const_charp message) { /* The internal buffer is just 192 bytes - enough for all our messages, @@ -346,29 +349,79 @@ png_formatted_warning(png_structp png_ptr, png_warning_parameters p, /* i is always less than (sizeof msg), so: */ msg[i] = '\0'; - /* And this is the formatted message, it may be larger than - * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these are - * not (currently) formatted. + /* And this is the formatted message. It may be larger than + * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these + * are not (currently) formatted. */ png_warning(png_ptr, msg); } -#endif /* PNG_WARNINGS_SUPPORTED */ +#endif /* WARNINGS */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI -png_benign_error(png_structp png_ptr, png_const_charp error_message) +png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) { - if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_warning(png_ptr, error_message); + else +# endif + png_warning(png_ptr, error_message); + } + + else + { +# ifdef PNG_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + png_ptr->chunk_name != 0) + png_chunk_error(png_ptr, error_message); + else +# endif + png_error(png_ptr, error_message); + } + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} + +void /* PRIVATE */ +png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0) png_warning(png_ptr, error_message); else png_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif } -#endif +void /* PRIVATE */ +png_app_error(png_const_structrp png_ptr, png_const_charp error_message) +{ + if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} +#endif /* BENIGN_ERRORS */ + +#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */ +#if defined(PNG_WARNINGS_SUPPORTED) || \ + (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)) /* These utilities are used internally to build an error message that relates * to the current chunk. The chunk name comes from png_ptr->chunk_name, - * this is used to prefix the message. The message is limited in length - * to 63 bytes, the name characters are output as hex digits wrapped in [] + * which is used to prefix the message. The message is limited in length + * to 63 bytes. The name characters are output as hex digits wrapped in [] * if the character is invalid. */ #define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) @@ -377,10 +430,8 @@ static PNG_CONST char png_digit[16] = { 'A', 'B', 'C', 'D', 'E', 'F' }; -#define PNG_MAX_ERROR_TEXT 64 -#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) static void /* PRIVATE */ -png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp +png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp error_message) { png_uint_32 chunk_name = png_ptr->chunk_name; @@ -391,7 +442,7 @@ png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp int c = (int)(chunk_name >> ishift) & 0xff; ishift -= 8; - if (isnonalpha(c)) + if (isnonalpha(c) != 0) { buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; buffer[iout++] = png_digit[(c & 0xf0) >> 4]; @@ -422,11 +473,11 @@ png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp buffer[iout] = '\0'; } } -#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ +#endif /* WARNINGS || ERROR_TEXT */ #if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) PNG_FUNCTION(void,PNGAPI -png_chunk_error,(png_structp png_ptr, png_const_charp error_message), +png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN) { char msg[18+PNG_MAX_ERROR_TEXT]; @@ -439,11 +490,11 @@ png_chunk_error,(png_structp png_ptr, png_const_charp error_message), png_error(png_ptr, msg); } } -#endif /* PNG_READ_SUPPORTED && PNG_ERROR_TEXT_SUPPORTED */ +#endif /* READ && ERROR_TEXT */ #ifdef PNG_WARNINGS_SUPPORTED void PNGAPI -png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) +png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) { char msg[18+PNG_MAX_ERROR_TEXT]; if (png_ptr == NULL) @@ -455,38 +506,83 @@ png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) png_warning(png_ptr, msg); } } -#endif /* PNG_WARNINGS_SUPPORTED */ +#endif /* WARNINGS */ #ifdef PNG_READ_SUPPORTED #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI -png_chunk_benign_error(png_structp png_ptr, png_const_charp error_message) +png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp + error_message) { - if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) png_chunk_warning(png_ptr, error_message); else png_chunk_error(png_ptr, error_message); + +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif } #endif -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ + +void /* PRIVATE */ +png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) +{ +# ifndef PNG_WARNINGS_SUPPORTED + PNG_UNUSED(message) +# endif + + /* This is always supported, but for just read or just write it + * unconditionally does the right thing. + */ +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) +# endif + +# ifdef PNG_READ_SUPPORTED + { + if (error < PNG_CHUNK_ERROR) + png_chunk_warning(png_ptr, message); + + else + png_chunk_benign_error(png_ptr, message); + } +# endif + +# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) +# endif + +# ifdef PNG_WRITE_SUPPORTED + { + if (error < PNG_CHUNK_WRITE_ERROR) + png_app_warning(png_ptr, message); + + else + png_app_error(png_ptr, message); + } +# endif +} #ifdef PNG_ERROR_TEXT_SUPPORTED #ifdef PNG_FLOATING_POINT_SUPPORTED PNG_FUNCTION(void, -png_fixed_error,(png_structp png_ptr, png_const_charp name),PNG_NORETURN) +png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) { # define fixed_message "fixed point overflow in " # define fixed_message_ln ((sizeof fixed_message)-1) int iin; char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; - png_memcpy(msg, fixed_message, fixed_message_ln); + memcpy(msg, fixed_message, fixed_message_ln); iin = 0; - if (name != NULL) while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) - { - msg[fixed_message_ln + iin] = name[iin]; - ++iin; - } + if (name != NULL) + while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) + { + msg[fixed_message_ln + iin] = name[iin]; + ++iin; + } msg[fixed_message_ln + iin] = 0; png_error(png_ptr, msg); } @@ -498,14 +594,111 @@ png_fixed_error,(png_structp png_ptr, png_const_charp name),PNG_NORETURN) * otherwise it is necessary for png_default_error to be overridden. */ jmp_buf* PNGAPI -png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn, +png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, size_t jmp_buf_size) { - if (png_ptr == NULL || jmp_buf_size != png_sizeof(jmp_buf)) + /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value + * and it must not change after that. Libpng doesn't care how big the + * buffer is, just that it doesn't change. + * + * If the buffer size is no *larger* than the size of jmp_buf when libpng is + * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0 + * semantics that this call will not fail. If the size is larger, however, + * the buffer is allocated and this may fail, causing the function to return + * NULL. + */ + if (png_ptr == NULL) return NULL; + if (png_ptr->jmp_buf_ptr == NULL) + { + png_ptr->jmp_buf_size = 0; /* not allocated */ + + if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local)) + png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; + + else + { + png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, + png_malloc_warn(png_ptr, jmp_buf_size)); + + if (png_ptr->jmp_buf_ptr == NULL) + return NULL; /* new NULL return on OOM */ + + png_ptr->jmp_buf_size = jmp_buf_size; + } + } + + else /* Already allocated: check the size */ + { + size_t size = png_ptr->jmp_buf_size; + + if (size == 0) + { + size = (sizeof png_ptr->jmp_buf_local); + if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local) + { + /* This is an internal error in libpng: somehow we have been left + * with a stack allocated jmp_buf when the application regained + * control. It's always possible to fix this up, but for the moment + * this is a png_error because that makes it easy to detect. + */ + png_error(png_ptr, "Libpng jmp_buf still allocated"); + /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */ + } + } + + if (size != jmp_buf_size) + { + png_warning(png_ptr, "Application jmp_buf size changed"); + return NULL; /* caller will probably crash: no choice here */ + } + } + + /* Finally fill in the function, now we have a satisfactory buffer. It is + * valid to change the function on every call. + */ png_ptr->longjmp_fn = longjmp_fn; - return &png_ptr->longjmp_buffer; + return png_ptr->jmp_buf_ptr; +} + +void /* PRIVATE */ +png_free_jmpbuf(png_structrp png_ptr) +{ + if (png_ptr != NULL) + { + jmp_buf *jb = png_ptr->jmp_buf_ptr; + + /* A size of 0 is used to indicate a local, stack, allocation of the + * pointer; used here and in png.c + */ + if (jb != NULL && png_ptr->jmp_buf_size > 0) + { + + /* This stuff is so that a failure to free the error control structure + * does not leave libpng in a state with no valid error handling: the + * free always succeeds, if there is an error it gets ignored. + */ + if (jb != &png_ptr->jmp_buf_local) + { + /* Make an internal, libpng, jmp_buf to return here */ + jmp_buf free_jmp_buf; + + if (!setjmp(free_jmp_buf)) + { + png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */ + png_ptr->jmp_buf_size = 0; /* stack allocation */ + png_ptr->longjmp_fn = longjmp; + png_free(png_ptr, jb); /* Return to setjmp on error */ + } + } + } + + /* *Always* cancel everything out: */ + png_ptr->jmp_buf_size = 0; + png_ptr->jmp_buf_ptr = NULL; + png_ptr->longjmp_fn = 0; + } } #endif @@ -515,7 +708,7 @@ png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn, * error function pointer in png_set_error_fn(). */ static PNG_FUNCTION(void /* PRIVATE */, -png_default_error,(png_structp png_ptr, png_const_charp error_message), +png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN) { #ifdef PNG_CONSOLE_IO_SUPPORTED @@ -562,24 +755,23 @@ png_default_error,(png_structp png_ptr, png_const_charp error_message), } PNG_FUNCTION(void,PNGAPI -png_longjmp,(png_structp png_ptr, int val),PNG_NORETURN) +png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN) { #ifdef PNG_SETJMP_SUPPORTED - if (png_ptr && png_ptr->longjmp_fn) - { -# ifdef USE_FAR_KEYWORD - { - jmp_buf tmp_jmpbuf; - png_memcpy(tmp_jmpbuf, png_ptr->longjmp_buffer, png_sizeof(jmp_buf)); - png_ptr->longjmp_fn(tmp_jmpbuf, val); - } - -# else - png_ptr->longjmp_fn(png_ptr->longjmp_buffer, val); -# endif - } + if (png_ptr != NULL && png_ptr->longjmp_fn != NULL && + png_ptr->jmp_buf_ptr != NULL) + png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(val) #endif - /* Here if not setjmp support or if png_ptr is null. */ + + /* If control reaches this point, png_longjmp() must not return. The only + * choice is to terminate the whole process (or maybe the thread); to do + * this the ANSI-C abort() function is used unless a different method is + * implemented by overriding the default configuration setting for + * PNG_ABORT(). + */ PNG_ABORT(); } @@ -590,7 +782,7 @@ png_longjmp,(png_structp png_ptr, int val),PNG_NORETURN) * not used, but it is passed in case it may be useful. */ static void /* PRIVATE */ -png_default_warning(png_structp png_ptr, png_const_charp warning_message) +png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) { #ifdef PNG_CONSOLE_IO_SUPPORTED # ifdef PNG_ERROR_NUMBERS_SUPPORTED @@ -632,15 +824,15 @@ png_default_warning(png_structp png_ptr, png_const_charp warning_message) #endif PNG_UNUSED(png_ptr) /* Make compiler happy */ } -#endif /* PNG_WARNINGS_SUPPORTED */ +#endif /* WARNINGS */ /* This function is called when the application wants to use another method * of handling errors and warnings. Note that the error function MUST NOT * return to the calling routine or serious problems will occur. The return - * method used in the default routine calls longjmp(png_ptr->longjmp_buffer, 1) + * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1) */ void PNGAPI -png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, +png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn) { if (png_ptr == NULL) @@ -661,7 +853,7 @@ png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, * pointer before png_write_destroy and png_read_destroy are called. */ png_voidp PNGAPI -png_get_error_ptr(png_const_structp png_ptr) +png_get_error_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return NULL; @@ -672,7 +864,7 @@ png_get_error_ptr(png_const_structp png_ptr) #ifdef PNG_ERROR_NUMBERS_SUPPORTED void PNGAPI -png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) +png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) { if (png_ptr != NULL) { @@ -682,4 +874,90 @@ png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode) } } #endif -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ + +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) + /* Currently the above both depend on SETJMP_SUPPORTED, however it would be + * possible to implement without setjmp support just so long as there is some + * way to handle the error return here: + */ +PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI +png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), + PNG_NORETURN) +{ + const png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* An error is always logged here, overwriting anything (typically a warning) + * that is already there: + */ + if (image != NULL) + { + png_safecat(image->message, (sizeof image->message), 0, error_message); + image->warning_or_error |= PNG_IMAGE_ERROR; + + /* Retrieve the jmp_buf from within the png_control, making this work for + * C++ compilation too is pretty tricky: C++ wants a pointer to the first + * element of a jmp_buf, but C doesn't tell us the type of that. + */ + if (image->opaque != NULL && image->opaque->error_buf != NULL) + longjmp(png_control_jmp_buf(image->opaque), 1); + + /* Missing longjmp buffer, the following is to help debugging: */ + { + size_t pos = png_safecat(image->message, (sizeof image->message), 0, + "bad longjmp: "); + png_safecat(image->message, (sizeof image->message), pos, + error_message); + } + } + + /* Here on an internal programming error. */ + abort(); +} + +#ifdef PNG_WARNINGS_SUPPORTED +void /* PRIVATE */ PNGCBAPI +png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) +{ + const png_const_structrp png_ptr = png_nonconst_ptr; + png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); + + /* A warning is only logged if there is no prior warning or error. */ + if (image->warning_or_error == 0) + { + png_safecat(image->message, (sizeof image->message), 0, warning_message); + image->warning_or_error |= PNG_IMAGE_WARNING; + } +} +#endif + +int /* PRIVATE */ +png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg) +{ + volatile png_imagep image = image_in; + volatile int result; + volatile png_voidp saved_error_buf; + jmp_buf safe_jmpbuf; + + /* Safely execute function(arg) with png_error returning to this function. */ + saved_error_buf = image->opaque->error_buf; + result = setjmp(safe_jmpbuf) == 0; + + if (result != 0) + { + + image->opaque->error_buf = safe_jmpbuf; + result = function(arg); + } + + image->opaque->error_buf = saved_error_buf; + + /* And do the cleanup prior to any failure return. */ + if (result == 0) + png_image_free(image); + + return result; +} +#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */ +#endif /* READ || WRITE */ diff --git a/src/3rdparty/libpng/pngget.c b/src/3rdparty/libpng/pngget.c index 43400cda7e..743a6a9bbc 100644 --- a/src/3rdparty/libpng/pngget.c +++ b/src/3rdparty/libpng/pngget.c @@ -1,8 +1,8 @@ /* pngget.c - retrieval of values from info struct * - * Last changed in libpng 1.5.7 [December 15, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -17,7 +17,7 @@ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) png_uint_32 PNGAPI -png_get_valid(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 flag) { if (png_ptr != NULL && info_ptr != NULL) @@ -27,7 +27,7 @@ png_get_valid(png_const_structp png_ptr, png_const_infop info_ptr, } png_size_t PNGAPI -png_get_rowbytes(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->rowbytes); @@ -37,7 +37,7 @@ png_get_rowbytes(png_const_structp png_ptr, png_const_infop info_ptr) #ifdef PNG_INFO_IMAGE_SUPPORTED png_bytepp PNGAPI -png_get_rows(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->row_pointers); @@ -49,7 +49,7 @@ png_get_rows(png_const_structp png_ptr, png_const_infop info_ptr) #ifdef PNG_EASY_ACCESS_SUPPORTED /* Easy access to info, added in libpng-0.99 */ png_uint_32 PNGAPI -png_get_image_width(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->width; @@ -58,7 +58,7 @@ png_get_image_width(png_const_structp png_ptr, png_const_infop info_ptr) } png_uint_32 PNGAPI -png_get_image_height(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->height; @@ -67,7 +67,7 @@ png_get_image_height(png_const_structp png_ptr, png_const_infop info_ptr) } png_byte PNGAPI -png_get_bit_depth(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->bit_depth; @@ -76,7 +76,7 @@ png_get_bit_depth(png_const_structp png_ptr, png_const_infop info_ptr) } png_byte PNGAPI -png_get_color_type(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->color_type; @@ -85,7 +85,7 @@ png_get_color_type(png_const_structp png_ptr, png_const_infop info_ptr) } png_byte PNGAPI -png_get_filter_type(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->filter_type; @@ -94,7 +94,7 @@ png_get_filter_type(png_const_structp png_ptr, png_const_infop info_ptr) } png_byte PNGAPI -png_get_interlace_type(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->interlace_type; @@ -103,7 +103,7 @@ png_get_interlace_type(png_const_structp png_ptr, png_const_infop info_ptr) } png_byte PNGAPI -png_get_compression_type(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->compression_type; @@ -112,10 +112,12 @@ png_get_compression_type(png_const_structp png_ptr, png_const_infop info_ptr) } png_uint_32 PNGAPI -png_get_x_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) { #ifdef PNG_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_x_pixels_per_meter"); @@ -123,16 +125,21 @@ png_get_x_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr) if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) return (info_ptr->x_pixels_per_unit); } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return (0); } png_uint_32 PNGAPI -png_get_y_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) { #ifdef PNG_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_y_pixels_per_meter"); @@ -140,16 +147,20 @@ png_get_y_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr) if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) return (info_ptr->y_pixels_per_unit); } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return (0); } png_uint_32 PNGAPI -png_get_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); @@ -157,6 +168,9 @@ png_get_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr) info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit) return (info_ptr->x_pixels_per_unit); } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return (0); @@ -164,10 +178,12 @@ png_get_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr) #ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI -png_get_pixel_aspect_ratio(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp + info_ptr) { #ifdef PNG_READ_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); @@ -175,6 +191,9 @@ png_get_pixel_aspect_ratio(png_const_structp png_ptr, png_const_infop info_ptr) return ((float)((float)info_ptr->y_pixels_per_unit /(float)info_ptr->x_pixels_per_unit)); } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return ((float)0.0); @@ -183,14 +202,15 @@ png_get_pixel_aspect_ratio(png_const_structp png_ptr, png_const_infop info_ptr) #ifdef PNG_FIXED_POINT_SUPPORTED png_fixed_point PNGAPI -png_get_pixel_aspect_ratio_fixed(png_const_structp png_ptr, - png_const_infop info_ptr) +png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) { #ifdef PNG_READ_pHYs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) - && info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 - && info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX - && info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0 && + info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 && + info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX && + info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) { png_fixed_point res; @@ -200,9 +220,12 @@ png_get_pixel_aspect_ratio_fixed(png_const_structp png_ptr, * range of 0..2^31-1; otherwise the cast might overflow. */ if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1, - (png_int_32)info_ptr->x_pixels_per_unit)) + (png_int_32)info_ptr->x_pixels_per_unit) != 0) return res; } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return 0; @@ -210,64 +233,80 @@ png_get_pixel_aspect_ratio_fixed(png_const_structp png_ptr, #endif png_int_32 PNGAPI -png_get_x_offset_microns(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) return (info_ptr->x_offset); } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return (0); } png_int_32 PNGAPI -png_get_y_offset_microns(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) return (info_ptr->y_offset); } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return (0); } png_int_32 PNGAPI -png_get_x_offset_pixels(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels"); if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) return (info_ptr->x_offset); } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return (0); } png_int_32 PNGAPI -png_get_y_offset_pixels(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels"); if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) return (info_ptr->y_offset); } +#else + PNG_UNUSED(png_ptr) + PNG_UNUSED(info_ptr) #endif return (0); @@ -298,7 +337,7 @@ ppi_from_ppm(png_uint_32 ppm) */ png_fixed_point result; if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127, - 5000)) + 5000) != 0) return result; /* Overflow. */ @@ -307,26 +346,26 @@ ppi_from_ppm(png_uint_32 ppm) } png_uint_32 PNGAPI -png_get_pixels_per_inch(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) { return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr)); } png_uint_32 PNGAPI -png_get_x_pixels_per_inch(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) { return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr)); } png_uint_32 PNGAPI -png_get_y_pixels_per_inch(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) { return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr)); } #ifdef PNG_FIXED_POINT_SUPPORTED static png_fixed_point -png_fixed_inches_from_microns(png_structp png_ptr, png_int_32 microns) +png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns) { /* Convert from metres * 1,000,000 to inches * 100,000, meters to * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127. @@ -337,8 +376,8 @@ png_fixed_inches_from_microns(png_structp png_ptr, png_int_32 microns) } png_fixed_point PNGAPI -png_get_x_offset_inches_fixed(png_structp png_ptr, - png_const_infop info_ptr) +png_get_x_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) { return png_fixed_inches_from_microns(png_ptr, png_get_x_offset_microns(png_ptr, info_ptr)); @@ -347,8 +386,8 @@ png_get_x_offset_inches_fixed(png_structp png_ptr, #ifdef PNG_FIXED_POINT_SUPPORTED png_fixed_point PNGAPI -png_get_y_offset_inches_fixed(png_structp png_ptr, - png_const_infop info_ptr) +png_get_y_offset_inches_fixed(png_const_structrp png_ptr, + png_const_inforp info_ptr) { return png_fixed_inches_from_microns(png_ptr, png_get_y_offset_microns(png_ptr, info_ptr)); @@ -357,7 +396,7 @@ png_get_y_offset_inches_fixed(png_structp png_ptr, #ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI -png_get_x_offset_inches(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) { /* To avoid the overflow do the conversion directly in floating * point. @@ -368,7 +407,7 @@ png_get_x_offset_inches(png_const_structp png_ptr, png_const_infop info_ptr) #ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI -png_get_y_offset_inches(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) { /* To avoid the overflow do the conversion directly in floating * point. @@ -379,12 +418,13 @@ png_get_y_offset_inches(png_const_structp png_ptr, png_const_infop info_ptr) #ifdef PNG_pHYs_SUPPORTED png_uint_32 PNGAPI -png_get_pHYs_dpi(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) { png_uint_32 retval = 0; - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "pHYs"); @@ -415,15 +455,16 @@ png_get_pHYs_dpi(png_const_structp png_ptr, png_const_infop info_ptr, return (retval); } -#endif /* PNG_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ +#endif /* pHYs */ +#endif /* INCH_CONVERSIONS */ /* png_get_channels really belongs in here, too, but it's been around longer */ -#endif /* PNG_EASY_ACCESS_SUPPORTED */ +#endif /* EASY_ACCESS */ + png_byte PNGAPI -png_get_channels(png_const_structp png_ptr, png_const_infop info_ptr) +png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->channels); @@ -431,22 +472,25 @@ png_get_channels(png_const_structp png_ptr, png_const_infop info_ptr) return (0); } +#ifdef PNG_READ_SUPPORTED png_const_bytep PNGAPI -png_get_signature(png_const_structp png_ptr, png_infop info_ptr) +png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->signature); return (NULL); } +#endif #ifdef PNG_bKGD_SUPPORTED png_uint_32 PNGAPI -png_get_bKGD(png_const_structp png_ptr, png_infop info_ptr, +png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, png_color_16p *background) { - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) - && background != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_bKGD) != 0 && + background != NULL) { png_debug1(1, "in %s retrieval function", "bKGD"); @@ -463,87 +507,47 @@ png_get_bKGD(png_const_structp png_ptr, png_infop info_ptr, * same time to correct the rgb grayscale coefficient defaults obtained from the * cHRM chunk in 1.5.4 */ -png_uint_32 PNGFAPI -png_get_cHRM_XYZ_fixed(png_structp png_ptr, png_const_infop info_ptr, - png_fixed_point *int_red_X, png_fixed_point *int_red_Y, - png_fixed_point *int_red_Z, png_fixed_point *int_green_X, - png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, - png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, - png_fixed_point *int_blue_Z) -{ - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - { - png_xy xy; - png_XYZ XYZ; - - png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); - - xy.whitex = info_ptr->x_white; - xy.whitey = info_ptr->y_white; - xy.redx = info_ptr->x_red; - xy.redy = info_ptr->y_red; - xy.greenx = info_ptr->x_green; - xy.greeny = info_ptr->y_green; - xy.bluex = info_ptr->x_blue; - xy.bluey = info_ptr->y_blue; - - /* The *_checked function handles error reporting, so just return 0 if - * there is a failure here. - */ - if (png_XYZ_from_xy_checked(png_ptr, &XYZ, xy)) - { - if (int_red_X != NULL) - *int_red_X = XYZ.redX; - if (int_red_Y != NULL) - *int_red_Y = XYZ.redY; - if (int_red_Z != NULL) - *int_red_Z = XYZ.redZ; - if (int_green_X != NULL) - *int_green_X = XYZ.greenX; - if (int_green_Y != NULL) - *int_green_Y = XYZ.greenY; - if (int_green_Z != NULL) - *int_green_Z = XYZ.greenZ; - if (int_blue_X != NULL) - *int_blue_X = XYZ.blueX; - if (int_blue_Y != NULL) - *int_blue_Y = XYZ.blueY; - if (int_blue_Z != NULL) - *int_blue_Z = XYZ.blueZ; - - return (PNG_INFO_cHRM); - } - } - - return (0); -} - # ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 PNGAPI -png_get_cHRM(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, double *red_y, double *green_x, double *green_y, double *blue_x, double *blue_y) { - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + /* Quiet API change: this code used to only return the end points if a cHRM + * chunk was present, but the end points can also come from iCCP or sRGB + * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and + * the png_set_ APIs merely check that set end points are mutually + * consistent. + */ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { png_debug1(1, "in %s retrieval function", "cHRM"); if (white_x != NULL) - *white_x = png_float(png_ptr, info_ptr->x_white, "cHRM white X"); + *white_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitex, "cHRM white X"); if (white_y != NULL) - *white_y = png_float(png_ptr, info_ptr->y_white, "cHRM white Y"); + *white_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y"); if (red_x != NULL) - *red_x = png_float(png_ptr, info_ptr->x_red, "cHRM red X"); + *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx, + "cHRM red X"); if (red_y != NULL) - *red_y = png_float(png_ptr, info_ptr->y_red, "cHRM red Y"); + *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy, + "cHRM red Y"); if (green_x != NULL) - *green_x = png_float(png_ptr, info_ptr->x_green, "cHRM green X"); + *green_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greenx, "cHRM green X"); if (green_y != NULL) - *green_y = png_float(png_ptr, info_ptr->y_green, "cHRM green Y"); + *green_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y"); if (blue_x != NULL) - *blue_x = png_float(png_ptr, info_ptr->x_blue, "cHRM blue X"); + *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex, + "cHRM blue X"); if (blue_y != NULL) - *blue_y = png_float(png_ptr, info_ptr->y_blue, "cHRM blue Y"); + *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey, + "cHRM blue Y"); return (PNG_INFO_cHRM); } @@ -551,35 +555,43 @@ png_get_cHRM(png_const_structp png_ptr, png_const_infop info_ptr, } png_uint_32 PNGAPI -png_get_cHRM_XYZ(png_structp png_ptr, png_const_infop info_ptr, +png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, double *green_X, double *green_Y, double *green_Z, double *blue_X, double *blue_Y, double *blue_Z) { - png_XYZ XYZ; - - if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, - &XYZ.redX, &XYZ.redY, &XYZ.redZ, &XYZ.greenX, &XYZ.greenY, &XYZ.greenZ, - &XYZ.blueX, &XYZ.blueY, &XYZ.blueZ) & PNG_INFO_cHRM) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); + if (red_X != NULL) - *red_X = png_float(png_ptr, XYZ.redX, "cHRM red X"); + *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X, + "cHRM red X"); if (red_Y != NULL) - *red_Y = png_float(png_ptr, XYZ.redY, "cHRM red Y"); + *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y, + "cHRM red Y"); if (red_Z != NULL) - *red_Z = png_float(png_ptr, XYZ.redZ, "cHRM red Z"); + *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z, + "cHRM red Z"); if (green_X != NULL) - *green_X = png_float(png_ptr, XYZ.greenX, "cHRM green X"); + *green_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X"); if (green_Y != NULL) - *green_Y = png_float(png_ptr, XYZ.greenY, "cHRM green Y"); + *green_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y"); if (green_Z != NULL) - *green_Z = png_float(png_ptr, XYZ.greenZ, "cHRM green Z"); + *green_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z"); if (blue_X != NULL) - *blue_X = png_float(png_ptr, XYZ.blueX, "cHRM blue X"); + *blue_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X"); if (blue_Y != NULL) - *blue_Y = png_float(png_ptr, XYZ.blueY, "cHRM blue Y"); + *blue_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y"); if (blue_Z != NULL) - *blue_Z = png_float(png_ptr, XYZ.blueZ, "cHRM blue Z"); + *blue_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z"); return (PNG_INFO_cHRM); } @@ -589,31 +601,69 @@ png_get_cHRM_XYZ(png_structp png_ptr, png_const_infop info_ptr, # ifdef PNG_FIXED_POINT_SUPPORTED png_uint_32 PNGAPI -png_get_cHRM_fixed(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z) +{ + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); + + if (int_red_X != NULL) + *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X; + if (int_red_Y != NULL) + *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y; + if (int_red_Z != NULL) + *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z; + if (int_green_X != NULL) + *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X; + if (int_green_Y != NULL) + *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y; + if (int_green_Z != NULL) + *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z; + if (int_blue_X != NULL) + *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X; + if (int_blue_Y != NULL) + *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y; + if (int_blue_Z != NULL) + *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z; + return (PNG_INFO_cHRM); + } + + return (0); +} + +png_uint_32 PNGAPI +png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, png_fixed_point *blue_x, png_fixed_point *blue_y) { png_debug1(1, "in %s retrieval function", "cHRM"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { if (white_x != NULL) - *white_x = info_ptr->x_white; + *white_x = info_ptr->colorspace.end_points_xy.whitex; if (white_y != NULL) - *white_y = info_ptr->y_white; + *white_y = info_ptr->colorspace.end_points_xy.whitey; if (red_x != NULL) - *red_x = info_ptr->x_red; + *red_x = info_ptr->colorspace.end_points_xy.redx; if (red_y != NULL) - *red_y = info_ptr->y_red; + *red_y = info_ptr->colorspace.end_points_xy.redy; if (green_x != NULL) - *green_x = info_ptr->x_green; + *green_x = info_ptr->colorspace.end_points_xy.greenx; if (green_y != NULL) - *green_y = info_ptr->y_green; + *green_y = info_ptr->colorspace.end_points_xy.greeny; if (blue_x != NULL) - *blue_x = info_ptr->x_blue; + *blue_x = info_ptr->colorspace.end_points_xy.bluex; if (blue_y != NULL) - *blue_y = info_ptr->y_blue; + *blue_y = info_ptr->colorspace.end_points_xy.bluey; return (PNG_INFO_cHRM); } @@ -623,49 +673,57 @@ png_get_cHRM_fixed(png_const_structp png_ptr, png_const_infop info_ptr, #endif #ifdef PNG_gAMA_SUPPORTED -png_uint_32 PNGFAPI -png_get_gAMA_fixed(png_const_structp png_ptr, png_const_infop info_ptr, +# ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 PNGAPI +png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *file_gamma) { png_debug1(1, "in %s retrieval function", "gAMA"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) - && file_gamma != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + file_gamma != NULL) { - *file_gamma = info_ptr->gamma; + *file_gamma = info_ptr->colorspace.gamma; return (PNG_INFO_gAMA); } return (0); } +# endif + # ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 PNGAPI -png_get_gAMA(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr, double *file_gamma) { - png_fixed_point igamma; - png_uint_32 ok = png_get_gAMA_fixed(png_ptr, info_ptr, &igamma); + png_debug1(1, "in %s retrieval function", "gAMA(float)"); - if (ok) - *file_gamma = png_float(png_ptr, igamma, "png_get_gAMA"); + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + file_gamma != NULL) + { + *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma, + "png_get_gAMA"); + return (PNG_INFO_gAMA); + } - return ok; + return (0); } - # endif #endif #ifdef PNG_sRGB_SUPPORTED png_uint_32 PNGAPI -png_get_sRGB(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr, int *file_srgb_intent) { png_debug1(1, "in %s retrieval function", "sRGB"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) - && file_srgb_intent != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL) { - *file_srgb_intent = (int)info_ptr->srgb_intent; + *file_srgb_intent = info_ptr->colorspace.rendering_intent; return (PNG_INFO_sRGB); } @@ -675,23 +733,24 @@ png_get_sRGB(png_const_structp png_ptr, png_const_infop info_ptr, #ifdef PNG_iCCP_SUPPORTED png_uint_32 PNGAPI -png_get_iCCP(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, png_charpp name, int *compression_type, png_bytepp profile, png_uint_32 *proflen) { png_debug1(1, "in %s retrieval function", "iCCP"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) - && name != NULL && compression_type != NULL && profile != NULL && - proflen != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_iCCP) != 0 && + name != NULL && compression_type != NULL && profile != NULL && + proflen != NULL) { *name = info_ptr->iccp_name; *profile = info_ptr->iccp_profile; - /* Compression_type is a dummy so the API won't have to change - * if we introduce multiple compression types later. + *proflen = png_get_uint_32(info_ptr->iccp_profile); + /* This is somewhat irrelevant since the profile data returned has + * actually been uncompressed. */ - *proflen = info_ptr->iccp_proflen; - *compression_type = info_ptr->iccp_compression; + *compression_type = PNG_COMPRESSION_TYPE_BASE; return (PNG_INFO_iCCP); } @@ -700,14 +759,14 @@ png_get_iCCP(png_const_structp png_ptr, png_const_infop info_ptr, #endif #ifdef PNG_sPLT_SUPPORTED -png_uint_32 PNGAPI -png_get_sPLT(png_const_structp png_ptr, png_const_infop info_ptr, +int PNGAPI +png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, png_sPLT_tpp spalettes) { if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) { *spalettes = info_ptr->splt_palettes; - return ((png_uint_32)info_ptr->splt_palettes_num); + return info_ptr->splt_palettes_num; } return (0); @@ -716,13 +775,13 @@ png_get_sPLT(png_const_structp png_ptr, png_const_infop info_ptr, #ifdef PNG_hIST_SUPPORTED png_uint_32 PNGAPI -png_get_hIST(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_16p *hist) { png_debug1(1, "in %s retrieval function", "hIST"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) - && hist != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL) { *hist = info_ptr->hist; return (PNG_INFO_hIST); @@ -733,22 +792,27 @@ png_get_hIST(png_const_structp png_ptr, png_const_infop info_ptr, #endif png_uint_32 PNGAPI -png_get_IHDR(png_structp png_ptr, png_infop info_ptr, +png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, int *interlace_type, int *compression_type, int *filter_type) - { png_debug1(1, "in %s retrieval function", "IHDR"); - if (png_ptr == NULL || info_ptr == NULL || width == NULL || - height == NULL || bit_depth == NULL || color_type == NULL) + if (png_ptr == NULL || info_ptr == NULL) return (0); - *width = info_ptr->width; - *height = info_ptr->height; - *bit_depth = info_ptr->bit_depth; - *color_type = info_ptr->color_type; + if (width != NULL) + *width = info_ptr->width; + + if (height != NULL) + *height = info_ptr->height; + + if (bit_depth != NULL) + *bit_depth = info_ptr->bit_depth; + + if (color_type != NULL) + *color_type = info_ptr->color_type; if (compression_type != NULL) *compression_type = info_ptr->compression_type; @@ -764,7 +828,7 @@ png_get_IHDR(png_structp png_ptr, png_infop info_ptr, * application has ignored our advice not to mess with the members * of info_ptr directly. */ - png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, + png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, info_ptr->compression_type, info_ptr->filter_type); @@ -773,13 +837,14 @@ png_get_IHDR(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_oFFs_SUPPORTED png_uint_32 PNGAPI -png_get_oFFs(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) { png_debug1(1, "in %s retrieval function", "oFFs"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) - && offset_x != NULL && offset_y != NULL && unit_type != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_oFFs) != 0 && + offset_x != NULL && offset_y != NULL && unit_type != NULL) { *offset_x = info_ptr->x_offset; *offset_y = info_ptr->y_offset; @@ -793,14 +858,15 @@ png_get_oFFs(png_const_structp png_ptr, png_const_infop info_ptr, #ifdef PNG_pCAL_SUPPORTED png_uint_32 PNGAPI -png_get_pCAL(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, png_charp *units, png_charpp *params) { png_debug1(1, "in %s retrieval function", "pCAL"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) - && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_pCAL) != 0 && + purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && nparams != NULL && units != NULL && params != NULL) { *purpose = info_ptr->pcal_purpose; @@ -819,16 +885,20 @@ png_get_pCAL(png_const_structp png_ptr, png_const_infop info_ptr, #ifdef PNG_sCAL_SUPPORTED # ifdef PNG_FIXED_POINT_SUPPORTED -# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED +# if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) png_uint_32 PNGAPI -png_get_sCAL_fixed(png_structp png_ptr, png_const_infop info_ptr, +png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, png_fixed_point *width, png_fixed_point *height) { if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) + (info_ptr->valid & PNG_INFO_sCAL) != 0) { *unit = info_ptr->scal_unit; - /*TODO: make this work without FP support */ + /*TODO: make this work without FP support; the API is currently eliminated + * if neither floating point APIs nor internal floating point arithmetic + * are enabled. + */ *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width"); *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height), "sCAL height"); @@ -841,11 +911,11 @@ png_get_sCAL_fixed(png_structp png_ptr, png_const_infop info_ptr, # endif /* FIXED_POINT */ # ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 PNGAPI -png_get_sCAL(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, double *width, double *height) { if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) + (info_ptr->valid & PNG_INFO_sCAL) != 0) { *unit = info_ptr->scal_unit; *width = atof(info_ptr->scal_s_width); @@ -857,11 +927,11 @@ png_get_sCAL(png_const_structp png_ptr, png_const_infop info_ptr, } # endif /* FLOATING POINT */ png_uint_32 PNGAPI -png_get_sCAL_s(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, png_charpp width, png_charpp height) { if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL)) + (info_ptr->valid & PNG_INFO_sCAL) != 0) { *unit = info_ptr->scal_unit; *width = info_ptr->scal_s_width; @@ -875,7 +945,7 @@ png_get_sCAL_s(png_const_structp png_ptr, png_const_infop info_ptr, #ifdef PNG_pHYs_SUPPORTED png_uint_32 PNGAPI -png_get_pHYs(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) { png_uint_32 retval = 0; @@ -883,7 +953,7 @@ png_get_pHYs(png_const_structp png_ptr, png_const_infop info_ptr, png_debug1(1, "in %s retrieval function", "pHYs"); if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs)) + (info_ptr->valid & PNG_INFO_pHYs) != 0) { if (res_x != NULL) { @@ -909,13 +979,13 @@ png_get_pHYs(png_const_structp png_ptr, png_const_infop info_ptr, #endif /* pHYs */ png_uint_32 PNGAPI -png_get_PLTE(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr, png_colorp *palette, int *num_palette) { png_debug1(1, "in %s retrieval function", "PLTE"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) - && palette != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_PLTE) != 0 && palette != NULL) { *palette = info_ptr->palette; *num_palette = info_ptr->num_palette; @@ -928,13 +998,13 @@ png_get_PLTE(png_const_structp png_ptr, png_const_infop info_ptr, #ifdef PNG_sBIT_SUPPORTED png_uint_32 PNGAPI -png_get_sBIT(png_const_structp png_ptr, png_infop info_ptr, +png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, png_color_8p *sig_bit) { png_debug1(1, "in %s retrieval function", "sBIT"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) - && sig_bit != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL) { *sig_bit = &(info_ptr->sig_bit); return (PNG_INFO_sBIT); @@ -945,8 +1015,8 @@ png_get_sBIT(png_const_structp png_ptr, png_infop info_ptr, #endif #ifdef PNG_TEXT_SUPPORTED -png_uint_32 PNGAPI -png_get_text(png_const_structp png_ptr, png_const_infop info_ptr, +int PNGAPI +png_get_text(png_const_structrp png_ptr, png_inforp info_ptr, png_textp *text_ptr, int *num_text) { if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) @@ -960,7 +1030,7 @@ png_get_text(png_const_structp png_ptr, png_const_infop info_ptr, if (num_text != NULL) *num_text = info_ptr->num_text; - return ((png_uint_32)info_ptr->num_text); + return info_ptr->num_text; } if (num_text != NULL) @@ -972,12 +1042,13 @@ png_get_text(png_const_structp png_ptr, png_const_infop info_ptr, #ifdef PNG_tIME_SUPPORTED png_uint_32 PNGAPI -png_get_tIME(png_const_structp png_ptr, png_infop info_ptr, png_timep *mod_time) +png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_timep *mod_time) { png_debug1(1, "in %s retrieval function", "tIME"); - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) - && mod_time != NULL) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL) { *mod_time = &(info_ptr->mod_time); return (PNG_INFO_tIME); @@ -989,11 +1060,12 @@ png_get_tIME(png_const_structp png_ptr, png_infop info_ptr, png_timep *mod_time) #ifdef PNG_tRNS_SUPPORTED png_uint_32 PNGAPI -png_get_tRNS(png_const_structp png_ptr, png_infop info_ptr, +png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) { png_uint_32 retval = 0; - if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + if (png_ptr != NULL && info_ptr != NULL && + (info_ptr->valid & PNG_INFO_tRNS) != 0) { png_debug1(1, "in %s retrieval function", "tRNS"); @@ -1032,9 +1104,9 @@ png_get_tRNS(png_const_structp png_ptr, png_infop info_ptr, } #endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED int PNGAPI -png_get_unknown_chunks(png_const_structp png_ptr, png_const_infop info_ptr, +png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, png_unknown_chunkpp unknowns) { if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) @@ -1049,7 +1121,7 @@ png_get_unknown_chunks(png_const_structp png_ptr, png_const_infop info_ptr, #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED png_byte PNGAPI -png_get_rgb_to_gray_status (png_const_structp png_ptr) +png_get_rgb_to_gray_status (png_const_structrp png_ptr) { return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); } @@ -1057,68 +1129,91 @@ png_get_rgb_to_gray_status (png_const_structp png_ptr) #ifdef PNG_USER_CHUNKS_SUPPORTED png_voidp PNGAPI -png_get_user_chunk_ptr(png_const_structp png_ptr) +png_get_user_chunk_ptr(png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_ptr : NULL); } #endif png_size_t PNGAPI -png_get_compression_buffer_size(png_const_structp png_ptr) +png_get_compression_buffer_size(png_const_structrp png_ptr) { - return (png_ptr ? png_ptr->zbuf_size : 0); + if (png_ptr == NULL) + return 0; + +#ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) +#endif + { +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + return png_ptr->IDAT_read_size; +#else + return PNG_IDAT_READ_SIZE; +#endif + } + +#ifdef PNG_WRITE_SUPPORTED + else + return png_ptr->zbuffer_size; +#endif } #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* These functions were added to libpng 1.2.6 and were enabled * by default in libpng-1.4.0 */ png_uint_32 PNGAPI -png_get_user_width_max (png_const_structp png_ptr) +png_get_user_width_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_width_max : 0); } png_uint_32 PNGAPI -png_get_user_height_max (png_const_structp png_ptr) +png_get_user_height_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_height_max : 0); } /* This function was added to libpng 1.4.0 */ png_uint_32 PNGAPI -png_get_chunk_cache_max (png_const_structp png_ptr) +png_get_chunk_cache_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_cache_max : 0); } /* This function was added to libpng 1.4.1 */ png_alloc_size_t PNGAPI -png_get_chunk_malloc_max (png_const_structp png_ptr) +png_get_chunk_malloc_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); } -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ +#endif /* SET_USER_LIMITS */ /* These functions were added to libpng 1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED png_uint_32 PNGAPI -png_get_io_state (png_structp png_ptr) +png_get_io_state (png_const_structrp png_ptr) { return png_ptr->io_state; } png_uint_32 PNGAPI -png_get_io_chunk_type (png_const_structp png_ptr) +png_get_io_chunk_type (png_const_structrp png_ptr) { return png_ptr->chunk_name; } +#endif /* IO_STATE */ -png_const_bytep PNGAPI -png_get_io_chunk_name (png_structp png_ptr) +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +int PNGAPI +png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) { - PNG_CSTRING_FROM_CHUNK(png_ptr->io_chunk_string, png_ptr->chunk_name); - return png_ptr->io_chunk_string; + if (png_ptr != NULL && info_ptr != NULL) + return png_ptr->num_palette_max; + + return (-1); } -#endif /* ?PNG_IO_STATE_SUPPORTED */ +# endif +#endif -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif /* READ || WRITE */ diff --git a/src/3rdparty/libpng/pnginfo.h b/src/3rdparty/libpng/pnginfo.h index a33bfab06d..c8c874dd1e 100644 --- a/src/3rdparty/libpng/pnginfo.h +++ b/src/3rdparty/libpng/pnginfo.h @@ -1,12 +1,11 @@ /* pnginfo.h - header file for PNG reference library * - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.0 [January 6, 2011] - * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h @@ -55,7 +54,7 @@ struct png_info_def { - /* the following are necessary for every PNG file */ + /* The following are necessary for every PNG file */ png_uint_32 width; /* width of image in pixels (from IHDR) */ png_uint_32 height; /* height of image in pixels (from IHDR) */ png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ @@ -70,11 +69,17 @@ struct png_info_def png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ - /* The following is informational only on read, and not used on writes. */ + /* The following are set by png_set_IHDR, called from the application on + * write, but the are never actually used by the write code. + */ png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ png_byte pixel_depth; /* number of bits per pixel */ png_byte spare_byte; /* to align the data, and for future use */ + +#ifdef PNG_READ_SUPPORTED + /* This is never set during write */ png_byte signature[8]; /* magic bytes read by libpng from start of file */ +#endif /* The rest of the data is optional. If you are reading, check the * valid field to see if the information in these are valid. If you @@ -82,18 +87,25 @@ struct png_info_def * and initialize the appropriate fields below. */ -#if defined(PNG_gAMA_SUPPORTED) - /* The gAMA chunk describes the gamma characteristics of the system - * on which the image was created, normally in the range [1.0, 2.5]. - * Data is valid if (valid & PNG_INFO_gAMA) is non-zero. +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are + * defined. When COLORSPACE is switched on all the colorspace-defining + * chunks should be enabled, when GAMMA is switched on all the gamma-defining + * chunks should be enabled. If this is not done it becomes possible to read + * inconsistent PNG files and assign a probably incorrect interpretation to + * the information. (In other words, by carefully choosing which chunks to + * recognize the system configuration can select an interpretation for PNG + * files containing ambiguous data and this will result in inconsistent + * behavior between different libpng builds!) */ - png_fixed_point gamma; + png_colorspace colorspace; #endif -#ifdef PNG_sRGB_SUPPORTED - /* GR-P, 0.96a */ - /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */ - png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */ +#ifdef PNG_iCCP_SUPPORTED + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_bytep iccp_profile; /* International Color Consortium profile data */ + png_uint_32 iccp_proflen; /* ICC profile data length */ #endif #ifdef PNG_TEXT_SUPPORTED @@ -108,7 +120,7 @@ struct png_info_def int num_text; /* number of comments read or comments to write */ int max_text; /* current size of text array */ png_textp text; /* array of comments read or comments to write */ -#endif /* PNG_TEXT_SUPPORTED */ +#endif /* TEXT */ #ifdef PNG_tIME_SUPPORTED /* The tIME chunk holds the last time the displayed image data was @@ -183,23 +195,6 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) png_uint_16p hist; #endif -#ifdef PNG_cHRM_SUPPORTED - /* The cHRM chunk describes the CIE color characteristics of the monitor - * on which the PNG was created. This data allows the viewer to do gamut - * mapping of the input image to ensure that the viewer sees the same - * colors in the image as the creator. Values are in the range - * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero. - */ - png_fixed_point x_white; - png_fixed_point y_white; - png_fixed_point x_red; - png_fixed_point y_red; - png_fixed_point x_green; - png_fixed_point y_green; - png_fixed_point x_blue; - png_fixed_point y_blue; -#endif - #ifdef PNG_pCAL_SUPPORTED /* The pCAL chunk describes a transformation between the stored pixel * values and original physical data values used to create the image. @@ -224,25 +219,20 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) /* New members added in libpng-1.0.6 */ png_uint_32 free_me; /* flags items libpng is responsible for freeing */ -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) || \ - defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED /* Storage for unknown chunks that the library doesn't recognize. */ png_unknown_chunkp unknown_chunks; - int unknown_chunks_num; -#endif -#ifdef PNG_iCCP_SUPPORTED - /* iCCP chunk data. */ - png_charp iccp_name; /* profile name */ - png_bytep iccp_profile; /* International Color Consortium profile data */ - png_uint_32 iccp_proflen; /* ICC profile data length */ - png_byte iccp_compression; /* Always zero */ + /* The type of this field is limited by the type of + * png_struct::user_chunk_cache_max, else overflow can occur. + */ + int unknown_chunks_num; #endif #ifdef PNG_sPLT_SUPPORTED /* Data on sPLT chunks (there may be more than one). */ png_sPLT_tp splt_palettes; - png_uint_32 splt_palettes_num; + int splt_palettes_num; /* Match type returned by png_get API */ #endif #ifdef PNG_sCAL_SUPPORTED diff --git a/src/3rdparty/libpng/pnglibconf.h b/src/3rdparty/libpng/pnglibconf.h index aa82b574a8..f0fdcf8068 100644 --- a/src/3rdparty/libpng/pnglibconf.h +++ b/src/3rdparty/libpng/pnglibconf.h @@ -1,48 +1,31 @@ - -/* libpng STANDARD API DEFINITION */ +/* libpng 1.6.17 STANDARD API DEFINITION */ /* pnglibconf.h - library build configuration */ -/* Libpng 1.5.10 - March 29, 2012 */ +/* Libpng version 1.6.17 - March 26, 2015 */ -/* Copyright (c) 1998-2012 Glenn Randers-Pehrson */ +/* Copyright (c) 1998-2014 Glenn Randers-Pehrson */ /* This code is released under the libpng license. */ /* For conditions of distribution and use, see the disclaimer */ /* and license in png.h */ /* pnglibconf.h */ +/* Machine generated file: DO NOT EDIT */ /* Derived from: scripts/pnglibconf.dfa */ -/* If you edit this file by hand you must obey the rules expressed in */ -/* pnglibconf.dfa with respect to the dependencies between the following */ -/* symbols. It is much better to generate a new file using */ -/* scripts/libpngconf.mak */ - #ifndef PNGLCONF_H #define PNGLCONF_H -/* settings */ -#define PNG_API_RULE 0 -#define PNG_CALLOC_SUPPORTED -#define PNG_COST_SHIFT 3 -#define PNG_DEFAULT_READ_MACROS 1 -#define PNG_GAMMA_THRESHOLD_FIXED 5000 -#define PNG_MAX_GAMMA_8 11 -#define PNG_QUANTIZE_BLUE_BITS 5 -#define PNG_QUANTIZE_GREEN_BITS 5 -#define PNG_QUANTIZE_RED_BITS 5 -#define PNG_sCAL_PRECISION 5 -#define PNG_WEIGHT_SHIFT 8 -#define PNG_ZBUF_SIZE 8192 -/* end of settings */ /* options */ #define PNG_16BIT_SUPPORTED -#define PNG_ALIGN_MEMORY_SUPPORTED +#define PNG_ALIGNED_MEMORY_SUPPORTED +/*#undef PNG_ARM_NEON_API_SUPPORTED*/ +/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ #define PNG_BENIGN_ERRORS_SUPPORTED -#define PNG_bKGD_SUPPORTED +#define PNG_BENIGN_READ_ERRORS_SUPPORTED +/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ #define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED -#define PNG_CHECK_cHRM_SUPPORTED #define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED -#define PNG_cHRM_SUPPORTED +#define PNG_COLORSPACE_SUPPORTED #define PNG_CONSOLE_IO_SUPPORTED #ifndef _WIN32_WCE #define PNG_CONVERT_tIME_SUPPORTED @@ -53,18 +36,15 @@ #define PNG_FIXED_POINT_SUPPORTED #define PNG_FLOATING_ARITHMETIC_SUPPORTED #define PNG_FLOATING_POINT_SUPPORTED -#define PNG_gAMA_SUPPORTED +#define PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_BGR_SUPPORTED +#define PNG_GAMMA_SUPPORTED +#define PNG_GET_PALETTE_MAX_SUPPORTED #define PNG_HANDLE_AS_UNKNOWN_SUPPORTED -#define PNG_hIST_SUPPORTED -#define PNG_iCCP_SUPPORTED #define PNG_INCH_CONVERSIONS_SUPPORTED #define PNG_INFO_IMAGE_SUPPORTED #define PNG_IO_STATE_SUPPORTED -#define PNG_iTXt_SUPPORTED #define PNG_MNG_FEATURES_SUPPORTED -#define PNG_oFFs_SUPPORTED -#define PNG_pCAL_SUPPORTED -#define PNG_pHYs_SUPPORTED #define PNG_POINTER_INDEXING_SUPPORTED #define PNG_PROGRESSIVE_READ_SUPPORTED #define PNG_READ_16BIT_SUPPORTED @@ -72,68 +52,74 @@ #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED #define PNG_READ_BACKGROUND_SUPPORTED #define PNG_READ_BGR_SUPPORTED -#define PNG_READ_bKGD_SUPPORTED #define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED -#define PNG_READ_cHRM_SUPPORTED #define PNG_READ_COMPOSITE_NODIV_SUPPORTED #define PNG_READ_COMPRESSED_TEXT_SUPPORTED #define PNG_READ_EXPAND_16_SUPPORTED #define PNG_READ_EXPAND_SUPPORTED #define PNG_READ_FILLER_SUPPORTED -#define PNG_READ_gAMA_SUPPORTED #define PNG_READ_GAMMA_SUPPORTED +#define PNG_READ_GET_PALETTE_MAX_SUPPORTED #define PNG_READ_GRAY_TO_RGB_SUPPORTED -#define PNG_READ_hIST_SUPPORTED -#define PNG_READ_iCCP_SUPPORTED #define PNG_READ_INTERLACING_SUPPORTED #define PNG_READ_INT_FUNCTIONS_SUPPORTED #define PNG_READ_INVERT_ALPHA_SUPPORTED #define PNG_READ_INVERT_SUPPORTED -#define PNG_READ_iTXt_SUPPORTED -#define PNG_READ_oFFs_SUPPORTED #define PNG_READ_OPT_PLTE_SUPPORTED -#define PNG_READ_PACK_SUPPORTED #define PNG_READ_PACKSWAP_SUPPORTED -#define PNG_READ_pCAL_SUPPORTED -#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_PACK_SUPPORTED #define PNG_READ_QUANTIZE_SUPPORTED #define PNG_READ_RGB_TO_GRAY_SUPPORTED -#define PNG_READ_sBIT_SUPPORTED #define PNG_READ_SCALE_16_TO_8_SUPPORTED -#define PNG_READ_sCAL_SUPPORTED #define PNG_READ_SHIFT_SUPPORTED -#define PNG_READ_sPLT_SUPPORTED -#define PNG_READ_sRGB_SUPPORTED #define PNG_READ_STRIP_16_TO_8_SUPPORTED #define PNG_READ_STRIP_ALPHA_SUPPORTED #define PNG_READ_SUPPORTED #define PNG_READ_SWAP_ALPHA_SUPPORTED #define PNG_READ_SWAP_SUPPORTED -#define PNG_READ_tEXt_SUPPORTED #define PNG_READ_TEXT_SUPPORTED -#define PNG_READ_tIME_SUPPORTED #define PNG_READ_TRANSFORMS_SUPPORTED -#define PNG_READ_tRNS_SUPPORTED #define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED #define PNG_READ_USER_CHUNKS_SUPPORTED #define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_bKGD_SUPPORTED +#define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_hIST_SUPPORTED +#define PNG_READ_iCCP_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED +#define PNG_READ_oFFs_SUPPORTED +#define PNG_READ_pCAL_SUPPORTED +#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_sBIT_SUPPORTED +#define PNG_READ_sCAL_SUPPORTED +#define PNG_READ_sPLT_SUPPORTED +#define PNG_READ_sRGB_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED +#define PNG_READ_tIME_SUPPORTED +#define PNG_READ_tRNS_SUPPORTED #define PNG_READ_zTXt_SUPPORTED #define PNG_SAVE_INT_32_SUPPORTED -#define PNG_sBIT_SUPPORTED -#define PNG_sCAL_SUPPORTED +#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_SEQUENTIAL_READ_SUPPORTED +#define PNG_SETJMP_SUPPORTED #define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED #define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED -#define PNG_SETJMP_SUPPORTED +#define PNG_SET_OPTION_SUPPORTED +#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED #define PNG_SET_USER_LIMITS_SUPPORTED -#define PNG_sPLT_SUPPORTED -#define PNG_sRGB_SUPPORTED +#ifndef _WIN32_WCE +#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED +#define PNG_SIMPLIFIED_READ_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_SUPPORTED +#endif #define PNG_STDIO_SUPPORTED -#define PNG_tEXt_SUPPORTED +#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_TEXT_SUPPORTED #define PNG_TIME_RFC1123_SUPPORTED -#define PNG_tIME_SUPPORTED -#define PNG_tRNS_SUPPORTED #define PNG_UNKNOWN_CHUNKS_SUPPORTED #define PNG_USER_CHUNKS_SUPPORTED #define PNG_USER_LIMITS_SUPPORTED @@ -144,46 +130,89 @@ #define PNG_WRITE_16BIT_SUPPORTED #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED #define PNG_WRITE_BGR_SUPPORTED -#define PNG_WRITE_bKGD_SUPPORTED #define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED -#define PNG_WRITE_cHRM_SUPPORTED #define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED #define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED #define PNG_WRITE_FILLER_SUPPORTED #define PNG_WRITE_FILTER_SUPPORTED #define PNG_WRITE_FLUSH_SUPPORTED -#define PNG_WRITE_gAMA_SUPPORTED -#define PNG_WRITE_hIST_SUPPORTED -#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED #define PNG_WRITE_INTERLACING_SUPPORTED #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED #define PNG_WRITE_INVERT_ALPHA_SUPPORTED #define PNG_WRITE_INVERT_SUPPORTED -#define PNG_WRITE_iTXt_SUPPORTED -#define PNG_WRITE_oFFs_SUPPORTED #define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED -#define PNG_WRITE_PACK_SUPPORTED #define PNG_WRITE_PACKSWAP_SUPPORTED -#define PNG_WRITE_pCAL_SUPPORTED -#define PNG_WRITE_pHYs_SUPPORTED -#define PNG_WRITE_sBIT_SUPPORTED -#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_PACK_SUPPORTED #define PNG_WRITE_SHIFT_SUPPORTED -#define PNG_WRITE_sPLT_SUPPORTED -#define PNG_WRITE_sRGB_SUPPORTED #define PNG_WRITE_SUPPORTED #define PNG_WRITE_SWAP_ALPHA_SUPPORTED #define PNG_WRITE_SWAP_SUPPORTED -#define PNG_WRITE_tEXt_SUPPORTED #define PNG_WRITE_TEXT_SUPPORTED -#define PNG_WRITE_tIME_SUPPORTED #define PNG_WRITE_TRANSFORMS_SUPPORTED -#define PNG_WRITE_tRNS_SUPPORTED #define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_WRITE_USER_TRANSFORM_SUPPORTED #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#define PNG_WRITE_bKGD_SUPPORTED +#define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_gAMA_SUPPORTED +#define PNG_WRITE_hIST_SUPPORTED +#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_WRITE_oFFs_SUPPORTED +#define PNG_WRITE_pCAL_SUPPORTED +#define PNG_WRITE_pHYs_SUPPORTED +#define PNG_WRITE_sBIT_SUPPORTED +#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_sPLT_SUPPORTED +#define PNG_WRITE_sRGB_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_WRITE_tIME_SUPPORTED +#define PNG_WRITE_tRNS_SUPPORTED #define PNG_WRITE_zTXt_SUPPORTED +#define PNG_bKGD_SUPPORTED +#define PNG_cHRM_SUPPORTED +#define PNG_gAMA_SUPPORTED +#define PNG_hIST_SUPPORTED +#define PNG_iCCP_SUPPORTED +#define PNG_iTXt_SUPPORTED +#define PNG_oFFs_SUPPORTED +#define PNG_pCAL_SUPPORTED +#define PNG_pHYs_SUPPORTED +#define PNG_sBIT_SUPPORTED +#define PNG_sCAL_SUPPORTED +#define PNG_sPLT_SUPPORTED +#define PNG_sRGB_SUPPORTED +#define PNG_tEXt_SUPPORTED +#define PNG_tIME_SUPPORTED +#define PNG_tRNS_SUPPORTED #define PNG_zTXt_SUPPORTED /* end of options */ -#define PNG_SAFE_LIMITS_SUPPORTED +/* settings */ +#define PNG_API_RULE 0 +#define PNG_COST_SHIFT 3 +#define PNG_DEFAULT_READ_MACROS 1 +#define PNG_GAMMA_THRESHOLD_FIXED 5000 +#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE +#define PNG_INFLATE_BUF_SIZE 1024 +#define PNG_MAX_GAMMA_8 11 +#define PNG_QUANTIZE_BLUE_BITS 5 +#define PNG_QUANTIZE_GREEN_BITS 5 +#define PNG_QUANTIZE_RED_BITS 5 +#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) +#define PNG_TEXT_Z_DEFAULT_STRATEGY 0 +#define PNG_USER_CHUNK_CACHE_MAX 1000 +#define PNG_USER_CHUNK_MALLOC_MAX 8000000 +#define PNG_USER_HEIGHT_MAX 1000000 +#define PNG_USER_WIDTH_MAX 1000000 +#define PNG_WEIGHT_SHIFT 8 +#define PNG_ZBUF_SIZE 8192 +#define PNG_ZLIB_VERNUM 0 /* unknown */ +#define PNG_Z_DEFAULT_COMPRESSION (-1) +#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 +#define PNG_Z_DEFAULT_STRATEGY 1 +#define PNG_sCAL_PRECISION 5 +#define PNG_sRGB_PROFILE_CHECKS 2 +/* end of settings */ #endif /* PNGLCONF_H */ diff --git a/src/3rdparty/libpng/pngmem.c b/src/3rdparty/libpng/pngmem.c index bf5ff037da..8b157e54d2 100644 --- a/src/3rdparty/libpng/pngmem.c +++ b/src/3rdparty/libpng/pngmem.c @@ -1,8 +1,8 @@ /* pngmem.c - stub functions for memory allocation * - * Last changed in libpng 1.5.7 [December 15, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -20,627 +20,241 @@ #include "pngpriv.h" #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) - -/* Borland DOS special memory handler */ -#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) -/* If you change this, be sure to change the one in png.h also */ - -/* Allocate memory for a png_struct. The malloc and memset can be replaced - by a single call to calloc() if this is thought to improve performance. */ -PNG_FUNCTION(png_voidp /* PRIVATE */, -png_create_struct,(int type),PNG_ALLOCATED) -{ -# ifdef PNG_USER_MEM_SUPPORTED - return (png_create_struct_2(type, NULL, NULL)); -} - -/* Alternate version of png_create_struct, for use with user-defined malloc. */ -PNG_FUNCTION(png_voidp /* PRIVATE */, -png_create_struct_2,(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr), - PNG_ALLOCATED) -{ -# endif /* PNG_USER_MEM_SUPPORTED */ - png_size_t size; - png_voidp struct_ptr; - - if (type == PNG_STRUCT_INFO) - size = png_sizeof(png_info); - - else if (type == PNG_STRUCT_PNG) - size = png_sizeof(png_struct); - - else - return (png_get_copyright(NULL)); - -# ifdef PNG_USER_MEM_SUPPORTED - if (malloc_fn != NULL) - { - png_struct dummy_struct; - memset(&dummy_struct, 0, sizeof dummy_struct); - dummy_struct.mem_ptr=mem_ptr; - struct_ptr = (*(malloc_fn))(&dummy_struct, (png_alloc_size_t)size); - } - - else -# endif /* PNG_USER_MEM_SUPPORTED */ - struct_ptr = (png_voidp)farmalloc(size); - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - - return (struct_ptr); -} - -/* Free memory allocated by a png_create_struct() call */ +/* Free a png_struct */ void /* PRIVATE */ -png_destroy_struct(png_voidp struct_ptr) +png_destroy_png_struct(png_structrp png_ptr) { -# ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2(struct_ptr, NULL, NULL); -} - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, - png_voidp mem_ptr) -{ -# endif - if (struct_ptr != NULL) + if (png_ptr != NULL) { -# ifdef PNG_USER_MEM_SUPPORTED - if (free_fn != NULL) - { - png_struct dummy_struct; - memset(&dummy_struct, 0, sizeof dummy_struct); - dummy_struct.mem_ptr=mem_ptr; - (*(free_fn))(&dummy_struct, struct_ptr); - return; - } - -# endif /* PNG_USER_MEM_SUPPORTED */ - farfree (struct_ptr); + /* png_free might call png_error and may certainly call + * png_get_mem_ptr, so fake a temporary png_struct to support this. + */ + png_struct dummy_struct = *png_ptr; + memset(png_ptr, 0, (sizeof *png_ptr)); + png_free(&dummy_struct, png_ptr); + +# ifdef PNG_SETJMP_SUPPORTED + /* We may have a jmp_buf left to deallocate. */ + png_free_jmpbuf(&dummy_struct); +# endif } } /* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does + * 64K. However, zlib may allocate more than 64K if you don't tell + * it not to. See zconf.h and png.h for more information. zlib does * need to allocate exactly 64K, so whatever you call here must * have the ability to do that. - * - * Borland seems to have a problem in DOS mode for exactly 64K. - * It gives you a segment with an offset of 8 (perhaps to store its - * memory stuff). zlib doesn't like this at all, so we have to - * detect and deal with it. This code should not be needed in - * Windows or OS/2 modes, and only in 16 bit mode. This code has - * been updated by Alexander Lehmann for version 0.89 to waste less - * memory. - * - * Note that we can't use png_size_t for the "size" declaration, - * since on some systems a png_size_t is a 16-bit quantity, and as a - * result, we would be truncating potentially larger memory requests - * (which should cause a fatal error) and introducing major problems. */ PNG_FUNCTION(png_voidp,PNGAPI -png_calloc,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) { png_voidp ret; - ret = (png_malloc(png_ptr, size)); + ret = png_malloc(png_ptr, size); if (ret != NULL) - png_memset(ret,0,(png_size_t)size); - - return (ret); -} - -PNG_FUNCTION(png_voidp,PNGAPI -png_malloc,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) -{ - png_voidp ret; - - if (png_ptr == NULL || size == 0) - return (NULL); - -# ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->malloc_fn != NULL) - ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, size)); - - else - ret = (png_malloc_default(png_ptr, size)); - - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory"); + memset(ret, 0, size); - return (ret); + return ret; } -PNG_FUNCTION(png_voidp,PNGAPI -png_malloc_default,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of + * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED. + * Checking and error handling must happen outside this routine; it returns NULL + * if the allocation cannot be done (for any reason.) + */ +PNG_FUNCTION(png_voidp /* PRIVATE */, +png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) { - png_voidp ret; -# endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || size == 0) - return (NULL); - -# ifdef PNG_MAX_MALLOC_64K - if (size > (png_uint_32)65536L) - { - png_warning(png_ptr, "Cannot Allocate > 64K"); - ret = NULL; - } - - else -# endif - - if (size != (size_t)size) - ret = NULL; - - else if (size == (png_uint_32)65536L) + /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS + * allocators have also been removed in 1.6.0, so any 16-bit system now has + * to implement a user memory handler. This checks to be sure it isn't + * called with big numbers. + */ +#ifndef PNG_USER_MEM_SUPPORTED + PNG_UNUSED(png_ptr) +#endif + + if (size > 0 && size <= PNG_SIZE_MAX +# ifdef PNG_MAX_MALLOC_64K + && size <= 65536U +# endif + ) { - if (png_ptr->offset_table == NULL) - { - /* Try to see if we need to do any of this fancy stuff */ - ret = farmalloc(size); - if (ret == NULL || ((png_size_t)ret & 0xffff)) - { - int num_blocks; - png_uint_32 total_size; - png_bytep table; - int i, mem_level, window_bits; - png_byte huge * hptr; - int window_bits - - if (ret != NULL) - { - farfree(ret); - ret = NULL; - } - - window_bits = - png_ptr->zlib_window_bits >= png_ptr->zlib_text_window_bits ? - png_ptr->zlib_window_bits : png_ptr->zlib_text_window_bits; - - if (window_bits > 14) - num_blocks = (int)(1 << (window_bits - 14)); - - else - num_blocks = 1; - - mem_level = - png_ptr->zlib_mem_level >= png_ptr->zlib_text_mem_level ? - png_ptr->zlib_mem_level : png_ptr->zlib_text_mem_level; - - if (mem_level >= 7) - num_blocks += (int)(1 << (mem_level - 7)); - - else - num_blocks++; - - total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16; - - table = farmalloc(total_size); - - if (table == NULL) - { -# ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out Of Memory"); /* Note "O", "M" */ - - else - png_warning(png_ptr, "Out Of Memory"); -# endif - return (NULL); - } - - if ((png_size_t)table & 0xfff0) - { -# ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, - "Farmalloc didn't return normalized pointer"); - - else - png_warning(png_ptr, - "Farmalloc didn't return normalized pointer"); -# endif - return (NULL); - } - - png_ptr->offset_table = table; - png_ptr->offset_table_ptr = farmalloc(num_blocks * - png_sizeof(png_bytep)); - - if (png_ptr->offset_table_ptr == NULL) - { -# ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out Of memory"); /* Note "O", "m" */ - - else - png_warning(png_ptr, "Out Of memory"); -# endif - return (NULL); - } - - hptr = (png_byte huge *)table; - if ((png_size_t)hptr & 0xf) - { - hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L); - hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */ - } - - for (i = 0; i < num_blocks; i++) - { - png_ptr->offset_table_ptr[i] = (png_bytep)hptr; - hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */ - } - - png_ptr->offset_table_number = num_blocks; - png_ptr->offset_table_count = 0; - png_ptr->offset_table_count_free = 0; - } - } - - if (png_ptr->offset_table_count >= png_ptr->offset_table_number) - { -# ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); /* Note "O" and "M" */ - - else - png_warning(png_ptr, "Out of Memory"); -# endif - return (NULL); - } - - ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++]; - } - - else - ret = farmalloc(size); - -# ifndef PNG_USER_MEM_SUPPORTED - if (ret == NULL) - { - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of memory"); /* Note "o" and "m" */ +#ifdef PNG_USER_MEM_SUPPORTED + if (png_ptr != NULL && png_ptr->malloc_fn != NULL) + return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size); else - png_warning(png_ptr, "Out of memory"); /* Note "o" and "m" */ +#endif + return malloc((size_t)size); /* checked for truncation above */ } -# endif - return (ret); + else + return NULL; } -/* Free a pointer allocated by png_malloc(). In the default - * configuration, png_ptr is not used, but is passed in case it - * is needed. If ptr is NULL, return without taking any action. +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7 + * that arises because of the checks in png_realloc_array that are repeated in + * png_malloc_array. */ -void PNGAPI -png_free(png_structp png_ptr, png_voidp ptr) +static png_voidp +png_malloc_array_checked(png_const_structrp png_ptr, int nelements, + size_t element_size) { - if (png_ptr == NULL || ptr == NULL) - return; + png_alloc_size_t req = nelements; /* known to be > 0 */ -# ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr->free_fn != NULL) - { - (*(png_ptr->free_fn))(png_ptr, ptr); - return; - } + if (req <= PNG_SIZE_MAX/element_size) + return png_malloc_base(png_ptr, req * element_size); - else - png_free_default(png_ptr, ptr); + /* The failure case when the request is too large */ + return NULL; } -void PNGAPI -png_free_default(png_structp png_ptr, png_voidp ptr) -{ -# endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || ptr == NULL) - return; - - if (png_ptr->offset_table != NULL) - { - int i; - - for (i = 0; i < png_ptr->offset_table_count; i++) - { - if (ptr == png_ptr->offset_table_ptr[i]) - { - ptr = NULL; - png_ptr->offset_table_count_free++; - break; - } - } - if (png_ptr->offset_table_count_free == png_ptr->offset_table_count) - { - farfree(png_ptr->offset_table); - farfree(png_ptr->offset_table_ptr); - png_ptr->offset_table = NULL; - png_ptr->offset_table_ptr = NULL; - } - } - - if (ptr != NULL) - farfree(ptr); -} - -#else /* Not the Borland DOS special memory handler */ - -/* Allocate memory for a png_struct or a png_info. The malloc and - memset can be replaced by a single call to calloc() if this is thought - to improve performance noticably. */ PNG_FUNCTION(png_voidp /* PRIVATE */, -png_create_struct,(int type),PNG_ALLOCATED) +png_malloc_array,(png_const_structrp png_ptr, int nelements, + size_t element_size),PNG_ALLOCATED) { -# ifdef PNG_USER_MEM_SUPPORTED - return (png_create_struct_2(type, NULL, NULL)); + if (nelements <= 0 || element_size == 0) + png_error(png_ptr, "internal error: array alloc"); + + return png_malloc_array_checked(png_ptr, nelements, element_size); } -/* Allocate memory for a png_struct or a png_info. The malloc and - memset can be replaced by a single call to calloc() if this is thought - to improve performance noticably. */ PNG_FUNCTION(png_voidp /* PRIVATE */, -png_create_struct_2,(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr), - PNG_ALLOCATED) +png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, + int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED) { -# endif /* PNG_USER_MEM_SUPPORTED */ - png_size_t size; - png_voidp struct_ptr; - - if (type == PNG_STRUCT_INFO) - size = png_sizeof(png_info); - - else if (type == PNG_STRUCT_PNG) - size = png_sizeof(png_struct); - - else - return (NULL); - -# ifdef PNG_USER_MEM_SUPPORTED - if (malloc_fn != NULL) + /* These are internal errors: */ + if (add_elements <= 0 || element_size == 0 || old_elements < 0 || + (old_array == NULL && old_elements > 0)) + png_error(png_ptr, "internal error: array realloc"); + + /* Check for overflow on the elements count (so the caller does not have to + * check.) + */ + if (add_elements <= INT_MAX - old_elements) { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - struct_ptr = (*(malloc_fn))(png_ptr, size); - - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - - return (struct_ptr); - } -# endif /* PNG_USER_MEM_SUPPORTED */ - -# if defined(__TURBOC__) && !defined(__FLAT__) - struct_ptr = (png_voidp)farmalloc(size); -# else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - struct_ptr = (png_voidp)halloc(size, 1); -# else - struct_ptr = (png_voidp)malloc(size); -# endif -# endif - - if (struct_ptr != NULL) - png_memset(struct_ptr, 0, size); - - return (struct_ptr); -} - + png_voidp new_array = png_malloc_array_checked(png_ptr, + old_elements+add_elements, element_size); -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct(png_voidp struct_ptr) -{ -# ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2(struct_ptr, NULL, NULL); -} - -/* Free memory allocated by a png_create_struct() call */ -void /* PRIVATE */ -png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, - png_voidp mem_ptr) -{ -# endif /* PNG_USER_MEM_SUPPORTED */ - if (struct_ptr != NULL) - { -# ifdef PNG_USER_MEM_SUPPORTED - if (free_fn != NULL) + if (new_array != NULL) { - png_struct dummy_struct; - png_structp png_ptr = &dummy_struct; - png_ptr->mem_ptr=mem_ptr; - (*(free_fn))(png_ptr, struct_ptr); - return; - } -# endif /* PNG_USER_MEM_SUPPORTED */ -# if defined(__TURBOC__) && !defined(__FLAT__) - farfree(struct_ptr); - -# else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - hfree(struct_ptr); + /* Because png_malloc_array worked the size calculations below cannot + * overflow. + */ + if (old_elements > 0) + memcpy(new_array, old_array, element_size*(unsigned)old_elements); -# else - free(struct_ptr); + memset((char*)new_array + element_size*(unsigned)old_elements, 0, + element_size*(unsigned)add_elements); -# endif -# endif + return new_array; + } } + + return NULL; /* error */ } +#endif /* TEXT || sPLT || STORE_UNKNOWN_CHUNKS */ -/* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does - * need to allocate exactly 64K, so whatever you call here must - * have the ability to do that. +/* Various functions that have different error handling are derived from this. + * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate + * function png_malloc_default is also provided. */ - PNG_FUNCTION(png_voidp,PNGAPI -png_calloc,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) { png_voidp ret; - ret = (png_malloc(png_ptr, size)); + if (png_ptr == NULL) + return NULL; - if (ret != NULL) - png_memset(ret,0,(png_size_t)size); + ret = png_malloc_base(png_ptr, size); - return (ret); + if (ret == NULL) + png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */ + + return ret; } +#ifdef PNG_USER_MEM_SUPPORTED PNG_FUNCTION(png_voidp,PNGAPI -png_malloc,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED PNG_DEPRECATED) { png_voidp ret; -# ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr == NULL || size == 0) - return (NULL); - - if (png_ptr->malloc_fn != NULL) - ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size)); + if (png_ptr == NULL) + return NULL; - else - ret = (png_malloc_default(png_ptr, size)); + /* Passing 'NULL' here bypasses the application provided memory handler. */ + ret = png_malloc_base(NULL/*use malloc*/, size); - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); + if (ret == NULL) + png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */ - return (ret); + return ret; } +#endif /* USER_MEM */ +/* This function was added at libpng version 1.2.3. The png_malloc_warn() + * function will issue a png_warning and return NULL instead of issuing a + * png_error, if it fails to allocate the requested memory. + */ PNG_FUNCTION(png_voidp,PNGAPI -png_malloc_default,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) +png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size), + PNG_ALLOCATED) { - png_voidp ret; -# endif /* PNG_USER_MEM_SUPPORTED */ - - if (png_ptr == NULL || size == 0) - return (NULL); - -# ifdef PNG_MAX_MALLOC_64K - if (size > (png_uint_32)65536L) + if (png_ptr != NULL) { -# ifndef PNG_USER_MEM_SUPPORTED - if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Cannot Allocate > 64K"); - - else -# endif - return NULL; - } -# endif - - /* Check for overflow */ -# if defined(__TURBOC__) && !defined(__FLAT__) - - if (size != (unsigned long)size) - ret = NULL; - - else - ret = farmalloc(size); - -# else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - if (size != (unsigned long)size) - ret = NULL; - - else - ret = halloc(size, 1); + png_voidp ret = png_malloc_base(png_ptr, size); -# else - if (size != (size_t)size) - ret = NULL; + if (ret != NULL) + return ret; - else - ret = malloc((size_t)size); -# endif -# endif - -# ifndef PNG_USER_MEM_SUPPORTED - if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); -# endif + png_warning(png_ptr, "Out of memory"); + } - return (ret); + return NULL; } /* Free a pointer allocated by png_malloc(). If ptr is NULL, return * without taking any action. */ void PNGAPI -png_free(png_structp png_ptr, png_voidp ptr) +png_free(png_const_structrp png_ptr, png_voidp ptr) { if (png_ptr == NULL || ptr == NULL) return; -# ifdef PNG_USER_MEM_SUPPORTED +#ifdef PNG_USER_MEM_SUPPORTED if (png_ptr->free_fn != NULL) - { - (*(png_ptr->free_fn))(png_ptr, ptr); - return; - } + png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr); else png_free_default(png_ptr, ptr); } -void PNGAPI -png_free_default(png_structp png_ptr, png_voidp ptr) +PNG_FUNCTION(void,PNGAPI +png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED) { if (png_ptr == NULL || ptr == NULL) return; +#endif /* USER_MEM */ -# endif /* PNG_USER_MEM_SUPPORTED */ - -# if defined(__TURBOC__) && !defined(__FLAT__) - farfree(ptr); - -# else -# if defined(_MSC_VER) && defined(MAXSEG_64K) - hfree(ptr); - -# else free(ptr); - -# endif -# endif -} -#endif /* Not Borland DOS special memory handler */ - -/* This function was added at libpng version 1.2.3. The png_malloc_warn() - * function will set up png_malloc() to issue a png_warning and return NULL - * instead of issuing a png_error, if it fails to allocate the requested - * memory. - */ -PNG_FUNCTION(png_voidp,PNGAPI -png_malloc_warn,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) -{ - png_voidp ptr; - png_uint_32 save_flags; - if (png_ptr == NULL) - return (NULL); - - save_flags = png_ptr->flags; - png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK; - ptr = (png_voidp)png_malloc((png_structp)png_ptr, size); - png_ptr->flags=save_flags; - return(ptr); } - #ifdef PNG_USER_MEM_SUPPORTED /* This function is called when the application wants to use another method * of allocating and freeing memory. */ void PNGAPI -png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr +png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn) { if (png_ptr != NULL) @@ -656,12 +270,12 @@ png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr * pointer before png_write_destroy and png_read_destroy are called. */ png_voidp PNGAPI -png_get_mem_ptr(png_const_structp png_ptr) +png_get_mem_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) - return (NULL); + return NULL; - return ((png_voidp)png_ptr->mem_ptr); + return png_ptr->mem_ptr; } -#endif /* PNG_USER_MEM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif /* USER_MEM */ +#endif /* READ || WRITE */ diff --git a/src/3rdparty/libpng/pngpread.c b/src/3rdparty/libpng/pngpread.c index 8a5aa29ec8..823dcad8c0 100644 --- a/src/3rdparty/libpng/pngpread.c +++ b/src/3rdparty/libpng/pngpread.c @@ -1,8 +1,8 @@ /* pngpread.c - read a png file in push mode * - * Last changed in libpng 1.5.9 [February 18, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -26,8 +26,15 @@ #define PNG_READ_iTXt_MODE 7 #define PNG_ERROR_MODE 8 +#define PNG_PUSH_SAVE_BUFFER_IF_FULL \ +if (png_ptr->push_length + 4 > png_ptr->buffer_size) \ + { png_push_save_buffer(png_ptr); return; } +#define PNG_PUSH_SAVE_BUFFER_IF_LT(N) \ +if (png_ptr->buffer_size < N) \ + { png_push_save_buffer(png_ptr); return; } + void PNGAPI -png_process_data(png_structp png_ptr, png_infop info_ptr, +png_process_data(png_structrp png_ptr, png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size) { if (png_ptr == NULL || info_ptr == NULL) @@ -42,14 +49,14 @@ png_process_data(png_structp png_ptr, png_infop info_ptr, } png_size_t PNGAPI -png_process_data_pause(png_structp png_ptr, int save) +png_process_data_pause(png_structrp png_ptr, int save) { if (png_ptr != NULL) { - /* It's easiest for the caller if we do the save, then the caller doesn't + /* It's easiest for the caller if we do the save; then the caller doesn't * have to supply the same data again: */ - if (save) + if (save != 0) png_push_save_buffer(png_ptr); else { @@ -69,7 +76,7 @@ png_process_data_pause(png_structp png_ptr, int save) } png_uint_32 PNGAPI -png_process_data_skip(png_structp png_ptr) +png_process_data_skip(png_structrp png_ptr) { png_uint_32 remaining = 0; @@ -103,7 +110,7 @@ png_process_data_skip(png_structp png_ptr) * doing before we ran out of data... */ void /* PRIVATE */ -png_process_some_data(png_structp png_ptr, png_infop info_ptr) +png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) { if (png_ptr == NULL) return; @@ -149,10 +156,10 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr) * routine. */ void /* PRIVATE */ -png_push_read_sig(png_structp png_ptr, png_infop info_ptr) +png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) { - png_size_t num_checked = png_ptr->sig_bytes, - num_to_check = 8 - num_checked; + png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */ + num_to_check = 8 - num_checked; if (png_ptr->buffer_size < num_to_check) { @@ -172,7 +179,6 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr) else png_error(png_ptr, "PNG file corrupted by ASCII conversion"); } - else { if (png_ptr->sig_bytes >= 8) @@ -183,27 +189,25 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr) } void /* PRIVATE */ -png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) +png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) { png_uint_32 chunk_name; +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; /* unknown handling method */ +#endif - /* First we make sure we have enough data for the 4 byte chunk name - * and the 4 byte chunk length before proceeding with decoding the + /* First we make sure we have enough data for the 4-byte chunk name + * and the 4-byte chunk length before proceeding with decoding the * chunk data. To fully decode each of these chunks, we also make - * sure we have enough data in the buffer for the 4 byte CRC at the + * sure we have enough data in the buffer for the 4-byte CRC at the * end of every chunk (except IDAT, which is handled separately). */ - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) { png_byte chunk_length[4]; png_byte chunk_tag[4]; - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_LT(8) png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); @@ -217,14 +221,29 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) if (chunk_name == png_IDAT) { - /* This is here above the if/else case statement below because if the - * unknown handling marks 'IDAT' as unknown then the IDAT handling case is - * completely skipped. - * - * TODO: there must be a better way of doing this. - */ - if (png_ptr->mode & PNG_AFTER_IDAT) + if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + + /* If we reach an IDAT chunk, this means we have read all of the + * header chunks, and we can start reading the image (or if this + * is called after the image has been read - we have an error). + */ + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + png_error(png_ptr, "Missing PLTE before IDAT"); + + png_ptr->mode |= PNG_HAVE_IDAT; + png_ptr->process_mode = PNG_READ_IDAT_MODE; + + if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0) + if (png_ptr->push_length == 0) + return; + + if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_benign_error(png_ptr, "Too many IDATs found"); } if (chunk_name == png_IHDR) @@ -232,23 +251,13 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) if (png_ptr->push_length != 13) png_error(png_ptr, "Invalid IHDR length"); - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IEND) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); png_ptr->process_mode = PNG_READ_DONE_MODE; @@ -256,70 +265,25 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) } #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_chunk_unknown_handling(png_ptr, chunk_name)) + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - - if (chunk_name == png_IDAT) - png_ptr->mode |= PNG_HAVE_IDAT; - - png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; - - else if (chunk_name == png_IDAT) - { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - } } - #endif + else if (chunk_name == png_PLTE) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IDAT) { - /* If we reach an IDAT chunk, this means we have read all of the - * header chunks, and we can start reading the image (or if this - * is called after the image has been read - we have an error). - */ - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - - if (png_ptr->mode & PNG_HAVE_IDAT) - { - if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) - if (png_ptr->push_length == 0) - return; - - if (png_ptr->mode & PNG_AFTER_IDAT) - png_benign_error(png_ptr, "Too many IDATs found"); - } - png_ptr->idat_size = png_ptr->push_length; - png_ptr->mode |= PNG_HAVE_IDAT; png_ptr->process_mode = PNG_READ_IDAT_MODE; png_push_have_info(png_ptr, info_ptr); png_ptr->zstream.avail_out = @@ -332,12 +296,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_gAMA_SUPPORTED else if (png_ptr->chunk_name == png_gAMA) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); } @@ -345,12 +304,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_sBIT_SUPPORTED else if (png_ptr->chunk_name == png_sBIT) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); } @@ -358,12 +312,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_cHRM_SUPPORTED else if (png_ptr->chunk_name == png_cHRM) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } @@ -371,12 +320,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_sRGB_SUPPORTED else if (chunk_name == png_sRGB) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); } @@ -384,12 +328,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_iCCP_SUPPORTED else if (png_ptr->chunk_name == png_iCCP) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); } @@ -397,12 +336,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_sPLT_SUPPORTED else if (chunk_name == png_sPLT) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); } @@ -410,12 +344,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_tRNS_SUPPORTED else if (chunk_name == png_tRNS) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); } @@ -423,12 +352,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_bKGD_SUPPORTED else if (chunk_name == png_bKGD) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); } @@ -436,12 +360,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_hIST_SUPPORTED else if (chunk_name == png_hIST) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); } @@ -449,12 +368,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_pHYs_SUPPORTED else if (chunk_name == png_pHYs) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); } @@ -462,12 +376,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_oFFs_SUPPORTED else if (chunk_name == png_oFFs) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); } #endif @@ -475,12 +384,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_pCAL_SUPPORTED else if (chunk_name == png_pCAL) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); } @@ -488,12 +392,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_sCAL_SUPPORTED else if (chunk_name == png_sCAL) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); } @@ -501,12 +400,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_tIME_SUPPORTED else if (chunk_name == png_tIME) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); } @@ -514,12 +408,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_tEXt_SUPPORTED else if (chunk_name == png_tEXt) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); } @@ -527,12 +416,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_zTXt_SUPPORTED else if (chunk_name == png_zTXt) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); } @@ -540,40 +424,32 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_iTXt_SUPPORTED else if (chunk_name == png_iTXt) { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } - #endif + else { - if (png_ptr->push_length + 4 > png_ptr->buffer_size) - { - png_push_save_buffer(png_ptr); - return; - } - png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); + PNG_PUSH_SAVE_BUFFER_IF_FULL + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, + PNG_HANDLE_CHUNK_AS_DEFAULT); } png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; } void /* PRIVATE */ -png_push_crc_skip(png_structp png_ptr, png_uint_32 skip) +png_push_crc_skip(png_structrp png_ptr, png_uint_32 skip) { png_ptr->process_mode = PNG_SKIP_MODE; png_ptr->skip_length = skip; } void /* PRIVATE */ -png_push_crc_finish(png_structp png_ptr) +png_push_crc_finish(png_structrp png_ptr) { - if (png_ptr->skip_length && png_ptr->save_buffer_size) + if (png_ptr->skip_length != 0 && png_ptr->save_buffer_size != 0) { png_size_t save_size = png_ptr->save_buffer_size; png_uint_32 skip_length = png_ptr->skip_length; @@ -597,8 +473,7 @@ png_push_crc_finish(png_structp png_ptr) png_ptr->save_buffer_size -= save_size; png_ptr->save_buffer_ptr += save_size; } - - if (png_ptr->skip_length && png_ptr->current_buffer_size) + if (png_ptr->skip_length != 0 && png_ptr->current_buffer_size != 0) { png_size_t save_size = png_ptr->current_buffer_size; png_uint_32 skip_length = png_ptr->skip_length; @@ -619,15 +494,9 @@ png_push_crc_finish(png_structp png_ptr) png_ptr->current_buffer_size -= save_size; png_ptr->current_buffer_ptr += save_size; } - - if (!png_ptr->skip_length) + if (png_ptr->skip_length == 0) { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_LT(4) png_crc_finish(png_ptr, 0); png_ptr->process_mode = PNG_READ_CHUNK_MODE; } @@ -642,8 +511,7 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) return; ptr = buffer; - - if (png_ptr->save_buffer_size) + if (png_ptr->save_buffer_size != 0) { png_size_t save_size; @@ -653,15 +521,14 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) else save_size = png_ptr->save_buffer_size; - png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size); + memcpy(ptr, png_ptr->save_buffer_ptr, save_size); length -= save_size; ptr += save_size; png_ptr->buffer_size -= save_size; png_ptr->save_buffer_size -= save_size; png_ptr->save_buffer_ptr += save_size; } - - if (length && png_ptr->current_buffer_size) + if (length != 0 && png_ptr->current_buffer_size != 0) { png_size_t save_size; @@ -671,7 +538,7 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) else save_size = png_ptr->current_buffer_size; - png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size); + memcpy(ptr, png_ptr->current_buffer_ptr, save_size); png_ptr->buffer_size -= save_size; png_ptr->current_buffer_size -= save_size; png_ptr->current_buffer_ptr += save_size; @@ -679,9 +546,9 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) } void /* PRIVATE */ -png_push_save_buffer(png_structp png_ptr) +png_push_save_buffer(png_structrp png_ptr) { - if (png_ptr->save_buffer_size) + if (png_ptr->save_buffer_size != 0) { if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) { @@ -690,7 +557,6 @@ png_push_save_buffer(png_structp png_ptr) png_bytep dp; istop = png_ptr->save_buffer_size; - for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; i < istop; i++, sp++, dp++) { @@ -698,7 +564,6 @@ png_push_save_buffer(png_structp png_ptr) } } } - if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > png_ptr->save_buffer_max) { @@ -713,33 +578,34 @@ png_push_save_buffer(png_structp png_ptr) new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; old_buffer = png_ptr->save_buffer; - png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, new_max); + png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, + (png_size_t)new_max); if (png_ptr->save_buffer == NULL) { png_free(png_ptr, old_buffer); + old_buffer = NULL; png_error(png_ptr, "Insufficient memory for save_buffer"); } - png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); + memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); png_free(png_ptr, old_buffer); + old_buffer = NULL; png_ptr->save_buffer_max = new_max; } - if (png_ptr->current_buffer_size) { - png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, + memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); png_ptr->save_buffer_size += png_ptr->current_buffer_size; png_ptr->current_buffer_size = 0; } - png_ptr->save_buffer_ptr = png_ptr->save_buffer; png_ptr->buffer_size = 0; } void /* PRIVATE */ -png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, +png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length) { png_ptr->current_buffer = buffer; @@ -749,20 +615,15 @@ png_push_restore_buffer(png_structp png_ptr, png_bytep buffer, } void /* PRIVATE */ -png_push_read_IDAT(png_structp png_ptr) +png_push_read_IDAT(png_structrp png_ptr) { - if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) + if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) { png_byte chunk_length[4]; png_byte chunk_tag[4]; /* TODO: this code can be commoned up with the same code in push_read */ - if (png_ptr->buffer_size < 8) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_LT(8) png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); @@ -774,7 +635,7 @@ png_push_read_IDAT(png_structp png_ptr) { png_ptr->process_mode = PNG_READ_CHUNK_MODE; - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) png_error(png_ptr, "Not enough compressed data"); return; @@ -783,7 +644,7 @@ png_push_read_IDAT(png_structp png_ptr) png_ptr->idat_size = png_ptr->push_length; } - if (png_ptr->idat_size && png_ptr->save_buffer_size) + if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0) { png_size_t save_size = png_ptr->save_buffer_size; png_uint_32 idat_size = png_ptr->idat_size; @@ -810,7 +671,7 @@ png_push_read_IDAT(png_structp png_ptr) png_ptr->save_buffer_ptr += save_size; } - if (png_ptr->idat_size && png_ptr->current_buffer_size) + if (png_ptr->idat_size != 0 && png_ptr->current_buffer_size != 0) { png_size_t save_size = png_ptr->current_buffer_size; png_uint_32 idat_size = png_ptr->idat_size; @@ -835,23 +696,18 @@ png_push_read_IDAT(png_structp png_ptr) png_ptr->current_buffer_size -= save_size; png_ptr->current_buffer_ptr += save_size; } - - if (!png_ptr->idat_size) + if (png_ptr->idat_size == 0) { - if (png_ptr->buffer_size < 4) - { - png_push_save_buffer(png_ptr); - return; - } - + PNG_PUSH_SAVE_BUFFER_IF_LT(4) png_crc_finish(png_ptr, 0); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->zowner = 0; } } void /* PRIVATE */ -png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, +png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length) { /* The caller checks for a non-zero buffer length. */ @@ -863,13 +719,14 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, * handle the uncompressed results. */ png_ptr->zstream.next_in = buffer; + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ png_ptr->zstream.avail_in = (uInt)buffer_length; /* Keep going until the decompressed data is all processed * or the stream marked as finished. */ while (png_ptr->zstream.avail_in > 0 && - !(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) + (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) { int ret; @@ -880,9 +737,9 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, */ if (!(png_ptr->zstream.avail_out > 0)) { - png_ptr->zstream.avail_out = - (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; + /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ + png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, + png_ptr->iwidth) + 1); png_ptr->zstream.next_out = png_ptr->row_buf; } @@ -900,7 +757,8 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, if (ret != Z_OK && ret != Z_STREAM_END) { /* Terminate the decompression. */ - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; /* This may be a truncated stream (missing or * damaged end code). Treat that as a warning. @@ -928,7 +786,8 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, { /* Extra data. */ png_warning(png_ptr, "Extra compressed data in IDAT"); - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + png_ptr->zowner = 0; /* Do no more processing; skip the unprocessed * input check below. @@ -943,7 +802,7 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, /* And check for the end of the stream. */ if (ret == Z_STREAM_END) - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; } /* All the data should have been processed, if anything @@ -955,7 +814,7 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer, } void /* PRIVATE */ -png_push_process_row(png_structp png_ptr) +png_push_process_row(png_structrp png_ptr) { /* 1.5.6: row_info moved out of png_struct to a local here. */ png_row_info row_info; @@ -981,10 +840,10 @@ png_push_process_row(png_structp png_ptr) * it may not be in the future, so this was changed just to copy the * interlaced row count: */ - png_memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); #ifdef PNG_READ_TRANSFORMS_SUPPORTED - if (png_ptr->transformations) + if (png_ptr->transformations != 0) png_do_read_transformations(png_ptr, &row_info); #endif @@ -1001,15 +860,16 @@ png_push_process_row(png_structp png_ptr) #ifdef PNG_READ_INTERLACING_SUPPORTED - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + /* Expand interlaced rows to full size */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { if (png_ptr->pass < 6) png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); - switch (png_ptr->pass) - { + switch (png_ptr->pass) + { case 0: { int i; @@ -1184,26 +1044,26 @@ png_push_process_row(png_structp png_ptr) } void /* PRIVATE */ -png_read_push_finish_row(png_structp png_ptr) +png_read_push_finish_row(png_structrp png_ptr) { #ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - static PNG_CONST png_byte FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - static PNG_CONST png_byte FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ - static PNG_CONST png_byte FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ - static PNG_CONST png_byte FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; /* Height of interlace block. This is not currently used - if you need * it, uncomment it here and in png.h - static PNG_CONST png_byte FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; */ #endif @@ -1212,10 +1072,10 @@ png_read_push_finish_row(png_structp png_ptr) return; #ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; - png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); do { @@ -1236,7 +1096,7 @@ png_read_push_finish_row(png_structp png_ptr) png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - if (png_ptr->transformations & PNG_INTERLACE) + if ((png_ptr->transformations & PNG_INTERLACE) != 0) break; png_ptr->num_rows = (png_ptr->height + @@ -1246,25 +1106,25 @@ png_read_push_finish_row(png_structp png_ptr) } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ +#endif /* READ_INTERLACING */ } void /* PRIVATE */ -png_push_have_info(png_structp png_ptr, png_infop info_ptr) +png_push_have_info(png_structrp png_ptr, png_inforp info_ptr) { if (png_ptr->info_fn != NULL) (*(png_ptr->info_fn))(png_ptr, info_ptr); } void /* PRIVATE */ -png_push_have_end(png_structp png_ptr, png_infop info_ptr) +png_push_have_end(png_structrp png_ptr, png_inforp info_ptr) { if (png_ptr->end_fn != NULL) (*(png_ptr->end_fn))(png_ptr, info_ptr); } void /* PRIVATE */ -png_push_have_row(png_structp png_ptr, png_bytep row) +png_push_have_row(png_structrp png_ptr, png_bytep row) { if (png_ptr->row_fn != NULL) (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, @@ -1273,7 +1133,7 @@ png_push_have_row(png_structp png_ptr, png_bytep row) #ifdef PNG_READ_INTERLACING_SUPPORTED void PNGAPI -png_progressive_combine_row (png_structp png_ptr, png_bytep old_row, +png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, png_const_bytep new_row) { if (png_ptr == NULL) @@ -1284,12 +1144,12 @@ png_progressive_combine_row (png_structp png_ptr, png_bytep old_row, * it must be png_ptr->row_buf+1 */ if (new_row != NULL) - png_combine_row(png_ptr, old_row, 1/*display*/); + png_combine_row(png_ptr, old_row, 1/*blocky display*/); } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ +#endif /* READ_INTERLACING */ void PNGAPI -png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, +png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn) { @@ -1304,11 +1164,11 @@ png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr, } png_voidp PNGAPI -png_get_progressive_ptr(png_const_structp png_ptr) +png_get_progressive_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); return png_ptr->io_ptr; } -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PROGRESSIVE_READ */ diff --git a/src/3rdparty/libpng/pngpriv.h b/src/3rdparty/libpng/pngpriv.h index f01e56f612..7185444f2c 100644 --- a/src/3rdparty/libpng/pngpriv.h +++ b/src/3rdparty/libpng/pngpriv.h @@ -1,20 +1,18 @@ /* pngpriv.h - private declarations for use inside libpng * - * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.10 [March 29, 2012] - * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ /* The symbols declared in this file (including the functions declared - * as PNG_EXTERN) are PRIVATE. They are not part of the libpng public + * as extern) are PRIVATE. They are not part of the libpng public * interface, and are not recommended for use by regular applications. * Some of them may become public in the future; others may stay private, * change in an incompatible way, or even disappear. @@ -45,15 +43,43 @@ */ #define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ -/* This is required for the definition of abort(), used as a last ditch - * error handler when all else fails. +#ifndef PNG_VERSION_INFO_ONLY +/* Standard library headers not required by png.h: */ +# include +# include +#endif + +#define PNGLIB_BUILD /*libpng is being built, not used*/ + +/* If HAVE_CONFIG_H is defined during the build then the build system must + * provide an appropriate "config.h" file on the include path. The header file + * must provide definitions as required below (search for "HAVE_CONFIG_H"); + * see configure.ac for more details of the requirements. The macro + * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on + * 'configure'; define this macro to prevent the configure build including the + * configure generated config.h. Libpng is expected to compile without *any* + * special build system support on a reasonably ANSI-C compliant system. */ -#include +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include -/* This is used to find 'offsetof', used below for alignment tests. */ -#include + /* Pick up the definition of 'restrict' from config.h if it was read: */ +# define PNG_RESTRICT restrict +#endif -#define PNGLIB_BUILD /*libpng is being built, not used*/ +/* To support symbol prefixing it is necessary to know *before* including png.h + * whether the fixed point (and maybe other) APIs are exported, because if they + * are not internal definitions may be required. This is handled below just + * before png.h is included, but load the configuration now if it is available. + */ +#ifndef PNGLCONF_H +# include "pnglibconf.h" +#endif + +/* Local renames may change non-exported API functions from png.h */ +#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) +# include "pngprefix.h" +#endif #ifdef PNG_USER_CONFIG # include "pngusr.h" @@ -66,6 +92,98 @@ # endif #endif +/* Compile time options. + * ===================== + * In a multi-arch build the compiler may compile the code several times for the + * same object module, producing different binaries for different architectures. + * When this happens configure-time setting of the target host options cannot be + * done and this interferes with the handling of the ARM NEON optimizations, and + * possibly other similar optimizations. Put additional tests here; in general + * this is needed when the same option can be changed at both compile time and + * run time depending on the target OS (i.e. iOS vs Android.) + * + * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because + * this is not possible with certain compilers (Oracle SUN OS CC), as a result + * it is necessary to ensure that all extern functions that *might* be used + * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__ + * below is one example of this behavior because it is controlled by the + * presence or not of -mfpu=neon on the GCC command line, it is possible to do + * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely + * do this. + */ +#ifndef PNG_ARM_NEON_OPT + /* ARM NEON optimizations are being controlled by the compiler settings, + * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon + * with GCC) then the compiler will define __ARM_NEON__ and we can rely + * unconditionally on NEON instructions not crashing, otherwise we must + * disable use of NEON instructions. + * + * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they + * can only be turned on automatically if that is supported too. If + * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail + * to compile with an appropriate #error if ALIGNED_MEMORY has been turned + * off. + * + * Note that gcc-4.9 defines __ARM_NEON instead of __ARM_NEON__, so we + * check both variants. + */ +# if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \ + defined(PNG_ALIGNED_MEMORY_SUPPORTED) +# define PNG_ARM_NEON_OPT 2 +# else +# define PNG_ARM_NEON_OPT 0 +# endif +#endif + +#if PNG_ARM_NEON_OPT > 0 + /* NEON optimizations are to be at least considered by libpng, so enable the + * callbacks to do this. + */ +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon + + /* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used + * if possible - if __ARM_NEON__ is set and the compiler version is not known + * to be broken. This is controlled by PNG_ARM_NEON_IMPLEMENTATION which can + * be: + * + * 1 The intrinsics code (the default with __ARM_NEON__) + * 2 The hand coded assembler (the default without __ARM_NEON__) + * + * It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however + * this is *NOT* supported and may cease to work even after a minor revision + * to libpng. It *is* valid to do this for testing purposes, e.g. speed + * testing or a new compiler, but the results should be communicated to the + * libpng implementation list for incorporation in the next minor release. + */ +# ifndef PNG_ARM_NEON_IMPLEMENTATION +# if defined(__ARM_NEON__) || defined(__ARM_NEON) +# if defined(__clang__) + /* At present it is unknown by the libpng developers which versions + * of clang support the intrinsics, however some or perhaps all + * versions do not work with the assembler so this may be + * irrelevant, so just use the default (do nothing here.) + */ +# elif defined(__GNUC__) + /* GCC 4.5.4 NEON support is known to be broken. 4.6.3 is known to + * work, so if this *is* GCC, or G++, look for a version >4.5 + */ +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) +# define PNG_ARM_NEON_IMPLEMENTATION 2 +# endif /* no GNUC support */ +# endif /* __GNUC__ */ +# else /* !defined __ARM_NEON__ */ + /* The 'intrinsics' code simply won't compile without this -mfpu=neon: + */ +# define PNG_ARM_NEON_IMPLEMENTATION 2 +# endif /* __ARM_NEON__ */ +# endif /* !PNG_ARM_NEON_IMPLEMENTATION */ + +# ifndef PNG_ARM_NEON_IMPLEMENTATION + /* Use the intrinsics code by default. */ +# define PNG_ARM_NEON_IMPLEMENTATION 1 +# endif +#endif /* PNG_ARM_NEON_OPT > 0 */ + /* Is this a build of a DLL where compilation of the object modules requires * different preprocessor settings to those required for a simple library? If * so PNG_BUILD_DLL must be set. @@ -135,76 +253,65 @@ # define PNG_PRIVATE #endif -#include "png.h" -#include "pnginfo.h" -#include "pngstruct.h" +/* Symbol preprocessing support. + * + * To enable listing global, but internal, symbols the following macros should + * always be used to declare an extern data or function object in this file. + */ +#ifndef PNG_INTERNAL_DATA +# define PNG_INTERNAL_DATA(type, name, array) extern type name array +#endif -/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ -#ifndef PNG_DLL_EXPORT -# define PNG_DLL_EXPORT +#ifndef PNG_INTERNAL_FUNCTION +# define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ + extern PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) #endif -/* SECURITY and SAFETY: +#ifndef PNG_INTERNAL_CALLBACK +# define PNG_INTERNAL_CALLBACK(type, name, args, attributes)\ + extern PNG_FUNCTION(type, (PNGCBAPI name), args, PNG_EMPTY attributes) +#endif + +/* If floating or fixed point APIs are disabled they may still be compiled + * internally. To handle this make sure they are declared as the appropriate + * internal extern function (otherwise the symbol prefixing stuff won't work and + * the functions will be used without definitions.) * - * By default libpng is built without any internal limits on image size, - * individual heap (png_malloc) allocations or the total amount of memory used. - * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used - * (unless individually overridden). These limits are believed to be fairly - * safe, but builders of secure systems should verify the values against the - * real system capabilities. - */ - -#ifdef PNG_SAFE_LIMITS_SUPPORTED - /* 'safe' limits */ -# ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 1000000 -# endif -# ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 1000000 -# endif -# ifndef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 128 -# endif -# ifndef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 8000000 -# endif -#else - /* values for no limits */ -# ifndef PNG_USER_WIDTH_MAX -# define PNG_USER_WIDTH_MAX 0x7fffffff -# endif -# ifndef PNG_USER_HEIGHT_MAX -# define PNG_USER_HEIGHT_MAX 0x7fffffff -# endif -# ifndef PNG_USER_CHUNK_CACHE_MAX -# define PNG_USER_CHUNK_CACHE_MAX 0 + * NOTE: although all the API functions are declared here they are not all + * actually built! Because the declarations are still made it is necessary to + * fake out types that they depend on. + */ +#ifndef PNG_FP_EXPORT +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# ifndef PNG_VERSION_INFO_ONLY + typedef struct png_incomplete png_double; + typedef png_double* png_doublep; + typedef const png_double* png_const_doublep; + typedef png_double** png_doublepp; +# endif # endif -# ifndef PNG_USER_CHUNK_MALLOC_MAX -# define PNG_USER_CHUNK_MALLOC_MAX 0 +#endif +#ifndef PNG_FIXED_EXPORT +# ifndef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); # endif #endif -/* This is used for 16 bit gamma tables - only the top level pointers are const, - * this could be changed: - */ -typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; - -/* Added at libpng-1.2.9 */ -/* Moved to pngpriv.h at libpng-1.5.0 */ +#include "png.h" -/* config.h is created by and PNG_CONFIGURE_LIBPNG is set by the "configure" - * script. We may need it here to get the correct configuration on things - * like limits. - */ -#ifdef PNG_CONFIGURE_LIBPNG -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif +/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ +#ifndef PNG_DLL_EXPORT +# define PNG_DLL_EXPORT #endif -/* Moved to pngpriv.h at libpng-1.5.0 */ -/* NOTE: some of these may have been used in external applications as - * these definitions were exposed in pngconf.h prior to 1.5. +/* SECURITY and SAFETY: + * + * libpng is built with support for internal limits on image dimensions and + * memory usage. These are documented in scripts/pnglibconf.dfa of the + * source and recorded in the machine generated header file pnglibconf.h. */ /* If you are running on a machine where you cannot allocate more @@ -240,30 +347,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; # define PNG_ZBUF_SIZE 65536L #endif -/* PNG_STATIC is used to mark internal file scope functions if they need to be - * accessed for implementation tests (see the code in tests/?*). - */ -#ifndef PNG_STATIC -# define PNG_STATIC static -#endif - -/* C99 restrict is used where possible, to do this 'restrict' is defined as - * empty if we can't be sure it is supported. configure builds have already - * done this work. - */ -#ifdef PNG_CONFIGURE_LIBPNG -# define PNG_RESTRICT restrict -#else - /* Modern compilers support restrict, but assume not for anything not - * recognized here: - */ -# if defined __GNUC__ || defined _MSC_VER || defined __WATCOMC__ -# define PNG_RESTRICT restrict -# else -# define PNG_RESTRICT -# endif -#endif - /* If warnings or errors are turned off the code is disabled or redirected here. * From 1.5.4 functions have been added to allow very limited formatting of * error and warning messages - this code will also be disabled here. @@ -271,8 +354,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #ifdef PNG_WARNINGS_SUPPORTED # define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; #else -# define png_warning(s1,s2) ((void)(s1)) -# define png_chunk_warning(s1,s2) ((void)(s1)) # define png_warning_parameter(p,number,string) ((void)0) # define png_warning_parameter_unsigned(p,number,format,value) ((void)0) # define png_warning_parameter_signed(p,number,format,value) ((void)0) @@ -280,8 +361,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; # define PNG_WARNING_PARAMETERS(p) #endif #ifndef PNG_ERROR_TEXT_SUPPORTED -# define png_error(s1,s2) png_err(s1) -# define png_chunk_error(s1,s2) png_err(s1) # define png_fixed_error(s1,s2) png_err(s1) #endif @@ -292,23 +371,18 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; */ #ifdef __cplusplus # define png_voidcast(type, value) static_cast(value) +# define png_constcast(type, value) const_cast(value) +# define png_aligncast(type, value) \ + static_cast(static_cast(value)) +# define png_aligncastconst(type, value) \ + static_cast(static_cast(value)) #else # define png_voidcast(type, value) (value) +# define png_constcast(type, value) ((type)(value)) +# define png_aligncast(type, value) ((void*)(value)) +# define png_aligncastconst(type, value) ((const void*)(value)) #endif /* __cplusplus */ -#ifndef PNG_EXTERN -/* The functions exported by PNG_EXTERN are internal functions, which - * aren't usually used outside the library (as far as I know), so it is - * debatable if they should be exported at all. In the future, when it - * is possible to have run-time registry of chunk-handling functions, - * some of these might be made available again. - * - * 1.5.7: turned the use of 'extern' back on, since it is localized to pngpriv.h - * it should be safe now (it is unclear why it was turned off.) - */ -# define PNG_EXTERN extern -#endif - /* Some fixed point APIs are still required even if not exported because * they get used by the corresponding floating point APIs. This magic * deals with this: @@ -319,6 +393,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; # define PNGFAPI /* PRIVATE */ #endif +#ifndef PNG_VERSION_INFO_ONLY /* Other defines specific to compilers can go here. Try to keep * them inside an appropriate ifdef/endif pair for portability. */ @@ -366,6 +441,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; # define _WINRT_ /* Define a macro for Windows Runtime builds */ # endif #endif +#endif /* PNG_VERSION_INFO_ONLY */ /* Moved here around 1.5.0beta36 from pngconf.h */ /* Users may want to use these so they are not private. Any library @@ -381,34 +457,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; # endif #endif -#ifdef USE_FAR_KEYWORD -/* Use this to make far-to-near assignments */ -# define CHECK 1 -# define NOCHECK 0 -# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) -# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) -# define png_strlen _fstrlen -# define png_memcmp _fmemcmp /* SJT: added */ -# define png_memcpy _fmemcpy -# define png_memset _fmemset -#else -# if defined(_WINDOWS_) && !defined(_WINRT_) /* Favor Windows over C runtime fns */ -# define CVT_PTR(ptr) (ptr) -# define CVT_PTR_NOCHECK(ptr) (ptr) -# define png_strlen lstrlenA -# define png_memcmp memcmp -# define png_memcpy CopyMemory -# define png_memset memset -# else -# define CVT_PTR(ptr) (ptr) -# define CVT_PTR_NOCHECK(ptr) (ptr) -# define png_strlen strlen -# define png_memcmp memcmp /* SJT: added */ -# define png_memcpy memcpy -# define png_memset memset -# endif -#endif - /* These macros may need to be architecture dependent. */ #define PNG_ALIGN_NONE 0 /* do not use data alignment */ #define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ @@ -430,7 +478,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE /* This is used because in some compiler implementations non-aligned * structure members are supported, so the offsetof approach below fails. - * Set PNG_ALIGN_TO_SIZE=0 for compiler combinations where unaligned access + * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access * is good for performance. Do not do this unless you have tested the result * and understand it. */ @@ -471,16 +519,17 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_HAVE_IDAT 0x04 /* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ #define PNG_HAVE_IEND 0x10 -#define PNG_HAVE_gAMA 0x20 -#define PNG_HAVE_cHRM 0x40 -#define PNG_HAVE_sRGB 0x80 + /* 0x20 (unused) */ + /* 0x40 (unused) */ + /* 0x80 (unused) */ #define PNG_HAVE_CHUNK_HEADER 0x100 #define PNG_WROTE_tIME 0x200 #define PNG_WROTE_INFO_BEFORE_PLTE 0x400 #define PNG_BACKGROUND_IS_GRAY 0x800 #define PNG_HAVE_PNG_SIGNATURE 0x1000 #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ -#define PNG_HAVE_iCCP 0x4000 + /* 0x4000 (unused) */ +#define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ /* Flags for the transformations the PNG library does on the image data */ #define PNG_BGR 0x0001 @@ -508,13 +557,13 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_RGB_TO_GRAY_WARN 0x400000 #define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ #define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ -#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ -#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ -#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ - /* 0x8000000 unused */ - /* 0x10000000 unused */ - /* 0x20000000 unused */ - /* 0x40000000 unused */ +#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ +#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ /* Flags for png_create_struct */ #define PNG_STRUCT_PNG 0x0001 #define PNG_STRUCT_INFO 0x0002 @@ -525,36 +574,36 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; /* Flags for the png_ptr->flags rather than declaring a byte for each one */ #define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 -#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 -#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 -#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 -#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 -#define PNG_FLAG_ZLIB_FINISHED 0x0020 +#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ + /* 0x0004 unused */ +#define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ + /* 0x0010 unused */ + /* 0x0020 unused */ #define PNG_FLAG_ROW_INIT 0x0040 #define PNG_FLAG_FILLER_AFTER 0x0080 #define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 #define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 #define PNG_FLAG_CRC_CRITICAL_USE 0x0400 #define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 -#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ -#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ -#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ -#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 -#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 -#define PNG_FLAG_LIBRARY_MISMATCH 0x20000 -#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 -#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 -#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000 - /* 0x200000 unused */ - /* 0x400000 unused */ -#define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000 /* Added to libpng-1.4.0 */ -#define PNG_FLAG_ZTXT_CUSTOM_STRATEGY 0x1000000 /* 5 lines added */ -#define PNG_FLAG_ZTXT_CUSTOM_LEVEL 0x2000000 /* to libpng-1.5.4 */ -#define PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL 0x4000000 -#define PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS 0x8000000 -#define PNG_FLAG_ZTXT_CUSTOM_METHOD 0x10000000 - /* 0x20000000 unused */ - /* 0x40000000 unused */ +#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ +/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 */ +/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 */ +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000 +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 +#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */ +#define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */ +#define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */ + /* 0x800000 unused */ + /* 0x1000000 unused */ + /* 0x2000000 unused */ + /* 0x4000000 unused */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ PNG_FLAG_CRC_ANCILLARY_NOWARN) @@ -565,24 +614,23 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ PNG_FLAG_CRC_CRITICAL_MASK) -/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib - * can handle at once. This type need be no larger than 16 bits (so maximum of - * 65535), this define allows us to discover how big it is, but limited by the - * maximuum for png_size_t. The value can be overriden in a library build - * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably - * lower value (e.g. 255 works). A lower value may help memory usage (slightly) - * and may even improve performance on some systems (and degrade it on others.) - */ -#ifndef ZLIB_IO_MAX -# define ZLIB_IO_MAX ((uInt)-1) -#endif - /* Save typing and make code easier to understand */ #define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ abs((int)((c1).green) - (int)((c2).green)) + \ abs((int)((c1).blue) - (int)((c2).blue))) +/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255 + * by dividing by 257 *with rounding*. This macro is exact for the given range. + * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the + * macro were established by experiment (modifying the added value). The macro + * has a second variant that takes a value already scaled by 255 and divides by + * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it + * only gives off-by-one errors and only for 0.5% (1 in 200) of the values. + */ +#define PNG_DIV65535(v24) (((v24) + 32895) >> 16) +#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255) + /* Added to libpng-1.2.6 JB */ #define PNG_ROWBYTES(pixel_bits, width) \ ((pixel_bits) >= 8 ? \ @@ -630,10 +678,10 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #ifdef PNG_FIXED_POINT_MACRO_SUPPORTED #define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) -#else -PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp, - png_const_charp text)); #endif +/* else the corresponding function is defined below, inside the scope of the + * cplusplus test. + */ #endif /* Constants for known chunk types. If you need to add a chunk, define the name @@ -650,53 +698,82 @@ PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp, * architectures where (int) is only 16 bits. */ #define PNG_32b(b,s) ((png_uint_32)(b) << (s)) -#define PNG_CHUNK(b1,b2,b3,b4) \ +#define PNG_U32(b1,b2,b3,b4) \ (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) -#define png_IHDR PNG_CHUNK( 73, 72, 68, 82) -#define png_IDAT PNG_CHUNK( 73, 68, 65, 84) -#define png_IEND PNG_CHUNK( 73, 69, 78, 68) -#define png_PLTE PNG_CHUNK( 80, 76, 84, 69) -#define png_bKGD PNG_CHUNK( 98, 75, 71, 68) -#define png_cHRM PNG_CHUNK( 99, 72, 82, 77) -#define png_gAMA PNG_CHUNK(103, 65, 77, 65) -#define png_hIST PNG_CHUNK(104, 73, 83, 84) -#define png_iCCP PNG_CHUNK(105, 67, 67, 80) -#define png_iTXt PNG_CHUNK(105, 84, 88, 116) -#define png_oFFs PNG_CHUNK(111, 70, 70, 115) -#define png_pCAL PNG_CHUNK(112, 67, 65, 76) -#define png_sCAL PNG_CHUNK(115, 67, 65, 76) -#define png_pHYs PNG_CHUNK(112, 72, 89, 115) -#define png_sBIT PNG_CHUNK(115, 66, 73, 84) -#define png_sPLT PNG_CHUNK(115, 80, 76, 84) -#define png_sRGB PNG_CHUNK(115, 82, 71, 66) -#define png_sTER PNG_CHUNK(115, 84, 69, 82) -#define png_tEXt PNG_CHUNK(116, 69, 88, 116) -#define png_tIME PNG_CHUNK(116, 73, 77, 69) -#define png_tRNS PNG_CHUNK(116, 82, 78, 83) -#define png_zTXt PNG_CHUNK(122, 84, 88, 116) +/* Constants for known chunk types. + * + * MAINTAINERS: If you need to add a chunk, define the name here. + * For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. Please keep the list sorted. + * + * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk + * type. In fact the specification does not express chunk types this way, + * however using a 32-bit value means that the chunk type can be read from the + * stream using exactly the same code as used for a 32-bit unsigned value and + * can be examined far more efficiently (using one arithmetic compare). + * + * Prior to 1.5.6 the chunk type constants were expressed as C strings. The + * libpng API still uses strings for 'unknown' chunks and a macro, + * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice + * that for portable code numeric values must still be used; the string "IHDR" + * is not portable and neither is PNG_U32('I', 'H', 'D', 'R'). + * + * In 1.7.0 the definitions will be made public in png.h to avoid having to + * duplicate the same definitions in application code. + */ +#define png_IDAT PNG_U32( 73, 68, 65, 84) +#define png_IEND PNG_U32( 73, 69, 78, 68) +#define png_IHDR PNG_U32( 73, 72, 68, 82) +#define png_PLTE PNG_U32( 80, 76, 84, 69) +#define png_bKGD PNG_U32( 98, 75, 71, 68) +#define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ +#define png_gAMA PNG_U32(103, 65, 77, 65) +#define png_gIFg PNG_U32(103, 73, 70, 103) +#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ +#define png_gIFx PNG_U32(103, 73, 70, 120) +#define png_hIST PNG_U32(104, 73, 83, 84) +#define png_iCCP PNG_U32(105, 67, 67, 80) +#define png_iTXt PNG_U32(105, 84, 88, 116) +#define png_oFFs PNG_U32(111, 70, 70, 115) +#define png_pCAL PNG_U32(112, 67, 65, 76) +#define png_pHYs PNG_U32(112, 72, 89, 115) +#define png_sBIT PNG_U32(115, 66, 73, 84) +#define png_sCAL PNG_U32(115, 67, 65, 76) +#define png_sPLT PNG_U32(115, 80, 76, 84) +#define png_sRGB PNG_U32(115, 82, 71, 66) +#define png_sTER PNG_U32(115, 84, 69, 82) +#define png_tEXt PNG_U32(116, 69, 88, 116) +#define png_tIME PNG_U32(116, 73, 77, 69) +#define png_tRNS PNG_U32(116, 82, 78, 83) +#define png_zTXt PNG_U32(122, 84, 88, 116) /* The following will work on (signed char*) strings, whereas the get_uint_32 * macro will fail on top-bit-set values because of the sign extension. */ #define PNG_CHUNK_FROM_STRING(s)\ - PNG_CHUNK(0xff&(s)[0], 0xff&(s)[1], 0xff&(s)[2], 0xff&(s)[3]) + PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3]) /* This uses (char), not (png_byte) to avoid warnings on systems where (char) is * signed and the argument is a (char[]) This macro will fail miserably on * systems where (char) is more than 8 bits. */ #define PNG_STRING_FROM_CHUNK(s,c)\ - (void)(((char*)(s))[0]=(char)((c)>>24), ((char*)(s))[1]=(char)((c)>>16),\ - ((char*)(s))[2]=(char)((c)>>8), ((char*)(s))[3]=(char)((c))) + (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \ + ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\ + ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \ + ((char*)(s))[3]=(char)((c & 0xff))) /* Do the same but terminate with a null character. */ #define PNG_CSTRING_FROM_CHUNK(s,c)\ (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0) /* Test on flag values as defined in the spec (section 5.4): */ -#define PNG_CHUNK_ANCILLIARY(c) (1 & ((c) >> 29)) -#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLIARY(c)) +#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) +#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) #define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) #define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) #define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) @@ -706,113 +783,212 @@ PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp, #define PNG_GAMMA_MAC_INVERSE 65909 #define PNG_GAMMA_sRGB_INVERSE 45455 +/* Almost everything below is C specific; the #defines above can be used in + * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. + */ +#ifndef PNG_VERSION_INFO_ONLY + +#include "pngstruct.h" +#include "pnginfo.h" + +/* Validate the include paths - the include path used to generate pnglibconf.h + * must match that used in the build, or we must be using pnglibconf.h.prebuilt: + */ +#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM +# error ZLIB_VERNUM != PNG_ZLIB_VERNUM \ + "-I (include path) error: see the notes in pngpriv.h" + /* This means that when pnglibconf.h was built the copy of zlib.h that it + * used is not the same as the one being used here. Because the build of + * libpng makes decisions to use inflateInit2 and inflateReset2 based on the + * zlib version number and because this affects handling of certain broken + * PNG files the -I directives must match. + * + * The most likely explanation is that you passed a -I in CFLAGS. This will + * not work; all the preprocessor directories and in particular all the -I + * directives must be in CPPFLAGS. + */ +#endif + +/* This is used for 16 bit gamma tables -- only the top level pointers are + * const; this could be changed: + */ +typedef const png_uint_16p * png_const_uint_16pp; + +/* Added to libpng-1.5.7: sRGB conversion tables */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); + /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value, + * 0..65535. This table gives the closest 16-bit answers (no errors). + */ +#endif + +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); +PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); + +#define PNG_sRGB_FROM_LINEAR(linear) \ + ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \ + + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8))) + /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB + * encoded value with maximum error 0.646365. Note that the input is not a + * 16-bit value; it has been multiplied by 255! */ +#endif /* SIMPLIFIED_READ/WRITE */ + /* Inhibit C++ name-mangling for libpng functions but not for system calls. */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/* These functions are used internally in the code. They generally - * shouldn't be used unless you are writing code to add or replace some - * functionality in libpng. More information about most functions can - * be found in the files where the functions are located. +/* Internal functions; these are not exported from a DLL however because they + * are used within several of the C source files they have to be C extern. + * + * All of these functions must be declared with PNG_INTERNAL_FUNCTION. */ +/* Zlib support */ +#define PNG_UNEXPECTED_ZLIB_RETURN (-7) +PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), + PNG_EMPTY); + /* Used by the zlib handling functions to ensure that z_stream::msg is always + * set before they return. + */ + +#ifdef PNG_WRITE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, + png_compression_bufferp *list),PNG_EMPTY); + /* Free the buffer list used by the compressed write code. */ +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, + double fp, png_const_charp text),PNG_EMPTY); +#endif + /* Check the user version string for compatibility, returns false if the version * numbers aren't compatible. */ -PNG_EXTERN int png_user_version_check(png_structp png_ptr, - png_const_charp user_png_ver); +PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, + png_const_charp user_png_ver),PNG_EMPTY); -/* Allocate memory for an internal libpng struct */ -PNG_EXTERN PNG_FUNCTION(png_voidp,png_create_struct,PNGARG((int type)), - PNG_ALLOCATED); +/* Internal base allocator - no messages, NULL on failure to allocate. This + * does, however, call the application provided allocator and that could call + * png_error (although that would be a bug in the application implementation.) + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, + png_alloc_size_t size),PNG_ALLOCATED); -/* Free memory from internal libpng struct */ -PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* Internal array allocator, outputs no error or warning messages on failure, + * just returns NULL. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, + int nelements, size_t element_size),PNG_ALLOCATED); -PNG_EXTERN PNG_FUNCTION(png_voidp,png_create_struct_2, - PNGARG((int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)), - PNG_ALLOCATED); -PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, - png_free_ptr free_fn, png_voidp mem_ptr)); +/* The same but an existing array is extended by add_elements. This function + * also memsets the new elements to 0 and copies the old elements. The old + * array is not freed or altered. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, + png_const_voidp array, int old_elements, int add_elements, + size_t element_size),PNG_ALLOCATED); +#endif /* text, sPLT or unknown chunks */ + +/* Magic to create a struct when there is no struct to call the user supplied + * memory allocators. Because error handling has not been set up the memory + * handlers can't safely call png_error, but this is an obscure and undocumented + * restriction so libpng has to assume that the 'free' handler, at least, might + * call png_error. + */ +PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, + png_free_ptr free_fn),PNG_ALLOCATED); + +/* Free memory from internal libpng struct */ +PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), + PNG_EMPTY); -/* Free any memory that info_ptr points to and reset struct. */ -PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, - png_infop info_ptr)); +/* Free an allocated jmp_buf (always succeeds) */ +PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); /* Function to allocate memory for zlib. PNGAPI is disallowed. */ -PNG_EXTERN PNG_FUNCTION(voidpf,png_zalloc,PNGARG((voidpf png_ptr, uInt items, - uInt size)),PNG_ALLOCATED); +PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), + PNG_ALLOCATED); /* Function to free memory for zlib. PNGAPI is disallowed. */ -PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); +PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); /* Next four functions are used internally as callbacks. PNGCBAPI is required * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to * PNGCBAPI at 1.5.0 */ -PNG_EXTERN void PNGCBAPI png_default_read_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void PNGCBAPI png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t length)); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, + png_bytep buffer, png_size_t length),PNG_EMPTY); #endif -PNG_EXTERN void PNGCBAPI png_default_write_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); #ifdef PNG_WRITE_FLUSH_SUPPORTED # ifdef PNG_STDIO_SUPPORTED -PNG_EXTERN void PNGCBAPI png_default_flush PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), + PNG_EMPTY); # endif #endif /* Reset the CRC variable */ -PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); /* Write the "data" buffer to whatever output you are using */ -PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, - png_const_bytep data, png_size_t length)); +PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, + png_const_bytep data, png_size_t length),PNG_EMPTY); /* Read and check the PNG file signature */ -PNG_EXTERN void png_read_sig PNGARG((png_structp png_ptr, png_infop info_ptr)); +PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); /* Read the chunk header (length + type name) */ -PNG_EXTERN png_uint_32 png_read_chunk_header PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), + PNG_EMPTY); /* Read data from whatever input you are using into the "data" buffer */ -PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); +PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, + png_size_t length),PNG_EMPTY); /* Read bytes into buf, and update png_ptr->crc */ -PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, - png_size_t length)); - -/* Decompress data in a chunk that uses compression */ -#if defined(PNG_READ_COMPRESSED_TEXT_SUPPORTED) -PNG_EXTERN void png_decompress_chunk PNGARG((png_structp png_ptr, - int comp_type, png_size_t chunklength, png_size_t prefix_length, - png_size_t *data_length)); -#endif +PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, + png_uint_32 length),PNG_EMPTY); /* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ -PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); +PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, + png_uint_32 skip),PNG_EMPTY); /* Read the CRC from the file and compare it to the libpng calculated CRC */ -PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY); /* Calculate the CRC over a section of data. Note that we are only * passing a maximum of 64K on systems that have this as a memory limit, * since this is the maximum buffer size we can specify. */ -PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, - png_const_bytep ptr, png_size_t length)); +PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, + png_const_bytep ptr, png_size_t length),PNG_EMPTY); #ifdef PNG_WRITE_FLUSH_SUPPORTED -PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); #endif /* Write various chunks */ @@ -820,145 +996,130 @@ PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); /* Write the IHDR chunk, and update the png_struct with the necessary * information. */ -PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, - png_uint_32 height, - int bit_depth, int color_type, int compression_method, int filter_method, - int interlace_method)); +PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, + int compression_method, int filter_method, int interlace_method),PNG_EMPTY); -PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, - png_const_colorp palette, png_uint_32 num_pal)); +PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, + png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); -PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); +PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, + png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), + PNG_EMPTY); -PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); #ifdef PNG_WRITE_gAMA_SUPPORTED -# ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); -# endif -# ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, - png_fixed_point file_gamma)); -# endif +PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, + png_fixed_point file_gamma),PNG_EMPTY); #endif #ifdef PNG_WRITE_sBIT_SUPPORTED -PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, - png_const_color_8p sbit, int color_type)); +PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, + png_const_color_8p sbit, int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_cHRM_SUPPORTED -# ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, - double white_x, double white_y, - double red_x, double red_y, double green_x, double green_y, - double blue_x, double blue_y)); -# endif -PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); +PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, + const png_xy *xy), PNG_EMPTY); + /* The xy value must have been previously validated */ #endif #ifdef PNG_WRITE_sRGB_SUPPORTED -PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, - int intent)); +PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, + int intent),PNG_EMPTY); #endif #ifdef PNG_WRITE_iCCP_SUPPORTED -PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, - png_const_charp name, int compression_type, - png_const_charp profile, int proflen)); - /* Note to maintainer: profile should be png_bytep */ +PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, + png_const_charp name, png_const_bytep profile), PNG_EMPTY); + /* The profile must have been previously validated for correctness, the + * length comes from the first four bytes. Only the base, deflate, + * compression is supported. + */ #endif #ifdef PNG_WRITE_sPLT_SUPPORTED -PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, - png_const_sPLT_tp palette)); +PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, + png_const_sPLT_tp palette),PNG_EMPTY); #endif #ifdef PNG_WRITE_tRNS_SUPPORTED -PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, png_const_bytep trans, png_const_color_16p values, int number, - int color_type)); + int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_bKGD_SUPPORTED -PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, - png_const_color_16p values, int color_type)); +PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, + png_const_color_16p values, int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_hIST_SUPPORTED -PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, - png_const_uint_16p hist, int num_hist)); +PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, + png_const_uint_16p hist, int num_hist),PNG_EMPTY); #endif /* Chunks that have keywords */ -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ - defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) -PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, - png_const_charp key, png_charpp new_key)); -#endif - #ifdef PNG_WRITE_tEXt_SUPPORTED -PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_const_charp key, - png_const_charp text, png_size_t text_len)); +PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, + png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY); #endif #ifdef PNG_WRITE_zTXt_SUPPORTED -PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_const_charp key, - png_const_charp text, png_size_t text_len, int compression)); +PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp + key, png_const_charp text, int compression),PNG_EMPTY); #endif #ifdef PNG_WRITE_iTXt_SUPPORTED -PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, int compression, png_const_charp key, png_const_charp lang, - png_const_charp lang_key, png_const_charp text)); + png_const_charp lang_key, png_const_charp text),PNG_EMPTY); #endif #ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ -PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, - png_infop info_ptr, png_const_textp text_ptr, int num_text)); +PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED -PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, - png_int_32 x_offset, png_int_32 y_offset, int unit_type)); +PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_pCAL_SUPPORTED -PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, - png_int_32 X0, png_int_32 X1, int type, int nparams, - png_const_charp units, png_charpp params)); +PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_const_charp units, png_charpp params),PNG_EMPTY); #endif #ifdef PNG_WRITE_pHYs_SUPPORTED -PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, - int unit_type)); + int unit_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_tIME_SUPPORTED -PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, - png_const_timep mod_time)); +PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, + png_const_timep mod_time),PNG_EMPTY); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED -PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, - int unit, png_const_charp width, png_const_charp height)); +PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, + int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); #endif /* Called when finished processing a row of data */ -PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), + PNG_EMPTY); /* Internal use only. Called before first row of data */ -PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), + PNG_EMPTY); /* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an * array of png_ptr->width pixels. If the image is not interlaced or this - * is the final pass this just does a png_memcpy, otherwise the "display" flag + * is the final pass this just does a memcpy, otherwise the "display" flag * is used to determine whether to copy pixels that are not in the current pass. * * Because 'png_do_read_interlace' (below) replicates pixels this allows this @@ -982,8 +1143,8 @@ PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); #ifndef PNG_USE_COMPILE_TIME_MASKS # define PNG_USE_COMPILE_TIME_MASKS 1 #endif -PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, - int display)); +PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, + png_bytep row, int display),PNG_EMPTY); #ifdef PNG_READ_INTERLACING_SUPPORTED /* Expand an interlaced row: the 'row_info' describes the pass data that has @@ -992,188 +1153,99 @@ PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, * the pixels are *replicated* to the intervening space. This is essential for * the correct operation of png_combine_row, above. */ -PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass, png_uint_32 transformations)); +PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); #endif /* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Grab pixels out of a row for an interlaced pass */ -PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass)); +PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, + png_bytep row, int pass),PNG_EMPTY); #endif /* Unfilter a row: check the filter value before calling this, there is no point * calling it for PNG_FILTER_VALUE_NONE. */ -PNG_EXTERN void png_read_filter_row PNGARG((png_structp pp, png_row_infop row_info, - png_bytep row, png_const_bytep prev_row, int filter)); - -PNG_EXTERN void png_read_filter_row_up_neon PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep prev_row)); -PNG_EXTERN void png_read_filter_row_sub3_neon PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep prev_row)); -PNG_EXTERN void png_read_filter_row_sub4_neon PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep prev_row)); -PNG_EXTERN void png_read_filter_row_avg3_neon PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep prev_row)); -PNG_EXTERN void png_read_filter_row_avg4_neon PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep prev_row)); -PNG_EXTERN void png_read_filter_row_paeth3_neon PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep prev_row)); -PNG_EXTERN void png_read_filter_row_paeth4_neon PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep prev_row)); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop + row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); /* Choose the best filter to use and filter the row data */ -PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, - png_row_infop row_info)); +PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, + png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); + /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer + * is NULL the function checks, instead, for the end of the stream. In this + * case a benign error will be issued if the stream end is not found or if + * extra data has to be consumed. + */ +PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), + PNG_EMPTY); + /* This cleans up when the IDAT LZ stream does not end when the last image + * byte is read; there is still some pending input. + */ -/* Finish a row while reading, dealing with interlacing passes, etc. */ -PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + /* Finish a row while reading, dealing with interlacing passes, etc. */ +#endif /* SEQUENTIAL_READ */ /* Initialize the row buffers, etc. */ -PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); #ifdef PNG_READ_TRANSFORMS_SUPPORTED /* Optional call to update the users info structure */ -PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif - -/* These are the functions that do the transformations */ -#ifdef PNG_READ_FILLER_SUPPORTED -PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 filler, png_uint_32 flags)); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); #endif +/* Shared transform functions, defined in pngtran.c */ #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_strip_channel PNGARG((png_row_infop row_info, - png_bytep row, int at_start)); +PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, + png_bytep row, int at_start),PNG_EMPTY); #endif #ifdef PNG_16BIT_SUPPORTED #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #endif #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ defined(PNG_WRITE_PACKSWAP_SUPPORTED) -PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, - png_row_infop row_info, png_bytep row)); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED -PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_PACK_SUPPORTED -PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED -PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, - png_bytep row, png_const_color_8p sig_bits)); +PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED -PNG_EXTERN void png_do_scale_16_to_8 PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED -PNG_EXTERN void png_do_quantize PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep palette_lookup, - png_const_bytep quantize_lookup)); - -# ifdef PNG_CORRECT_PALETTE_SUPPORTED -PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, - png_colorp palette, int num_palette)); -# endif +PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#ifdef PNG_WRITE_PACK_SUPPORTED -PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 bit_depth)); -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED -PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, - png_bytep row, png_const_color_8p bit_depth)); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) -PNG_EXTERN void png_do_compose PNGARG((png_row_infop row_info, - png_bytep row, png_structp png_ptr)); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED -PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, - png_bytep row, png_structp png_ptr)); -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED -PNG_EXTERN void png_do_encode_alpha PNGARG((png_row_infop row_info, - png_bytep row, png_structp png_ptr)); -#endif - -#ifdef PNG_READ_EXPAND_SUPPORTED -PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, - png_bytep row, png_const_colorp palette, png_const_bytep trans, - int num_trans)); -PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, - png_bytep row, png_const_color_16p trans_color)); -#endif - -#ifdef PNG_READ_EXPAND_16_SUPPORTED -PNG_EXTERN void png_do_expand_16 PNGARG((png_row_infop row_info, - png_bytep row)); +PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #endif /* The following decodes the appropriate chunks, and does error correction, @@ -1181,256 +1253,283 @@ PNG_EXTERN void png_do_expand_16 PNGARG((png_row_infop row_info, */ /* Decode the IHDR chunk */ -PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #ifdef PNG_READ_bKGD_SUPPORTED -PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_cHRM_SUPPORTED -PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_gAMA_SUPPORTED -PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_hIST_SUPPORTED -PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_iCCP_SUPPORTED -PNG_EXTERN void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_iCCP_SUPPORTED */ +PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* READ_iCCP */ #ifdef PNG_READ_iTXt_SUPPORTED -PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_oFFs_SUPPORTED -PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_pCAL_SUPPORTED -PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_pHYs_SUPPORTED -PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sBIT_SUPPORTED -PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sCAL_SUPPORTED -PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sPLT_SUPPORTED -PNG_EXTERN void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_sPLT_SUPPORTED */ +PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* READ_sPLT */ #ifdef PNG_READ_sRGB_SUPPORTED -PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tEXt_SUPPORTED -PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tIME_SUPPORTED -PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tRNS_SUPPORTED -PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_zTXt_SUPPORTED -PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); +PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -#endif +PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr, + png_uint_32 chunk_name),PNG_EMPTY); -PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, - png_uint_32 chunk_name)); +PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY); + /* This is the function that gets called for unknown chunks. The 'keep' + * argument is either non-zero for a known chunk that has been set to be + * handled as unknown or zero for an unknown chunk. By default the function + * just skips the chunk or errors out if it is critical. + */ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -/* Exactly as png_handle_as_unknown() except that the argument is a 32-bit chunk - * name, not a string. - */ -PNG_EXTERN int png_chunk_unknown_handling PNGARG((png_structp png_ptr, - png_uint_32 chunk_name)); -#endif +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, + (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); + /* Exactly as the API png_handle_as_unknown() except that the argument is a + * 32-bit chunk name, not a string. + */ +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ /* Handle the transformations for reading and writing */ #ifdef PNG_READ_TRANSFORMS_SUPPORTED -PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr, - png_row_infop row_info)); +PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); #endif #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED -PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr, - png_row_infop row_info)); +PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); #endif #ifdef PNG_READ_TRANSFORMS_SUPPORTED -PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), + PNG_EMPTY); #endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, - png_uint_32 length)); -PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t buffer_length)); -PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t buffer_length)); -PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); -PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); +PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_skip,(png_structrp png_ptr, + png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_finish,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), + PNG_EMPTY); # ifdef PNG_READ_tEXt_SUPPORTED -PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); # endif # ifdef PNG_READ_zTXt_SUPPORTED -PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); # endif # ifdef PNG_READ_iTXt_SUPPORTED -PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); +PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); # endif -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PROGRESSIVE_READ */ -#ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)); -PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)); -#endif +/* Added at libpng version 1.6.0 */ +#ifdef PNG_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY); + /* Set the colorspace gamma with a value provided by the application or by + * the gAMA chunk on read. The value will override anything set by an ICC + * profile. + */ -/* Added at libpng version 1.4.0 */ -#ifdef PNG_CHECK_cHRM_SUPPORTED -PNG_EXTERN int png_check_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); -#endif +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Synchronize the info 'valid' flags with the colorspace */ -#ifdef PNG_CHECK_cHRM_SUPPORTED -/* Added at libpng version 1.2.34 and 1.4.0 */ -/* Currently only used by png_check_cHRM_fixed */ -PNG_EXTERN void png_64bit_product PNGARG((long v1, long v2, - unsigned long *hi_product, unsigned long *lo_product)); +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Copy the png_struct colorspace to the info_struct and call the above to + * synchronize the flags. Checks for NULL info_ptr and does nothing. + */ #endif -#ifdef PNG_cHRM_SUPPORTED -/* Added at libpng version 1.5.5 */ -typedef struct png_xy -{ - png_fixed_point redx, redy; - png_fixed_point greenx, greeny; - png_fixed_point bluex, bluey; - png_fixed_point whitex, whitey; -} png_xy; - -typedef struct png_XYZ -{ - png_fixed_point redX, redY, redZ; - png_fixed_point greenX, greenY, greenZ; - png_fixed_point blueX, blueY, blueZ; -} png_XYZ; - -/* The conversion APIs return 0 on success, non-zero on a parameter error. They - * allow conversion between the above representations of a color encoding. When - * converting from XYZ end points to chromaticities the absolute magnitude of - * the end points is lost, when converting back the sum of the Y values of the - * three end points will be 1.0 +/* Added at libpng version 1.4.0 */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* These internal functions are for maintaining the colorspace structure within + * a png_info or png_struct (or, indeed, both). */ -PNG_EXTERN int png_xy_from_XYZ PNGARG((png_xy *xy, png_XYZ XYZ)); -PNG_EXTERN int png_XYZ_from_xy PNGARG((png_XYZ *XYZ, png_xy xy)); -PNG_EXTERN int png_XYZ_from_xy_checked PNGARG((png_structp png_ptr, - png_XYZ *XYZ, png_xy xy)); +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, + int preferred), PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ, + int preferred), PNG_EMPTY); + +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr, + png_colorspacerp colorspace, int intent), PNG_EMPTY); + /* This does set the colorspace gAMA and cHRM values too, but doesn't set the + * flags to write them, if it returns false there was a problem and an error + * message has already been output (but the colorspace may still need to be + * synced to record the invalid flag). + */ +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, png_const_bytep profile, int color_type), + PNG_EMPTY); + /* The 'name' is used for information only */ + +/* Routines for checking parts of an ICC profile. */ +PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* first 132 bytes only */, int color_type), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,( + png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_bytep profile, uLong adler), PNG_EMPTY); + /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may + * be zero to indicate that it is not available. It is used, if provided, + * as a fast check on the profile when checking to see if it is sRGB. + */ #endif +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients, + (png_structrp png_ptr), PNG_EMPTY); + /* Set the rgb_to_gray coefficients from the colorspace Y values */ +#endif /* READ_RGB_TO_GRAY */ +#endif /* COLORSPACE */ /* Added at libpng version 1.4.0 */ -PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, - int filter_type)); + int filter_type),PNG_EMPTY); /* Added at libpng version 1.5.10 */ #if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) -PNG_EXTERN void png_do_check_palette_indexes PNGARG((png_structp png_ptr, - png_row_infop row_info)); +PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, + (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); #endif -/* Free all memory used by the read (old method - NOT DLL EXPORTED) */ -PNG_EXTERN void png_read_destroy PNGARG((png_structp png_ptr, - png_infop info_ptr, png_infop end_info_ptr)); - -/* Free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */ -PNG_EXTERN void png_write_destroy PNGARG((png_structp png_ptr)); - -#ifdef USE_FAR_KEYWORD /* memory model conversion function */ -PNG_EXTERN void *png_far_to_near PNGARG((png_structp png_ptr, png_voidp ptr, - int check)); -#endif /* USE_FAR_KEYWORD */ - #if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) -PNG_EXTERN PNG_FUNCTION(void, png_fixed_error, (png_structp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN); #endif @@ -1438,8 +1537,8 @@ PNG_EXTERN PNG_FUNCTION(void, png_fixed_error, (png_structp png_ptr, * the end. Always leaves the buffer nul terminated. Never errors out (and * there is no error code.) */ -PNG_EXTERN size_t png_safecat(png_charp buffer, size_t bufsize, size_t pos, - png_const_charp string); +PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, + size_t pos, png_const_charp string),PNG_EMPTY); /* Various internal functions to handle formatted warning messages, currently * only implemented for warnings. @@ -1450,8 +1549,8 @@ PNG_EXTERN size_t png_safecat(png_charp buffer, size_t bufsize, size_t pos, * Returns the pointer to the start of the formatted string. This utility only * does unsigned values. */ -PNG_EXTERN png_charp png_format_number(png_const_charp start, png_charp end, - int format, png_alloc_size_t number); +PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, + png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); /* Convenience macro that takes an array: */ #define PNG_FORMAT_NUMBER(buffer,format,number) \ @@ -1475,7 +1574,7 @@ PNG_EXTERN png_charp png_format_number(png_const_charp start, png_charp end, #ifdef PNG_WARNINGS_SUPPORTED /* New defines and members adding in libpng-1.5.4 */ # define PNG_WARNING_PARAMETER_SIZE 32 -# define PNG_WARNING_PARAMETER_COUNT 8 +# define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */ /* An l-value of this type has to be passed to the APIs below to cache the * values of the parameters to a formatted warning message. @@ -1483,48 +1582,97 @@ PNG_EXTERN png_charp png_format_number(png_const_charp start, png_charp end, typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ PNG_WARNING_PARAMETER_SIZE]; -PNG_EXTERN void png_warning_parameter(png_warning_parameters p, int number, - png_const_charp string); - /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, - * including the trailing '\0'. - */ -PNG_EXTERN void png_warning_parameter_unsigned(png_warning_parameters p, - int number, int format, png_alloc_size_t value); - /* Use png_alloc_size_t because it is an unsigned type as big as any we - * need to output. Use the following for a signed value. - */ -PNG_EXTERN void png_warning_parameter_signed(png_warning_parameters p, - int number, int format, png_int_32 value); - -PNG_EXTERN void png_formatted_warning(png_structp png_ptr, - png_warning_parameters p, png_const_charp message); - /* 'message' follows the X/Open approach of using @1, @2 to insert - * parameters previously supplied using the above functions. Errors in - * specifying the paramters will simple result in garbage substitutions. - */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, + int number, png_const_charp string),PNG_EMPTY); + /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, + * including the trailing '\0'. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, + (png_warning_parameters p, int number, int format, png_alloc_size_t value), + PNG_EMPTY); + /* Use png_alloc_size_t because it is an unsigned type as big as any we + * need to output. Use the following for a signed value. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, + (png_warning_parameters p, int number, int format, png_int_32 value), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, + png_warning_parameters p, png_const_charp message),PNG_EMPTY); + /* 'message' follows the X/Open approach of using @1, @2 to insert + * parameters previously supplied using the above functions. Errors in + * specifying the parameters will simply result in garbage substitutions. + */ #endif +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Application errors (new in 1.6); use these functions (declared below) for + * errors in the parameters or order of API function calls on read. The + * 'warning' should be used for an error that can be handled completely; the + * 'error' for one which can be handled safely but which may lose application + * information or settings. + * + * By default these both result in a png_error call prior to release, while in a + * released version the 'warning' is just a warning. However if the application + * explicitly disables benign errors (explicitly permitting the code to lose + * information) they both turn into warnings. + * + * If benign errors aren't supported they end up as the corresponding base call + * (png_warning or png_error.) + */ +PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* The application provided invalid parameters to an API function or called + * an API function at the wrong time, libpng can completely recover. + */ + +PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* As above but libpng will ignore the call, or attempt some other partial + * recovery from the error. + */ +#else +# define png_app_warning(pp,s) png_warning(pp,s) +# define png_app_error(pp,s) png_error(pp,s) +#endif + +PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, + png_const_charp message, int error),PNG_EMPTY); + /* Report a recoverable issue in chunk data. On read this is used to report + * a problem found while reading a particular chunk and the + * png_chunk_benign_error or png_chunk_warning function is used as + * appropriate. On write this is used to report an error that comes from + * data set via an application call to a png_set_ API and png_app_error or + * png_app_warning is used as appropriate. + * + * The 'error' parameter must have one of the following values: + */ +#define PNG_CHUNK_WARNING 0 /* never an error */ +#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */ +#define PNG_CHUNK_ERROR 2 /* always an error */ + /* ASCII to FP interfaces, currently only implemented if sCAL * support is required. */ -#if defined(PNG_READ_sCAL_SUPPORTED) +#if defined(PNG_sCAL_SUPPORTED) /* MAX_DIGITS is actually the maximum number of characters in an sCAL * width or height, derived from the precision (number of significant - * digits - a build time settable option) and assumpitions about the + * digits - a build time settable option) and assumptions about the * maximum ridiculous exponent. */ #define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) #ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_ascii_from_fp PNGARG((png_structp png_ptr, png_charp ascii, - png_size_t size, double fp, unsigned int precision)); +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, double fp, unsigned int precision), + PNG_EMPTY); #endif /* FLOATING_POINT */ #ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr, - png_charp ascii, png_size_t size, png_fixed_point fp)); +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY); #endif /* FIXED_POINT */ -#endif /* READ_sCAL */ +#endif /* sCAL */ #if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) /* An internal API to validate the format of a floating point number. @@ -1548,7 +1696,7 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr, * NOTE: The dangling E problem. * There is a PNG valid floating point number in the following: * - * PNG floating point numb1.ers are not greedy. + * PNG floating point numbers are not greedy. * * Working this out requires *TWO* character lookahead (because of the * sign), the parser does not do this - it will fail at the 'r' - this @@ -1598,15 +1746,15 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr, #define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) #define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) #define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) - -/* The actual parser. This can be called repeatedly, it updates + +/* The actual parser. This can be called repeatedly. It updates * the index into the string and the state variable (which must - * be initialzed to 0). It returns a result code, as above. There + * be initialized to 0). It returns a result code, as above. There * is no point calling the parser any more if it fails to advance to * the end of the string - it is stuck on an invalid character (or * terminated by '\0'). * - * Note that the pointer will consume an E or even an E+ then leave + * Note that the pointer will consume an E or even an E+ and then leave * a 'maybe' state even though a preceding integer.fraction is valid. * The PNG_FP_WAS_VALID flag indicates that a preceding substring was * a valid number. It's possible to recover from this by calling @@ -1614,8 +1762,8 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr, * that omits the last character (i.e. set the size to the index of * the problem character.) This has not been tested within libpng. */ -PNG_EXTERN int png_check_fp_number PNGARG((png_const_charp string, - png_size_t size, int *statep, png_size_tp whereami)); +PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, + png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); /* This is the same but it checks a complete string and returns true * only if it just contains a floating point number. As of 1.5.4 this @@ -1623,11 +1771,11 @@ PNG_EXTERN int png_check_fp_number PNGARG((png_const_charp string, * it was valid (otherwise it returns 0.) This can be used for testing * for negative or zero values using the sticky flag. */ -PNG_EXTERN int png_check_fp_string PNGARG((png_const_charp string, - png_size_t size)); +PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, + png_size_t size),PNG_EMPTY); #endif /* pCAL || sCAL */ -#if defined(PNG_READ_GAMMA_SUPPORTED) ||\ +#if defined(PNG_GAMMA_SUPPORTED) ||\ defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) /* Added at libpng version 1.5.0 */ /* This is a utility to provide a*times/div (rounded) and indicate @@ -1635,29 +1783,37 @@ PNG_EXTERN int png_check_fp_string PNGARG((png_const_charp string, * for overflow, true (1) if no overflow, in which case *res * holds the result. */ -PNG_EXTERN int png_muldiv PNGARG((png_fixed_point_p res, png_fixed_point a, - png_int_32 multiplied_by, png_int_32 divided_by)); +PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, + png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); #endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) /* Same deal, but issue a warning on overflow and return 0. */ -PNG_EXTERN png_fixed_point png_muldiv_warn PNGARG((png_structp png_ptr, - png_fixed_point a, png_int_32 multiplied_by, png_int_32 divided_by)); +PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn, + (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by, + png_int_32 divided_by),PNG_EMPTY); #endif -#ifdef PNG_READ_GAMMA_SUPPORTED +#ifdef PNG_GAMMA_SUPPORTED /* Calculate a reciprocal - used for gamma values. This returns - * 0 if the argument is 0 in order to maintain an undefined value, + * 0 if the argument is 0 in order to maintain an undefined value; * there are no warnings. */ -PNG_EXTERN png_fixed_point png_reciprocal PNGARG((png_fixed_point a)); +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), + PNG_EMPTY); +#ifdef PNG_READ_GAMMA_SUPPORTED /* The same but gives a reciprocal of the product of two fixed point * values. Accuracy is suitable for gamma calculations but this is - * not exact - use png_muldiv for that. + * not exact - use png_muldiv for that. Only required at present on read. */ -PNG_EXTERN png_fixed_point png_reciprocal2 PNGARG((png_fixed_point a, - png_fixed_point b)); +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, + png_fixed_point b),PNG_EMPTY); +#endif + +/* Return true if the gamma value is significantly different from 1.0 */ +PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), + PNG_EMPTY); #endif #ifdef PNG_READ_GAMMA_SUPPORTED @@ -1668,19 +1824,93 @@ PNG_EXTERN png_fixed_point png_reciprocal2 PNGARG((png_fixed_point a, * While the input is an 'unsigned' value it must actually be the * correct bit value - 0..255 or 0..65535 as required. */ -PNG_EXTERN png_uint_16 png_gamma_correct PNGARG((png_structp png_ptr, - unsigned int value, png_fixed_point gamma_value)); -PNG_EXTERN int png_gamma_significant PNGARG((png_fixed_point gamma_value)); -PNG_EXTERN png_uint_16 png_gamma_16bit_correct PNGARG((unsigned int value, - png_fixed_point gamma_value)); -PNG_EXTERN png_byte png_gamma_8bit_correct PNGARG((unsigned int value, - png_fixed_point gamma_value)); -PNG_EXTERN void png_destroy_gamma_table(png_structp png_ptr); -PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr, - int bit_depth)); +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, + unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, + int bit_depth),PNG_EMPTY); +#endif + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* The internal structure that png_image::opaque points to. */ +typedef struct png_control +{ + png_structp png_ptr; + png_infop info_ptr; + png_voidp error_buf; /* Always a jmp_buf at present. */ + + png_const_bytep memory; /* Memory buffer. */ + png_size_t size; /* Size of the memory buffer. */ + + unsigned int for_write :1; /* Otherwise it is a read structure */ + unsigned int owned_file :1; /* We own the file in io_ptr */ +} png_control; + +/* Return the pointer to the jmp_buf from a png_control: necessary because C + * does not reveal the type of the elements of jmp_buf. + */ +#ifdef __cplusplus +# define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0]) +#else +# define png_control_jmp_buf(pc) ((pc)->error_buf) +#endif + +/* Utility to safely execute a piece of libpng code catching and logging any + * errors that might occur. Returns true on success, false on failure (either + * of the function or as a result of a png_error.) + */ +PNG_INTERNAL_CALLBACK(void,png_safe_error,(png_structp png_ptr, + png_const_charp error_message),PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +PNG_INTERNAL_CALLBACK(void,png_safe_warning,(png_structp png_ptr, + png_const_charp warning_message),PNG_EMPTY); +#else +# define png_safe_warning 0/*dummy argument*/ +#endif + +PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, + int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); + +/* Utility to log an error; this also cleans up the png_image; the function + * always returns 0 (false). + */ +PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, + png_const_charp error_message),PNG_EMPTY); + +#ifndef PNG_SIMPLIFIED_READ_SUPPORTED +/* png_image_free is used by the write code but not exported */ +PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); +#endif /* !SIMPLIFIED_READ */ + +#endif /* SIMPLIFIED READ/WRITE */ + +/* These are initialization functions for hardware specific PNG filter + * optimizations; list these here then select the appropriate one at compile + * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined + * the generic code is used. + */ +#ifdef PNG_FILTER_OPTIMIZATIONS +PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, + unsigned int bpp), PNG_EMPTY); + /* Just declare the optimization that will be used */ +#else + /* List *all* the possible optimizations here - this branch is required if + * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in + * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. + */ +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); #endif -/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ +/* Maintainer: Put new private prototypes here ^ */ #include "pngdebug.h" @@ -1688,4 +1918,5 @@ PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr, } #endif +#endif /* PNG_VERSION_INFO_ONLY */ #endif /* PNGPRIV_H */ diff --git a/src/3rdparty/libpng/pngread.c b/src/3rdparty/libpng/pngread.c index 1d8c6b3346..6764dbe561 100644 --- a/src/3rdparty/libpng/pngread.c +++ b/src/3rdparty/libpng/pngread.c @@ -1,8 +1,8 @@ /* pngread.c - read a PNG file * - * Last changed in libpng 1.5.10 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -15,6 +15,9 @@ */ #include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif #ifdef PNG_READ_SUPPORTED @@ -23,10 +26,12 @@ PNG_FUNCTION(png_structp,PNGAPI png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) { - -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, NULL, NULL, NULL)); +#ifndef PNG_USER_MEM_SUPPORTED + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_read_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); } /* Alternate create PNG structure for reading, and allocate any memory @@ -37,131 +42,40 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { -#endif /* PNG_USER_MEM_SUPPORTED */ - -#ifdef PNG_SETJMP_SUPPORTED - volatile -#endif - png_structp png_ptr; - volatile int png_cleanup_needed = 0; - -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf tmp_jmpbuf; -#endif -#endif - - png_debug(1, "in png_create_read_struct"); - -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, - malloc_fn, mem_ptr); -#else - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); -#endif - if (png_ptr == NULL) - return (NULL); - - /* Added at libpng-1.2.6 */ -#ifdef PNG_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; - - /* Added at libpng-1.2.43 and 1.4.0 */ - png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; - - /* Added at libpng-1.2.43 and 1.4.1 */ - png_ptr->user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; -#endif - -#ifdef PNG_SETJMP_SUPPORTED -/* Applications that neglect to set up their own setjmp() and then - * encounter a png_error() will longjmp here. Since the jmpbuf is - * then meaningless we abort instead of returning. - */ -#ifdef USE_FAR_KEYWORD - if (setjmp(tmp_jmpbuf)) -#else - if (setjmp(png_jmpbuf(png_ptr))) /* Sets longjmp to match setjmp */ -#endif - PNG_ABORT(); -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf)); -#endif -#endif /* PNG_SETJMP_SUPPORTED */ - -#ifdef PNG_USER_MEM_SUPPORTED - png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); -#endif + png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ - png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); - - /* Call the general version checker (shared with read and write code): */ - if (!png_user_version_check(png_ptr, user_png_ver)) - png_cleanup_needed = 1; - - if (!png_cleanup_needed) - { - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, png_ptr->zbuf_size); - - if (png_ptr->zbuf == NULL) - png_cleanup_needed = 1; - } - - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - - if (!png_cleanup_needed) + if (png_ptr != NULL) { - switch (inflateInit(&png_ptr->zstream)) - { - case Z_OK: - break; /* Do nothing */ - - case Z_MEM_ERROR: - png_warning(png_ptr, "zlib memory error"); - png_cleanup_needed = 1; - break; - - case Z_STREAM_ERROR: - png_warning(png_ptr, "zlib stream error"); - png_cleanup_needed = 1; - break; + png_ptr->mode = PNG_IS_READ_STRUCT; - case Z_VERSION_ERROR: - png_warning(png_ptr, "zlib version error"); - png_cleanup_needed = 1; - break; + /* Added in libpng-1.6.0; this can be used to detect a read structure if + * required (it will be zero in a write structure.) + */ +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE; +# endif - default: png_warning(png_ptr, "Unknown zlib error"); - png_cleanup_needed = 1; - } - } +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; - if (png_cleanup_needed) - { - /* Clean up PNG structure and deallocate any memory. */ - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, - (png_free_ptr)free_fn, (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - return (NULL); + /* In stable builds only warn if an application error can be completely + * handled. + */ +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; +# endif +# endif + + /* TODO: delay this, it can be done in png_init_io (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_read_fn(png_ptr, NULL, NULL); } - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - - png_set_read_fn(png_ptr, NULL, NULL); - - - return (png_ptr); + return png_ptr; } @@ -175,8 +89,12 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, * read if it is determined that this isn't a valid PNG file. */ void PNGAPI -png_read_info(png_structp png_ptr, png_infop info_ptr) +png_read_info(png_structrp png_ptr, png_inforp info_ptr) { +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + png_debug(1, "in png_read_info"); if (png_ptr == NULL || info_ptr == NULL) @@ -190,13 +108,30 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) png_uint_32 length = png_read_chunk_header(png_ptr); png_uint_32 chunk_name = png_ptr->chunk_name; - /* This should be a binary subdivision search or a hash for - * matching the chunk name rather than a linear search. + /* IDAT logic needs to happen here to simplify getting the two flags + * right. */ if (chunk_name == png_IDAT) - if (png_ptr->mode & PNG_AFTER_IDAT) - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + { + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "Missing IHDR before IDAT"); + + else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0) + png_chunk_error(png_ptr, "Missing PLTE before IDAT"); + + else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + png_chunk_benign_error(png_ptr, "Too many IDATs found"); + + png_ptr->mode |= PNG_HAVE_IDAT; + } + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + png_ptr->mode |= PNG_AFTER_IDAT; + /* This should be a binary subdivision search or a hash for + * matching the chunk name rather than a linear search. + */ if (chunk_name == png_IHDR) png_handle_IHDR(png_ptr, info_ptr, length); @@ -204,26 +139,16 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) png_handle_IEND(png_ptr, info_ptr, length); #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_chunk_unknown_handling(png_ptr, chunk_name) != - PNG_HANDLE_CHUNK_AS_DEFAULT) + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { - if (chunk_name == png_IDAT) - png_ptr->mode |= PNG_HAVE_IDAT; - - png_handle_unknown(png_ptr, info_ptr, length); + png_handle_unknown(png_ptr, info_ptr, length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; else if (chunk_name == png_IDAT) { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - + png_ptr->idat_size = 0; /* It has been consumed */ break; } } @@ -233,15 +158,7 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) else if (chunk_name == png_IDAT) { - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before IDAT"); - - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) - png_error(png_ptr, "Missing PLTE before IDAT"); - png_ptr->idat_size = length; - png_ptr->mode |= PNG_HAVE_IDAT; break; } @@ -331,27 +248,36 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) #endif else - png_handle_unknown(png_ptr, info_ptr, length); + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); } } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ /* Optional call to update the users info_ptr structure */ void PNGAPI -png_read_update_info(png_structp png_ptr, png_infop info_ptr) +png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_read_update_info"); - if (png_ptr == NULL) - return; + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + png_read_start_row(png_ptr); - png_read_start_row(png_ptr); +# ifdef PNG_READ_TRANSFORMS_SUPPORTED + png_read_transform_info(png_ptr, info_ptr); +# else + PNG_UNUSED(info_ptr) +# endif + } -#ifdef PNG_READ_TRANSFORMS_SUPPORTED - png_read_transform_info(png_ptr, info_ptr); -#else - PNG_UNUSED(info_ptr) -#endif + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_read_update_info/png_start_read_image: duplicate call"); + } } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED @@ -361,21 +287,93 @@ png_read_update_info(png_structp png_ptr, png_infop info_ptr) * If the user doesn't call this, we will do it ourselves. */ void PNGAPI -png_start_read_image(png_structp png_ptr) +png_start_read_image(png_structrp png_ptr) { png_debug(1, "in png_start_read_image"); if (png_ptr != NULL) - png_read_start_row(png_ptr); + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + png_read_start_row(png_ptr); + + /* New in 1.6.0 this avoids the bug of doing the initializations twice */ + else + png_app_error(png_ptr, + "png_start_read_image/png_read_update_info: duplicate call"); + } } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED -void PNGAPI -png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing, + * NOTE: this is apparently only supported in the 'sequential' reader. + */ +static void +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) { - int ret; + png_debug(1, "in png_do_read_intrapixel"); + + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); + *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); + } + } + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (s0 + s1 + 65536) & 0xffff; + png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp + 1) = (png_byte)(red & 0xff); + *(rp + 4) = (png_byte)((blue >> 8) & 0xff); + *(rp + 5) = (png_byte)(blue & 0xff); + } + } + } +} +#endif /* MNG_FEATURES */ + +void PNGAPI +png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) +{ png_row_info row_info; if (png_ptr == NULL) @@ -387,7 +385,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) /* png_read_start_row sets the information (in particular iwidth) for this * interlace pass. */ - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) png_read_start_row(png_ptr); /* 1.5.6: row_info moved out of png_struct to a local here. */ @@ -398,45 +396,47 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) row_info.pixel_depth = png_ptr->pixel_depth; row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); +#ifdef PNG_WARNINGS_SUPPORTED if (png_ptr->row_number == 0 && png_ptr->pass == 0) { /* Check for transforms that have been set but were defined out */ #if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) + if ((png_ptr->transformations & PNG_FILLER) != 0) png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ !defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) + if ((png_ptr->transformations & PNG_PACK) != 0) png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) + if ((png_ptr->transformations & PNG_SHIFT) != 0) png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) + if ((png_ptr->transformations & PNG_BGR) != 0) png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); #endif } +#endif /* WARNINGS */ #ifdef PNG_READ_INTERLACING_SUPPORTED /* If interlaced and we do not need a new row, combine row and return. @@ -445,7 +445,8 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) * untransformed) and, because of the libpng API for interlaced images, this * means we must transform before de-interlacing. */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { switch (png_ptr->pass) { @@ -502,6 +503,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) return; } break; + case 5: if ((png_ptr->row_number & 1) || png_ptr->width < 2) { @@ -515,7 +517,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) default: case 6: - if (!(png_ptr->row_number & 1)) + if ((png_ptr->row_number & 1) == 0) { png_read_finish_row(png_ptr); return; @@ -525,52 +527,11 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) } #endif - if (!(png_ptr->mode & PNG_HAVE_IDAT)) + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) png_error(png_ptr, "Invalid attempt to read row data"); - png_ptr->zstream.next_out = png_ptr->row_buf; - png_ptr->zstream.avail_out = - (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1); - - do - { - if (!(png_ptr->zstream.avail_in)) - { - while (!png_ptr->idat_size) - { - png_crc_finish(png_ptr, 0); - - png_ptr->idat_size = png_read_chunk_header(png_ptr); - if (png_ptr->chunk_name != png_IDAT) - png_error(png_ptr, "Not enough image data"); - } - png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_in = png_ptr->zbuf; - if (png_ptr->zbuf_size > png_ptr->idat_size) - png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; - png_crc_read(png_ptr, png_ptr->zbuf, - (png_size_t)png_ptr->zstream.avail_in); - png_ptr->idat_size -= png_ptr->zstream.avail_in; - } - - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - - if (ret == Z_STREAM_END) - { - if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || - png_ptr->idat_size) - png_benign_error(png_ptr, "Extra compressed data"); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - - if (ret != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : - "Decompression error"); - - } while (png_ptr->zstream.avail_out); + /* Fill the row with IDAT data: */ + png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) { @@ -586,10 +547,10 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) * it may not be in the future, so this was changed just to copy the * interlaced count: */ - png_memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); + memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ @@ -597,7 +558,6 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) } #endif - #ifdef PNG_READ_TRANSFORMS_SUPPORTED if (png_ptr->transformations) png_do_read_transformations(png_ptr, &row_info); @@ -615,9 +575,9 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) png_error(png_ptr, "internal sequential row size calculation error"); #ifdef PNG_READ_INTERLACING_SUPPORTED - /* Blow up interlaced rows to full size */ - if (png_ptr->interlaced && - (png_ptr->transformations & PNG_INTERLACE)) + /* Expand interlaced rows to full size */ + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { if (png_ptr->pass < 6) png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, @@ -643,8 +603,9 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) if (png_ptr->read_row_fn != NULL) (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); + } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. If the image is interlaced, @@ -672,7 +633,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) */ void PNGAPI -png_read_rows(png_structp png_ptr, png_bytepp row, +png_read_rows(png_structrp png_ptr, png_bytepp row, png_bytepp display_row, png_uint_32 num_rows) { png_uint_32 i; @@ -711,7 +672,7 @@ png_read_rows(png_structp png_ptr, png_bytepp row, dp++; } } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the entire image. If the image has an alpha channel or a tRNS @@ -727,7 +688,7 @@ png_read_rows(png_structp png_ptr, png_bytepp row, * [*] png_handle_alpha() does not exist yet, as of this version of libpng */ void PNGAPI -png_read_image(png_structp png_ptr, png_bytepp image) +png_read_image(png_structrp png_ptr, png_bytepp image) { png_uint_32 i, image_height; int pass, j; @@ -739,7 +700,7 @@ png_read_image(png_structp png_ptr, png_bytepp image) return; #ifdef PNG_READ_INTERLACING_SUPPORTED - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) { pass = png_set_interlace_handling(png_ptr); /* And make sure transforms are initialized. */ @@ -747,7 +708,8 @@ png_read_image(png_structp png_ptr, png_bytepp image) } else { - if (png_ptr->interlaced && !(png_ptr->transformations & PNG_INTERLACE)) + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) == 0) { /* Caller called png_start_read_image or png_read_update_info without * first turning on the PNG_INTERLACE transform. We can fix this here, @@ -784,7 +746,7 @@ png_read_image(png_structp png_ptr, png_bytepp image) } } } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. Will not read past the end of the @@ -792,14 +754,24 @@ png_read_image(png_structp png_ptr, png_bytepp image) * or time information at the end of the file, if info is not NULL. */ void PNGAPI -png_read_end(png_structp png_ptr, png_infop info_ptr) +png_read_end(png_structrp png_ptr, png_inforp info_ptr) { +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + int keep; +#endif + png_debug(1, "in png_read_end"); if (png_ptr == NULL) return; - png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ + /* If png_read_end is called in the middle of reading the rows there may + * still be pending IDAT data and an owned zstream. Deal with this here. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0) +#endif + png_read_finish_IDAT(png_ptr); #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Report invalid palette index; added at libng-1.5.10 */ @@ -813,22 +785,25 @@ png_read_end(png_structp png_ptr, png_infop info_ptr) png_uint_32 length = png_read_chunk_header(png_ptr); png_uint_32 chunk_name = png_ptr->chunk_name; - if (chunk_name == png_IHDR) + if (chunk_name == png_IEND) + png_handle_IEND(png_ptr, info_ptr, length); + + else if (chunk_name == png_IHDR) png_handle_IHDR(png_ptr, info_ptr, length); - else if (chunk_name == png_IEND) - png_handle_IEND(png_ptr, info_ptr, length); + else if (info_ptr == NULL) + png_crc_finish(png_ptr, length); #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - else if (png_chunk_unknown_handling(png_ptr, chunk_name) != - PNG_HANDLE_CHUNK_AS_DEFAULT) + else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { if (chunk_name == png_IDAT) { - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + if ((length > 0) || + (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) png_benign_error(png_ptr, "Too many IDATs found"); } - png_handle_unknown(png_ptr, info_ptr, length); + png_handle_unknown(png_ptr, info_ptr, length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; } @@ -839,7 +814,7 @@ png_read_end(png_structp png_ptr, png_infop info_ptr) /* Zero length IDATs are legal after the last IDAT has been * read, but not after other chunks have been read. */ - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) png_benign_error(png_ptr, "Too many IDATs found"); png_crc_finish(png_ptr, length); @@ -933,181 +908,106 @@ png_read_end(png_structp png_ptr, png_infop info_ptr) #endif else - png_handle_unknown(png_ptr, info_ptr, length); - } while (!(png_ptr->mode & PNG_HAVE_IEND)); -} -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ - -/* Free all memory used by the read */ -void PNGAPI -png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, - png_infopp end_info_ptr_ptr) -{ - png_structp png_ptr = NULL; - png_infop info_ptr = NULL, end_info_ptr = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn = NULL; - png_voidp mem_ptr = NULL; -#endif - - png_debug(1, "in png_destroy_read_struct"); - - if (png_ptr_ptr != NULL) - png_ptr = *png_ptr_ptr; - if (png_ptr == NULL) - return; - -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; -#endif - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (end_info_ptr_ptr != NULL) - end_info_ptr = *end_info_ptr_ptr; - - png_read_destroy(png_ptr, info_ptr, end_info_ptr); - - if (info_ptr != NULL) - { -#ifdef PNG_TEXT_SUPPORTED - png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1); -#endif - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif - *info_ptr_ptr = NULL; - } - - if (end_info_ptr != NULL) - { -#ifdef PNG_READ_TEXT_SUPPORTED - png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1); -#endif -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)end_info_ptr); -#endif - *end_info_ptr_ptr = NULL; - } - - if (png_ptr != NULL) - { -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - *png_ptr_ptr = NULL; - } + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } while ((png_ptr->mode & PNG_HAVE_IEND) == 0); } +#endif /* SEQUENTIAL_READ */ -/* Free all memory used by the read (old method) */ -void /* PRIVATE */ -png_read_destroy(png_structp png_ptr, png_infop info_ptr, - png_infop end_info_ptr) +/* Free all memory used in the read struct */ +static void +png_read_destroy(png_structrp png_ptr) { -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; -#endif - png_error_ptr error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - png_error_ptr warning_fn; -#endif - png_voidp error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn; -#endif - png_debug(1, "in png_read_destroy"); - if (info_ptr != NULL) - png_info_destroy(png_ptr, info_ptr); - - if (end_info_ptr != NULL) - png_info_destroy(png_ptr, end_info_ptr); - #ifdef PNG_READ_GAMMA_SUPPORTED png_destroy_gamma_table(png_ptr); #endif - png_free(png_ptr, png_ptr->zbuf); png_free(png_ptr, png_ptr->big_row_buf); + png_ptr->big_row_buf = NULL; png_free(png_ptr, png_ptr->big_prev_row); - png_free(png_ptr, png_ptr->chunkdata); + png_ptr->big_prev_row = NULL; + png_free(png_ptr, png_ptr->read_buffer); + png_ptr->read_buffer = NULL; #ifdef PNG_READ_QUANTIZE_SUPPORTED png_free(png_ptr, png_ptr->palette_lookup); + png_ptr->palette_lookup = NULL; png_free(png_ptr, png_ptr->quantize_index); + png_ptr->quantize_index = NULL; #endif - if (png_ptr->free_me & PNG_FREE_PLTE) + if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) + { png_zfree(png_ptr, png_ptr->palette); + png_ptr->palette = NULL; + } png_ptr->free_me &= ~PNG_FREE_PLTE; #if defined(PNG_tRNS_SUPPORTED) || \ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->free_me & PNG_FREE_TRNS) + if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) + { png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; + } png_ptr->free_me &= ~PNG_FREE_TRNS; #endif -#ifdef PNG_READ_hIST_SUPPORTED - if (png_ptr->free_me & PNG_FREE_HIST) - png_free(png_ptr, png_ptr->hist); - png_ptr->free_me &= ~PNG_FREE_HIST; -#endif - inflateEnd(&png_ptr->zstream); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED png_free(png_ptr, png_ptr->save_buffer); + png_ptr->save_buffer = NULL; #endif - /* Save the important info out of the png_struct, in case it is - * being used again. - */ -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf)); +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; #endif - error_fn = png_ptr->error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - warning_fn = png_ptr->warning_fn; -#endif - error_ptr = png_ptr->error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; #endif - png_memset(png_ptr, 0, png_sizeof(png_struct)); + /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error + * callbacks are still set at this point. They are required to complete the + * destruction of the png_struct itself. + */ +} - png_ptr->error_fn = error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - png_ptr->warning_fn = warning_fn; -#endif - png_ptr->error_ptr = error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr->free_fn = free_fn; -#endif +/* Free all memory used by the read */ +void PNGAPI +png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, + png_infopp end_info_ptr_ptr) +{ + png_structrp png_ptr = NULL; -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->longjmp_buffer, tmp_jmp, png_sizeof(jmp_buf)); -#endif + png_debug(1, "in png_destroy_read_struct"); + + if (png_ptr_ptr != NULL) + png_ptr = *png_ptr_ptr; + + if (png_ptr == NULL) + return; + + /* libpng 1.6.0: use the API to destroy info structs to ensure consistent + * behavior. Prior to 1.6.0 libpng did extra 'info' destruction in this API. + * The extra was, apparently, unnecessary yet this hides memory leak bugs. + */ + png_destroy_info_struct(png_ptr, end_info_ptr_ptr); + png_destroy_info_struct(png_ptr, info_ptr_ptr); + *png_ptr_ptr = NULL; + png_read_destroy(png_ptr); + png_destroy_png_struct(png_ptr); } void PNGAPI -png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) +png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) { if (png_ptr == NULL) return; @@ -1119,12 +1019,10 @@ png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn) #ifdef PNG_SEQUENTIAL_READ_SUPPORTED #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI -png_read_png(png_structp png_ptr, png_infop info_ptr, +png_read_png(png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params) { - int row; - if (png_ptr == NULL || info_ptr == NULL) return; @@ -1132,130 +1030,153 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); - if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) + if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep))) png_error(png_ptr, "Image is too high to process with png_read_png()"); /* -------------- image transformations start here ------------------- */ + /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM + * is not implemented. This will only happen in de-configured (non-default) + * libpng builds. The results can be unexpected - png_read_png may return + * short or mal-formed rows because the transform is skipped. + */ -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Tell libpng to strip 16-bit/color files down to 8 bits per color. */ - if (transforms & PNG_TRANSFORM_SCALE_16) - { + if ((transforms & PNG_TRANSFORM_SCALE_16) != 0) /* Added at libpng-1.5.4. "strip_16" produces the same result that it * did in earlier versions, while "scale_16" is now more accurate. */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(png_ptr); - } +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SCALE_16 not supported"); #endif -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* If both SCALE and STRIP are required pngrtran will effectively cancel the * latter by doing SCALE first. This is ok and allows apps not to check for * which is supported to get the right answer. */ - if (transforms & PNG_TRANSFORM_STRIP_16) + if ((transforms & PNG_TRANSFORM_STRIP_16) != 0) +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED png_set_strip_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_16 not supported"); #endif -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED /* Strip alpha bytes from the input data without combining with * the background (not recommended). */ - if (transforms & PNG_TRANSFORM_STRIP_ALPHA) + if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0) +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED png_set_strip_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_ALPHA not supported"); #endif -#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ - if (transforms & PNG_TRANSFORM_PACKING) + if ((transforms & PNG_TRANSFORM_PACKING) != 0) +#ifdef PNG_READ_PACK_SUPPORTED png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); #endif -#ifdef PNG_READ_PACKSWAP_SUPPORTED /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ - if (transforms & PNG_TRANSFORM_PACKSWAP) + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) +#ifdef PNG_READ_PACKSWAP_SUPPORTED png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif -#ifdef PNG_READ_EXPAND_SUPPORTED /* Expand paletted colors into true RGB triplets * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel * Expand paletted or RGB images with transparency to full alpha * channels so the data will be available as RGBA quartets. */ - if (transforms & PNG_TRANSFORM_EXPAND) - if ((png_ptr->bit_depth < 8) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || - (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) - png_set_expand(png_ptr); + if ((transforms & PNG_TRANSFORM_EXPAND) != 0) +#ifdef PNG_READ_EXPAND_SUPPORTED + png_set_expand(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND not supported"); #endif /* We don't handle background color or gamma transformation or quantizing. */ -#ifdef PNG_READ_INVERT_SUPPORTED /* Invert monochrome files to have 0 as white and 1 as black */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) +#ifdef PNG_READ_INVERT_SUPPORTED png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif -#ifdef PNG_READ_SHIFT_SUPPORTED /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ - if ((transforms & PNG_TRANSFORM_SHIFT) - && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) - { - png_color_8p sig_bit; - - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - png_set_shift(png_ptr, sig_bit); - } + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); #endif -#ifdef PNG_READ_BGR_SUPPORTED /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ - if (transforms & PNG_TRANSFORM_BGR) + if ((transforms & PNG_TRANSFORM_BGR) != 0) +#ifdef PNG_READ_BGR_SUPPORTED png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif -#ifdef PNG_READ_SWAP_SUPPORTED /* Swap bytes of 16-bit files to least significant byte first */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) +#ifdef PNG_READ_SWAP_SUPPORTED png_set_swap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif /* Added at libpng-1.2.41 */ -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel from opacity to transparency */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* Added at libpng-1.2.41 */ -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale image to RGB */ - if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) + if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0) +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED png_set_gray_to_rgb(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_GRAY_TO_RGB not supported"); #endif /* Added at libpng-1.5.4 */ + if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0) #ifdef PNG_READ_EXPAND_16_SUPPORTED - if (transforms & PNG_TRANSFORM_EXPAND_16) png_set_expand_16(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND_16 not supported"); #endif /* We don't handle adding filler bytes */ @@ -1278,16 +1199,17 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, { png_uint_32 iptr; - info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, - info_ptr->height * png_sizeof(png_bytep)); + info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr, + info_ptr->height * (sizeof (png_bytep)))); + for (iptr=0; iptrheight; iptr++) info_ptr->row_pointers[iptr] = NULL; info_ptr->free_me |= PNG_FREE_ROWS; - for (row = 0; row < (int)info_ptr->height; row++) - info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, - png_get_rowbytes(png_ptr, info_ptr)); + for (iptr = 0; iptr < info_ptr->height; iptr++) + info_ptr->row_pointers[iptr] = png_voidcast(png_bytep, + png_malloc(png_ptr, info_ptr->rowbytes)); } png_read_image(png_ptr, info_ptr->row_pointers); @@ -1296,10 +1218,2917 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); - PNG_UNUSED(transforms) /* Quiet compiler warnings */ PNG_UNUSED(params) +} +#endif /* INFO_IMAGE */ +#endif /* SEQUENTIAL_READ */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* SIMPLIFIED READ + * + * This code currently relies on the sequential reader, though it could easily + * be made to work with the progressive one. + */ +/* Arguments to png_image_finish_read: */ + +/* Encoding of PNG data (used by the color-map code) */ +# define P_NOTSET 0 /* File encoding not yet known */ +# define P_sRGB 1 /* 8-bit encoded to sRGB gamma */ +# define P_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ +# define P_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ +# define P_LINEAR8 4 /* 8-bit linear: only from a file value */ + +/* Color-map processing: after libpng has run on the PNG image further + * processing may be needed to convert the data to color-map indices. + */ +#define PNG_CMAP_NONE 0 +#define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */ +#define PNG_CMAP_TRANS 2 /* Process GA data to a background index */ +#define PNG_CMAP_RGB 3 /* Process RGB data */ +#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */ + +/* The following document where the background is for each processing case. */ +#define PNG_CMAP_NONE_BACKGROUND 256 +#define PNG_CMAP_GA_BACKGROUND 231 +#define PNG_CMAP_TRANS_BACKGROUND 254 +#define PNG_CMAP_RGB_BACKGROUND 256 +#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216 + +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_voidp buffer; + png_int_32 row_stride; + png_voidp colormap; + png_const_colorp background; + /* Local variables: */ + png_voidp local_row; + png_voidp first_row; + ptrdiff_t row_bytes; /* step between rows */ + int file_encoding; /* E_ values above */ + png_fixed_point gamma_to_linear; /* For P_FILE, reciprocal of gamma */ + int colormap_processing; /* PNG_CMAP_ values above */ +} png_image_read_control; + +/* Do all the *safe* initialization - 'safe' means that png_error won't be + * called, so setting up the jmp_buf is not required. This means that anything + * called from here must *not* call png_malloc - it has to call png_malloc_warn + * instead so that control is returned safely back to this routine. + */ +static int +png_image_read_init(png_imagep image) +{ + if (image->opaque == NULL) + { + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + /* And set the rest of the structure to NULL to ensure that the various + * fields are consistent. + */ + memset(image, 0, (sizeof *image)); + image->version = PNG_IMAGE_VERSION; + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 0; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_read_struct(&png_ptr, NULL, NULL); + } + + return png_image_error(image, "png_image_read: out of memory"); + } + + return png_image_error(image, "png_image_read: opaque pointer not NULL"); +} + +/* Utility to find the base format of a PNG file from a png_struct. */ +static png_uint_32 +png_image_format(png_structrp png_ptr) +{ + png_uint_32 format = 0; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + format |= PNG_FORMAT_FLAG_COLOR; + + if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS + * sets the png_struct fields; that's all we are interested in here. The + * precise interaction with an app call to png_set_tRNS and PNG file reading + * is unclear. + */ + else if (png_ptr->num_trans > 0) + format |= PNG_FORMAT_FLAG_ALPHA; + + if (png_ptr->bit_depth == 16) + format |= PNG_FORMAT_FLAG_LINEAR; + + if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0) + format |= PNG_FORMAT_FLAG_COLORMAP; + + return format; +} + +/* Is the given gamma significantly different from sRGB? The test is the same + * one used in pngrtran.c when deciding whether to do gamma correction. The + * arithmetic optimizes the division by using the fact that the inverse of the + * file sRGB gamma is 2.2 + */ +static int +png_gamma_not_sRGB(png_fixed_point g) +{ + if (g < PNG_FP_1) + { + /* An uninitialized gamma is assumed to be sRGB for the simplified API. */ + if (g == 0) + return 0; + + return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); + } + + return 1; +} + +/* Do the main body of a 'png_image_begin_read' function; read the PNG file + * header and fill in all the information. This is executed in a safe context, + * unlike the init routine above. + */ +static int +png_image_read_header(png_voidp argument) +{ + png_imagep image = png_voidcast(png_imagep, argument); + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_set_benign_errors(png_ptr, 1/*warn*/); + png_read_info(png_ptr, info_ptr); + + /* Do this the fast way; just read directly out of png_struct. */ + image->width = png_ptr->width; + image->height = png_ptr->height; + + { + png_uint_32 format = png_image_format(png_ptr); + + image->format = format; + +#ifdef PNG_COLORSPACE_SUPPORTED + /* Does the colorspace match sRGB? If there is no color endpoint + * (colorant) information assume yes, otherwise require the + * 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set. If the + * colorspace has been determined to be invalid ignore it. + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags + & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB| + PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS)) + image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB; +#endif + } + + /* We need the maximum number of entries regardless of the format the + * application sets here. + */ + { + png_uint_32 cmap_entries; + + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + cmap_entries = 1U << png_ptr->bit_depth; + break; + + case PNG_COLOR_TYPE_PALETTE: + cmap_entries = png_ptr->num_palette; + break; + + default: + cmap_entries = 256; + break; + } + + if (cmap_entries > 256) + cmap_entries = 256; + + image->colormap_entries = cmap_entries; + } + + return 1; +} + +#ifdef PNG_STDIO_SUPPORTED +int PNGAPI +png_image_begin_read_from_stdio(png_imagep image, FILE* file) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_read_init(image) != 0) + { + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +int PNGAPI +png_image_begin_read_from_file(png_imagep image, const char *file_name) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "rb"); + + if (fp != NULL) + { + if (png_image_read_init(image) != 0) + { + image->opaque->png_ptr->io_ptr = fp; + image->opaque->owned_file = 1; + return png_safe_execute(image, png_image_read_header, image); + } + + /* Clean up: just the opened file. */ + (void)fclose(fp); + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_begin_read_from_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); + + return 0; +} +#endif /* STDIO */ + +static void PNGCBAPI +png_image_memory_read(png_structp png_ptr, png_bytep out, png_size_t need) +{ + if (png_ptr != NULL) + { + png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr); + if (image != NULL) + { + png_controlp cp = image->opaque; + if (cp != NULL) + { + png_const_bytep memory = cp->memory; + png_size_t size = cp->size; + if (memory != NULL && size >= need) + { + memcpy(out, memory, need); + cp->memory = memory + need; + cp->size = size - need; + return; + } + + png_error(png_ptr, "read beyond end of data"); + } + } + + png_error(png_ptr, "invalid memory read"); + } +} + +int PNGAPI png_image_begin_read_from_memory(png_imagep image, + png_const_voidp memory, png_size_t size) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (memory != NULL && size > 0) + { + if (png_image_read_init(image) != 0) + { + /* Now set the IO functions to read from the memory buffer and + * store it into io_ptr. Again do this in-place to avoid calling a + * libpng function that requires error handling. + */ + image->opaque->memory = png_voidcast(png_const_bytep, memory); + image->opaque->size = size; + image->opaque->png_ptr->io_ptr = image; + image->opaque->png_ptr->read_data_fn = png_image_memory_read; + + return png_safe_execute(image, png_image_read_header, image); + } + } + + else + return png_image_error(image, + "png_image_begin_read_from_memory: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); + + return 0; +} + +/* Utility function to skip chunks that are not used by the simplified image + * read functions and an appropriate macro to call it. + */ +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static void +png_image_skip_unused_chunks(png_structrp png_ptr) +{ + /* Prepare the reader to ignore all recognized chunks whose data will not + * be used, i.e., all chunks recognized by libpng except for those + * involved in basic image reading: + * + * IHDR, PLTE, IDAT, IEND + * + * Or image data handling: + * + * tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT. + * + * This provides a small performance improvement and eliminates any + * potential vulnerability to security problems in the unused chunks. + * + * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored + * too. This allows the simplified API to be compiled without iCCP support, + * however if the support is there the chunk is still checked to detect + * errors (which are unfortunately quite common.) + */ + { + static PNG_CONST png_byte chunks_to_process[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ +# ifdef PNG_READ_iCCP_SUPPORTED + 105, 67, 67, 80, '\0', /* iCCP */ +# endif + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 82, 71, 66, '\0', /* sRGB */ + }; + + /* Ignore unknown chunks and all other chunks except for the + * IHDR, PLTE, tRNS, IDAT, and IEND chunks. + */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, + NULL, -1); + + /* But do not ignore image data handling chunks */ + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT, + chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5); + } +} + +# define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p) +#else +# define PNG_SKIP_CHUNKS(p) ((void)0) +#endif /* HANDLE_AS_UNKNOWN */ + +/* The following macro gives the exact rounded answer for all values in the + * range 0..255 (it actually divides by 51.2, but the rounding still generates + * the correct numbers 0..5 + */ +#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8) + +/* Utility functions to make particular color-maps */ +static void +set_file_encoding(png_image_read_control *display) +{ + png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma; + if (png_gamma_significant(g) != 0) + { + if (png_gamma_not_sRGB(g) != 0) + { + display->file_encoding = P_FILE; + display->gamma_to_linear = png_reciprocal(g); + } + + else + display->file_encoding = P_sRGB; + } + + else + display->file_encoding = P_LINEAR8; +} + +static unsigned int +decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) +{ + if (encoding == P_FILE) /* double check */ + encoding = display->file_encoding; + + if (encoding == P_NOTSET) /* must be the file encoding */ + { + set_file_encoding(display); + encoding = display->file_encoding; + } + + switch (encoding) + { + case P_FILE: + value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); + break; + + case P_sRGB: + value = png_sRGB_table[value]; + break; + + case P_LINEAR: + break; + + case P_LINEAR8: + value *= 257; + break; + + default: + png_error(display->image->opaque->png_ptr, + "unexpected encoding (internal error)"); + break; + } + + return value; +} + +static png_uint_32 +png_colormap_compose(png_image_read_control *display, + png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, + png_uint_32 background, int encoding) +{ + /* The file value is composed on the background, the background has the given + * encoding and so does the result, the file is encoded with P_FILE and the + * file and alpha are 8-bit values. The (output) encoding will always be + * P_LINEAR or P_sRGB. + */ + png_uint_32 f = decode_gamma(display, foreground, foreground_encoding); + png_uint_32 b = decode_gamma(display, background, encoding); + + /* The alpha is always an 8-bit value (it comes from the palette), the value + * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires. + */ + f = f * alpha + b * (255-alpha); + + if (encoding == P_LINEAR) + { + /* Scale to 65535; divide by 255, approximately (in fact this is extremely + * accurate, it divides by 255.00000005937181414556, with no overflow.) + */ + f *= 257; /* Now scaled by 65535 */ + f += f >> 16; + f = (f+32768) >> 16; + } + + else /* P_sRGB */ + f = PNG_sRGB_FROM_LINEAR(f); + + return f; } -#endif /* PNG_INFO_IMAGE_SUPPORTED */ -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ + +/* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must + * be 8-bit. + */ +static void +png_create_colormap_entry(png_image_read_control *display, + png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, + png_uint_32 alpha, int encoding) +{ + png_imagep image = display->image; + const int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ? + P_LINEAR : P_sRGB; + const int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && + (red != green || green != blue); + + if (ip > 255) + png_error(image->opaque->png_ptr, "color-map index out of range"); + + /* Update the cache with whether the file gamma is significantly different + * from sRGB. + */ + if (encoding == P_FILE) + { + if (display->file_encoding == P_NOTSET) + set_file_encoding(display); + + /* Note that the cached value may be P_FILE too, but if it is then the + * gamma_to_linear member has been set. + */ + encoding = display->file_encoding; + } + + if (encoding == P_FILE) + { + png_fixed_point g = display->gamma_to_linear; + + red = png_gamma_16bit_correct(red*257, g); + green = png_gamma_16bit_correct(green*257, g); + blue = png_gamma_16bit_correct(blue*257, g); + + if (convert_to_Y != 0 || output_encoding == P_LINEAR) + { + alpha *= 257; + encoding = P_LINEAR; + } + + else + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + encoding = P_sRGB; + } + } + + else if (encoding == P_LINEAR8) + { + /* This encoding occurs quite frequently in test cases because PngSuite + * includes a gAMA 1.0 chunk with most images. + */ + red *= 257; + green *= 257; + blue *= 257; + alpha *= 257; + encoding = P_LINEAR; + } + + else if (encoding == P_sRGB && + (convert_to_Y != 0 || output_encoding == P_LINEAR)) + { + /* The values are 8-bit sRGB values, but must be converted to 16-bit + * linear. + */ + red = png_sRGB_table[red]; + green = png_sRGB_table[green]; + blue = png_sRGB_table[blue]; + alpha *= 257; + encoding = P_LINEAR; + } + + /* This is set if the color isn't gray but the output is. */ + if (encoding == P_LINEAR) + { + if (convert_to_Y != 0) + { + /* NOTE: these values are copied from png_do_rgb_to_gray */ + png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green + + (png_uint_32)2366 * blue; + + if (output_encoding == P_LINEAR) + y = (y + 16384) >> 15; + + else + { + /* y is scaled by 32768, we need it scaled by 255: */ + y = (y + 128) >> 8; + y *= 255; + y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); + alpha = PNG_DIV257(alpha); + encoding = P_sRGB; + } + + blue = red = green = y; + } + + else if (output_encoding == P_sRGB) + { + red = PNG_sRGB_FROM_LINEAR(red * 255); + green = PNG_sRGB_FROM_LINEAR(green * 255); + blue = PNG_sRGB_FROM_LINEAR(blue * 255); + alpha = PNG_DIV257(alpha); + encoding = P_sRGB; + } + } + + if (encoding != output_encoding) + png_error(image->opaque->png_ptr, "bad encoding (internal error)"); + + /* Store the value. */ + { +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + const int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + if (output_encoding == P_LINEAR) + { + png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + /* The linear 16-bit values must be pre-multiplied by the alpha channel + * value, if less than 65535 (this is, effectively, composite on black + * if the alpha channel is removed.) + */ + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_uint_16)alpha; + /* FALL THROUGH */ + + case 3: + if (alpha < 65535) + { + if (alpha > 0) + { + blue = (blue * alpha + 32767U)/65535U; + green = (green * alpha + 32767U)/65535U; + red = (red * alpha + 32767U)/65535U; + } + + else + red = green = blue = 0; + } + entry[afirst + (2 ^ bgr)] = (png_uint_16)blue; + entry[afirst + 1] = (png_uint_16)green; + entry[afirst + bgr] = (png_uint_16)red; + break; + + case 2: + entry[1 ^ afirst] = (png_uint_16)alpha; + /* FALL THROUGH */ + + case 1: + if (alpha < 65535) + { + if (alpha > 0) + green = (green * alpha + 32767U)/65535U; + + else + green = 0; + } + entry[afirst] = (png_uint_16)green; + break; + + default: + break; + } + } + + else /* output encoding is P_sRGB */ + { + png_bytep entry = png_voidcast(png_bytep, display->colormap); + + entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); + + switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) + { + case 4: + entry[afirst ? 0 : 3] = (png_byte)alpha; + case 3: + entry[afirst + (2 ^ bgr)] = (png_byte)blue; + entry[afirst + 1] = (png_byte)green; + entry[afirst + bgr] = (png_byte)red; + break; + + case 2: + entry[1 ^ afirst] = (png_byte)alpha; + case 1: + entry[afirst] = (png_byte)green; + break; + + default: + break; + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + } +} + +static int +make_gray_file_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, P_FILE); + + return i; +} + +static int +make_gray_colormap(png_image_read_control *display) +{ + unsigned int i; + + for (i=0; i<256; ++i) + png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB); + + return i; +} +#define PNG_GRAY_COLORMAP_ENTRIES 256 + +static int +make_ga_colormap(png_image_read_control *display) +{ + unsigned int i, a; + + /* Alpha is retained, the output will be a color-map with entries + * selected by six levels of alpha. One transparent entry, 6 gray + * levels for all the intermediate alpha values, leaving 230 entries + * for the opaque grays. The color-map entries are the six values + * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the + * relevant entry. + * + * if (alpha > 229) // opaque + * { + * // The 231 entries are selected to make the math below work: + * base = 0; + * entry = (231 * gray + 128) >> 8; + * } + * else if (alpha < 26) // transparent + * { + * base = 231; + * entry = 0; + * } + * else // partially opaque + * { + * base = 226 + 6 * PNG_DIV51(alpha); + * entry = PNG_DIV51(gray); + * } + */ + i = 0; + while (i < 231) + { + unsigned int gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB); + } + + /* 255 is used here for the component values for consistency with the code + * that undoes premultiplication in pngwrite.c. + */ + png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB); + + for (a=1; a<5; ++a) + { + unsigned int g; + + for (g=0; g<6; ++g) + png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51, + P_sRGB); + } + + return i; +} + +#define PNG_GA_COLORMAP_ENTRIES 256 + +static int +make_rgb_colormap(png_image_read_control *display) +{ + unsigned int i, r; + + /* Build a 6x6x6 opaque RGB cube */ + for (i=r=0; r<6; ++r) + { + unsigned int g; + + for (g=0; g<6; ++g) + { + unsigned int b; + + for (b=0; b<6; ++b) + png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255, + P_sRGB); + } + } + + return i; +} + +#define PNG_RGB_COLORMAP_ENTRIES 216 + +/* Return a palette index to the above palette given three 8-bit sRGB values. */ +#define PNG_RGB_INDEX(r,g,b) \ + ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b))) + +static int +png_image_read_colormap(png_voidp argument) +{ + png_image_read_control *display = + png_voidcast(png_image_read_control*, argument); + const png_imagep image = display->image; + + const png_structrp png_ptr = image->opaque->png_ptr; + const png_uint_32 output_format = image->format; + const int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ? + P_LINEAR : P_sRGB; + + unsigned int cmap_entries; + unsigned int output_processing; /* Output processing option */ + unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */ + + /* Background information; the background color and the index of this color + * in the color-map if it exists (else 256). + */ + unsigned int background_index = 256; + png_uint_32 back_r, back_g, back_b; + + /* Flags to accumulate things that need to be done to the input. */ + int expand_tRNS = 0; + + /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is + * very difficult to do, the results look awful, and it is difficult to see + * what possible use it is because the application can't control the + * color-map. + */ + if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 || + png_ptr->num_trans > 0) /* alpha in input */ && + ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */) + { + if (output_encoding == P_LINEAR) /* compose on black */ + back_b = back_g = back_r = 0; + + else if (display->background == NULL /* no way to remove it */) + png_error(png_ptr, + "a background color must be supplied to remove alpha/transparency"); + + /* Get a copy of the background color (this avoids repeating the checks + * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the + * output format. + */ + else + { + back_g = display->background->green; + if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0) + { + back_r = display->background->red; + back_b = display->background->blue; + } + else + back_b = back_r = back_g; + } + } + + else if (output_encoding == P_LINEAR) + back_b = back_r = back_g = 65535; + + else + back_b = back_r = back_g = 255; + + /* Default the input file gamma if required - this is necessary because + * libpng assumes that if no gamma information is present the data is in the + * output format, but the simplified API deduces the gamma from the input + * format. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0) + { + /* Do this directly, not using the png_colorspace functions, to ensure + * that it happens even if the colorspace is invalid (though probably if + * it is the setting will be ignored) Note that the same thing can be + * achieved at the application interface with png_set_gAMA. + */ + if (png_ptr->bit_depth == 16 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR; + + else + png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE; + + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + + /* Decide what to do based on the PNG color type of the input data. The + * utility function png_create_colormap_entry deals with most aspects of the + * output transformations; this code works out how to produce bytes of + * color-map entries from the original format. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth <= 8) + { + /* There at most 256 colors in the output, regardless of + * transparency. + */ + unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0; + + cmap_entries = 1U << png_ptr->bit_depth; + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "gray[8] color-map: too few entries"); + + step = 255 / (cmap_entries - 1); + output_processing = PNG_CMAP_NONE; + + /* If there is a tRNS chunk then this either selects a transparent + * value or, if the output has no alpha, the background color. + */ + if (png_ptr->num_trans > 0) + { + trans = png_ptr->trans_color.gray; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) + back_alpha = output_encoding == P_LINEAR ? 65535 : 255; + } + + /* png_create_colormap_entry just takes an RGBA and writes the + * corresponding color-map entry using the format from 'image', + * including the required conversion to sRGB or linear as + * appropriate. The input values are always either sRGB (if the + * gamma correction flag is 0) or 0..255 scaled file encoded values + * (if the function must gamma correct them). + */ + for (i=val=0; ibit_depth < 8) + png_set_packing(png_ptr); + } + + else /* bit depth is 16 */ + { + /* The 16-bit input values can be converted directly to 8-bit gamma + * encoded values; however, if a tRNS chunk is present 257 color-map + * entries are required. This means that the extra entry requires + * special processing; add an alpha channel, sacrifice gray level + * 254 and convert transparent (alpha==0) entries to that. + * + * Use libpng to chop the data to 8 bits. Convert it to sRGB at the + * same time to minimize quality loss. If a tRNS chunk is present + * this means libpng must handle it too; otherwise it is impossible + * to do the exact match on the 16-bit value. + * + * If the output has no alpha channel *and* the background color is + * gray then it is possible to let libpng handle the substitution by + * ensuring that the corresponding gray level matches the background + * color exactly. + */ + data_encoding = P_sRGB; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray[16] color-map: too few entries"); + + cmap_entries = make_gray_colormap(display); + + if (png_ptr->num_trans > 0) + { + unsigned int back_alpha; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + back_alpha = 0; + + else + { + if (back_r == back_g && back_g == back_b) + { + /* Background is gray; no special processing will be + * required. + */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry + * matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, P_LINEAR); + } + + /* The background passed to libpng, however, must be the + * sRGB value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: does this work without expanding tRNS to alpha? + * It should be the color->gray case below apparently + * doesn't. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + break; + } +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ + back_alpha = 255; +#else + back_alpha = output_encoding == P_LINEAR ? 65535 : 255; +#endif + } + + /* output_processing means that the libpng-processed row will be + * 8-bit GA and it has to be processing to single byte color-map + * values. Entry 254 is replaced by either a completely + * transparent entry or by the background color at full + * precision (and the background color is not a simple gray + * level in this case.) + */ + expand_tRNS = 1; + output_processing = PNG_CMAP_TRANS; + background_index = 254; + + /* And set (overwrite) color-map entry 254 to the actual + * background color at full precision. + */ + png_create_colormap_entry(display, 254, back_r, back_g, back_b, + back_alpha, output_encoding); + } + + else + output_processing = PNG_CMAP_NONE; + } + break; + + case PNG_COLOR_TYPE_GRAY_ALPHA: + /* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum + * of 65536 combinations. If, however, the alpha channel is to be + * removed there are only 256 possibilities if the background is gray. + * (Otherwise there is a subset of the 65536 possibilities defined by + * the triangle between black, white and the background color.) + * + * Reduce 16-bit files to 8-bit and sRGB encode the result. No need to + * worry about tRNS matching - tRNS is ignored if there is an alpha + * channel. + */ + data_encoding = P_sRGB; + + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray+alpha color-map: too few entries"); + + cmap_entries = make_ga_colormap(display); + + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else /* alpha is removed */ + { + /* Alpha must be removed as the PNG data is processed when the + * background is a color because the G and A channels are + * independent and the vector addition (non-parallel vectors) is a + * 2-D problem. + * + * This can be reduced to the same algorithm as above by making a + * colormap containing gray levels (for the opaque grays), a + * background entry (for a transparent pixel) and a set of four six + * level color values, one set for each intermediate alpha value. + * See the comments in make_ga_colormap for how this works in the + * per-pixel processing. + * + * If the background is gray, however, we only need a 256 entry gray + * level color map. It is sufficient to make the entry generated + * for the background color be exactly the color specified. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 || + (back_r == back_g && back_g == back_b)) + { + /* Background is gray; no special processing will be required. */ + png_color_16 c; + png_uint_32 gray = back_g; + + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "gray-alpha color-map: too few entries"); + + cmap_entries = make_gray_colormap(display); + + if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 65535, P_LINEAR); + } + + /* The background passed to libpng, however, must be the sRGB + * value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_NONE; + } + + else + { + png_uint_32 i, a; + + /* This is the same as png_make_ga_colormap, above, except that + * the entries are all opaque. + */ + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "ga-alpha color-map: too few entries"); + + i = 0; + while (i < 231) + { + png_uint_32 gray = (i * 256 + 115) / 231; + png_create_colormap_entry(display, i++, gray, gray, gray, + 255, P_sRGB); + } + + /* NOTE: this preserves the full precision of the application + * background color. + */ + background_index = i; + png_create_colormap_entry(display, i++, back_r, back_g, back_b, +#ifdef __COVERITY__ + /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) + * here. + */ 255U, +#else + output_encoding == P_LINEAR ? 65535U : 255U, +#endif + output_encoding); + + /* For non-opaque input composite on the sRGB background - this + * requires inverting the encoding for each component. The input + * is still converted to the sRGB encoding because this is a + * reasonable approximate to the logarithmic curve of human + * visual sensitivity, at least over the narrow range which PNG + * represents. Consequently 'G' is always sRGB encoded, while + * 'A' is linear. We need the linear background colors. + */ + if (output_encoding == P_sRGB) /* else already linear */ + { + /* This may produce a value not exactly matching the + * background, but that's ok because these numbers are only + * used when alpha != 0 + */ + back_r = png_sRGB_table[back_r]; + back_g = png_sRGB_table[back_g]; + back_b = png_sRGB_table[back_b]; + } + + for (a=1; a<5; ++a) + { + unsigned int g; + + /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled + * by an 8-bit alpha value (0..255). + */ + png_uint_32 alpha = 51 * a; + png_uint_32 back_rx = (255-alpha) * back_r; + png_uint_32 back_gx = (255-alpha) * back_g; + png_uint_32 back_bx = (255-alpha) * back_b; + + for (g=0; g<6; ++g) + { + png_uint_32 gray = png_sRGB_table[g*51] * alpha; + + png_create_colormap_entry(display, i++, + PNG_sRGB_FROM_LINEAR(gray + back_rx), + PNG_sRGB_FROM_LINEAR(gray + back_gx), + PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB); + } + } + + cmap_entries = i; + output_processing = PNG_CMAP_GA; + } + } + break; + + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + /* Exclude the case where the output is gray; we can always handle this + * with the cases above. + */ + if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0) + { + /* The color-map will be grayscale, so we may as well convert the + * input RGB values to a simple grayscale and use the grayscale + * code above. + * + * NOTE: calling this apparently damages the recognition of the + * transparent color in background color handling; call + * png_set_tRNS_to_alpha before png_set_background_fixed. + */ + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1, + -1); + data_encoding = P_sRGB; + + /* The output will now be one or two 8-bit gray or gray+alpha + * channels. The more complex case arises when the input has alpha. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + (output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Both input and output have an alpha channel, so no background + * processing is required; just map the GA bytes to the right + * color-map entry. + */ + expand_tRNS = 1; + + if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[ga] color-map: too few entries"); + + cmap_entries = make_ga_colormap(display); + background_index = PNG_CMAP_GA_BACKGROUND; + output_processing = PNG_CMAP_GA; + } + + else + { + /* Either the input or the output has no alpha channel, so there + * will be no non-opaque pixels in the color-map; it will just be + * grayscale. + */ + if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb[gray] color-map: too few entries"); + + /* Ideally this code would use libpng to do the gamma correction, + * but if an input alpha channel is to be removed we will hit the + * libpng bug in gamma+compose+rgb-to-gray (the double gamma + * correction bug). Fix this by dropping the gamma correction in + * this case and doing it in the palette; this will result in + * duplicate palette entries, but that's better than the + * alternative of double gamma correction. + */ + if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) && + png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0) + { + cmap_entries = make_gray_file_colormap(display); + data_encoding = P_FILE; + } + + else + cmap_entries = make_gray_colormap(display); + + /* But if the input has alpha or transparency it must be removed + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + png_color_16 c; + png_uint_32 gray = back_g; + + /* We need to ensure that the application background exists in + * the colormap and that completely transparent pixels map to + * it. Achieve this simply by ensuring that the entry + * selected for the background really is the background color. + */ + if (data_encoding == P_FILE) /* from the fixup above */ + { + /* The app supplied a gray which is in output_encoding, we + * need to convert it to a value of the input (P_FILE) + * encoding then set this palette entry to the required + * output encoding. + */ + if (output_encoding == P_sRGB) + gray = png_sRGB_table[gray]; /* now P_LINEAR */ + + gray = PNG_DIV257(png_gamma_16bit_correct(gray, + png_ptr->colorspace.gamma)); /* now P_FILE */ + + /* And make sure the corresponding palette entry contains + * exactly the required sRGB value. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, output_encoding); + } + + else if (output_encoding == P_LINEAR) + { + gray = PNG_sRGB_FROM_LINEAR(gray * 255); + + /* And make sure the corresponding palette entry matches. + */ + png_create_colormap_entry(display, gray, back_g, back_g, + back_g, 0/*unused*/, P_LINEAR); + } + + /* The background passed to libpng, however, must be the + * output (normally sRGB) value. + */ + c.index = 0; /*unused*/ + c.gray = c.red = c.green = c.blue = (png_uint_16)gray; + + /* NOTE: the following is apparently a bug in libpng. Without + * it the transparent color recognition in + * png_set_background_fixed seems to go wrong. + */ + expand_tRNS = 1; + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + output_processing = PNG_CMAP_NONE; + } + } + + else /* output is color */ + { + /* We could use png_quantize here so long as there is no transparent + * color or alpha; png_quantize ignores alpha. Easier overall just + * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube. + * Consequently we always want libpng to produce sRGB data. + */ + data_encoding = P_sRGB; + + /* Is there any transparency or alpha? */ + if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->num_trans > 0) + { + /* Is there alpha in the output too? If so all four channels are + * processed into a special RGB cube with alpha support. + */ + if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_uint_32 r; + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb+alpha color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + + /* Add a transparent entry. */ + png_create_colormap_entry(display, cmap_entries, 255, 255, + 255, 0, P_sRGB); + + /* This is stored as the background index for the processing + * algorithm. + */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with alpha 0.5. */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + png_uint_32 g; + + for (g=0; g<256; g = (g << 1) | 0x7f) + { + png_uint_32 b; + + /* This generates components with the values 0, 127 and + * 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + r, g, b, 128, P_sRGB); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else + { + /* Alpha/transparency must be removed. The background must + * exist in the color map (achieved by setting adding it after + * the 666 color-map). If the standard processing code will + * pick up this entry automatically that's all that is + * required; libpng can be called to do the background + * processing. + */ + unsigned int sample_size = + PNG_IMAGE_SAMPLE_SIZE(output_format); + png_uint_32 r, g, b; /* sRGB background */ + + if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) + png_error(png_ptr, "rgb-alpha color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + + png_create_colormap_entry(display, cmap_entries, back_r, + back_g, back_b, 0/*unused*/, output_encoding); + + if (output_encoding == P_LINEAR) + { + r = PNG_sRGB_FROM_LINEAR(back_r * 255); + g = PNG_sRGB_FROM_LINEAR(back_g * 255); + b = PNG_sRGB_FROM_LINEAR(back_b * 255); + } + + else + { + r = back_r; + g = back_g; + b = back_g; + } + + /* Compare the newly-created color-map entry with the one the + * PNG_CMAP_RGB algorithm will use. If the two entries don't + * match, add the new one and set this as the background + * index. + */ + if (memcmp((png_const_bytep)display->colormap + + sample_size * cmap_entries, + (png_const_bytep)display->colormap + + sample_size * PNG_RGB_INDEX(r,g,b), + sample_size) != 0) + { + /* The background color must be added. */ + background_index = cmap_entries++; + + /* Add 27 r,g,b entries each with created by composing with + * the background at alpha 0.5. + */ + for (r=0; r<256; r = (r << 1) | 0x7f) + { + for (g=0; g<256; g = (g << 1) | 0x7f) + { + /* This generates components with the values 0, 127 + * and 255 + */ + for (b=0; b<256; b = (b << 1) | 0x7f) + png_create_colormap_entry(display, cmap_entries++, + png_colormap_compose(display, r, P_sRGB, 128, + back_r, output_encoding), + png_colormap_compose(display, g, P_sRGB, 128, + back_g, output_encoding), + png_colormap_compose(display, b, P_sRGB, 128, + back_b, output_encoding), + 0/*unused*/, output_encoding); + } + } + + expand_tRNS = 1; + output_processing = PNG_CMAP_RGB_ALPHA; + } + + else /* background color is in the standard color-map */ + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = (png_uint_16)back_r; + c.gray = c.green = (png_uint_16)back_g; + c.blue = (png_uint_16)back_b; + + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + + output_processing = PNG_CMAP_RGB; + } + } + } + + else /* no alpha or transparency in the input */ + { + /* Alpha in the output is irrelevant, simply map the opaque input + * pixels to the 6x6x6 color-map. + */ + if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries) + png_error(png_ptr, "rgb color-map: too few entries"); + + cmap_entries = make_rgb_colormap(display); + output_processing = PNG_CMAP_RGB; + } + } + break; + + case PNG_COLOR_TYPE_PALETTE: + /* It's already got a color-map. It may be necessary to eliminate the + * tRNS entries though. + */ + { + unsigned int num_trans = png_ptr->num_trans; + png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL; + png_const_colorp colormap = png_ptr->palette; + const int do_background = trans != NULL && + (output_format & PNG_FORMAT_FLAG_ALPHA) == 0; + unsigned int i; + + /* Just in case: */ + if (trans == NULL) + num_trans = 0; + + output_processing = PNG_CMAP_NONE; + data_encoding = P_FILE; /* Don't change from color-map indices */ + cmap_entries = png_ptr->num_palette; + if (cmap_entries > 256) + cmap_entries = 256; + + if (cmap_entries > image->colormap_entries) + png_error(png_ptr, "palette color-map: too few entries"); + + for (i=0; i < cmap_entries; ++i) + { + if (do_background != 0 && i < num_trans && trans[i] < 255) + { + if (trans[i] == 0) + png_create_colormap_entry(display, i, back_r, back_g, + back_b, 0, output_encoding); + + else + { + /* Must compose the PNG file color in the color-map entry + * on the sRGB color in 'back'. + */ + png_create_colormap_entry(display, i, + png_colormap_compose(display, colormap[i].red, P_FILE, + trans[i], back_r, output_encoding), + png_colormap_compose(display, colormap[i].green, P_FILE, + trans[i], back_g, output_encoding), + png_colormap_compose(display, colormap[i].blue, P_FILE, + trans[i], back_b, output_encoding), + output_encoding == P_LINEAR ? trans[i] * 257U : + trans[i], + output_encoding); + } + } + + else + png_create_colormap_entry(display, i, colormap[i].red, + colormap[i].green, colormap[i].blue, + i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/); + } + + /* The PNG data may have indices packed in fewer than 8 bits, it + * must be expanded if so. + */ + if (png_ptr->bit_depth < 8) + png_set_packing(png_ptr); + } + break; + + default: + png_error(png_ptr, "invalid PNG color type"); + /*NOT REACHED*/ + break; + } + + /* Now deal with the output processing */ + if (expand_tRNS != 0 && png_ptr->num_trans > 0 && + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) + png_set_tRNS_to_alpha(png_ptr); + + switch (data_encoding) + { + default: + png_error(png_ptr, "bad data option (internal error)"); + break; + + case P_sRGB: + /* Change to 8-bit sRGB */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); + /* FALL THROUGH */ + + case P_FILE: + if (png_ptr->bit_depth > 8) + png_set_scale_16(png_ptr); + break; + } + + if (cmap_entries > 256 || cmap_entries > image->colormap_entries) + png_error(png_ptr, "color map overflow (BAD internal error)"); + + image->colormap_entries = cmap_entries; + + /* Double check using the recorded background index */ + switch (output_processing) + { + case PNG_CMAP_NONE: + if (background_index != PNG_CMAP_NONE_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_GA: + if (background_index != PNG_CMAP_GA_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_TRANS: + if (background_index >= cmap_entries || + background_index != PNG_CMAP_TRANS_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB: + if (background_index != PNG_CMAP_RGB_BACKGROUND) + goto bad_background; + break; + + case PNG_CMAP_RGB_ALPHA: + if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND) + goto bad_background; + break; + + default: + png_error(png_ptr, "bad processing option (internal error)"); + + bad_background: + png_error(png_ptr, "bad background index (internal error)"); + } + + display->colormap_processing = output_processing; + + return 1/*ok*/; +} + +/* The final part of the color-map read called from png_image_finish_read. */ +static int +png_image_read_and_map(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + /* Called when the libpng data must be transformed into the color-mapped + * form. There is a local row buffer in display->local and this routine must + * do the interlace handling. + */ + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int proc = display->colormap_processing; + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read read the libpng data into the temporary buffer. */ + png_read_row(png_ptr, inrow, NULL); + + /* Now process the row according to the processing option, note + * that the caller verifies that the format of the libpng output + * data is as required. + */ + outrow += startx; + switch (proc) + { + case PNG_CMAP_GA: + for (; outrow < end_row; outrow += stepx) + { + /* The data is always in the PNG order */ + unsigned int gray = *inrow++; + unsigned int alpha = *inrow++; + unsigned int entry; + + /* NOTE: this code is copied as a comment in + * make_ga_colormap above. Please update the + * comment if you change this code! + */ + if (alpha > 229) /* opaque */ + { + entry = (231 * gray + 128) >> 8; + } + else if (alpha < 26) /* transparent */ + { + entry = 231; + } + else /* partially opaque */ + { + entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray); + } + + *outrow = (png_byte)entry; + } + break; + + case PNG_CMAP_TRANS: + for (; outrow < end_row; outrow += stepx) + { + png_byte gray = *inrow++; + png_byte alpha = *inrow++; + + if (alpha == 0) + *outrow = PNG_CMAP_TRANS_BACKGROUND; + + else if (gray != PNG_CMAP_TRANS_BACKGROUND) + *outrow = gray; + + else + *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1); + } + break; + + case PNG_CMAP_RGB: + for (; outrow < end_row; outrow += stepx) + { + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); + inrow += 3; + } + break; + + case PNG_CMAP_RGB_ALPHA: + for (; outrow < end_row; outrow += stepx) + { + unsigned int alpha = inrow[3]; + + /* Because the alpha entries only hold alpha==0.5 values + * split the processing at alpha==0.25 (64) and 0.75 + * (196). + */ + + if (alpha >= 196) + *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], + inrow[2]); + + else if (alpha < 64) + *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND; + + else + { + /* Likewise there are three entries for each of r, g + * and b. We could select the entry by popcount on + * the top two bits on those architectures that + * support it, this is what the code below does, + * crudely. + */ + unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1; + + /* Here are how the values map: + * + * 0x00 .. 0x3f -> 0 + * 0x40 .. 0xbf -> 1 + * 0xc0 .. 0xff -> 2 + * + * So, as above with the explicit alpha checks, the + * breakpoints are at 64 and 196. + */ + if (inrow[0] & 0x80) back_i += 9; /* red */ + if (inrow[0] & 0x40) back_i += 9; + if (inrow[0] & 0x80) back_i += 3; /* green */ + if (inrow[0] & 0x40) back_i += 3; + if (inrow[0] & 0x80) back_i += 1; /* blue */ + if (inrow[0] & 0x40) back_i += 1; + + *outrow = (png_byte)back_i; + } + + inrow += 4; + } + break; + + default: + break; + } + } + } + } + + return 1; +} + +static int +png_image_read_colormapped(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_controlp control = image->opaque; + png_structrp png_ptr = control->png_ptr; + png_inforp info_ptr = control->info_ptr; + + int passes = 0; /* As a flag */ + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + */ + if (display->colormap_processing == PNG_CMAP_NONE) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + /* The expected output can be deduced from the colormap_processing option. */ + switch (display->colormap_processing) + { + case PNG_CMAP_NONE: + /* Output must be one channel and one byte per pixel, the output + * encoding can be anything. + */ + if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY) && + info_ptr->bit_depth == 8) + break; + + goto bad_output; + + case PNG_CMAP_TRANS: + case PNG_CMAP_GA: + /* Output must be two channels and the 'G' one must be sRGB, the latter + * can be checked with an exact number because it should have been set + * to this number above! + */ + if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 256) + break; + + goto bad_output; + + case PNG_CMAP_RGB: + /* Output must be 8-bit sRGB encoded RGB */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 216) + break; + + goto bad_output; + + case PNG_CMAP_RGB_ALPHA: + /* Output must be 8-bit sRGB encoded RGBA */ + if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA && + info_ptr->bit_depth == 8 && + png_ptr->screen_gamma == PNG_GAMMA_sRGB && + image->colormap_entries == 244 /* 216 + 1 + 27 */) + break; + + /* goto bad_output; */ + /* FALL THROUGH */ + + default: + bad_output: + png_error(png_ptr, "bad color-map processing (internal error)"); + } + + /* Now read the rows. Do this here if it is possible to read directly into + * the output buffer, otherwise allocate a local row buffer of the maximum + * size libpng requires and call the relevant processing routine safely. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (passes == 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_and_map, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + while (y-- > 0) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +/* Just the row reading part of png_image_read. */ +static int +png_image_read_composite(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + int passes; + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + { + png_uint_32 height = image->height; + png_uint_32 width = image->width; + ptrdiff_t step_row = display->row_bytes; + unsigned int channels = + (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + int pass; + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * channels; + stepx = PNG_PASS_COL_OFFSET(pass) * channels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = channels; + stepy = 1; + } + + for (; ylocal_row); + png_bytep outrow; + png_const_bytep end_row; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + outrow = png_voidcast(png_bytep, display->first_row); + outrow += y * step_row; + end_row = outrow + width * channels; + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[channels]; + + if (alpha > 0) /* else no change to the output */ + { + unsigned int c; + + for (c=0; cimage; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int pass, passes; + + /* Double check the convoluted logic below. We expect to get here with + * libpng doing rgb to gray and gamma correction but background processing + * left to the png_image_read_background function. The rows libpng produce + * might be 8 or 16-bit but should always have two channels; gray plus alpha. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) + png_error(png_ptr, "lost rgb to gray"); + + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_error(png_ptr, "unexpected compose"); + + if (png_get_channels(png_ptr, info_ptr) != 2) + png_error(png_ptr, "lost/gained channels"); + + /* Expect the 8-bit case to always remove the alpha channel */ + if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 && + (image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_error(png_ptr, "unexpected 8-bit transformation"); + + switch (png_ptr->interlaced) + { + case PNG_INTERLACE_NONE: + passes = 1; + break; + + case PNG_INTERLACE_ADAM7: + passes = PNG_INTERLACE_ADAM7_PASSES; + break; + + default: + png_error(png_ptr, "unknown interlace type"); + } + + /* Use direct access to info_ptr here because otherwise the simplified API + * would require PNG_EASY_ACCESS_SUPPORTED (just for this.) Note this is + * checking the value after libpng expansions, not the original value in the + * PNG. + */ + switch (info_ptr->bit_depth) + { + default: + png_error(png_ptr, "unexpected bit depth"); + break; + + case 8: + /* 8-bit sRGB gray values with an alpha channel; the alpha channel is + * to be removed by composing on a background: either the row if + * display->background is NULL or display->background->green if not. + * Unlike the code above ALPHA_OPTIMIZED has *not* been done. + */ + { + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; + + for (pass = 0; pass < passes; ++pass) + { + png_bytep row = png_voidcast(png_bytep, + display->first_row); + unsigned int startx, stepx, stepy; + png_uint_32 y; + + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass); + stepx = PNG_PASS_COL_OFFSET(pass); + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = stepy = 1; + } + + if (display->background == NULL) + { + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else no change to the output */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + /* Since PNG_OPTIMIZED_ALPHA was not set it is + * necessary to invert the sRGB transfer + * function and multiply the alpha out. + */ + component = png_sRGB_table[component] * alpha; + component += png_sRGB_table[outrow[0]] * + (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + inrow += 2; /* gray and alpha channel */ + } + } + } + + else /* constant background value */ + { + png_byte background8 = display->background->green; + png_uint_16 background = png_sRGB_table[background8]; + + for (; ylocal_row); + png_bytep outrow = first_row + y * step_row; + png_const_bytep end_row = outrow + width; + + /* Read the row, which is packed: */ + png_read_row(png_ptr, inrow, NULL); + + /* Now do the composition on each pixel in this row. */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_byte alpha = inrow[1]; + + if (alpha > 0) /* else use background */ + { + png_uint_32 component = inrow[0]; + + if (alpha < 255) /* else just use component */ + { + component = png_sRGB_table[component] * alpha; + component += background * (255-alpha); + component = PNG_sRGB_FROM_LINEAR(component); + } + + outrow[0] = (png_byte)component; + } + + else + outrow[0] = background8; + + inrow += 2; /* gray and alpha channel */ + } + + row += display->row_bytes; + } + } + } + } + break; + + case 16: + /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must + * still be done and, maybe, the alpha channel removed. This code also + * handles the alpha-first option. + */ + { + png_uint_16p first_row = png_voidcast(png_uint_16p, + display->first_row); + /* The division by two is safe because the caller passed in a + * stride which was multiplied by 2 (below) to get row_bytes. + */ + ptrdiff_t step_row = display->row_bytes / 2; + int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; + unsigned int outchannels = 1+preserve_alpha; + int swap_alpha = 0; + +# ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED + if (preserve_alpha != 0 && + (image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + swap_alpha = 1; +# endif + + for (pass = 0; pass < passes; ++pass) + { + unsigned int startx, stepx, stepy; + png_uint_32 y; + + /* The 'x' start and step are adjusted to output components here. + */ + if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) + { + /* The row may be empty for a short image: */ + if (PNG_PASS_COLS(width, pass) == 0) + continue; + + startx = PNG_PASS_START_COL(pass) * outchannels; + stepx = PNG_PASS_COL_OFFSET(pass) * outchannels; + y = PNG_PASS_START_ROW(pass); + stepy = PNG_PASS_ROW_OFFSET(pass); + } + + else + { + y = 0; + startx = 0; + stepx = outchannels; + stepy = 1; + } + + for (; ylocal_row), NULL); + inrow = png_voidcast(png_const_uint_16p, display->local_row); + + /* Now do the pre-multiplication on each pixel in this row. + */ + outrow += startx; + for (; outrow < end_row; outrow += stepx) + { + png_uint_32 component = inrow[0]; + png_uint_16 alpha = inrow[1]; + + if (alpha > 0) /* else 0 */ + { + if (alpha < 65535) /* else just use component */ + { + component *= alpha; + component += 32767; + component /= 65535; + } + } + + else + component = 0; + + outrow[swap_alpha] = (png_uint_16)component; + if (preserve_alpha != 0) + outrow[1 ^ swap_alpha] = alpha; + + inrow += 2; /* components and alpha channel */ + } + } + } + } + break; + } + + return 1; +} + +/* The guts of png_image_finish_read as a png_safe_execute callback. */ +static int +png_image_read_direct(png_voidp argument) +{ + png_image_read_control *display = png_voidcast(png_image_read_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + + png_uint_32 format = image->format; + int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; + int do_local_compose = 0; + int do_local_background = 0; /* to avoid double gamma correction bug */ + int passes = 0; + + /* Add transforms to ensure the correct output format is produced then check + * that the required implementation support is there. Always expand; always + * need 8 bits minimum, no palette and expanded tRNS. + */ + png_set_expand(png_ptr); + + /* Now check the format to see if it was modified. */ + { + png_uint_32 base_format = png_image_format(png_ptr) & + ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */; + png_uint_32 change = format ^ base_format; + png_fixed_point output_gamma; + int mode; /* alpha mode */ + + /* Do this first so that we have a record if rgb to gray is happening. */ + if ((change & PNG_FORMAT_FLAG_COLOR) != 0) + { + /* gray<->color transformation required. */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_gray_to_rgb(png_ptr); + + else + { + /* libpng can't do both rgb to gray and + * background/pre-multiplication if there is also significant gamma + * correction, because both operations require linear colors and + * the code only supports one transform doing the gamma correction. + * Handle this by doing the pre-multiplication or background + * operation in this code, if necessary. + * + * TODO: fix this by rewriting pngrtran.c (!) + * + * For the moment (given that fixing this in pngrtran.c is an + * enormous change) 'do_local_background' is used to indicate that + * the problem exists. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + do_local_background = 1/*maybe*/; + + png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, + PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); + } + + change &= ~PNG_FORMAT_FLAG_COLOR; + } + + /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise. + */ + { + png_fixed_point input_gamma_default; + + if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + input_gamma_default = PNG_GAMMA_LINEAR; + else + input_gamma_default = PNG_DEFAULT_sRGB; + + /* Call png_set_alpha_mode to set the default for the input gamma; the + * output gamma is set by a second call below. + */ + png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default); + } + + if (linear != 0) + { + /* If there *is* an alpha channel in the input it must be multiplied + * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + mode = PNG_ALPHA_STANDARD; /* associated alpha */ + + else + mode = PNG_ALPHA_PNG; + + output_gamma = PNG_GAMMA_LINEAR; + } + + else + { + mode = PNG_ALPHA_PNG; + output_gamma = PNG_DEFAULT_sRGB; + } + + /* If 'do_local_background' is set check for the presence of gamma + * correction; this is part of the work-round for the libpng bug + * described above. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background != 0) + { + png_fixed_point gtest; + + /* This is 'png_gamma_threshold' from pngrtran.c; the test used for + * gamma correction, the screen gamma hasn't been set on png_struct + * yet; it's set below. png_struct::gamma, however, is set to the + * final value. + */ + if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma, + PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0) + do_local_background = 0; + + else if (mode == PNG_ALPHA_STANDARD) + { + do_local_background = 2/*required*/; + mode = PNG_ALPHA_PNG; /* prevent libpng doing it */ + } + + /* else leave as 1 for the checks below */ + } + + /* If the bit-depth changes then handle that here. */ + if ((change & PNG_FORMAT_FLAG_LINEAR) != 0) + { + if (linear != 0 /*16-bit output*/) + png_set_expand_16(png_ptr); + + else /* 8-bit output */ + png_set_scale_16(png_ptr); + + change &= ~PNG_FORMAT_FLAG_LINEAR; + } + + /* Now the background/alpha channel changes. */ + if ((change & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Removing an alpha channel requires composition for the 8-bit + * formats; for the 16-bit it is already done, above, by the + * pre-multiplication and the channel just needs to be stripped. + */ + if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* If RGB->gray is happening the alpha channel must be left and the + * operation completed locally. + * + * TODO: fix libpng and remove this. + */ + if (do_local_background != 0) + do_local_background = 2/*required*/; + + /* 16-bit output: just remove the channel */ + else if (linear != 0) /* compose on black (well, pre-multiply) */ + png_set_strip_alpha(png_ptr); + + /* 8-bit output: do an appropriate compose */ + else if (display->background != NULL) + { + png_color_16 c; + + c.index = 0; /*unused*/ + c.red = display->background->red; + c.green = display->background->green; + c.blue = display->background->blue; + c.gray = display->background->green; + + /* This is always an 8-bit sRGB value, using the 'green' channel + * for gray is much better than calculating the luminance here; + * we can get off-by-one errors in that calculation relative to + * the app expectations and that will show up in transparent + * pixels. + */ + png_set_background_fixed(png_ptr, &c, + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); + } + + else /* compose on row: implemented below. */ + { + do_local_compose = 1; + /* This leaves the alpha channel in the output, so it has to be + * removed by the code below. Set the encoding to the 'OPTIMIZE' + * one so the code only has to hack on the pixels that require + * composition. + */ + mode = PNG_ALPHA_OPTIMIZED; + } + } + + else /* output needs an alpha channel */ + { + /* This is tricky because it happens before the swap operation has + * been accomplished; however, the swap does *not* swap the added + * alpha channel (weird API), so it must be added in the correct + * place. + */ + png_uint_32 filler; /* opaque filler */ + int where; + + if (linear != 0) + filler = 65535; + + else + filler = 255; + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + where = PNG_FILLER_BEFORE; + change &= ~PNG_FORMAT_FLAG_AFIRST; + } + + else +# endif + where = PNG_FILLER_AFTER; + + png_set_add_alpha(png_ptr, filler, where); + } + + /* This stops the (irrelevant) call to swap_alpha below. */ + change &= ~PNG_FORMAT_FLAG_ALPHA; + } + + /* Now set the alpha mode correctly; this is always done, even if there is + * no alpha channel in either the input or the output because it correctly + * sets the output gamma. + */ + png_set_alpha_mode_fixed(png_ptr, mode, output_gamma); + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if ((change & PNG_FORMAT_FLAG_BGR) != 0) + { + /* Check only the output format; PNG is never BGR; don't do this if + * the output is gray, but fix up the 'format' value in that case. + */ + if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + + else + format &= ~PNG_FORMAT_FLAG_BGR; + + change &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((change & PNG_FORMAT_FLAG_AFIRST) != 0) + { + /* Only relevant if there is an alpha channel - it's particularly + * important to handle this correctly because do_local_compose may + * be set above and then libpng will keep the alpha channel for this + * code to remove. + */ + if ((format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + /* Disable this if doing a local background, + * TODO: remove this when local background is no longer required. + */ + if (do_local_background != 2) + png_set_swap_alpha(png_ptr); + } + + else + format &= ~PNG_FORMAT_FLAG_AFIRST; + + change &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If the *output* is 16-bit then we need to check for a byte-swap on this + * architecture. + */ + if (linear != 0) + { + PNG_CONST png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + + /* If change is not now 0 some transformation is missing - error out. */ + if (change != 0) + png_error(png_ptr, "png_read_image: unsupported transformation"); + } + + PNG_SKIP_CHUNKS(png_ptr); + + /* Update the 'info' structure and make sure the result is as required; first + * make sure to turn on the interlace handling if it will be required + * (because it can't be turned on *after* the call to png_read_update_info!) + * + * TODO: remove the do_local_background fixup below. + */ + if (do_local_compose == 0 && do_local_background != 2) + passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + { + png_uint_32 info_format = 0; + + if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + info_format |= PNG_FORMAT_FLAG_COLOR; + + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + { + /* do_local_compose removes this channel below. */ + if (do_local_compose == 0) + { + /* do_local_background does the same if required. */ + if (do_local_background != 2 || + (format & PNG_FORMAT_FLAG_ALPHA) != 0) + info_format |= PNG_FORMAT_FLAG_ALPHA; + } + } + + else if (do_local_compose != 0) /* internal error */ + png_error(png_ptr, "png_image_read: alpha channel lost"); + + if (info_ptr->bit_depth == 16) + info_format |= PNG_FORMAT_FLAG_LINEAR; + +# ifdef PNG_FORMAT_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + info_format |= PNG_FORMAT_FLAG_BGR; +# endif + +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (do_local_background == 2) + { + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + info_format |= PNG_FORMAT_FLAG_AFIRST; + } + + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 || + ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 && + (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0)) + { + if (do_local_background == 2) + png_error(png_ptr, "unexpected alpha swap transformation"); + + info_format |= PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* This is actually an internal error. */ + if (info_format != format) + png_error(png_ptr, "png_read_image: invalid transformations"); + } + + /* Now read the rows. If do_local_compose is set then it is necessary to use + * a local row buffer. The output will be GA, RGBA or BGRA and must be + * converted to G, RGB or BGR as appropriate. The 'local_row' member of the + * display acts as a flag. + */ + { + png_voidp first_row = display->buffer; + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= 2; + + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. + */ + if (row_bytes < 0) + { + char *ptr = png_voidcast(char*, first_row); + ptr += (image->height-1) * (-row_bytes); + first_row = png_voidcast(png_voidp, ptr); + } + + display->first_row = first_row; + display->row_bytes = row_bytes; + } + + if (do_local_compose != 0) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_composite, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else if (do_local_background == 2) + { + int result; + png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); + + display->local_row = row; + result = png_safe_execute(image, png_image_read_background, display); + display->local_row = NULL; + png_free(png_ptr, row); + + return result; + } + + else + { + png_alloc_size_t row_bytes = display->row_bytes; + + while (--passes >= 0) + { + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); + + while (y-- > 0) + { + png_read_row(png_ptr, row, NULL); + row += row_bytes; + } + } + + return 1; + } +} + +int PNGAPI +png_image_finish_read(png_imagep image, png_const_colorp background, + void *buffer, png_int_32 row_stride, void *colormap) +{ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + png_uint_32 check; + + if (row_stride == 0) + row_stride = PNG_IMAGE_ROW_STRIDE(*image); + + if (row_stride < 0) + check = -row_stride; + + else + check = row_stride; + + if (image->opaque != NULL && buffer != NULL && + check >= PNG_IMAGE_ROW_STRIDE(*image)) + { + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || + (image->colormap_entries > 0 && colormap != NULL)) + { + int result; + png_image_read_control display; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.background = background; + display.local_row = NULL; + + /* Choose the correct 'end' routine; for the color-map case all the + * setup has already been done. + */ + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) + result = + png_safe_execute(image, png_image_read_colormap, &display) && + png_safe_execute(image, png_image_read_colormapped, &display); + + else + result = + png_safe_execute(image, png_image_read_direct, &display); + + png_image_free(image); + return result; + } + + else + return png_image_error(image, + "png_image_finish_read[color-map]: no color-map"); + } + + else + return png_image_error(image, + "png_image_finish_read: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_finish_read: damaged PNG_IMAGE_VERSION"); + + return 0; +} + +#endif /* SIMPLIFIED_READ */ +#endif /* READ */ diff --git a/src/3rdparty/libpng/pngrio.c b/src/3rdparty/libpng/pngrio.c index e9c381c5ba..bb5c825109 100644 --- a/src/3rdparty/libpng/pngrio.c +++ b/src/3rdparty/libpng/pngrio.c @@ -1,8 +1,8 @@ /* pngrio.c - functions for data input * - * Last changed in libpng 1.5.0 [January 6, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -26,10 +26,10 @@ * reads from a file pointer. Note that this routine sometimes gets called * with very small lengths, so you should implement some kind of simple * buffering if you are using unbuffered reads. This should never be asked - * to read more then 64K on a 16 bit machine. + * to read more than 64K on a 16 bit machine. */ void /* PRIVATE */ -png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) +png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length) { png_debug1(4, "reading %d bytes", (int)length); @@ -46,7 +46,6 @@ png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) * read_data function and use it at run time with png_set_read_fn(), rather * than changing the library. */ -# ifndef USE_FAR_KEYWORD void PNGCBAPI png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { @@ -58,68 +57,11 @@ png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) /* fread() returns 0 on error, so it is OK to store this in a png_size_t * instead of an int, which is what fread() actually returns. */ - check = fread(data, 1, length, (png_FILE_p)png_ptr->io_ptr); + check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr)); if (check != length) png_error(png_ptr, "Read Error"); } -# else -/* This is the model-independent version. Since the standard I/O library - can't handle far buffers in the medium and small models, we have to copy - the data. -*/ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -static void PNGCBAPI -png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_size_t check; - png_byte *n_data; - png_FILE_p io_ptr; - - if (png_ptr == NULL) - return; - - /* Check if data really is near. If so, use usual code. */ - n_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - - if ((png_bytep)n_data == data) - { - check = fread(n_data, 1, length, io_ptr); - } - - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t read, remaining, err; - check = 0; - remaining = length; - - do - { - read = MIN(NEAR_BUF_SIZE, remaining); - err = fread(buf, 1, read, io_ptr); - png_memcpy(data, buf, read); /* copy far buffer to near buffer */ - - if (err != read) - break; - - else - check += err; - - data += read; - remaining -= read; - } - while (remaining != 0); - } - - if ((png_uint_32)check != (png_uint_32)length) - png_error(png_ptr, "read Error"); -} -# endif #endif /* This function allows the application to supply a new input function @@ -142,7 +84,7 @@ png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) * be used. */ void PNGAPI -png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, +png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn) { if (png_ptr == NULL) @@ -160,6 +102,7 @@ png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, png_ptr->read_data_fn = read_data_fn; #endif +#ifdef PNG_WRITE_SUPPORTED /* It is an error to write to a read device */ if (png_ptr->write_data_fn != NULL) { @@ -168,9 +111,10 @@ png_set_read_fn(png_structp png_ptr, png_voidp io_ptr, "Can't set both read_data_fn and write_data_fn in the" " same structure"); } +#endif #ifdef PNG_WRITE_FLUSH_SUPPORTED png_ptr->output_flush_fn = NULL; #endif } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ diff --git a/src/3rdparty/libpng/pngrtran.c b/src/3rdparty/libpng/pngrtran.c index 5561852860..cad7a8daa5 100644 --- a/src/3rdparty/libpng/pngrtran.c +++ b/src/3rdparty/libpng/pngrtran.c @@ -1,8 +1,8 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * Last changed in libpng 1.5.10 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -22,7 +22,7 @@ /* Set the action on getting a CRC error for an ancillary or critical chunk. */ void PNGAPI -png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) +png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) { png_debug(1, "in png_set_crc_action"); @@ -88,16 +88,47 @@ png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) } } +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Is it OK to set a transformation now? Only if png_start_read_image or + * png_read_update_info have not been called. It is not necessary for the IHDR + * to have been read in all cases; the need_IHDR parameter allows for this + * check too. + */ +static int +png_rtran_ok(png_structrp png_ptr, int need_IHDR) +{ + if (png_ptr != NULL) + { + if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + png_app_error(png_ptr, + "invalid after png_start_read_image or png_read_update_info"); + + else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_app_error(png_ptr, "invalid before the PNG header has been read"); + + else + { + /* Turn on failure to initialize correctly for all transforms. */ + png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; + + return 1; /* Ok */ + } + } + + return 0; /* no png_error possible! */ +} +#endif + #ifdef PNG_READ_BACKGROUND_SUPPORTED /* Handle alpha and tRNS via a background color */ void PNGFAPI -png_set_background_fixed(png_structp png_ptr, +png_set_background_fixed(png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, png_fixed_point background_gamma) { png_debug(1, "in png_set_background_fixed"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL) return; if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) @@ -110,11 +141,10 @@ png_set_background_fixed(png_structp png_ptr, png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - png_memcpy(&(png_ptr->background), background_color, - png_sizeof(png_color_16)); + png_ptr->background = *background_color; png_ptr->background_gamma = background_gamma; png_ptr->background_gamma_type = (png_byte)(background_gamma_code); - if (need_expand) + if (need_expand != 0) png_ptr->transformations |= PNG_BACKGROUND_EXPAND; else png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; @@ -122,7 +152,7 @@ png_set_background_fixed(png_structp png_ptr, # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_background(png_structp png_ptr, +png_set_background(png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma) { @@ -138,11 +168,11 @@ png_set_background(png_structp png_ptr, */ #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED void PNGAPI -png_set_scale_16(png_structp png_ptr) +png_set_scale_16(png_structrp png_ptr) { png_debug(1, "in png_set_scale_16"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_SCALE_16_TO_8; @@ -152,11 +182,11 @@ png_set_scale_16(png_structp png_ptr) #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* Chop 16-bit depth files to 8-bit depth */ void PNGAPI -png_set_strip_16(png_structp png_ptr) +png_set_strip_16(png_structrp png_ptr) { png_debug(1, "in png_set_strip_16"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_16_TO_8; @@ -165,11 +195,11 @@ png_set_strip_16(png_structp png_ptr) #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED void PNGAPI -png_set_strip_alpha(png_structp png_ptr) +png_set_strip_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_strip_alpha"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_STRIP_ALPHA; @@ -178,7 +208,7 @@ png_set_strip_alpha(png_structp png_ptr) #if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) static png_fixed_point -translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma, +translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma, int is_screen) { /* Check for flag values. The main reason for having the old Mac value as a @@ -194,8 +224,10 @@ translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma, */ # ifdef PNG_READ_sRGB_SUPPORTED png_ptr->flags |= PNG_FLAG_ASSUME_sRGB; +# else + PNG_UNUSED(png_ptr) # endif - if (is_screen) + if (is_screen != 0) output_gamma = PNG_GAMMA_sRGB; else output_gamma = PNG_GAMMA_sRGB_INVERSE; @@ -204,7 +236,7 @@ translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma, else if (output_gamma == PNG_GAMMA_MAC_18 || output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) { - if (is_screen) + if (is_screen != 0) output_gamma = PNG_GAMMA_MAC_OLD; else output_gamma = PNG_GAMMA_MAC_INVERSE; @@ -215,7 +247,7 @@ translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma, # ifdef PNG_FLOATING_POINT_SUPPORTED static png_fixed_point -convert_gamma_value(png_structp png_ptr, double output_gamma) +convert_gamma_value(png_structrp png_ptr, double output_gamma) { /* The following silently ignores cases where fixed point (times 100,000) * gamma values are passed to the floating point API. This is safe and it @@ -240,7 +272,7 @@ convert_gamma_value(png_structp png_ptr, double output_gamma) #ifdef PNG_READ_ALPHA_MODE_SUPPORTED void PNGFAPI -png_set_alpha_mode_fixed(png_structp png_ptr, int mode, +png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, png_fixed_point output_gamma) { int compose = 0; @@ -248,7 +280,7 @@ png_set_alpha_mode_fixed(png_structp png_ptr, int mode, png_debug(1, "in png_set_alpha_mode"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); @@ -320,8 +352,11 @@ png_set_alpha_mode_fixed(png_structp png_ptr, int mode, * the side effect that the gamma in a second call to png_set_alpha_mode will * be ignored.) */ - if (png_ptr->gamma == 0) - png_ptr->gamma = file_gamma; + if (png_ptr->colorspace.gamma == 0) + { + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } /* But always set the output gamma: */ png_ptr->screen_gamma = output_gamma; @@ -329,28 +364,25 @@ png_set_alpha_mode_fixed(png_structp png_ptr, int mode, /* Finally, if pre-multiplying, set the background fields to achieve the * desired result. */ - if (compose) + if (compose != 0) { /* And obtain alpha pre-multiplication by composing on black: */ - png_memset(&png_ptr->background, 0, sizeof png_ptr->background); - png_ptr->background_gamma = png_ptr->gamma; /* just in case */ + memset(&png_ptr->background, 0, (sizeof png_ptr->background)); + png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */ png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; - if (png_ptr->transformations & PNG_COMPOSE) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) png_error(png_ptr, "conflicting calls to set alpha mode and background"); png_ptr->transformations |= PNG_COMPOSE; } - - /* New API, make sure apps call the correct initializers: */ - png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_alpha_mode(png_structp png_ptr, int mode, double output_gamma) +png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) { png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, output_gamma)); @@ -362,7 +394,7 @@ png_set_alpha_mode(png_structp png_ptr, int mode, double output_gamma) /* Dither file to 8-bit. Supply a palette, the current number * of elements in the palette, the maximum number of elements * allowed, and a histogram if possible. If the current number - * of colors is greater then the maximum number, the palette will be + * of colors is greater than the maximum number, the palette will be * modified to fit in the maximum number. "full_quantize" indicates * whether we need a quantizing cube set up for RGB images, or if we * simply are reducing the number of colors in a paletted image. @@ -370,31 +402,31 @@ png_set_alpha_mode(png_structp png_ptr, int mode, double output_gamma) typedef struct png_dsort_struct { - struct png_dsort_struct FAR * next; + struct png_dsort_struct * next; png_byte left; png_byte right; } png_dsort; -typedef png_dsort FAR * png_dsortp; -typedef png_dsort FAR * FAR * png_dsortpp; +typedef png_dsort * png_dsortp; +typedef png_dsort * * png_dsortpp; void PNGAPI -png_set_quantize(png_structp png_ptr, png_colorp palette, +png_set_quantize(png_structrp png_ptr, png_colorp palette, int num_palette, int maximum_colors, png_const_uint_16p histogram, int full_quantize) { png_debug(1, "in png_set_quantize"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_QUANTIZE; - if (!full_quantize) + if (full_quantize == 0) { int i; png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); + (png_uint_32)(num_palette * (sizeof (png_byte)))); for (i = 0; i < num_palette; i++) png_ptr->quantize_index[i] = (png_byte)i; } @@ -411,7 +443,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, /* Initialize an array to sort colors */ png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); + (png_uint_32)(num_palette * (sizeof (png_byte)))); /* Initialize the quantize_sort array */ for (i = 0; i < num_palette; i++) @@ -444,12 +476,12 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, } } - if (done) + if (done != 0) break; } /* Swap the palette around, and set up a table, if necessary */ - if (full_quantize) + if (full_quantize != 0) { int j = num_palette; @@ -545,9 +577,9 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, /* Initialize palette index arrays */ png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); + (png_uint_32)(num_palette * (sizeof (png_byte)))); png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(num_palette * png_sizeof(png_byte))); + (png_uint_32)(num_palette * (sizeof (png_byte)))); /* Initialize the sort array */ for (i = 0; i < num_palette; i++) @@ -557,7 +589,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, } hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * - png_sizeof(png_dsortp))); + (sizeof (png_dsortp)))); num_new_palette = num_palette; @@ -587,7 +619,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, { t = (png_dsortp)png_malloc_warn(png_ptr, - (png_uint_32)(png_sizeof(png_dsort))); + (png_uint_32)(sizeof (png_dsort))); if (t == NULL) break; @@ -632,7 +664,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, num_new_palette--; palette[png_ptr->index_to_palette[j]] = palette[num_new_palette]; - if (!full_quantize) + if (full_quantize == 0) { int k; @@ -700,7 +732,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, } png_ptr->num_palette = (png_uint_16)num_palette; - if (full_quantize) + if (full_quantize != 0) { int i; png_bytep distance; @@ -712,12 +744,12 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, png_size_t num_entries = ((png_size_t)1 << total_bits); png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr, - (png_uint_32)(num_entries * png_sizeof(png_byte))); + (png_uint_32)(num_entries * (sizeof (png_byte)))); distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * - png_sizeof(png_byte))); + (sizeof (png_byte)))); - png_memset(distance, 0xff, num_entries * png_sizeof(png_byte)); + memset(distance, 0xff, num_entries * (sizeof (png_byte))); for (i = 0; i < num_palette; i++) { @@ -762,23 +794,22 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, png_free(png_ptr, distance); } } -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ +#endif /* READ_QUANTIZE */ #ifdef PNG_READ_GAMMA_SUPPORTED void PNGFAPI -png_set_gamma_fixed(png_structp png_ptr, png_fixed_point scrn_gamma, +png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, png_fixed_point file_gamma) { png_debug(1, "in png_set_gamma_fixed"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; /* New in libpng-1.5.4 - reserve particular negative values as flags. */ scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); -#if PNG_LIBPNG_VER >= 10600 /* Checking the gamma values for being >0 was added in 1.5.4 along with the * premultiplied alpha support; this actually hides an undocumented feature * of the previous implementation which allowed gamma processing to be @@ -787,31 +818,32 @@ png_set_gamma_fixed(png_structp png_ptr, png_fixed_point scrn_gamma, * accept '0' for the gamma value it takes, because it isn't always used. * * Since this is an API change (albeit a very minor one that removes an - * undocumented API feature) it will not be made until libpng-1.6.0. + * undocumented API feature) the following checks were only enabled in + * libpng-1.6.0. */ if (file_gamma <= 0) png_error(png_ptr, "invalid file gamma in png_set_gamma"); if (scrn_gamma <= 0) png_error(png_ptr, "invalid screen gamma in png_set_gamma"); -#endif /* Set the gamma values unconditionally - this overrides the value in the PNG * file if a gAMA chunk was present. png_set_alpha_mode provides a * different, easier, way to default the file gamma. */ - png_ptr->gamma = file_gamma; + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; png_ptr->screen_gamma = scrn_gamma; } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) +png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) { png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), convert_gamma_value(png_ptr, file_gamma)); } -# endif /* FLOATING_POINT_SUPPORTED */ +# endif /* FLOATING_POINT */ #endif /* READ_GAMMA */ #ifdef PNG_READ_EXPAND_SUPPORTED @@ -820,15 +852,14 @@ png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) * to alpha channels. */ void PNGAPI -png_set_expand(png_structp png_ptr) +png_set_expand(png_structrp png_ptr) { png_debug(1, "in png_set_expand"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } /* GRR 19990627: the following three functions currently are identical @@ -851,90 +882,85 @@ png_set_expand(png_structp png_ptr) /* Expand paletted images to RGB. */ void PNGAPI -png_set_palette_to_rgb(png_structp png_ptr) +png_set_palette_to_rgb(png_structrp png_ptr) { png_debug(1, "in png_set_palette_to_rgb"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } /* Expand grayscale images of less than 8-bit depth to 8 bits. */ void PNGAPI -png_set_expand_gray_1_2_4_to_8(png_structp png_ptr) +png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) { png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_EXPAND; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } - - /* Expand tRNS chunks to alpha channels. */ void PNGAPI -png_set_tRNS_to_alpha(png_structp png_ptr) +png_set_tRNS_to_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_tRNS_to_alpha"); + if (png_rtran_ok(png_ptr, 0) == 0) + return; + png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; } -#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ +#endif /* READ_EXPAND */ #ifdef PNG_READ_EXPAND_16_SUPPORTED /* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise * it may not work correctly.) */ void PNGAPI -png_set_expand_16(png_structp png_ptr) +png_set_expand_16(png_structrp png_ptr) { png_debug(1, "in png_set_expand_16"); - if (png_ptr == NULL) + if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; - - /* New API, make sure apps call the correct initializers: */ - png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; } #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED void PNGAPI -png_set_gray_to_rgb(png_structp png_ptr) +png_set_gray_to_rgb(png_structrp png_ptr) { png_debug(1, "in png_set_gray_to_rgb"); - if (png_ptr != NULL) - { - /* Because rgb must be 8 bits or more: */ - png_set_expand_gray_1_2_4_to_8(png_ptr); - png_ptr->transformations |= PNG_GRAY_TO_RGB; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; - } + if (png_rtran_ok(png_ptr, 0) == 0) + return; + + /* Because rgb must be 8 bits or more: */ + png_set_expand_gray_1_2_4_to_8(png_ptr); + png_ptr->transformations |= PNG_GRAY_TO_RGB; } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED void PNGFAPI -png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, +png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, png_fixed_point red, png_fixed_point green) { png_debug(1, "in png_set_rgb_to_gray"); - if (png_ptr == NULL) + /* Need the IHDR here because of the check on color_type below. */ + /* TODO: fix this */ + if (png_rtran_ok(png_ptr, 1) == 0) return; - switch(error_action) + switch (error_action) { case PNG_ERROR_ACTION_NONE: png_ptr->transformations |= PNG_RGB_TO_GRAY; @@ -952,15 +978,19 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, png_error(png_ptr, "invalid error action to rgb_to_gray"); break; } + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) #ifdef PNG_READ_EXPAND_SUPPORTED png_ptr->transformations |= PNG_EXPAND; #else { - png_warning(png_ptr, + /* Make this an error in 1.6 because otherwise the application may assume + * that it just worked and get a memory overwrite. + */ + png_error(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); - png_ptr->transformations &= ~PNG_RGB_TO_GRAY; + /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */ } #endif { @@ -969,7 +999,7 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, png_uint_16 red_int, green_int; /* NOTE: this calculation does not round, but this behavior is retained - * for consistency, the inaccuracy is very small. The code here always + * for consistency; the inaccuracy is very small. The code here always * overwrites the coefficients, regardless of whether they have been * defaulted or set already. */ @@ -984,7 +1014,7 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, else { if (red >= 0 && green >= 0) - png_warning(png_ptr, + png_app_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); /* Use the defaults, from the cHRM chunk if set, else the historical @@ -1010,31 +1040,25 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, */ void PNGAPI -png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red, +png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, double green) { - if (png_ptr == NULL) - return; - png_set_rgb_to_gray_fixed(png_ptr, error_action, png_fixed(png_ptr, red, "rgb to gray red coefficient"), png_fixed(png_ptr, green, "rgb to gray green coefficient")); } #endif /* FLOATING POINT */ -#endif +#endif /* RGB_TO_GRAY */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) void PNGAPI -png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr +png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr read_user_transform_fn) { png_debug(1, "in png_set_read_user_transform_fn"); - if (png_ptr == NULL) - return; - #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED png_ptr->transformations |= PNG_USER_TRANSFORM; png_ptr->read_user_transform_fn = read_user_transform_fn; @@ -1068,13 +1092,13 @@ png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) * the palette. */ -/*For the moment 'png_init_palette_transformations' and +/* For the moment 'png_init_palette_transformations' and * 'png_init_rgb_transformations' only do some flag canceling optimizations. * The intent is that these two routines should have palette or rgb operations * extracted from 'png_init_read_transformations'. */ static void /* PRIVATE */ -png_init_palette_transformations(png_structp png_ptr) +png_init_palette_transformations(png_structrp png_ptr) { /* Called to handle the (input) palette case. In png_do_read_transformations * the first step is to expand the palette if requested, so this code must @@ -1093,25 +1117,31 @@ png_init_palette_transformations(png_structp png_ptr) /* Ignore if all the entries are opaque (unlikely!) */ for (i=0; inum_trans; ++i) + { if (png_ptr->trans_alpha[i] == 255) continue; else if (png_ptr->trans_alpha[i] == 0) input_has_transparency = 1; else + { + input_has_transparency = 1; input_has_alpha = 1; + break; + } + } } /* If no alpha we can optimize. */ - if (!input_has_alpha) + if (input_has_alpha == 0) { /* Any alpha means background and associative alpha processing is - * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA + * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA * and ENCODE_ALPHA are irrelevant. */ png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - if (!input_has_transparency) + if (input_has_transparency == 0) png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); } @@ -1124,8 +1154,8 @@ png_init_palette_transformations(png_structp png_ptr) /* The following code cannot be entered in the alpha pre-multiplication case * because PNG_BACKGROUND_EXPAND is cancelled below. */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_EXPAND)) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) { { png_ptr->background.red = @@ -1136,9 +1166,9 @@ png_init_palette_transformations(png_structp png_ptr) png_ptr->palette[png_ptr->background.index].blue; #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) { - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) { /* Invert the alpha channel (in tRNS) unless the pixels are * going to be expanded, in which case leave it for later @@ -1150,14 +1180,14 @@ png_init_palette_transformations(png_structp png_ptr) png_ptr->trans_alpha[i]); } } -#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */ +#endif /* READ_INVERT_ALPHA */ } } /* background expand and (therefore) no alpha association. */ -#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ +#endif /* READ_EXPAND && READ_BACKGROUND */ } static void /* PRIVATE */ -png_init_rgb_transformations(png_structp png_ptr) +png_init_rgb_transformations(png_structrp png_ptr) { /* Added to libpng-1.5.4: check the color type to determine whether there * is any alpha or transparency in the image and simply cancel the @@ -1167,10 +1197,10 @@ png_init_rgb_transformations(png_structp png_ptr) int input_has_transparency = png_ptr->num_trans > 0; /* If no alpha we can optimize. */ - if (!input_has_alpha) + if (input_has_alpha == 0) { /* Any alpha means background and associative alpha processing is - * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA + * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA * and ENCODE_ALPHA are irrelevant. */ # ifdef PNG_READ_ALPHA_MODE_SUPPORTED @@ -1178,7 +1208,7 @@ png_init_rgb_transformations(png_structp png_ptr) png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; # endif - if (!input_has_transparency) + if (input_has_transparency == 0) png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); } @@ -1191,9 +1221,9 @@ png_init_rgb_transformations(png_structp png_ptr) /* The following code cannot be entered in the alpha pre-multiplication case * because PNG_BACKGROUND_EXPAND is cancelled below. */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_EXPAND) && - !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0 && + (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* i.e., GRAY or GRAY_ALPHA */ { { @@ -1221,7 +1251,7 @@ png_init_rgb_transformations(png_structp png_ptr) default: case 8: - /* Already 8 bits, fall through */ + /* FALL THROUGH (Already 8 bits) */ case 16: /* Already a full 16 bits */ @@ -1231,18 +1261,18 @@ png_init_rgb_transformations(png_structp png_ptr) png_ptr->background.red = png_ptr->background.green = png_ptr->background.blue = (png_uint_16)gray; - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) { png_ptr->trans_color.red = png_ptr->trans_color.green = png_ptr->trans_color.blue = (png_uint_16)trans_gray; } } } /* background expand and (therefore) no alpha association. */ -#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ +#endif /* READ_EXPAND && READ_BACKGROUND */ } void /* PRIVATE */ -png_init_read_transformations(png_structp png_ptr) +png_init_read_transformations(png_structrp png_ptr) { png_debug(1, "in png_init_read_transformations"); @@ -1267,17 +1297,17 @@ png_init_read_transformations(png_structp png_ptr) */ int gamma_correction = 0; - if (png_ptr->gamma != 0) /* has been set */ + if (png_ptr->colorspace.gamma != 0) /* has been set */ { if (png_ptr->screen_gamma != 0) /* screen set too */ - gamma_correction = png_gamma_threshold(png_ptr->gamma, + gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma, png_ptr->screen_gamma); else /* Assume the output matches the input; a long time default behavior * of libpng, although the standard has nothing to say about this. */ - png_ptr->screen_gamma = png_reciprocal(png_ptr->gamma); + png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma); } else if (png_ptr->screen_gamma != 0) @@ -1286,7 +1316,7 @@ png_init_read_transformations(png_structp png_ptr) * png_set_alpha_mode (even if the alpha handling mode isn't required * or isn't changed from the default.) */ - png_ptr->gamma = png_reciprocal(png_ptr->screen_gamma); + png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma); else /* neither are set */ /* Just in case the following prevents any processing - file and screen @@ -1294,7 +1324,10 @@ png_init_read_transformations(png_structp png_ptr) * third gamma value other than png_set_background with 'UNIQUE', and, * prior to 1.5.4 */ - png_ptr->screen_gamma = png_ptr->gamma = PNG_FP_1; + png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1; + + /* We have a gamma value now. */ + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; /* Now turn the gamma transformation on or off as appropriate. Notice * that PNG_GAMMA just refers to the file->screen correction. Alpha @@ -1304,7 +1337,7 @@ png_init_read_transformations(png_structp png_ptr) * the code immediately below if the transform can be handled outside the * row loop. */ - if (gamma_correction) + if (gamma_correction != 0) png_ptr->transformations |= PNG_GAMMA; else @@ -1313,7 +1346,7 @@ png_init_read_transformations(png_structp png_ptr) #endif /* Certain transformations have the effect of preventing other - * transformations that happen afterward in png_do_read_transformations, + * transformations that happen afterward in png_do_read_transformations; * resolve the interdependencies here. From the code of * png_do_read_transformations the order is: * @@ -1331,19 +1364,19 @@ png_init_read_transformations(png_structp png_ptr) * 12) PNG_EXPAND_16 * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY * 14) PNG_INVERT_MONO - * 15) PNG_SHIFT - * 16) PNG_PACK - * 17) PNG_BGR - * 18) PNG_PACKSWAP - * 19) PNG_FILLER (includes PNG_ADD_ALPHA) - * 20) PNG_INVERT_ALPHA + * 15) PNG_INVERT_ALPHA + * 16) PNG_SHIFT + * 17) PNG_PACK + * 18) PNG_BGR + * 19) PNG_PACKSWAP + * 20) PNG_FILLER (includes PNG_ADD_ALPHA) * 21) PNG_SWAP_ALPHA * 22) PNG_SWAP_BYTES * 23) PNG_USER_TRANSFORM [must be last] */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) && - !(png_ptr->transformations & PNG_COMPOSE)) + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0) { /* Stripping the alpha channel happens immediately after the 'expand' * transformations, before all other transformation, so it cancels out @@ -1369,16 +1402,23 @@ png_init_read_transformations(png_structp png_ptr) /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA * settings will have no effect. */ - if (!png_gamma_significant(png_ptr->screen_gamma)) + if (png_gamma_significant(png_ptr->screen_gamma) == 0) { png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; } #endif -#if defined(PNG_READ_EXPAND_SUPPORTED) && \ - defined(PNG_READ_BACKGROUND_SUPPORTED) && \ - defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Make sure the coefficients for the rgb to gray conversion are set + * appropriately. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + png_colorspace_set_rgb_coefficients(png_ptr); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) /* Detect gray background and attempt to enable optimization for * gray --> RGB case. * @@ -1394,23 +1434,23 @@ png_init_read_transformations(png_structp png_ptr) * png_set_background, along with the bit depth, then the code has a record * of exactly what color space the background is currently in. */ - if (png_ptr->transformations & PNG_BACKGROUND_EXPAND) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0) { /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if * the file was grayscale the background value is gray. */ - if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; } - else if (png_ptr->transformations & PNG_COMPOSE) + else if ((png_ptr->transformations & PNG_COMPOSE) != 0) { /* PNG_COMPOSE: png_set_background was called with need_expand false, * so the color is in the color space of the output or png_set_alpha_mode * was called and the color is black. Ignore RGB_TO_GRAY because that * happens before GRAY_TO_RGB. */ - if (png_ptr->transformations & PNG_GRAY_TO_RGB) + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) { if (png_ptr->background.red == png_ptr->background.green && png_ptr->background.red == png_ptr->background.blue) @@ -1420,7 +1460,8 @@ png_init_read_transformations(png_structp png_ptr) } } } -#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED (etc) */ +#endif /* READ_EXPAND && READ_BACKGROUND */ +#endif /* READ_GRAY_TO_RGB */ /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations * can be performed directly on the palette, and some (such as rgb to gray) @@ -1441,10 +1482,10 @@ png_init_read_transformations(png_structp png_ptr) #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ defined(PNG_READ_EXPAND_16_SUPPORTED) - if ((png_ptr->transformations & PNG_EXPAND_16) && - (png_ptr->transformations & PNG_COMPOSE) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - png_ptr->bit_depth != 16) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth != 16) { /* TODO: fix this. Because the expand_16 operation is after the compose * handling the background color must be 8, not 16, bits deep, but the @@ -1456,22 +1497,22 @@ png_init_read_transformations(png_structp png_ptr) * NOTE: this discards the low 16 bits of the user supplied background * color, but until expand_16 works properly there is no choice! */ -# define CHOP(x) (x)=((png_uint_16)(((png_uint_32)(x)*255+32895) >> 16)) +# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x)) CHOP(png_ptr->background.red); CHOP(png_ptr->background.green); CHOP(png_ptr->background.blue); CHOP(png_ptr->background.gray); # undef CHOP } -#endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */ +#endif /* READ_BACKGROUND && READ_EXPAND_16 */ #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) - if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) && - (png_ptr->transformations & PNG_COMPOSE) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - png_ptr->bit_depth == 16) + if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth == 16) { /* On the other hand, if a 16-bit file is to be reduced to 8-bits per * component this will also happen after PNG_COMPOSE and so the background @@ -1514,25 +1555,24 @@ png_init_read_transformations(png_structp png_ptr) * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the * tables. */ - if ((png_ptr->transformations & PNG_GAMMA) - || ((png_ptr->transformations & PNG_RGB_TO_GRAY) - && (png_gamma_significant(png_ptr->gamma) || - png_gamma_significant(png_ptr->screen_gamma))) - || ((png_ptr->transformations & PNG_COMPOSE) - && (png_gamma_significant(png_ptr->gamma) - || png_gamma_significant(png_ptr->screen_gamma) + if ((png_ptr->transformations & PNG_GAMMA) != 0 || + ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 && + (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0)) || + ((png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0 # ifdef PNG_READ_BACKGROUND_SUPPORTED - || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE - && png_gamma_significant(png_ptr->background_gamma)) + || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE && + png_gamma_significant(png_ptr->background_gamma) != 0) # endif - )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) - && png_gamma_significant(png_ptr->screen_gamma)) - ) + )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + png_gamma_significant(png_ptr->screen_gamma) != 0)) { png_build_gamma_table(png_ptr, png_ptr->bit_depth); #ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_COMPOSE) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) { /* Issue a warning about this combination: because RGB_TO_GRAY is * optimized to do the gamma transform if present yet do_background has @@ -1540,11 +1580,11 @@ png_init_read_transformations(png_structp png_ptr) * double-gamma-correction happens. This is true in all versions of * libpng to date. */ - if (png_ptr->transformations & PNG_RGB_TO_GRAY) + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) png_warning(png_ptr, "libpng does not support gamma+background+rgb_to_gray"); - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0) { /* We don't get to here unless there is a tRNS chunk with non-opaque * entries - see the checking code at the start of this function. @@ -1576,8 +1616,8 @@ png_init_read_transformations(png_structp png_ptr) break; case PNG_BACKGROUND_GAMMA_FILE: - g = png_reciprocal(png_ptr->gamma); - gs = png_reciprocal2(png_ptr->gamma, + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma); break; @@ -1592,7 +1632,7 @@ png_init_read_transformations(png_structp png_ptr) break; } - if (png_gamma_significant(gs)) + if (png_gamma_significant(gs) != 0) { back.red = png_gamma_8bit_correct(png_ptr->background.red, gs); @@ -1609,7 +1649,7 @@ png_init_read_transformations(png_structp png_ptr) back.blue = (png_byte)png_ptr->background.blue; } - if (png_gamma_significant(g)) + if (png_gamma_significant(g) != 0) { back_1.red = png_gamma_8bit_correct(png_ptr->background.red, g); @@ -1685,8 +1725,9 @@ png_init_read_transformations(png_structp png_ptr) break; case PNG_BACKGROUND_GAMMA_FILE: - g = png_reciprocal(png_ptr->gamma); - gs = png_reciprocal2(png_ptr->gamma, png_ptr->screen_gamma); + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); break; case PNG_BACKGROUND_GAMMA_UNIQUE: @@ -1702,11 +1743,11 @@ png_init_read_transformations(png_structp png_ptr) g_sig = png_gamma_significant(g); gs_sig = png_gamma_significant(gs); - if (g_sig) + if (g_sig != 0) png_ptr->background_1.gray = png_gamma_correct(png_ptr, png_ptr->background.gray, g); - if (gs_sig) + if (gs_sig != 0) png_ptr->background.gray = png_gamma_correct(png_ptr, png_ptr->background.gray, gs); @@ -1715,7 +1756,7 @@ png_init_read_transformations(png_structp png_ptr) (png_ptr->background.red != png_ptr->background.gray)) { /* RGB or RGBA with color background */ - if (g_sig) + if (g_sig != 0) { png_ptr->background_1.red = png_gamma_correct(png_ptr, png_ptr->background.red, g); @@ -1727,7 +1768,7 @@ png_init_read_transformations(png_structp png_ptr) png_ptr->background.blue, g); } - if (gs_sig) + if (gs_sig != 0) { png_ptr->background.red = png_gamma_correct(png_ptr, png_ptr->background.red, gs); @@ -1757,7 +1798,7 @@ png_init_read_transformations(png_structp png_ptr) else /* Transformation does not include PNG_BACKGROUND */ -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ +#endif /* READ_BACKGROUND */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ @@ -1770,8 +1811,8 @@ png_init_read_transformations(png_structp png_ptr) int num_palette = png_ptr->num_palette; int i; - /*NOTE: there are other transformations that should probably be in here - * too. + /* NOTE: there are other transformations that should probably be in + * here too. */ for (i = 0; i < num_palette; i++) { @@ -1787,11 +1828,11 @@ png_init_read_transformations(png_structp png_ptr) #ifdef PNG_READ_BACKGROUND_SUPPORTED else #endif -#endif /* PNG_READ_GAMMA_SUPPORTED */ +#endif /* READ_GAMMA */ #ifdef PNG_READ_BACKGROUND_SUPPORTED /* No GAMMA transformation (see the hanging else 4 lines above) */ - if ((png_ptr->transformations & PNG_COMPOSE) && + if ((png_ptr->transformations & PNG_COMPOSE) != 0 && (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; @@ -1826,11 +1867,11 @@ png_init_read_transformations(png_structp png_ptr) png_ptr->transformations &= ~PNG_COMPOSE; } -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ +#endif /* READ_BACKGROUND */ #ifdef PNG_READ_SHIFT_SUPPORTED - if ((png_ptr->transformations & PNG_SHIFT) && - !(png_ptr->transformations & PNG_EXPAND) && + if ((png_ptr->transformations & PNG_SHIFT) != 0 && + (png_ptr->transformations & PNG_EXPAND) == 0 && (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; @@ -1843,33 +1884,36 @@ png_init_read_transformations(png_structp png_ptr) * the number of significant bits is 0 then no shift is done (this is an * error condition which is silently ignored.) */ - if (shift > 0 && shift < 8) for (i=0; ipalette[i].red; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].red; - component >>= shift; - png_ptr->palette[i].red = (png_byte)component; - } + component >>= shift; + png_ptr->palette[i].red = (png_byte)component; + } shift = 8 - png_ptr->sig_bit.green; - if (shift > 0 && shift < 8) for (i=0; ipalette[i].green; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].green; - component >>= shift; - png_ptr->palette[i].green = (png_byte)component; - } + component >>= shift; + png_ptr->palette[i].green = (png_byte)component; + } shift = 8 - png_ptr->sig_bit.blue; - if (shift > 0 && shift < 8) for (i=0; ipalette[i].blue; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].blue; - component >>= shift; - png_ptr->palette[i].blue = (png_byte)component; - } + component >>= shift; + png_ptr->palette[i].blue = (png_byte)component; + } } -#endif /* PNG_READ_SHIFT_SUPPORTED */ +#endif /* READ_SHIFT */ } /* Modify the info structure to reflect the transformations. The @@ -1877,12 +1921,12 @@ png_init_read_transformations(png_structp png_ptr) * assuming the transformations result in valid PNG data. */ void /* PRIVATE */ -png_read_transform_info(png_structp png_ptr, png_infop info_ptr) +png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_read_transform_info"); #ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) + if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { @@ -1898,12 +1942,15 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) info_ptr->bit_depth = 8; info_ptr->num_trans = 0; + + if (png_ptr->palette == NULL) + png_error (png_ptr, "Palette is NULL in indexed image"); } else { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) { - if (png_ptr->transformations & PNG_EXPAND_tRNS) + if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0) info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } if (info_ptr->bit_depth < 8) @@ -1919,7 +1966,7 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) /* The following is almost certainly wrong unless the background value is in * the screen space! */ - if (png_ptr->transformations & PNG_COMPOSE) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) info_ptr->background = png_ptr->background; #endif @@ -1928,20 +1975,24 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) * however it seems that the code in png_init_read_transformations, which has * been called before this from png_read_update_info->png_read_start_row * sometimes does the gamma transform and cancels the flag. + * + * TODO: this looks wrong; the info_ptr should end up with a gamma equal to + * the screen_gamma value. The following probably results in weirdness if + * the info_ptr is used by the app after the rows have been read. */ - info_ptr->gamma = png_ptr->gamma; + info_ptr->colorspace.gamma = png_ptr->colorspace.gamma; #endif if (info_ptr->bit_depth == 16) { # ifdef PNG_READ_16BIT_SUPPORTED # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_SCALE_16_TO_8) + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) info_ptr->bit_depth = 8; # endif # ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_16_TO_8) + if ((png_ptr->transformations & PNG_16_TO_8) != 0) info_ptr->bit_depth = 8; # endif @@ -1967,27 +2018,27 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) CONFIGURATION ERROR: you must enable at least one 16 to 8 method # endif # endif -#endif /* !READ_16BIT_SUPPORTED */ +#endif /* !READ_16BIT */ } #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) info_ptr->color_type = (png_byte)(info_ptr->color_type | PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) info_ptr->color_type = (png_byte)(info_ptr->color_type & ~PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED - if (png_ptr->transformations & PNG_QUANTIZE) + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) { if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && - png_ptr->palette_lookup && info_ptr->bit_depth == 8) + png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8) { info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; } @@ -1995,29 +2046,31 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 && - info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { info_ptr->bit_depth = 16; } #endif #ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + if ((png_ptr->transformations & PNG_PACK) != 0 && + (info_ptr->bit_depth < 8)) info_ptr->bit_depth = 8; #endif if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_ptr->channels = 3; else info_ptr->channels = 1; #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_STRIP_ALPHA) + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0) { info_ptr->color_type = (png_byte)(info_ptr->color_type & ~PNG_COLOR_MASK_ALPHA); @@ -2025,25 +2078,25 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) } #endif - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) info_ptr->channels++; #ifdef PNG_READ_FILLER_SUPPORTED /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ - if ((png_ptr->transformations & PNG_FILLER) && - ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || - (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) + if ((png_ptr->transformations & PNG_FILLER) != 0 && + (info_ptr->color_type == PNG_COLOR_TYPE_RGB || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY)) { info_ptr->channels++; /* If adding a true alpha channel not just filler */ - if (png_ptr->transformations & PNG_ADD_ALPHA) + if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0) info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } #endif #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) { if (info_ptr->bit_depth < png_ptr->user_transform_depth) info_ptr->bit_depth = png_ptr->user_transform_depth; @@ -2067,441 +2120,146 @@ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) png_ptr->info_rowbytes = info_ptr->rowbytes; #ifndef PNG_READ_EXPAND_SUPPORTED - if (png_ptr) + if (png_ptr != NULL) return; #endif } -/* Transform the row. The order of transformations is significant, - * and is very touchy. If you add a transformation, take care to - * decide how it fits in with the other transformations here. +#ifdef PNG_READ_PACK_SUPPORTED +/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, + * without changing the actual values. Thus, if you had a row with + * a bit depth of 1, you would end up with bytes that only contained + * the numbers 0 or 1. If you would rather they contain 0 and 255, use + * png_do_shift() after this. */ -void /* PRIVATE */ -png_do_read_transformations(png_structp png_ptr, png_row_infop row_info) +static void +png_do_unpack(png_row_infop row_info, png_bytep row) { - png_debug(1, "in png_do_read_transformations"); - - if (png_ptr->row_buf == NULL) - { - /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this - * error is incredibly rare and incredibly easy to debug without this - * information. - */ - png_error(png_ptr, "NULL row buffer"); - } + png_debug(1, "in png_do_unpack"); - /* The following is debugging; prior to 1.5.4 the code was never compiled in; - * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro - * PNG_WARN_UNINITIALIZED_ROW removed. In 1.5 the new flag is set only for - * selected new APIs to ensure that there is no API change. - */ - if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && - !(png_ptr->flags & PNG_FLAG_ROW_INIT)) + if (row_info->bit_depth < 8) { - /* Application has failed to call either png_read_start_image() or - * png_read_update_info() after setting transforms that expand pixels. - * This check added to libpng-1.2.19 (but not enabled until 1.5.4). - */ - png_error(png_ptr, "Uninitialized row"); - } + png_uint_32 i; + png_uint_32 row_width=row_info->width; -#ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) - { - if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + switch (row_info->bit_depth) { - png_do_expand_palette(row_info, png_ptr->row_buf + 1, - png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); - } + case 1: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x01); - else - { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) - png_do_expand(row_info, png_ptr->row_buf + 1, - &(png_ptr->trans_color)); + if (shift == 7) + { + shift = 0; + sp--; + } - else - png_do_expand(row_info, png_ptr->row_buf + 1, - NULL); + else + shift++; + + dp--; + } + break; + } + + case 2: + { + + png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x03); + + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + *dp = (png_byte)((*sp >> shift) & 0x0f); + + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift = 4; + + dp--; + } + break; + } + + default: + break; } + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_width * row_info->channels; } +} #endif -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) && - !(png_ptr->transformations & PNG_COMPOSE) && - (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - 0 /* at_start == false, because SWAP_ALPHA happens later */); -#endif +#ifdef PNG_READ_SHIFT_SUPPORTED +/* Reverse the effects of png_do_shift. This routine merely shifts the + * pixels back to their significant bits values. Thus, if you have + * a row of bit depth 8, but only 5 are significant, this will shift + * the values back to 0 through 31. + */ +static void +png_do_unshift(png_row_infop row_info, png_bytep row, + png_const_color_8p sig_bits) +{ + int color_type; -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) + png_debug(1, "in png_do_unshift"); + + /* The palette case has already been handled in the _init routine. */ + color_type = row_info->color_type; + + if (color_type != PNG_COLOR_TYPE_PALETTE) { - int rgb_error = - png_do_rgb_to_gray(png_ptr, row_info, - png_ptr->row_buf + 1); + int shift[4]; + int channels = 0; + int bit_depth = row_info->bit_depth; - if (rgb_error) + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { - png_ptr->rgb_to_gray_status=1; - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_WARN) - png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + shift[channels++] = bit_depth - sig_bits->red; + shift[channels++] = bit_depth - sig_bits->green; + shift[channels++] = bit_depth - sig_bits->blue; + } - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_ERR) - png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + else + { + shift[channels++] = bit_depth - sig_bits->gray; } - } -#endif -/* From Andreas Dilger e-mail to png-implement, 26 March 1998: - * - * In most cases, the "simple transparency" should be done prior to doing - * gray-to-RGB, or you will have to test 3x as many bytes to check if a - * pixel is transparent. You would also need to make sure that the - * transparency information is upgraded to RGB. - * - * To summarize, the current flow is: - * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite - * with background "in place" if transparent, - * convert to RGB if necessary - * - Gray + alpha -> composite with gray background and remove alpha bytes, - * convert to RGB if necessary - * - * To support RGB backgrounds for gray images we need: - * - Gray + simple transparency -> convert to RGB + simple transparency, - * compare 3 or 6 bytes and composite with - * background "in place" if transparent - * (3x compare/pixel compared to doing - * composite with gray bkgrnd) - * - Gray + alpha -> convert to RGB + alpha, composite with background and - * remove alpha bytes (3x float - * operations/pixel compared with composite - * on gray background) - * - * Greg's change will do this. The reason it wasn't done before is for - * performance, as this increases the per-pixel operations. If we would check - * in advance if the background was gray or RGB, and position the gray-to-RGB - * transform appropriately, then it would save a lot of work/time. - */ - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* If gray -> RGB, do so now only if background is non-gray; else do later - * for performance reasons - */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); -#endif - -#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\ - (defined PNG_READ_ALPHA_MODE_SUPPORTED) - if (png_ptr->transformations & PNG_COMPOSE) - png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - if ((png_ptr->transformations & PNG_GAMMA) && -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* Because RGB_TO_GRAY does the gamma transform. */ - !(png_ptr->transformations & PNG_RGB_TO_GRAY) && -#endif -#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\ - (defined PNG_READ_ALPHA_MODE_SUPPORTED) - /* Because PNG_COMPOSE does the gamma transform if there is something to - * do (if there is an alpha channel or transparency.) - */ - !((png_ptr->transformations & PNG_COMPOSE) && - ((png_ptr->num_trans != 0) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && -#endif - /* Because png_init_read_transformations transforms the palette, unless - * RGB_TO_GRAY will do the transform. - */ - (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) - png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) && - (png_ptr->transformations & PNG_COMPOSE) && - (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - 0 /* at_start == false, because SWAP_ALPHA happens later */); -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - if ((png_ptr->transformations & PNG_ENCODE_ALPHA) && - (row_info->color_type & PNG_COLOR_MASK_ALPHA)) - png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_SCALE_16_TO_8) - png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - /* There is no harm in doing both of these because only one has any effect, - * by putting the 'scale' option first if the app asks for scale (either by - * calling the API or in a TRANSFORM flag) this is what happens. - */ - if (png_ptr->transformations & PNG_16_TO_8) - png_do_chop(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - if (png_ptr->transformations & PNG_QUANTIZE) - { - png_do_quantize(row_info, png_ptr->row_buf + 1, - png_ptr->palette_lookup, png_ptr->quantize_index); - - if (row_info->rowbytes == 0) - png_error(png_ptr, "png_do_quantize returned rowbytes=0"); - } -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_16_SUPPORTED - /* Do the expansion now, after all the arithmetic has been done. Notice - * that previous transformations can handle the PNG_EXPAND_16 flag if this - * is efficient (particularly true in the case of gamma correction, where - * better accuracy results faster!) - */ - if (png_ptr->transformations & PNG_EXPAND_16) - png_do_expand_16(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /*NOTE: moved here in 1.5.4 (from much later in this list.) */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED - if (png_ptr->transformations & PNG_SHIFT) - png_do_unshift(row_info, png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#ifdef PNG_READ_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_unpack(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Added at libpng-1.5.10 */ - if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) - png_do_check_palette_indexes(png_ptr, row_info); -#endif - -#ifdef PNG_READ_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & PNG_FILLER) - png_do_read_filler(row_info, png_ptr->row_buf + 1, - (png_uint_32)png_ptr->filler, png_ptr->flags); -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_16BIT_SUPPORTED -#ifdef PNG_READ_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(row_info, png_ptr->row_buf + 1); -#endif -#endif - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - if (png_ptr->read_user_transform_fn != NULL) - (*(png_ptr->read_user_transform_fn)) /* User read transform function */ - (png_ptr, /* png_ptr */ - row_info, /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_size_t rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED - if (png_ptr->user_transform_depth) - row_info->bit_depth = png_ptr->user_transform_depth; - - if (png_ptr->user_transform_channels) - row_info->channels = png_ptr->user_transform_channels; -#endif - row_info->pixel_depth = (png_byte)(row_info->bit_depth * - row_info->channels); - - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); - } -#endif -} - -#ifdef PNG_READ_PACK_SUPPORTED -/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, - * without changing the actual values. Thus, if you had a row with - * a bit depth of 1, you would end up with bytes that only contained - * the numbers 0 or 1. If you would rather they contain 0 and 255, use - * png_do_shift() after this. - */ -void /* PRIVATE */ -png_do_unpack(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_unpack"); - - if (row_info->bit_depth < 8) - { - png_uint_32 i; - png_uint_32 row_width=row_info->width; - - switch (row_info->bit_depth) - { - case 1: - { - png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x01); - - if (shift == 7) - { - shift = 0; - sp--; - } - - else - shift++; - - dp--; - } - break; - } - - case 2: - { - - png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x03); - - if (shift == 6) - { - shift = 0; - sp--; - } - - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); - png_bytep dp = row + (png_size_t)row_width - 1; - png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); - for (i = 0; i < row_width; i++) - { - *dp = (png_byte)((*sp >> shift) & 0x0f); - - if (shift == 4) - { - shift = 0; - sp--; - } - - else - shift = 4; - - dp--; - } - break; - } - - default: - break; - } - row_info->bit_depth = 8; - row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_width * row_info->channels; - } -} -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED -/* Reverse the effects of png_do_shift. This routine merely shifts the - * pixels back to their significant bits values. Thus, if you have - * a row of bit depth 8, but only 5 are significant, this will shift - * the values back to 0 through 31. - */ -void /* PRIVATE */ -png_do_unshift(png_row_infop row_info, png_bytep row, - png_const_color_8p sig_bits) -{ - int color_type; - - png_debug(1, "in png_do_unshift"); - - /* The palette case has already been handled in the _init routine. */ - color_type = row_info->color_type; - - if (color_type != PNG_COLOR_TYPE_PALETTE) - { - int shift[4]; - int channels = 0; - int bit_depth = row_info->bit_depth; - - if (color_type & PNG_COLOR_MASK_COLOR) - { - shift[channels++] = bit_depth - sig_bits->red; - shift[channels++] = bit_depth - sig_bits->green; - shift[channels++] = bit_depth - sig_bits->blue; - } - - else - { - shift[channels++] = bit_depth - sig_bits->gray; - } - - if (color_type & PNG_COLOR_MASK_ALPHA) + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) { shift[channels++] = bit_depth - sig_bits->alpha; } @@ -2521,7 +2279,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, have_shift = 1; } - if (!have_shift) + if (have_shift == 0) return; } @@ -2599,7 +2357,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, if (++channel >= channels) channel = 0; *bp++ = (png_byte)(value >> 8); - *bp++ = (png_byte)(value & 0xff); + *bp++ = (png_byte)value; } break; } @@ -2611,7 +2369,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale rows of bit depth 16 down to 8 accurately */ -void /* PRIVATE */ +static void png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_scale_16_to_8"); @@ -2669,7 +2427,7 @@ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -void /* PRIVATE */ +static void /* Simply discard the low byte. This was the default behavior prior * to libpng-1.5.4. */ @@ -2697,7 +2455,7 @@ png_do_chop(png_row_infop row_info, png_bytep row) #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_read_swap_alpha"); @@ -2794,7 +2552,7 @@ png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) { png_uint_32 row_width; @@ -2896,7 +2654,7 @@ png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) #ifdef PNG_READ_FILLER_SUPPORTED /* Add filler channel if we have RGB color */ -void /* PRIVATE */ +static void png_do_read_filler(png_row_infop row_info, png_bytep row, png_uint_32 filler, png_uint_32 flags) { @@ -2904,9 +2662,9 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, png_uint_32 row_width = row_info->width; #ifdef PNG_READ_16BIT_SUPPORTED - png_byte hi_filler = (png_byte)((filler>>8) & 0xff); + png_byte hi_filler = (png_byte)(filler>>8); #endif - png_byte lo_filler = (png_byte)(filler & 0xff); + png_byte lo_filler = (png_byte)filler; png_debug(1, "in png_do_read_filler"); @@ -2915,7 +2673,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, { if (row_info->bit_depth == 8) { - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from G to GX */ png_bytep sp = row + (png_size_t)row_width; @@ -2950,20 +2708,20 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, #ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from GG to GGXX */ png_bytep sp = row + (png_size_t)row_width * 2; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); } - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; row_info->channels = 2; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; @@ -2978,8 +2736,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, { *(--dp) = *(--sp); *(--dp) = *(--sp); - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; } row_info->channels = 2; row_info->pixel_depth = 32; @@ -2992,7 +2750,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, { if (row_info->bit_depth == 8) { - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from RGB to RGBX */ png_bytep sp = row + (png_size_t)row_width * 3; @@ -3031,15 +2789,15 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, #ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from RRGGBB to RRGGBBXX */ png_bytep sp = row + (png_size_t)row_width * 6; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); @@ -3047,8 +2805,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = *(--sp); *(--dp) = *(--sp); } - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; row_info->channels = 4; row_info->pixel_depth = 64; row_info->rowbytes = row_width * 8; @@ -3067,8 +2825,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); - *(--dp) = hi_filler; *(--dp) = lo_filler; + *(--dp) = hi_filler; } row_info->channels = 4; @@ -3083,7 +2841,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale files to RGB, with or without alpha */ -void /* PRIVATE */ +static void png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) { png_uint_32 i; @@ -3092,7 +2850,7 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) png_debug(1, "in png_do_gray_to_rgb"); if (row_info->bit_depth >= 8 && - !(row_info->color_type & PNG_COLOR_MASK_COLOR)) + (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0) { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { @@ -3222,16 +2980,16 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) * calculated to make the sum 32768. This will result in different rounding * to that used above. */ -int /* PRIVATE */ -png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) +static int +png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) { int rgb_error = 0; png_debug(1, "in png_do_rgb_to_gray"); - if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) && - (row_info->color_type & PNG_COLOR_MASK_COLOR)) + if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 && + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; @@ -3242,7 +3000,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) if (row_info->bit_depth == 8) { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) +#ifdef PNG_READ_GAMMA_SUPPORTED /* Notice that gamma to/from 1 are not necessarily inverses (if * there is an overall gamma correction). Prior to 1.5.5 this code * checked the linearized values for equality; this doesn't match @@ -3282,7 +3040,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) *(dp++) = red; } - if (have_alpha) + if (have_alpha != 0) *(dp++) = *(sp++); } } @@ -3302,7 +3060,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) if (red != green || red != blue) { rgb_error |= 1; - /*NOTE: this is the historical approach which simply + /* NOTE: this is the historical approach which simply * truncates the results. */ *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); @@ -3311,7 +3069,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) else *(dp++) = red; - if (have_alpha) + if (have_alpha != 0) *(dp++) = *(sp++); } } @@ -3319,7 +3077,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) else /* RGB bit_depth == 16 */ { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) +#ifdef PNG_READ_GAMMA_SUPPORTED if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) { png_bytep sp = row; @@ -3329,16 +3087,17 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, w; + png_byte hi,lo; - red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); if (red == green && red == blue) { if (png_ptr->gamma_16_table != NULL) - w = png_ptr->gamma_16_table[(red&0xff) - >> png_ptr->gamma_shift][red>>8]; + w = png_ptr->gamma_16_table[(red & 0xff) + >> png_ptr->gamma_shift][red >> 8]; else w = red; @@ -3346,16 +3105,16 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) else { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red & 0xff) >> png_ptr->gamma_shift][red>>8]; png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_16_to_1[(green & 0xff) >> png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue & 0xff) >> png_ptr->gamma_shift][blue>>8]; png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + bc*blue_1 + 16384)>>15); - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >> png_ptr->gamma_shift][gray16 >> 8]; rgb_error |= 1; } @@ -3363,7 +3122,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) *(dp++) = (png_byte)((w>>8) & 0xff); *(dp++) = (png_byte)(w & 0xff); - if (have_alpha) + if (have_alpha != 0) { *(dp++) = *(sp++); *(dp++) = *(sp++); @@ -3380,10 +3139,11 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, gray16; + png_byte hi,lo; - red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); + hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); if (red != green || red != blue) rgb_error |= 1; @@ -3394,10 +3154,10 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) */ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> 15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); + *(dp++) = (png_byte)((gray16 >> 8) & 0xff); *(dp++) = (png_byte)(gray16 & 0xff); - if (have_alpha) + if (have_alpha != 0) { *(dp++) = *(sp++); *(dp++) = *(sp++); @@ -3416,74 +3176,15 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) return rgb_error; } #endif -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ -#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED -/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth - * large of png_color. This lets grayscale images be treated as - * paletted. Most useful for gamma correction and simplification - * of code. This API is not used internally. - */ -void PNGAPI -png_build_grayscale_palette(int bit_depth, png_colorp palette) -{ - int num_palette; - int color_inc; - int i; - int v; - - png_debug(1, "in png_do_build_grayscale_palette"); - - if (palette == NULL) - return; - - switch (bit_depth) - { - case 1: - num_palette = 2; - color_inc = 0xff; - break; - - case 2: - num_palette = 4; - color_inc = 0x55; - break; - - case 4: - num_palette = 16; - color_inc = 0x11; - break; - - case 8: - num_palette = 256; - color_inc = 1; - break; - - default: - num_palette = 0; - color_inc = 0; - break; - } - - for (i = 0, v = 0; i < num_palette; i++, v += color_inc) - { - palette[i].red = (png_byte)v; - palette[i].green = (png_byte)v; - palette[i].blue = (png_byte)v; - } -} -#endif - - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\ - (defined PNG_READ_ALPHA_MODE_SUPPORTED) +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* Replace any alpha or transparency with the supplied background color. * "background" is already in the screen gamma, while "background_1" is * at a gamma of 1.0. Paletted files have already been taken care of. */ -void /* PRIVATE */ -png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) +static void +png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { #ifdef PNG_READ_GAMMA_SUPPORTED png_const_bytep gamma_table = png_ptr->gamma_table; @@ -3493,12 +3194,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; int gamma_shift = png_ptr->gamma_shift; + int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; #endif png_bytep sp; png_uint_32 i; png_uint_32 row_width = row_info->width; - int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; int shift; png_debug(1, "in png_do_compose"); @@ -3519,11 +3220,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) if ((png_uint_16)((*sp >> shift) & 0x01) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 7; sp++; @@ -3547,20 +3249,22 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) if ((png_uint_16)((*sp >> shift) & 0x03) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } else { - png_byte p = (png_byte)((*sp >> shift) & 0x03); - png_byte g = (png_byte)((gamma_table [p | (p << 2) | - (p << 4) | (p << 6)] >> 6) & 0x03); - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(g << shift); + unsigned int p = (*sp >> shift) & 0x03; + unsigned int g = (gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03; + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 6; sp++; @@ -3581,11 +3285,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) if ((png_uint_16)((*sp >> shift) & 0x03) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 6; sp++; @@ -3610,20 +3315,22 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) if ((png_uint_16)((*sp >> shift) & 0x0f) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } else { - png_byte p = (png_byte)((*sp >> shift) & 0x0f); - png_byte g = (png_byte)((gamma_table[p | - (p << 4)] >> 4) & 0x0f); - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(g << shift); + unsigned int p = (*sp >> shift) & 0x0f; + unsigned int g = (gamma_table[p | (p << 4)] >> 4) & + 0x0f; + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 4; sp++; @@ -3644,11 +3351,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) if ((png_uint_16)((*sp >> shift) & 0x0f) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 4; sp++; @@ -3704,8 +3412,10 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) if (v == png_ptr->trans_color.gray) { /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); } else @@ -3728,8 +3438,10 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) if (v == png_ptr->trans_color.gray) { - *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); } } } @@ -3809,9 +3521,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } @@ -3852,9 +3567,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) { *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } } @@ -3891,7 +3609,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) v = gamma_to_1[*sp]; png_composite(w, v, a, png_ptr->background_1.gray); - if (!optimize) + if (optimize == 0) w = gamma_from_1[w]; *sp = w; } @@ -3909,7 +3627,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) *sp = (png_byte)png_ptr->background.gray; else if (a < 0xff) - png_composite(*sp, *sp, a, png_ptr->background_1.gray); + png_composite(*sp, *sp, a, png_ptr->background.gray); } } } @@ -3937,7 +3655,8 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) else if (a == 0) { /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } @@ -3947,10 +3666,11 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; png_composite_16(v, g, a, png_ptr->background_1.gray); - if (optimize) + if (optimize != 0) w = v; else - w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + w = gamma_16_from_1[(v & 0xff) >> + gamma_shift][v >> 8]; *sp = (png_byte)((w >> 8) & 0xff); *(sp + 1) = (png_byte)(w & 0xff); } @@ -3967,7 +3687,8 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) if (a == 0) { - *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } @@ -3976,7 +3697,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) png_uint_16 g, v; g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_composite_16(v, g, a, png_ptr->background_1.gray); + png_composite_16(v, g, a, png_ptr->background.gray); *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); } @@ -4020,17 +3741,17 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) v = gamma_to_1[*sp]; png_composite(w, v, a, png_ptr->background_1.red); - if (!optimize) w = gamma_from_1[w]; + if (optimize == 0) w = gamma_from_1[w]; *sp = w; v = gamma_to_1[*(sp + 1)]; png_composite(w, v, a, png_ptr->background_1.green); - if (!optimize) w = gamma_from_1[w]; + if (optimize == 0) w = gamma_from_1[w]; *(sp + 1) = w; v = gamma_to_1[*(sp + 2)]; png_composite(w, v, a, png_ptr->background_1.blue); - if (!optimize) w = gamma_from_1[w]; + if (optimize == 0) w = gamma_from_1[w]; *(sp + 2) = w; } } @@ -4097,9 +3818,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } @@ -4109,23 +3833,26 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; png_composite_16(w, v, a, png_ptr->background_1.red); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; *sp = (png_byte)((w >> 8) & 0xff); *(sp + 1) = (png_byte)(w & 0xff); v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; png_composite_16(w, v, a, png_ptr->background_1.green); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; *(sp + 2) = (png_byte)((w >> 8) & 0xff); *(sp + 3) = (png_byte)(w & 0xff); v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; png_composite_16(w, v, a, png_ptr->background_1.blue); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + if (optimize == 0) + w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> + 8]; *(sp + 4) = (png_byte)((w >> 8) & 0xff); *(sp + 5) = (png_byte)(w & 0xff); @@ -4146,9 +3873,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) { *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } @@ -4185,7 +3915,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) } } } -#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_READ_ALPHA_MODE_SUPPORTED */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ #ifdef PNG_READ_GAMMA_SUPPORTED /* Gamma correct the image, avoiding the alpha channel. Make sure @@ -4194,8 +3924,8 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) * is 16, use gamma_16_table and gamma_shift. Build these with * build_gamma_table(). */ -void /* PRIVATE */ -png_do_gamma(png_row_infop row_info, png_bytep row, png_structp png_ptr) +static void +png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { png_const_bytep gamma_table = png_ptr->gamma_table; png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; @@ -4395,14 +4125,14 @@ png_do_gamma(png_row_infop row_info, png_bytep row, png_structp png_ptr) * linear.) Called only with color types that have an alpha channel. Needs the * from_1 tables. */ -void /* PRIVATE */ -png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structp png_ptr) +static void +png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { png_uint_32 row_width = row_info->width; png_debug(1, "in png_do_encode_alpha"); - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) { if (row_info->bit_depth == 8) { @@ -4461,7 +4191,7 @@ png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structp png_ptr) /* Expands a palette row to an RGB or RGBA row depending * upon whether you supply trans and num_trans. */ -void /* PRIVATE */ +static void png_do_expand_palette(png_row_infop row_info, png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) { @@ -4614,7 +4344,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, /* If the bit depth < 8, it is expanded to 8. Also, if the already * expanded transparency value is supplied, an alpha channel is built. */ -void /* PRIVATE */ +static void png_do_expand(png_row_infop row_info, png_bytep row, png_const_color_16p trans_color) { @@ -4628,7 +4358,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { - png_uint_16 gray = (png_uint_16)(trans_color ? trans_color->gray : 0); + unsigned int gray = trans_color != NULL ? trans_color->gray : 0; if (row_info->bit_depth < 8) { @@ -4636,7 +4366,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, { case 1: { - gray = (png_uint_16)((gray & 0x01) * 0xff); + gray = (gray & 0x01) * 0xff; sp = row + (png_size_t)((row_width - 1) >> 3); dp = row + (png_size_t)row_width - 1; shift = 7 - (int)((row_width + 7) & 0x07); @@ -4664,7 +4394,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, case 2: { - gray = (png_uint_16)((gray & 0x03) * 0x55); + gray = (gray & 0x03) * 0x55; sp = row + (png_size_t)((row_width - 1) >> 2); dp = row + (png_size_t)row_width - 1; shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); @@ -4689,7 +4419,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, case 4: { - gray = (png_uint_16)((gray & 0x0f) * 0x11); + gray = (gray & 0x0f) * 0x11; sp = row + (png_size_t)((row_width - 1) >> 1); dp = row + (png_size_t)row_width - 1; shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); @@ -4742,8 +4472,8 @@ png_do_expand(png_row_infop row_info, png_bytep row, else if (row_info->bit_depth == 16) { - png_byte gray_high = (png_byte)((gray >> 8) & 0xff); - png_byte gray_low = (png_byte)(gray & 0xff); + unsigned int gray_high = (gray >> 8) & 0xff; + unsigned int gray_low = gray & 0xff; sp = row + row_info->rowbytes - 1; dp = row + (row_info->rowbytes << 1) - 1; for (i = 0; i < row_width; i++) @@ -4772,7 +4502,8 @@ png_do_expand(png_row_infop row_info, png_bytep row, row_width); } } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color) + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && + trans_color != NULL) { if (row_info->bit_depth == 8) { @@ -4844,7 +4575,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, /* If the bit depth is 8 and the color type is not a palette type expand the * whole row to 16 bits. Has no effect otherwise. */ -void /* PRIVATE */ +static void png_do_expand_16(png_row_infop row_info, png_bytep row) { if (row_info->bit_depth == 8 && @@ -4872,7 +4603,7 @@ png_do_expand_16(png_row_infop row_info, png_bytep row) #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED -void /* PRIVATE */ +static void png_do_quantize(png_row_infop row_info, png_bytep row, png_const_bytep palette_lookup, png_const_bytep quantize_lookup) { @@ -4963,70 +4694,304 @@ png_do_quantize(png_row_infop row_info, png_bytep row, } } } -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ +#endif /* READ_QUANTIZE */ -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ void /* PRIVATE */ -png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) { - png_debug(1, "in png_do_read_intrapixel"); + png_debug(1, "in png_do_read_transformations"); - if ( - (row_info->color_type & PNG_COLOR_MASK_COLOR)) + if (png_ptr->row_buf == NULL) { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; + /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this + * error is incredibly rare and incredibly easy to debug without this + * information. + */ + png_error(png_ptr, "NULL row buffer"); + } - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; + /* The following is debugging; prior to 1.5.4 the code was never compiled in; + * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro + * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for + * all transformations, however in practice the ROW_INIT always gets done on + * demand, if necessary. + */ + if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + /* Application has failed to call either png_read_start_image() or + * png_read_update_info() after setting transforms that expand pixels. + * This check added to libpng-1.2.19 (but not enabled until 1.5.4). + */ + png_error(png_ptr, "Uninitialized row"); + } - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_do_expand_palette(row_info, png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); + } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; + else + { + if (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + png_do_expand(row_info, png_ptr->row_buf + 1, + &(png_ptr->trans_color)); else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); - *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); - } + png_do_expand(row_info, png_ptr->row_buf + 1, + NULL); } - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; + } +#endif - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, row_info, + png_ptr->row_buf + 1); - else - return; + if (rgb_error != 0) + { + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (s0 + s1 + 65536) & 0xffff; - png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp + 1) = (png_byte)(red & 0xff); - *(rp + 4) = (png_byte)((blue >> 8) & 0xff); - *(rp + 5) = (png_byte)(blue & 0xff); - } + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); } } +#endif + +/* From Andreas Dilger e-mail to png-implement, 26 March 1998: + * + * In most cases, the "simple transparency" should be done prior to doing + * gray-to-RGB, or you will have to test 3x as many bytes to check if a + * pixel is transparent. You would also need to make sure that the + * transparency information is upgraded to RGB. + * + * To summarize, the current flow is: + * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + * with background "in place" if transparent, + * convert to RGB if necessary + * - Gray + alpha -> composite with gray background and remove alpha bytes, + * convert to RGB if necessary + * + * To support RGB backgrounds for gray images we need: + * - Gray + simple transparency -> convert to RGB + simple transparency, + * compare 3 or 6 bytes and composite with + * background "in place" if transparent + * (3x compare/pixel compared to doing + * composite with gray bkgrnd) + * - Gray + alpha -> convert to RGB + alpha, composite with background and + * remove alpha bytes (3x float + * operations/pixel compared with composite + * on gray background) + * + * Greg's change will do this. The reason it wasn't done before is for + * performance, as this increases the per-pixel operations. If we would check + * in advance if the background was gray or RGB, and position the gray-to-RGB + * transform appropriately, then it would save a lot of work/time. + */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) != 0 && +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Because RGB_TO_GRAY does the gamma transform. */ + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 && +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* Because PNG_COMPOSE does the gamma transform if there is something to + * do (if there is an alpha channel or transparency.) + */ + !((png_ptr->transformations & PNG_COMPOSE) != 0 && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) && +#endif + /* Because png_init_read_transformations transforms the palette, unless + * RGB_TO_GRAY will do the transform. + */ + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* There is no harm in doing both of these because only one has any effect, + * by putting the 'scale' option first if the app asks for scale (either by + * calling the API or in a TRANSFORM flag) this is what happens. + */ + if ((png_ptr->transformations & PNG_16_TO_8) != 0) + png_do_chop(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) + { + png_do_quantize(row_info, png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); + + if (row_info->rowbytes == 0) + png_error(png_ptr, "png_do_quantize returned rowbytes=0"); + } +#endif /* READ_QUANTIZE */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + /* Do the expansion now, after all the arithmetic has been done. Notice + * that previous transformations can handle the PNG_EXPAND_16 flag if this + * is efficient (particularly true in the case of gamma correction, where + * better accuracy results faster!) + */ + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) + png_do_expand_16(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* NOTE: moved here in 1.5.4 (from much later in this list.) */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_unshift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_unpack(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Added at libpng-1.5.10 */ + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, row_info); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_read_filler(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_16BIT_SUPPORTED +#ifdef PNG_READ_SWAP_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth != 0) + row_info->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels != 0) + row_info->channels = png_ptr->user_transform_channels; +#endif + row_info->pixel_depth = (png_byte)(row_info->bit_depth * + row_info->channels); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); + } +#endif } -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ + +#endif /* READ_TRANSFORMS */ +#endif /* READ */ diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c index aa592ccfbd..6c5c37526b 100644 --- a/src/3rdparty/libpng/pngrutil.c +++ b/src/3rdparty/libpng/pngrutil.c @@ -1,8 +1,8 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.5.10 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -18,10 +18,8 @@ #ifdef PNG_READ_SUPPORTED -#define png_strtod(p,a,b) strtod(a,b) - png_uint_32 PNGAPI -png_get_uint_31(png_structp png_ptr, png_const_bytep buf) +png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); @@ -40,7 +38,7 @@ png_get_uint_31(png_structp png_ptr, png_const_bytep buf) #define PNG_FIXED_ERROR (-1) static png_fixed_point /* PRIVATE */ -png_get_fixed_point(png_structp png_ptr, png_const_bytep buf) +png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); @@ -110,11 +108,11 @@ png_get_uint_16)(png_const_bytep buf) return (png_uint_16)val; } -#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */ +#endif /* READ_INT_FUNCTIONS */ /* Read and check the PNG file signature */ void /* PRIVATE */ -png_read_sig(png_structp png_ptr, png_infop info_ptr) +png_read_sig(png_structrp png_ptr, png_inforp info_ptr) { png_size_t num_checked, num_to_check; @@ -133,7 +131,7 @@ png_read_sig(png_structp png_ptr, png_infop info_ptr) png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); png_ptr->sig_bytes = 8; - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0) { if (num_checked < 4 && png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) @@ -149,7 +147,7 @@ png_read_sig(png_structp png_ptr, png_infop info_ptr) * Put the type name into png_ptr->chunk_name, and return the length. */ png_uint_32 /* PRIVATE */ -png_read_chunk_header(png_structp png_ptr) +png_read_chunk_header(png_structrp png_ptr) { png_byte buf[8]; png_uint_32 length; @@ -186,7 +184,7 @@ png_read_chunk_header(png_structp png_ptr) /* Read data, and (optionally) run it through the CRC. */ void /* PRIVATE */ -png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) +png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) { if (png_ptr == NULL) return; @@ -196,40 +194,40 @@ png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) } /* Optionally skip data and then check the CRC. Depending on whether we - * are reading a ancillary or critical chunk, and how the program has set + * are reading an ancillary or critical chunk, and how the program has set * things up, we may calculate the CRC on the data and print a message. * Returns '1' if there was a CRC error, '0' otherwise. */ int /* PRIVATE */ -png_crc_finish(png_structp png_ptr, png_uint_32 skip) +png_crc_finish(png_structrp png_ptr, png_uint_32 skip) { - png_size_t i; - png_size_t istop = png_ptr->zbuf_size; - - for (i = (png_size_t)skip; i > istop; i -= istop) + /* The size of the local buffer for inflate is a good guess as to a + * reasonable size to use for buffering reads from the application. + */ + while (skip > 0) { - png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - } + png_uint_32 len; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; - if (i) - { - png_crc_read(png_ptr, png_ptr->zbuf, i); + len = (sizeof tmpbuf); + if (len > skip) + len = skip; + skip -= len; + + png_crc_read(png_ptr, tmpbuf, len); } - if (png_crc_error(png_ptr)) + if (png_crc_error(png_ptr) != 0) { - if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name) ? - !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) : - (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)) + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ? + (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 : + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0) { png_chunk_warning(png_ptr, "CRC error"); } else - { - png_chunk_benign_error(png_ptr, "CRC error"); - return (0); - } + png_chunk_error(png_ptr, "CRC error"); return (1); } @@ -241,13 +239,13 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip) * the data it has read thus far. */ int /* PRIVATE */ -png_crc_error(png_structp png_ptr) +png_crc_error(png_structrp png_ptr) { png_byte crc_bytes[4]; png_uint_32 crc; int need_crc = 1; - if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name)) + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) @@ -256,7 +254,7 @@ png_crc_error(png_structp png_ptr) else /* critical */ { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) need_crc = 0; } @@ -267,7 +265,7 @@ png_crc_error(png_structp png_ptr) /* The chunk CRC must be serialized in a single I/O call. */ png_read_data(png_ptr, crc_bytes, 4); - if (need_crc) + if (need_crc != 0) { crc = png_get_uint_32(crc_bytes); return ((int)(crc != png_ptr->crc)); @@ -277,248 +275,522 @@ png_crc_error(png_structp png_ptr) return (0); } -#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED -static png_size_t -png_inflate(png_structp png_ptr, png_bytep data, png_size_t size, - png_bytep output, png_size_t output_size) +#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ + defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\ + defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\ + defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED) +/* Manage the read buffer; this simply reallocates the buffer if it is not small + * enough (or if it is not allocated). The routine returns a pointer to the + * buffer; if an error occurs and 'warn' is set the routine returns NULL, else + * it will call png_error (via png_malloc) on failure. (warn == 2 means + * 'silent'). + */ +static png_bytep +png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) { - png_size_t count = 0; - - /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't - * even necessarily handle 65536 bytes) because the type uInt is "16 bits or - * more". Consequently it is necessary to chunk the input to zlib. This - * code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the maximum value - * that can be stored in a uInt.) It is possible to set ZLIB_IO_MAX to a - * lower value in pngpriv.h and this may sometimes have a performance - * advantage, because it forces access of the input data to be separated from - * at least some of the use by some period of time. - */ - png_ptr->zstream.next_in = data; - /* avail_in is set below from 'size' */ - png_ptr->zstream.avail_in = 0; + png_bytep buffer = png_ptr->read_buffer; + + if (buffer != NULL && new_size > png_ptr->read_buffer_size) + { + png_ptr->read_buffer = NULL; + png_ptr->read_buffer = NULL; + png_ptr->read_buffer_size = 0; + png_free(png_ptr, buffer); + buffer = NULL; + } - while (1) + if (buffer == NULL) { - int ret, avail; + buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size)); - /* The setting of 'avail_in' used to be outside the loop; by setting it - * inside it is possible to chunk the input to zlib and simply rely on - * zlib to advance the 'next_in' pointer. This allows arbitrary amounts o - * data to be passed through zlib at the unavoidable cost of requiring a - * window save (memcpy of up to 32768 output bytes) every ZLIB_IO_MAX - * input bytes. - */ - if (png_ptr->zstream.avail_in == 0 && size > 0) + if (buffer != NULL) { - if (size <= ZLIB_IO_MAX) - { - /* The value is less than ZLIB_IO_MAX so the cast is safe: */ - png_ptr->zstream.avail_in = (uInt)size; - size = 0; - } + png_ptr->read_buffer = buffer; + png_ptr->read_buffer_size = new_size; + } + + else if (warn < 2) /* else silent */ + { + if (warn != 0) + png_chunk_warning(png_ptr, "insufficient memory to read chunk"); else - { - png_ptr->zstream.avail_in = ZLIB_IO_MAX; - size -= ZLIB_IO_MAX; - } + png_chunk_error(png_ptr, "insufficient memory to read chunk"); } + } + + return buffer; +} +#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */ + +/* png_inflate_claim: claim the zstream for some nefarious purpose that involves + * decompression. Returns Z_OK on success, else a zlib error code. It checks + * the owner but, in final release builds, just issues a warning if some other + * chunk apparently owns the stream. Prior to release it does a png_error. + */ +static int +png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) +{ + if (png_ptr->zowner != 0) + { + char msg[64]; - /* Reset the output buffer each time round - we empty it - * after every inflate call. + PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = png_ptr->zbuf_size; + (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_chunk_warning(png_ptr, msg); + png_ptr->zowner = 0; +#else + png_chunk_error(png_ptr, msg); +#endif + } - ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); - avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out; + /* Implementation note: unlike 'png_deflate_claim' this internal function + * does not take the size of the data as an argument. Some efficiency could + * be gained by using this when it is known *if* the zlib stream itself does + * not record the number; however, this is an illusion: the original writer + * of the PNG may have selected a lower window size, and we really must + * follow that because, for systems with with limited capabilities, we + * would otherwise reject the application's attempts to use a smaller window + * size (zlib doesn't have an interface to say "this or lower"!). + * + * inflateReset2 was added to zlib 1.2.4; before this the window could not be + * reset, therefore it is necessary to always allocate the maximum window + * size with earlier zlibs just in case later compressed chunks need it. + */ + { + int ret; /* zlib return code */ +#if PNG_ZLIB_VERNUM >= 0x1240 + +# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW) + int window_bits; + + if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == + PNG_OPTION_ON) + window_bits = 15; + + else + window_bits = 0; +# else +# define window_bits 0 +# endif +#endif - /* First copy/count any new output - but only if we didn't - * get an error code. + /* Set this for safety, just in case the previous owner left pointers to + * memory allocations. */ - if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0) - { - png_size_t space = avail; /* > 0, see above */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; - if (output != 0 && output_size > count) - { - png_size_t copy = output_size - count; + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + { +#if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateReset(&png_ptr->zstream); +#else + ret = inflateReset2(&png_ptr->zstream, window_bits); +#endif + } - if (space < copy) - copy = space; + else + { +#if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateInit(&png_ptr->zstream); +#else + ret = inflateInit2(&png_ptr->zstream, window_bits); +#endif - png_memcpy(output + count, png_ptr->zbuf, copy); - } - count += space; + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; } if (ret == Z_OK) - continue; + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } + +#ifdef window_bits +# undef window_bits +#endif +} - /* Termination conditions - always reset the zstream, it - * must be left in inflateInit state. +#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED +/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to + * allow the caller to do multiple calls if required. If the 'finish' flag is + * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must + * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and + * Z_OK or Z_STREAM_END will be returned on success. + * + * The input and output sizes are updated to the actual amounts of data consumed + * or written, not the amount available (as in a z_stream). The data pointers + * are not changed, so the next input is (data+input_size) and the next + * available output is (output+output_size). + */ +static int +png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, + /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr, + /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr) +{ + if (png_ptr->zowner == owner) /* Else not claimed */ + { + int ret; + png_alloc_size_t avail_out = *output_size_ptr; + png_uint_32 avail_in = *input_size_ptr; + + /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it + * can't even necessarily handle 65536 bytes) because the type uInt is + * "16 bits or more". Consequently it is necessary to chunk the input to + * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the + * maximum value that can be stored in a uInt.) It is possible to set + * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have + * a performance advantage, because it reduces the amount of data accessed + * at each step and that may give the OS more time to page it in. */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + /* avail_in and avail_out are set below from 'size' */ png_ptr->zstream.avail_in = 0; - inflateReset(&png_ptr->zstream); - - if (ret == Z_STREAM_END) - return count; /* NOTE: may be zero. */ + png_ptr->zstream.avail_out = 0; - /* Now handle the error codes - the API always returns 0 - * and the error message is dumped into the uncompressed - * buffer if available. + /* Read directly into the output if it is available (this is set to + * a local buffer below if output is NULL). */ -# ifdef PNG_WARNINGS_SUPPORTED + if (output != NULL) + png_ptr->zstream.next_out = output; + + do { - png_const_charp msg; + uInt avail; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + + /* zlib INPUT BUFFER */ + /* The setting of 'avail_in' used to be outside the loop; by setting it + * inside it is possible to chunk the input to zlib and simply rely on + * zlib to advance the 'next_in' pointer. This allows arbitrary + * amounts of data to be passed through zlib at the unavoidable cost of + * requiring a window save (memcpy of up to 32768 output bytes) + * every ZLIB_IO_MAX input bytes. + */ + avail_in += png_ptr->zstream.avail_in; /* not consumed last time */ - if (png_ptr->zstream.msg != 0) - msg = png_ptr->zstream.msg; + avail = ZLIB_IO_MAX; - else switch (ret) - { - case Z_BUF_ERROR: - msg = "Buffer error in compressed datastream"; - break; + if (avail_in < avail) + avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */ - case Z_DATA_ERROR: - msg = "Data error in compressed datastream"; - break; + avail_in -= avail; + png_ptr->zstream.avail_in = avail; - default: - msg = "Incomplete compressed datastream"; - break; + /* zlib OUTPUT BUFFER */ + avail_out += png_ptr->zstream.avail_out; /* not written last time */ + + avail = ZLIB_IO_MAX; /* maximum zlib can process */ + + if (output == NULL) + { + /* Reset the output buffer each time round if output is NULL and + * make available the full buffer, up to 'remaining_space' + */ + png_ptr->zstream.next_out = local_buffer; + if ((sizeof local_buffer) < avail) + avail = (sizeof local_buffer); } - png_chunk_warning(png_ptr, msg); - } -# endif + if (avail_out < avail) + avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */ + + png_ptr->zstream.avail_out = avail; + avail_out -= avail; + + /* zlib inflate call */ + /* In fact 'avail_out' may be 0 at this point, that happens at the end + * of the read when the final LZ end code was not passed at the end of + * the previous chunk of input data. Tell zlib if we have reached the + * end of the output buffer. + */ + ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH : + (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } while (ret == Z_OK); + + /* For safety kill the local buffer pointer now */ + if (output == NULL) + png_ptr->zstream.next_out = NULL; - /* 0 means an error - notice that this code simply ignores - * zero length compressed chunks as a result. + /* Claw back the 'size' and 'remaining_space' byte counts. */ + avail_in += png_ptr->zstream.avail_in; + avail_out += png_ptr->zstream.avail_out; + + /* Update the input and output sizes; the updated values are the amount + * consumed or written, effectively the inverse of what zlib uses. */ - return 0; + if (avail_out > 0) + *output_size_ptr -= avail_out; + + if (avail_in > 0) + *input_size_ptr -= avail_in; + + /* Ensure png_ptr->zstream.msg is set (even in the success case!) */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + /* This is a bad internal error. The recovery assigns to the zstream msg + * pointer, which is not owned by the caller, but this is safe; it's only + * used on errors! + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; } } /* - * Decompress trailing data in a chunk. The assumption is that chunkdata + * Decompress trailing data in a chunk. The assumption is that read_buffer * points at an allocated area holding the contents of a chunk with a * trailing compressed part. What we get back is an allocated area * holding the original prefix part and an uncompressed version of the * trailing part (the malloc area passed in is freed). */ -void /* PRIVATE */ -png_decompress_chunk(png_structp png_ptr, int comp_type, - png_size_t chunklength, - png_size_t prefix_size, png_size_t *newlength) +static int +png_decompress_chunk(png_structrp png_ptr, + png_uint_32 chunklength, png_uint_32 prefix_size, + png_alloc_size_t *newlength /* must be initialized to the maximum! */, + int terminate /*add a '\0' to the end of the uncompressed data*/) { - /* The caller should guarantee this */ - if (prefix_size > chunklength) - { - /* The recovery is to delete the chunk. */ - png_warning(png_ptr, "invalid chunklength"); - prefix_size = 0; /* To delete everything */ - } + /* TODO: implement different limits for different types of chunk. + * + * The caller supplies *newlength set to the maximum length of the + * uncompressed data, but this routine allocates space for the prefix and + * maybe a '\0' terminator too. We have to assume that 'prefix_size' is + * limited only by the maximum chunk size. + */ + png_alloc_size_t limit = PNG_SIZE_MAX; - else if (comp_type == PNG_COMPRESSION_TYPE_BASE) +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (limit >= prefix_size + (terminate != 0)) { - png_size_t expanded_size = png_inflate(png_ptr, - (png_bytep)(png_ptr->chunkdata + prefix_size), - chunklength - prefix_size, - 0, /* output */ - 0); /* output size */ + int ret; - /* Now check the limits on this chunk - if the limit fails the - * compressed data will be removed, the prefix will remain. - */ - if (prefix_size >= (~(png_size_t)0) - 1 || - expanded_size >= (~(png_size_t)0) - 1 - prefix_size -#ifdef PNG_USER_LIMITS_SUPPORTED - || (png_ptr->user_chunk_malloc_max && - (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1)) -#else - || ((PNG_USER_CHUNK_MALLOC_MAX > 0) && - prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) -#endif - ) - png_warning(png_ptr, "Exceeded size limit while expanding chunk"); + limit -= prefix_size + (terminate != 0); - /* If the size is zero either there was an error and a message - * has already been output (warning) or the size really is zero - * and we have nothing to do - the code will exit through the - * error case below. - */ - else if (expanded_size > 0) + if (limit < *newlength) + *newlength = limit; + + /* Now try to claim the stream. */ + ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); + + if (ret == Z_OK) { - /* Success (maybe) - really uncompress the chunk. */ - png_size_t new_size = 0; - png_charp text = (png_charp)png_malloc_warn(png_ptr, - prefix_size + expanded_size + 1); + png_uint_32 lzsize = chunklength - prefix_size; - if (text != NULL) + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, + /* output: */ NULL, newlength); + + if (ret == Z_STREAM_END) { - png_memcpy(text, png_ptr->chunkdata, prefix_size); - new_size = png_inflate(png_ptr, - (png_bytep)(png_ptr->chunkdata + prefix_size), - chunklength - prefix_size, - (png_bytep)(text + prefix_size), expanded_size); - text[prefix_size + expanded_size] = 0; /* just in case */ - - if (new_size == expanded_size) + /* Use 'inflateReset' here, not 'inflateReset2' because this + * preserves the previously decided window size (otherwise it would + * be necessary to store the previous window size.) In practice + * this doesn't matter anyway, because png_inflate will call inflate + * with Z_FINISH in almost all cases, so the window will not be + * maintained. + */ + if (inflateReset(&png_ptr->zstream) == Z_OK) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; - *newlength = prefix_size + expanded_size; - return; /* The success return! */ + /* Because of the limit checks above we know that the new, + * expanded, size will fit in a size_t (let alone an + * png_alloc_size_t). Use png_malloc_base here to avoid an + * extra OOM message. + */ + png_alloc_size_t new_size = *newlength; + png_alloc_size_t buffer_size = prefix_size + new_size + + (terminate != 0); + png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, + buffer_size)); + + if (text != NULL) + { + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + png_ptr->read_buffer + prefix_size, &lzsize, + text + prefix_size, newlength); + + if (ret == Z_STREAM_END) + { + if (new_size == *newlength) + { + if (terminate != 0) + text[prefix_size + *newlength] = 0; + + if (prefix_size > 0) + memcpy(text, png_ptr->read_buffer, prefix_size); + + { + png_bytep old_ptr = png_ptr->read_buffer; + + png_ptr->read_buffer = text; + png_ptr->read_buffer_size = buffer_size; + text = old_ptr; /* freed below */ + } + } + + else + { + /* The size changed on the second read, there can be no + * guarantee that anything is correct at this point. + * The 'msg' pointer has been set to "unexpected end of + * LZ stream", which is fine, but return an error code + * that the caller won't accept. + */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */ + + /* Free the text pointer (this is the old read_buffer on + * success) + */ + png_free(png_ptr, text); + text = NULL; + + /* This really is very benign, but it's still an error because + * the extra space may otherwise be used as a Trojan Horse. + */ + if (ret == Z_STREAM_END && + chunklength - prefix_size != lzsize) + png_chunk_benign_error(png_ptr, "extra compressed data"); + } + + else + { + /* Out of memory allocating the buffer */ + ret = Z_MEM_ERROR; + png_zstream_error(png_ptr, Z_MEM_ERROR); + } } - png_warning(png_ptr, "png_inflate logic error"); - png_free(png_ptr, text); + else + { + /* inflateReset failed, store the error message */ + png_zstream_error(png_ptr, ret); + + if (ret == Z_STREAM_END) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } } - else - png_warning(png_ptr, "Not enough memory to decompress chunk"); + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + /* Release the claimed stream */ + png_ptr->zowner = 0; } + + else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + return ret; } - else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ + else { - PNG_WARNING_PARAMETERS(p) - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, comp_type); - png_formatted_warning(png_ptr, p, "Unknown compression type @1"); - - /* The recovery is to simply drop the data. */ + /* Application/configuration limits exceeded */ + png_zstream_error(png_ptr, Z_MEM_ERROR); + return Z_MEM_ERROR; } +} +#endif /* READ_COMPRESSED_TEXT */ - /* Generic error return - leave the prefix, delete the compressed - * data, reallocate the chunkdata to remove the potentially large - * amount of compressed data. - */ +#ifdef PNG_READ_iCCP_SUPPORTED +/* Perform a partial read and decompress, producing 'avail_out' bytes and + * reading from the current chunk as required. + */ +static int +png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, + png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, + int finish) +{ + if (png_ptr->zowner == png_ptr->chunk_name) { - png_charp text = (png_charp)png_malloc_warn(png_ptr, prefix_size + 1); + int ret; - if (text != NULL) + /* next_in and avail_in must have been initialized by the caller. */ + png_ptr->zstream.next_out = next_out; + png_ptr->zstream.avail_out = 0; /* set in the loop */ + + do { - if (prefix_size > 0) - png_memcpy(text, png_ptr->chunkdata, prefix_size); + if (png_ptr->zstream.avail_in == 0) + { + if (read_size > *chunk_bytes) + read_size = (uInt)*chunk_bytes; + *chunk_bytes -= read_size; + + if (read_size > 0) + png_crc_read(png_ptr, read_buffer, read_size); + + png_ptr->zstream.next_in = read_buffer; + png_ptr->zstream.avail_in = read_size; + } - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; + if (png_ptr->zstream.avail_out == 0) + { + uInt avail = ZLIB_IO_MAX; + if (avail > *out_size) + avail = (uInt)*out_size; + *out_size -= avail; + + png_ptr->zstream.avail_out = avail; + } - /* This is an extra zero in the 'uncompressed' part. */ - *(png_ptr->chunkdata + prefix_size) = 0x00; + /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all + * the available output is produced; this allows reading of truncated + * streams. + */ + ret = inflate(&png_ptr->zstream, + *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); } - /* Ignore a malloc error here - it is safe. */ + while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); + + *out_size += png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ + + /* Ensure the error message pointer is always set: */ + png_zstream_error(png_ptr, ret); + return ret; } - *newlength = prefix_size; + else + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } } -#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */ +#endif /* Read and check the IDHR chunk */ + void /* PRIVATE */ -png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[13]; png_uint_32 width, height; @@ -527,12 +799,12 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_IHDR"); - if (png_ptr->mode & PNG_HAVE_IHDR) - png_error(png_ptr, "Out of place IHDR"); + if ((png_ptr->mode & PNG_HAVE_IHDR) != 0) + png_chunk_error(png_ptr, "out of place"); /* Check the length */ if (length != 13) - png_error(png_ptr, "Invalid IHDR chunk"); + png_chunk_error(png_ptr, "invalid"); png_ptr->mode |= PNG_HAVE_IHDR; @@ -581,8 +853,7 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } /* Set up other useful info */ - png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * - png_ptr->channels); + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); png_debug1(3, "channels = %d", png_ptr->channels); @@ -593,7 +864,7 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Read and check the palette */ void /* PRIVATE */ -png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_color palette[PNG_MAX_PALETTE_LENGTH]; int num, i; @@ -603,26 +874,33 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_PLTE"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before PLTE"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + /* Moved to before the 'after IDAT' check below because otherwise duplicate + * PLTE chunks are potentially ignored (the spec says there shall not be more + * than one PLTE, the error is not treated as benign, so this check trumps + * the requirement that PLTE appears before IDAT.) + */ + else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0) + png_chunk_error(png_ptr, "duplicate"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid PLTE after IDAT"); + /* This is benign because the non-benign error happened before, when an + * IDAT was encountered in a color-mapped image with no PLTE. + */ png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->mode & PNG_HAVE_PLTE) - png_error(png_ptr, "Duplicate PLTE chunk"); - png_ptr->mode |= PNG_HAVE_PLTE; - if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) { - png_warning(png_ptr, - "Ignoring PLTE chunk in grayscale PNG"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); return; } @@ -636,19 +914,18 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) { + png_crc_finish(png_ptr, length); + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - png_warning(png_ptr, "Invalid palette chunk"); - png_crc_finish(png_ptr, length); - return; - } + png_chunk_benign_error(png_ptr, "invalid"); else - { - png_error(png_ptr, "Invalid palette chunk"); - } + png_chunk_error(png_ptr, "invalid"); + + return; } + /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ num = (int)length / 3; #ifdef PNG_POINTER_INDEXING_SUPPORTED @@ -687,214 +964,196 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #ifndef PNG_READ_OPT_PLTE_SUPPORTED - else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + else if (png_crc_error(png_ptr) != 0) /* Only if we have a CRC error */ { /* If we don't want to use the data from an ancillary chunk, * we have two options: an error abort, or a warning and we * ignore the data in this chunk (which should be OK, since * it's considered ancillary for a RGB or RGBA image). + * + * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the + * chunk type to determine whether to check the ancillary or the critical + * flags. */ - if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0) { - if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) - { - png_chunk_benign_error(png_ptr, "CRC error"); - } + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0) + return; else - { - png_chunk_warning(png_ptr, "CRC error"); - return; - } + png_chunk_error(png_ptr, "CRC error"); } /* Otherwise, we (optionally) emit a warning and use the chunk. */ - else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) - { + else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0) png_chunk_warning(png_ptr, "CRC error"); - } } #endif + /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its + * own copy of the palette. This has the side effect that when png_start_row + * is called (this happens after any call to png_read_update_info) the + * info_ptr palette gets changed. This is extremely unexpected and + * confusing. + * + * Fix this by not sharing the palette in this way. + */ png_set_PLTE(png_ptr, info_ptr, palette, num); + /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before + * IDAT. Prior to 1.6.0 this was not checked; instead the code merely + * checked the apparent validity of a tRNS chunk inserted before PLTE on a + * palette PNG. 1.6.0 attempts to rigorously follow the standard and + * therefore does a benign error if the erroneous condition is detected *and* + * cancels the tRNS if the benign error returns. The alternative is to + * amend the standard since it would be rather hypocritical of the standards + * maintainers to ignore it. + */ #ifdef PNG_READ_tRNS_SUPPORTED - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + if (png_ptr->num_trans > 0 || + (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)) { - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - if (png_ptr->num_trans > (png_uint_16)num) - { - png_warning(png_ptr, "Truncating incorrect tRNS chunk length"); - png_ptr->num_trans = (png_uint_16)num; - } + /* Cancel this because otherwise it would be used if the transforms + * require it. Don't cancel the 'valid' flag because this would prevent + * detection of duplicate chunks. + */ + png_ptr->num_trans = 0; - if (info_ptr->num_trans > (png_uint_16)num) - { - png_warning(png_ptr, "Truncating incorrect info tRNS chunk length"); - info_ptr->num_trans = (png_uint_16)num; - } - } + if (info_ptr != NULL) + info_ptr->num_trans = 0; + + png_chunk_benign_error(png_ptr, "tRNS must be after"); } #endif +#ifdef PNG_READ_hIST_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) + png_chunk_benign_error(png_ptr, "hIST must be after"); +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) + png_chunk_benign_error(png_ptr, "bKGD must be after"); +#endif } void /* PRIVATE */ -png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_debug(1, "in png_handle_IEND"); - if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) - { - png_error(png_ptr, "No image in file"); - } + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 || + (png_ptr->mode & PNG_HAVE_IDAT) == 0) + png_chunk_error(png_ptr, "out of place"); png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); - if (length != 0) - { - png_warning(png_ptr, "Incorrect IEND chunk length"); - } - png_crc_finish(png_ptr, length); - PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */ + if (length != 0) + png_chunk_benign_error(png_ptr, "invalid"); + + PNG_UNUSED(info_ptr) } #ifdef PNG_READ_gAMA_SUPPORTED void /* PRIVATE */ -png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_fixed_point igamma; png_byte buf[4]; png_debug(1, "in png_handle_gAMA"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before gAMA"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid gAMA after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place gAMA chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) -#ifdef PNG_READ_sRGB_SUPPORTED - && !(info_ptr->valid & PNG_INFO_sRGB) -#endif - ) - { - png_warning(png_ptr, "Duplicate gAMA chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 4) { - png_warning(png_ptr, "Incorrect gAMA chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 4); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; igamma = png_get_fixed_point(NULL, buf); - /* Check for zero gamma or an error. */ - if (igamma <= 0) - { - png_warning(png_ptr, - "Ignoring gAMA chunk with out of range gamma"); - - return; - } - -# ifdef PNG_READ_sRGB_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) - { - if (PNG_OUT_OF_RANGE(igamma, 45500, 500)) - { - PNG_WARNING_PARAMETERS(p) - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, igamma); - png_formatted_warning(png_ptr, p, - "Ignoring incorrect gAMA value @1 when sRGB is also present"); - return; - } - } -# endif /* PNG_READ_sRGB_SUPPORTED */ - -# ifdef PNG_READ_GAMMA_SUPPORTED - /* Gamma correction on read is supported. */ - png_ptr->gamma = igamma; -# endif - /* And set the 'info' structure members. */ - png_set_gAMA_fixed(png_ptr, info_ptr, igamma); + png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma); + png_colorspace_sync(png_ptr, info_ptr); } #endif #ifdef PNG_READ_sBIT_SUPPORTED void /* PRIVATE */ -png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_size_t truelen; + unsigned int truelen, i; + png_byte sample_depth; png_byte buf[4]; png_debug(1, "in png_handle_sBIT"); - buf[0] = buf[1] = buf[2] = buf[3] = 0; - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sBIT"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid sBIT after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->mode & PNG_HAVE_PLTE) - { - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sBIT chunk"); - } - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0) { - png_warning(png_ptr, "Duplicate sBIT chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { truelen = 3; + sample_depth = 8; + } else - truelen = (png_size_t)png_ptr->channels; + { + truelen = png_ptr->channels; + sample_depth = png_ptr->bit_depth; + } if (length != truelen || length > 4) { - png_warning(png_ptr, "Incorrect sBIT chunk length"); + png_chunk_benign_error(png_ptr, "invalid"); png_crc_finish(png_ptr, length); return; } + buf[0] = buf[1] = buf[2] = buf[3] = sample_depth; png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + for (i=0; i sample_depth) + { + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) { png_ptr->sig_bit.red = buf[0]; png_ptr->sig_bit.green = buf[1]; @@ -917,474 +1176,418 @@ png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_cHRM_SUPPORTED void /* PRIVATE */ -png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[32]; - png_fixed_point x_white, y_white, x_red, y_red, x_green, y_green, x_blue, - y_blue; - - png_debug(1, "in png_handle_cHRM"); - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before cHRM"); + png_xy xy; - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid cHRM after IDAT"); - png_crc_finish(png_ptr, length); - return; - } + png_debug(1, "in png_handle_cHRM"); - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place cHRM chunk"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) -# ifdef PNG_READ_sRGB_SUPPORTED - && !(info_ptr->valid & PNG_INFO_sRGB) -# endif - ) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Duplicate cHRM chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 32) { - png_warning(png_ptr, "Incorrect cHRM chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 32); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; - x_white = png_get_fixed_point(NULL, buf); - y_white = png_get_fixed_point(NULL, buf + 4); - x_red = png_get_fixed_point(NULL, buf + 8); - y_red = png_get_fixed_point(NULL, buf + 12); - x_green = png_get_fixed_point(NULL, buf + 16); - y_green = png_get_fixed_point(NULL, buf + 20); - x_blue = png_get_fixed_point(NULL, buf + 24); - y_blue = png_get_fixed_point(NULL, buf + 28); - - if (x_white == PNG_FIXED_ERROR || - y_white == PNG_FIXED_ERROR || - x_red == PNG_FIXED_ERROR || - y_red == PNG_FIXED_ERROR || - x_green == PNG_FIXED_ERROR || - y_green == PNG_FIXED_ERROR || - x_blue == PNG_FIXED_ERROR || - y_blue == PNG_FIXED_ERROR) - { - png_warning(png_ptr, "Ignoring cHRM chunk with negative chromaticities"); + xy.whitex = png_get_fixed_point(NULL, buf); + xy.whitey = png_get_fixed_point(NULL, buf + 4); + xy.redx = png_get_fixed_point(NULL, buf + 8); + xy.redy = png_get_fixed_point(NULL, buf + 12); + xy.greenx = png_get_fixed_point(NULL, buf + 16); + xy.greeny = png_get_fixed_point(NULL, buf + 20); + xy.bluex = png_get_fixed_point(NULL, buf + 24); + xy.bluey = png_get_fixed_point(NULL, buf + 28); + + if (xy.whitex == PNG_FIXED_ERROR || + xy.whitey == PNG_FIXED_ERROR || + xy.redx == PNG_FIXED_ERROR || + xy.redy == PNG_FIXED_ERROR || + xy.greenx == PNG_FIXED_ERROR || + xy.greeny == PNG_FIXED_ERROR || + xy.bluex == PNG_FIXED_ERROR || + xy.bluey == PNG_FIXED_ERROR) + { + png_chunk_benign_error(png_ptr, "invalid values"); return; } -#ifdef PNG_READ_sRGB_SUPPORTED - if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB)) - { - if (PNG_OUT_OF_RANGE(x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(x_red, 64000, 1000) || - PNG_OUT_OF_RANGE(y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(y_green, 60000, 1000) || - PNG_OUT_OF_RANGE(x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(y_blue, 6000, 1000)) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, x_white); - png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_fixed, y_white); - png_warning_parameter_signed(p, 3, PNG_NUMBER_FORMAT_fixed, x_red); - png_warning_parameter_signed(p, 4, PNG_NUMBER_FORMAT_fixed, y_red); - png_warning_parameter_signed(p, 5, PNG_NUMBER_FORMAT_fixed, x_green); - png_warning_parameter_signed(p, 6, PNG_NUMBER_FORMAT_fixed, y_green); - png_warning_parameter_signed(p, 7, PNG_NUMBER_FORMAT_fixed, x_blue); - png_warning_parameter_signed(p, 8, PNG_NUMBER_FORMAT_fixed, y_blue); - - png_formatted_warning(png_ptr, p, - "Ignoring incorrect cHRM white(@1,@2) r(@3,@4)g(@5,@6)b(@7,@8) " - "when sRGB is also present"); - } + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) return; - } -#endif /* PNG_READ_sRGB_SUPPORTED */ -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* Store the _white values as default coefficients for the rgb to gray - * operation if it is supported. Check if the transform is already set to - * avoid destroying the transform values. - */ - if (!png_ptr->rgb_to_gray_coefficients_set) + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0) { - /* png_set_background has not been called and we haven't seen an sRGB - * chunk yet. Find the XYZ of the three end points. - */ - png_XYZ XYZ; - png_xy xy; - - xy.redx = x_red; - xy.redy = y_red; - xy.greenx = x_green; - xy.greeny = y_green; - xy.bluex = x_blue; - xy.bluey = y_blue; - xy.whitex = x_white; - xy.whitey = y_white; - - if (png_XYZ_from_xy_checked(png_ptr, &XYZ, xy)) - { - /* The success case, because XYZ_from_xy normalises to a reference - * white Y of 1.0 we just need to scale the numbers. This should - * always work just fine. It is an internal error if this overflows. - */ - { - png_fixed_point r, g, b; - if (png_muldiv(&r, XYZ.redY, 32768, PNG_FP_1) && - r >= 0 && r <= 32768 && - png_muldiv(&g, XYZ.greenY, 32768, PNG_FP_1) && - g >= 0 && g <= 32768 && - png_muldiv(&b, XYZ.blueY, 32768, PNG_FP_1) && - b >= 0 && b <= 32768 && - r+g+b <= 32769) - { - /* We allow 0 coefficients here. r+g+b may be 32769 if two or - * all of the coefficients were rounded up. Handle this by - * reducing the *largest* coefficient by 1; this matches the - * approach used for the default coefficients in pngrtran.c - */ - int add = 0; - - if (r+g+b > 32768) - add = -1; - else if (r+g+b < 32768) - add = 1; - - if (add != 0) - { - if (g >= r && g >= b) - g += add; - else if (r >= g && r >= b) - r += add; - else - b += add; - } - - /* Check for an internal error. */ - if (r+g+b != 32768) - png_error(png_ptr, - "internal error handling cHRM coefficients"); - - png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; - png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; - } - - /* This is a png_error at present even though it could be ignored - - * it should never happen, but it is important that if it does, the - * bug is fixed. - */ - else - png_error(png_ptr, "internal error handling cHRM->XYZ"); - } - } + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "duplicate"); + return; } -#endif - png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red, - x_green, y_green, x_blue, y_blue); + png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy, + 1/*prefer cHRM values*/); + png_colorspace_sync(png_ptr, info_ptr); } #endif #ifdef PNG_READ_sRGB_SUPPORTED void /* PRIVATE */ -png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - int intent; - png_byte buf[1]; + png_byte intent; png_debug(1, "in png_handle_sRGB"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sRGB"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid sRGB after IDAT"); - png_crc_finish(png_ptr, length); - return; - } - - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sRGB chunk"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Duplicate sRGB chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 1) { - png_warning(png_ptr, "Incorrect sRGB chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } - png_crc_read(png_ptr, buf, 1); + png_crc_read(png_ptr, &intent, 1); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; - intent = buf[0]; - - /* Check for bad intent */ - if (intent >= PNG_sRGB_INTENT_LAST) - { - png_warning(png_ptr, "Unknown sRGB intent"); + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) return; - } -#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)) + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0) { - if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500, 500)) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, - info_ptr->gamma); - - png_formatted_warning(png_ptr, p, - "Ignoring incorrect gAMA value @1 when sRGB is also present"); - } + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "too many profiles"); + return; } -#endif /* PNG_READ_gAMA_SUPPORTED */ - -#ifdef PNG_READ_cHRM_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - if (PNG_OUT_OF_RANGE(info_ptr->x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(info_ptr->y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(info_ptr->x_red, 64000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->y_green, 60000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->y_blue, 6000, 1000)) - { - png_warning(png_ptr, - "Ignoring incorrect cHRM value when sRGB is also present"); - } -#endif /* PNG_READ_cHRM_SUPPORTED */ - - /* This is recorded for use when handling the cHRM chunk above. An sRGB - * chunk unconditionally overwrites the coefficients for grayscale conversion - * too. - */ - png_ptr->is_sRGB = 1; - -# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* Don't overwrite user supplied values: */ - if (!png_ptr->rgb_to_gray_coefficients_set) - { - /* These numbers come from the sRGB specification (or, since one has to - * pay much money to get a copy, the wikipedia sRGB page) the - * chromaticity values quoted have been inverted to get the reverse - * transformation from RGB to XYZ and the 'Y' coefficients scaled by - * 32768 (then rounded). - * - * sRGB and ITU Rec-709 both truncate the values for the D65 white - * point to four digits and, even though it actually stores five - * digits, the PNG spec gives the truncated value. - * - * This means that when the chromaticities are converted back to XYZ - * end points we end up with (6968,23435,2366), which, as described in - * pngrtran.c, would overflow. If the five digit precision and up is - * used we get, instead: - * - * 6968*R + 23435*G + 2365*B - * - * (Notice that this rounds the blue coefficient down, rather than the - * choice used in pngrtran.c which is to round the green one down.) - */ - png_ptr->rgb_to_gray_red_coeff = 6968; /* 0.212639005871510 */ - png_ptr->rgb_to_gray_green_coeff = 23434; /* 0.715168678767756 */ - /* png_ptr->rgb_to_gray_blue_coeff = 2366; 0.072192315360734 */ - /* The following keeps the cHRM chunk from destroying the - * coefficients again in the event that it follows the sRGB chunk. - */ - png_ptr->rgb_to_gray_coefficients_set = 1; - } -# endif - - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); + (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent); + png_colorspace_sync(png_ptr, info_ptr); } -#endif /* PNG_READ_sRGB_SUPPORTED */ +#endif /* READ_sRGB */ #ifdef PNG_READ_iCCP_SUPPORTED void /* PRIVATE */ -png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -/* Note: this does not properly handle chunks that are > 64K under DOS */ +png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle profiles that are > 64K under DOS */ { - png_byte compression_type; - png_bytep pC; - png_charp profile; - png_uint_32 skip = 0; - png_uint_32 profile_size; - png_alloc_size_t profile_length; - png_size_t slength, prefix_length, data_length; + png_const_charp errmsg = NULL; /* error message output, or no error */ + int finished = 0; /* crc checked */ png_debug(1, "in png_handle_iCCP"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iCCP"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid iCCP after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place iCCP chunk"); - - if ((png_ptr->mode & PNG_HAVE_iCCP) || (info_ptr != NULL && - (info_ptr->valid & (PNG_INFO_iCCP|PNG_INFO_sRGB)))) + /* Consistent with all the above colorspace handling an obviously *invalid* + * chunk is just ignored, so does not invalidate the color space. An + * alternative is to set the 'invalid' flags at the start of this routine + * and only clear them in they were not set before and all the tests pass. + * The minimum 'deflate' stream is assumed to be just the 2 byte header and + * 4 byte checksum. The keyword must be at least one character and there is + * a terminator (0) byte and the compression method. + */ + if (length < 9) { - png_warning(png_ptr, "Duplicate iCCP chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too short"); return; } - png_ptr->mode |= PNG_HAVE_iCCP; - -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) { - png_warning(png_ptr, "iCCP chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; + png_crc_finish(png_ptr, length); + return; } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); - slength = length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - if (png_crc_finish(png_ptr, skip)) + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + uInt read_length, keyword_length; + char keyword[81]; - png_ptr->chunkdata[slength] = 0x00; + /* Find the keyword; the keyword plus separator and compression method + * bytes can be at most 81 characters long. + */ + read_length = 81; /* maximum */ + if (read_length > length) + read_length = (uInt)length; - for (profile = png_ptr->chunkdata; *profile; profile++) - /* Empty loop to find end of name */ ; + png_crc_read(png_ptr, (png_bytep)keyword, read_length); + length -= read_length; - ++profile; + keyword_length = 0; + while (keyword_length < 80 && keyword_length < read_length && + keyword[keyword_length] != 0) + ++keyword_length; - /* There should be at least one zero (the compression type byte) - * following the separator, and we should be on it - */ - if (profile >= png_ptr->chunkdata + slength - 1) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Malformed iCCP chunk"); - return; - } + /* TODO: make the keyword checking common */ + if (keyword_length >= 1 && keyword_length <= 79) + { + /* We only understand '0' compression - deflate - so if we get a + * different value we can't safely decode the chunk. + */ + if (keyword_length+1 < read_length && + keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE) + { + read_length -= keyword_length+2; - /* Compression_type should always be zero */ - compression_type = *profile++; + if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) + { + Byte profile_header[132]; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + png_alloc_size_t size = (sizeof profile_header); - if (compression_type) - { - png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); - compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 - wrote nonzero) */ - } + png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); + png_ptr->zstream.avail_in = read_length; + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, profile_header, &size, + 0/*finish: don't, because the output is too small*/); + + if (size == 0) + { + /* We have the ICC profile header; do the basic header checks. + */ + const png_uint_32 profile_length = + png_get_uint_32(profile_header); - prefix_length = profile - png_ptr->chunkdata; - png_decompress_chunk(png_ptr, compression_type, - slength, prefix_length, &data_length); + if (png_icc_check_length(png_ptr, &png_ptr->colorspace, + keyword, profile_length) != 0) + { + /* The length is apparently ok, so we can check the 132 + * byte header. + */ + if (png_icc_check_header(png_ptr, &png_ptr->colorspace, + keyword, profile_length, profile_header, + png_ptr->color_type) != 0) + { + /* Now read the tag table; a variable size buffer is + * needed at this point, allocate one for the whole + * profile. The header check has already validated + * that none of these stuff will overflow. + */ + const png_uint_32 tag_count = png_get_uint_32( + profile_header+128); + png_bytep profile = png_read_buffer(png_ptr, + profile_length, 2/*silent*/); + + if (profile != NULL) + { + memcpy(profile, profile_header, + (sizeof profile_header)); + + size = 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header), &size, 0); + + /* Still expect a buffer error because we expect + * there to be some tag data! + */ + if (size == 0) + { + if (png_icc_check_tag_table(png_ptr, + &png_ptr->colorspace, keyword, profile_length, + profile) != 0) + { + /* The profile has been validated for basic + * security issues, so read the whole thing in. + */ + size = profile_length - (sizeof profile_header) + - 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header) + + 12 * tag_count, &size, 1/*finish*/); + + if (length > 0 && !(png_ptr->flags & + PNG_FLAG_BENIGN_ERRORS_WARN)) + errmsg = "extra compressed data"; + + /* But otherwise allow extra data: */ + else if (size == 0) + { + if (length > 0) + { + /* This can be handled completely, so + * keep going. + */ + png_chunk_warning(png_ptr, + "extra compressed data"); + } + + png_crc_finish(png_ptr, length); + finished = 1; + +# ifdef PNG_sRGB_SUPPORTED + /* Check for a match against sRGB */ + png_icc_set_sRGB(png_ptr, + &png_ptr->colorspace, profile, + png_ptr->zstream.adler); +# endif + + /* Steal the profile for info_ptr. */ + if (info_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, + PNG_FREE_ICCP, 0); + + info_ptr->iccp_name = png_voidcast(char*, + png_malloc_base(png_ptr, + keyword_length+1)); + if (info_ptr->iccp_name != NULL) + { + memcpy(info_ptr->iccp_name, keyword, + keyword_length+1); + info_ptr->iccp_proflen = + profile_length; + info_ptr->iccp_profile = profile; + png_ptr->read_buffer = NULL; /*steal*/ + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; + } + + else + { + png_ptr->colorspace.flags |= + PNG_COLORSPACE_INVALID; + errmsg = "out of memory"; + } + } + + /* else the profile remains in the read + * buffer which gets reused for subsequent + * chunks. + */ + + if (info_ptr != NULL) + png_colorspace_sync(png_ptr, info_ptr); + + if (errmsg == NULL) + { + png_ptr->zowner = 0; + return; + } + } + + else if (size > 0) + errmsg = "truncated"; + +#ifndef __COVERITY__ + else + errmsg = png_ptr->zstream.msg; +#endif + } - profile_length = data_length - prefix_length; + /* else png_icc_check_tag_table output an error */ + } - if (prefix_length > data_length || profile_length < 4) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Profile size field missing from iCCP chunk"); - return; - } + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + } - /* Check the profile_size recorded in the first 32 bits of the ICC profile */ - pC = (png_bytep)(png_ptr->chunkdata + prefix_length); - profile_size = ((*(pC )) << 24) | - ((*(pC + 1)) << 16) | - ((*(pC + 2)) << 8) | - ((*(pC + 3)) ); + else + errmsg = "out of memory"; + } - /* NOTE: the following guarantees that 'profile_length' fits into 32 bits, - * because profile_size is a 32 bit value. - */ - if (profile_size < profile_length) - profile_length = profile_size; + /* else png_icc_check_header output an error */ + } - /* And the following guarantees that profile_size == profile_length. */ - if (profile_size > profile_length) - { - PNG_WARNING_PARAMETERS(p) + /* else png_icc_check_length output an error */ + } - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; - png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_u, profile_size); - png_warning_parameter_unsigned(p, 2, PNG_NUMBER_FORMAT_u, profile_length); - png_formatted_warning(png_ptr, p, - "Ignoring iCCP chunk with declared size = @1 and actual length = @2"); - return; + /* Release the stream */ + png_ptr->zowner = 0; + } + + else /* png_inflate_claim failed */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "bad compression method"; /* or missing */ + } + + else + errmsg = "bad keyword"; } - png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata, - compression_type, (png_bytep)png_ptr->chunkdata + prefix_length, - profile_size); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + else + errmsg = "too many profiles"; + + /* Failure: the reason is in 'errmsg' */ + if (finished == 0) + png_crc_finish(png_ptr, length); + + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + if (errmsg != NULL) /* else already output */ + png_chunk_benign_error(png_ptr, errmsg); } -#endif /* PNG_READ_iCCP_SUPPORTED */ +#endif /* READ_iCCP */ #ifdef PNG_READ_sPLT_SUPPORTED void /* PRIVATE */ -png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { - png_bytep entry_start; + png_bytep entry_start, buffer; png_sPLT_t new_palette; png_sPLT_entryp pp; png_uint_32 data_length; int entry_size, i; png_uint_32 skip = 0; - png_size_t slength; png_uint_32 dl; png_size_t max_dl; png_debug(1, "in png_handle_sPLT"); #ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) { if (png_ptr->user_chunk_cache_max == 1) @@ -1402,55 +1605,53 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sPLT"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid sPLT after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } #ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) + if (length > 65535U) { - png_warning(png_ptr, "sPLT chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; } #endif - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + /* WARNING: this may break if size_t is less than 32 bits; it is assumed * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a * potential breakage point if the types in pngconf.h aren't exactly right. */ - slength = length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + if (png_crc_finish(png_ptr, skip) != 0) return; - } - png_ptr->chunkdata[slength] = 0x00; + buffer[length] = 0; - for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; - entry_start++) + for (entry_start = buffer; *entry_start; entry_start++) /* Empty loop to find end of name */ ; ++entry_start; /* A sample depth should follow the separator, and we should be on it */ - if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2) + if (entry_start > buffer + length - 2) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_warning(png_ptr, "malformed sPLT chunk"); return; } @@ -1458,23 +1659,19 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) new_palette.depth = *entry_start++; entry_size = (new_palette.depth == 8 ? 6 : 10); /* This must fit in a png_uint_32 because it is derived from the original - * chunk data length (and use 'length', not 'slength' here for clarity - - * they are guaranteed to be the same, see the tests above.) + * chunk data length. */ - data_length = length - (png_uint_32)(entry_start - - (png_bytep)png_ptr->chunkdata); + data_length = length - (png_uint_32)(entry_start - buffer); /* Integrity-check the data length */ - if (data_length % entry_size) + if ((data_length % entry_size) != 0) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_warning(png_ptr, "sPLT chunk has bad length"); return; } dl = (png_int_32)(data_length / entry_size); - max_dl = PNG_SIZE_MAX / png_sizeof(png_sPLT_entry); + max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); if (dl > max_dl) { @@ -1485,7 +1682,7 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) new_palette.nentries = (png_int_32)(data_length / entry_size); new_palette.entries = (png_sPLT_entryp)png_malloc_warn( - png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); + png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry))); if (new_palette.entries == NULL) { @@ -1543,38 +1740,36 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #endif /* Discard all chunk data except the name and stash that */ - new_palette.name = png_ptr->chunkdata; + new_palette.name = (png_charp)buffer; png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_free(png_ptr, new_palette.entries); } -#endif /* PNG_READ_sPLT_SUPPORTED */ +#endif /* READ_sPLT */ #ifdef PNG_READ_tRNS_SUPPORTED void /* PRIVATE */ -png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_tRNS"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tRNS"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid tRNS after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0) { - png_warning(png_ptr, "Duplicate tRNS chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } @@ -1584,8 +1779,8 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (length != 2) { - png_warning(png_ptr, "Incorrect tRNS chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } @@ -1600,12 +1795,12 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (length != 6) { - png_warning(png_ptr, "Incorrect tRNS chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } - png_crc_read(png_ptr, buf, (png_size_t)length); + png_crc_read(png_ptr, buf, length); png_ptr->num_trans = 1; png_ptr->trans_color.red = png_get_uint_16(buf); png_ptr->trans_color.green = png_get_uint_16(buf + 2); @@ -1614,44 +1809,43 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (!(png_ptr->mode & PNG_HAVE_PLTE)) - { - /* Should be an error, but we can cope with it. */ - png_warning(png_ptr, "Missing PLTE before tRNS"); - } - - if (length > (png_uint_32)png_ptr->num_palette || - length > PNG_MAX_PALETTE_LENGTH) + if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) { - png_warning(png_ptr, "Incorrect tRNS chunk length"); + /* TODO: is this actually an error in the ISO spec? */ png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - if (length == 0) + if (length > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH || + length == 0) { - png_warning(png_ptr, "Zero length tRNS chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } - png_crc_read(png_ptr, readbuf, (png_size_t)length); + png_crc_read(png_ptr, readbuf, length); png_ptr->num_trans = (png_uint_16)length; } else { - png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid with alpha channel"); return; } - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) { png_ptr->num_trans = 0; return; } + /* TODO: this is a horrible side effect in the palette case because the + * png_struct ends up with a pointer to the tRNS buffer owned by the + * png_info. Fix this. + */ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, &(png_ptr->trans_color)); } @@ -1659,43 +1853,37 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_bKGD_SUPPORTED void /* PRIVATE */ -png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_size_t truelen; + unsigned int truelen; png_byte buf[6]; png_color_16 background; png_debug(1, "in png_handle_bKGD"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before bKGD"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) - { - png_warning(png_ptr, "Invalid bKGD after IDAT"); - png_crc_finish(png_ptr, length); - return; - } + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0)) { - png_warning(png_ptr, "Missing PLTE before bKGD"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) { - png_warning(png_ptr, "Duplicate bKGD chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) truelen = 1; - else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) truelen = 6; else @@ -1703,14 +1891,14 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (length != truelen) { - png_warning(png_ptr, "Incorrect bKGD chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; /* We convert the index value into RGB components so that we can allow @@ -1722,11 +1910,11 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { background.index = buf[0]; - if (info_ptr && info_ptr->num_palette) + if (info_ptr != NULL && info_ptr->num_palette != 0) { if (buf[0] >= info_ptr->num_palette) { - png_warning(png_ptr, "Incorrect bKGD chunk index value"); + png_chunk_benign_error(png_ptr, "invalid index"); return; } @@ -1741,7 +1929,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) background.gray = 0; } - else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */ { background.index = 0; background.red = @@ -1765,47 +1953,40 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_hIST_SUPPORTED void /* PRIVATE */ -png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int num, i; png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_hIST"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before hIST"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || + (png_ptr->mode & PNG_HAVE_PLTE) == 0) { - png_warning(png_ptr, "Invalid hIST after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (!(png_ptr->mode & PNG_HAVE_PLTE)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) { - png_warning(png_ptr, "Missing PLTE before hIST"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) - { - png_warning(png_ptr, "Duplicate hIST chunk"); - png_crc_finish(png_ptr, length); - return; - } + num = length / 2 ; - if (length > 2*PNG_MAX_PALETTE_LENGTH || - length != (unsigned int) (2*png_ptr->num_palette)) + if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH) { - png_warning(png_ptr, "Incorrect hIST chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } - num = length / 2 ; - for (i = 0; i < num; i++) { png_byte buf[2]; @@ -1814,7 +1995,7 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) readbuf[i] = png_get_uint_16(buf); } - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; png_set_hIST(png_ptr, info_ptr, readbuf); @@ -1823,7 +2004,7 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_pHYs_SUPPORTED void /* PRIVATE */ -png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; png_uint_32 res_x, res_y; @@ -1831,33 +2012,33 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_pHYs"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pHYs"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid pHYs after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { - png_warning(png_ptr, "Duplicate pHYs chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (length != 9) { - png_warning(png_ptr, "Incorrect pHYs chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; res_x = png_get_uint_32(buf); @@ -1869,7 +2050,7 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_oFFs_SUPPORTED void /* PRIVATE */ -png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; png_int_32 offset_x, offset_y; @@ -1877,33 +2058,33 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_oFFs"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before oFFs"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid oFFs after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) { - png_warning(png_ptr, "Duplicate oFFs chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (length != 9) { - png_warning(png_ptr, "Incorrect oFFs chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; offset_x = png_get_int_32(buf); @@ -1916,71 +2097,64 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_pCAL_SUPPORTED /* Read the pCAL chunk (described in the PNG Extensions document) */ void /* PRIVATE */ -png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_int_32 X0, X1; png_byte type, nparams; - png_charp buf, units, endptr; + png_bytep buffer, buf, units, endptr; png_charpp params; - png_size_t slength; int i; png_debug(1, "in png_handle_pCAL"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pCAL"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid pCAL after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0) { - png_warning(png_ptr, "Duplicate pCAL chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", length + 1); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (png_ptr->chunkdata == NULL) + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) { - png_warning(png_ptr, "No memory for pCAL purpose"); + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - slength = length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + if (png_crc_finish(png_ptr, 0) != 0) return; - } - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + buffer[length] = 0; /* Null terminate the last string */ png_debug(3, "Finding end of pCAL purpose string"); - for (buf = png_ptr->chunkdata; *buf; buf++) + for (buf = buffer; *buf; buf++) /* Empty loop */ ; - endptr = png_ptr->chunkdata + slength; + endptr = buffer + length; /* We need to have at least 12 bytes after the purpose string * in order to get the parameter information. */ if (endptr <= buf + 12) { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid"); return; } @@ -2000,15 +2174,13 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) (type == PNG_EQUATION_ARBITRARY && nparams != 3) || (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) { - png_warning(png_ptr, "Invalid pCAL parameters for equation type"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid parameter count"); return; } else if (type >= PNG_EQUATION_LAST) { - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + png_chunk_benign_error(png_ptr, "unrecognized equation type"); } for (buf = units; *buf; buf++) @@ -2016,43 +2188,37 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(3, "Allocating pCAL parameters array"); - params = (png_charpp)png_malloc_warn(png_ptr, - (png_size_t)(nparams * png_sizeof(png_charp))); + params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + nparams * (sizeof (png_charp)))); if (params == NULL) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "No memory for pCAL params"); + png_chunk_benign_error(png_ptr, "out of memory"); return; } /* Get pointers to the start of each parameter string. */ - for (i = 0; i < (int)nparams; i++) + for (i = 0; i < nparams; i++) { buf++; /* Skip the null string terminator from previous parameter. */ png_debug1(3, "Reading pCAL parameter %d", i); - for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++) + for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++) /* Empty loop to move past each parameter string */ ; /* Make sure we haven't run out of data yet */ if (buf > endptr) { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_free(png_ptr, params); + png_chunk_benign_error(png_ptr, "invalid data"); return; } } - png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams, - units, params); + png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, + (png_charp)units, params); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_free(png_ptr, params); } #endif @@ -2060,67 +2226,61 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_sCAL_SUPPORTED /* Read the sCAL chunk */ void /* PRIVATE */ -png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_size_t slength, i; + png_bytep buffer; + png_size_t i; int state; png_debug(1, "in png_handle_sCAL"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sCAL"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (png_ptr->mode & PNG_HAVE_IDAT) + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid sCAL after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0) { - png_warning(png_ptr, "Duplicate sCAL chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } /* Need unit type, width, \0, height: minimum 4 bytes */ else if (length < 4) { - png_warning(png_ptr, "sCAL chunk too short"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", length + 1); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); - if (png_ptr->chunkdata == NULL) + if (buffer == NULL) { - png_warning(png_ptr, "Out of memory while processing sCAL chunk"); + png_chunk_benign_error(png_ptr, "out of memory"); png_crc_finish(png_ptr, length); return; } - slength = length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + png_crc_read(png_ptr, buffer, length); + buffer[length] = 0; /* Null terminate the last string */ - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + if (png_crc_finish(png_ptr, 0) != 0) return; - } /* Validate the unit. */ - if (png_ptr->chunkdata[0] != 1 && png_ptr->chunkdata[0] != 2) + if (buffer[0] != 1 && buffer[0] != 2) { - png_warning(png_ptr, "Invalid sCAL ignored: invalid unit"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid unit"); return; } @@ -2130,70 +2290,65 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) i = 1; state = 0; - if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || - i >= slength || png_ptr->chunkdata[i++] != 0) - png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format"); + if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 || + i >= length || buffer[i++] != 0) + png_chunk_benign_error(png_ptr, "bad width format"); - else if (!PNG_FP_IS_POSITIVE(state)) - png_warning(png_ptr, "Invalid sCAL chunk ignored: non-positive width"); + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive width"); else { png_size_t heighti = i; state = 0; - if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || - i != slength) - png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format"); + if (png_check_fp_number((png_const_charp)buffer, length, + &state, &i) == 0 || i != length) + png_chunk_benign_error(png_ptr, "bad height format"); - else if (!PNG_FP_IS_POSITIVE(state)) - png_warning(png_ptr, - "Invalid sCAL chunk ignored: non-positive height"); + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive height"); else /* This is the (only) success case. */ - png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], - png_ptr->chunkdata+1, png_ptr->chunkdata+heighti); + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], + (png_charp)buffer+1, (png_charp)buffer+heighti); } - - /* Clean up - just free the temporarily allocated buffer. */ - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; } #endif #ifdef PNG_READ_tIME_SUPPORTED void /* PRIVATE */ -png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[7]; png_time mod_time; png_debug(1, "in png_handle_tIME"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Out of place tIME chunk"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0) { - png_warning(png_ptr, "Duplicate tIME chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; if (length != 7) { - png_warning(png_ptr, "Incorrect tIME chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 7); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; mod_time.second = buf[6]; @@ -2210,14 +2365,13 @@ png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_tEXt_SUPPORTED /* Note: this does not properly handle chunks that are > 64K under DOS */ void /* PRIVATE */ -png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; + png_text text_info; + png_bytep buffer; png_charp key; png_charp text; png_uint_32 skip = 0; - png_size_t slength; - int ret; png_debug(1, "in png_handle_tEXt"); @@ -2232,84 +2386,59 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for tEXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tEXt"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; #ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) + if (length > 65535U) { - png_warning(png_ptr, "tEXt chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; } #endif - png_free(png_ptr, png_ptr->chunkdata); + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - - if (png_ptr->chunkdata == NULL) + if (buffer == NULL) { - png_warning(png_ptr, "No memory to process text chunk"); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - slength = length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + if (png_crc_finish(png_ptr, skip) != 0) return; - } - - key = png_ptr->chunkdata; - key[slength] = 0x00; + key = (png_charp)buffer; + key[length] = 0; for (text = key; *text; text++) /* Empty loop to find end of key */ ; - if (text != key + slength) + if (text != key + length) text++; - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); - - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process text chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr->key = key; - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; - text_ptr->text = text; - text_ptr->text_length = png_strlen(text); - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + text_info.compression = PNG_TEXT_COMPRESSION_NONE; + text_info.key = key; + text_info.lang = NULL; + text_info.lang_key = NULL; + text_info.itxt_length = 0; + text_info.text = text; + text_info.text_length = strlen(text); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, text_ptr); - - if (ret) + if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0) png_warning(png_ptr, "Insufficient memory to process text chunk"); } #endif @@ -2317,13 +2446,11 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_READ_zTXt_SUPPORTED /* Note: this does not correctly handle chunks that are > 64K under DOS */ void /* PRIVATE */ -png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; - png_charp text; - int comp_type; - int ret; - png_size_t slength, prefix_len, data_len; + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 keyword_length; png_debug(1, "in png_handle_zTXt"); @@ -2338,123 +2465,101 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for zTXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before zTXt"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; -#ifdef PNG_MAX_MALLOC_64K - /* We will no doubt have problems with chunks even half this size, but - * there is no hard and fast rule to tell us where to stop. - */ - if (length > (png_uint_32)65535L) + buffer = png_read_buffer(png_ptr, length, 2/*silent*/); + + if (buffer == NULL) { - png_warning(png_ptr, "zTXt chunk too large to fit in memory"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } -#endif - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + png_crc_read(png_ptr, buffer, length); - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "Out of memory processing zTXt chunk"); + if (png_crc_finish(png_ptr, 0) != 0) return; - } - slength = length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + /* TODO: also check that the keyword contents match the spec! */ + for (keyword_length = 0; + keyword_length < length && buffer[keyword_length] != 0; + ++keyword_length) + /* Empty loop to find end of name */ ; - png_ptr->chunkdata[slength] = 0x00; + if (keyword_length > 79 || keyword_length < 1) + errmsg = "bad keyword"; - for (text = png_ptr->chunkdata; *text; text++) - /* Empty loop */ ; + /* zTXt must have some LZ data after the keyword, although it may expand to + * zero bytes; we need a '\0' at the end of the keyword, the compression type + * then the LZ data: + */ + else if (keyword_length + 3 > length) + errmsg = "truncated"; - /* zTXt must have some text after the chunkdataword */ - if (text >= png_ptr->chunkdata + slength - 2) - { - png_warning(png_ptr, "Truncated zTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE) + errmsg = "unknown compression type"; else { - comp_type = *(++text); - - if (comp_type != PNG_TEXT_COMPRESSION_zTXt) - { - png_warning(png_ptr, "Unknown compression type in zTXt chunk"); - comp_type = PNG_TEXT_COMPRESSION_zTXt; - } - - text++; /* Skip the compression_method byte */ - } - - prefix_len = text - png_ptr->chunkdata; + png_alloc_size_t uncompressed_length = PNG_SIZE_MAX; - png_decompress_chunk(png_ptr, comp_type, - (png_size_t)length, prefix_len, &data_len); + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for iCCP + * and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, keyword_length+2, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + { + png_text text; - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); + /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except + * for the extra compression type byte and the fact that it isn't + * necessarily '\0' terminated. + */ + buffer = png_ptr->read_buffer; + buffer[uncompressed_length+(keyword_length+2)] = 0; + + text.compression = PNG_TEXT_COMPRESSION_zTXt; + text.key = (png_charp)buffer; + text.text = (png_charp)(buffer + keyword_length+2); + text.text_length = uncompressed_length; + text.itxt_length = 0; + text.lang = NULL; + text.lang_key = NULL; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) + errmsg = "insufficient memory"; + } - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process zTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; + else + errmsg = png_ptr->zstream.msg; } - text_ptr->compression = comp_type; - text_ptr->key = png_ptr->chunkdata; - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; - text_ptr->text = png_ptr->chunkdata + prefix_len; - text_ptr->text_length = data_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - - if (ret) - png_error(png_ptr, "Insufficient memory to store zTXt chunk"); + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); } #endif #ifdef PNG_READ_iTXt_SUPPORTED /* Note: this does not correctly handle chunks that are > 64K under DOS */ void /* PRIVATE */ -png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; - png_charp key, lang, text, lang_key; - int comp_flag; - int comp_type = 0; - int ret; - png_size_t slength, prefix_len, data_len; + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 prefix_length; png_debug(1, "in png_handle_iTXt"); @@ -2469,279 +2574,393 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for iTXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iTXt"); + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; -#ifdef PNG_MAX_MALLOC_64K - /* We will no doubt have problems with chunks even half this size, but - * there is no hard and fast rule to tell us where to stop. - */ - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "iTXt chunk too large to fit in memory"); - png_crc_finish(png_ptr, length); - return; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); - if (png_ptr->chunkdata == NULL) + if (buffer == NULL) { - png_warning(png_ptr, "No memory to process iTXt chunk"); + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - slength = length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); + png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + if (png_crc_finish(png_ptr, 0) != 0) return; - } - - png_ptr->chunkdata[slength] = 0x00; - for (lang = png_ptr->chunkdata; *lang; lang++) + /* First the keyword. */ + for (prefix_length=0; + prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) /* Empty loop */ ; - lang++; /* Skip NUL separator */ + /* Perform a basic check on the keyword length here. */ + if (prefix_length > 79 || prefix_length < 1) + errmsg = "bad keyword"; - /* iTXt must have a language tag (possibly empty), two compression bytes, - * translated keyword (possibly empty), and possibly some text after the - * keyword + /* Expect keyword, compression flag, compression type, language, translated + * keyword (both may be empty but are 0 terminated) then the text, which may + * be empty. */ + else if (prefix_length + 5 > length) + errmsg = "truncated"; - if (lang >= png_ptr->chunkdata + slength - 3) + else if (buffer[prefix_length+1] == 0 || + (buffer[prefix_length+1] == 1 && + buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE)) { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + int compressed = buffer[prefix_length+1] != 0; + png_uint_32 language_offset, translated_keyword_offset; + png_alloc_size_t uncompressed_length = 0; - else - { - comp_flag = *lang++; - comp_type = *lang++; - } + /* Now the language tag */ + prefix_length += 3; + language_offset = prefix_length; - if (comp_type || (comp_flag && comp_flag != PNG_TEXT_COMPRESSION_zTXt)) - { - png_warning(png_ptr, "Unknown iTXt compression type or method"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; - for (lang_key = lang; *lang_key; lang_key++) - /* Empty loop */ ; + /* WARNING: the length may be invalid here, this is checked below. */ + translated_keyword_offset = ++prefix_length; - lang_key++; /* Skip NUL separator */ + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; - if (lang_key >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + /* prefix_length should now be at the trailing '\0' of the translated + * keyword, but it may already be over the end. None of this arithmetic + * can overflow because chunks are at most 2^31 bytes long, but on 16-bit + * systems the available allocation may overflow. + */ + ++prefix_length; - for (text = lang_key; *text; text++) - /* Empty loop */ ; + if (compressed == 0 && prefix_length <= length) + uncompressed_length = length - prefix_length; - text++; /* Skip NUL separator */ + else if (compressed != 0 && prefix_length < length) + { + uncompressed_length = PNG_SIZE_MAX; - if (text >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Malformed iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for + * iCCP and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, prefix_length, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + buffer = png_ptr->read_buffer; - prefix_len = text - png_ptr->chunkdata; + else + errmsg = png_ptr->zstream.msg; + } - key=png_ptr->chunkdata; + else + errmsg = "truncated"; - if (comp_flag) - png_decompress_chunk(png_ptr, comp_type, - (size_t)length, prefix_len, &data_len); + if (errmsg == NULL) + { + png_text text; - else - data_len = png_strlen(png_ptr->chunkdata + prefix_len); + buffer[uncompressed_length+prefix_length] = 0; - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); + if (compressed == 0) + text.compression = PNG_ITXT_COMPRESSION_NONE; - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + else + text.compression = PNG_ITXT_COMPRESSION_zTXt; - text_ptr->compression = (int)comp_flag + 1; - text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key); - text_ptr->lang = png_ptr->chunkdata + (lang - key); - text_ptr->itxt_length = data_len; - text_ptr->text_length = 0; - text_ptr->key = png_ptr->chunkdata; - text_ptr->text = png_ptr->chunkdata + prefix_len; + text.key = (png_charp)buffer; + text.lang = (png_charp)buffer + language_offset; + text.lang_key = (png_charp)buffer + translated_keyword_offset; + text.text = (png_charp)buffer + prefix_length; + text.text_length = 0; + text.itxt_length = uncompressed_length; - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) + errmsg = "insufficient memory"; + } + } - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + else + errmsg = "bad compression info"; - if (ret) - png_error(png_ptr, "Insufficient memory to store iTXt chunk"); + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); } #endif -/* This function is called when we haven't found a handler for a - * chunk. If there isn't a problem with the chunk itself (ie bad - * chunk name, CRC, or a critical chunk), the chunk is silently ignored - * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which - * case it will be saved away to be written out later. - */ -void /* PRIVATE */ -png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ +static int +png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) { - png_uint_32 skip = 0; + png_alloc_size_t limit = PNG_SIZE_MAX; - png_debug(1, "in png_handle_unknown"); + if (png_ptr->unknown_chunk.data != NULL) + { + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; + } -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; + +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (length <= limit) { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } + PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); + /* The following is safe because of the PNG_SIZE_MAX init above */ + png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/; + /* 'mode' is a flag array, only the bottom four bits matter here */ + png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; - if (--png_ptr->user_chunk_cache_max == 1) + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + + else { - png_warning(png_ptr, "No space in chunk cache for unknown chunk"); - png_crc_finish(png_ptr, length); - return; + /* Do a 'warn' here - it is handled below. */ + png_ptr->unknown_chunk.data = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, length)); } } -#endif - if (png_ptr->mode & PNG_HAVE_IDAT) + if (png_ptr->unknown_chunk.data == NULL && length > 0) { - if (png_ptr->chunk_name != png_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; + /* This is benign because we clean up correctly */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits"); + return 0; } - if (PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) + else { -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - && png_ptr->read_user_chunk_fn == NULL -#endif - ) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); + if (length > 0) + png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); + png_crc_finish(png_ptr, 0); + return 1; } +} +#endif /* READ_UNKNOWN_CHUNKS */ + +/* Handle an unknown, or known but disabled, chunk */ +void /* PRIVATE */ +png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, + png_uint_32 length, int keep) +{ + int handled = 0; /* the chunk was handled */ + + png_debug(1, "in png_handle_unknown"); #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - || (png_ptr->read_user_chunk_fn != NULL) -#endif - ) - { -#ifdef PNG_MAX_MALLOC_64K - if (length > 65535) - { - png_warning(png_ptr, "unknown chunk too large to fit in memory"); - skip = length - 65535; - length = 65535; - } -#endif + /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing + * the bug which meant that setting a non-default behavior for a specific + * chunk would be ignored (the default was always used unless a user + * callback was installed). + * + * 'keep' is the value from the png_chunk_unknown_handling, the setting for + * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it + * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here. + * This is just an optimization to avoid multiple calls to the lookup + * function. + */ +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); +# endif +# endif - /* TODO: this code is very close to the unknown handling in pngpread.c, - * maybe it can be put into a common utility routine? - * png_struct::unknown_chunk is just used as a temporary variable, along - * with the data into which the chunk is read. These can be eliminated. + /* One of the following methods will read the chunk or skip it (at least one + * of these is always defined because this is the only way to switch on + * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + */ +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* The user callback takes precedence over the chunk keep value, but the + * keep value is still required to validate a save of a critical chunk. */ - PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); - png_ptr->unknown_chunk.size = (png_size_t)length; + if (png_ptr->read_user_chunk_fn != NULL) + { + if (png_cache_unknown_chunk(png_ptr, length) != 0) + { + /* Callback to user unknown chunk handler */ + int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, + &png_ptr->unknown_chunk); + + /* ret is: + * negative: An error occurred; png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be discarded + * unless png_set_keep_unknown_chunks has been used to set + * a 'keep' behavior for this particular chunk, in which + * case that will be used. A critical chunk will cause an + * error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + */ + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); - if (length == 0) - png_ptr->unknown_chunk.data = NULL; + else if (ret == 0) + { + /* If the keep value is 'default' or 'never' override it, but + * still error out on critical chunks unless the keep value is + * 'always' While this is weird it is the behavior in 1.4.12. + * A possible improvement would be to obey the value set for the + * chunk, but this would be an API change that would probably + * damage some applications. + * + * The png_app_warning below catches the case that matters, where + * the application has not set specific save or ignore for this + * chunk or global save or ignore. + */ + if (keep < PNG_HANDLE_CHUNK_IF_SAFE) + { +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) + { + png_chunk_warning(png_ptr, "Saving unknown chunk:"); + png_app_warning(png_ptr, + "forcing save of an unhandled chunk;" + " please call png_set_keep_unknown_chunks"); + /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ + } +# endif + keep = PNG_HANDLE_CHUNK_IF_SAFE; + } + } + + else /* chunk was handled */ + { + handled = 1; + /* Critical chunks can be safely discarded at this point. */ + keep = PNG_HANDLE_CHUNK_NEVER; + } + } + + else + keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ + } else + /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ +# endif /* READ_USER_CHUNKS */ + +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED { - png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); - png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); + /* keep is currently just the per-chunk setting, if there was no + * setting change it to the global default now (not that this may + * still be AS_DEFAULT) then obtain the cache of the chunk if required, + * if not simply skip the chunk. + */ + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + keep = png_ptr->unknown_default; + + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { + if (png_cache_unknown_chunk(png_ptr, length) == 0) + keep = PNG_HANDLE_CHUNK_NEVER; + } + + else + png_crc_finish(png_ptr, length); } +# else +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED +# error no method to support READ_UNKNOWN_CHUNKS +# endif -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - if (png_ptr->read_user_chunk_fn != NULL) { - /* Callback to user unknown chunk handler */ - int ret; - - ret = (*(png_ptr->read_user_chunk_fn)) - (png_ptr, &png_ptr->unknown_chunk); + /* If here there is no read callback pointer set and no support is + * compiled in to just save the unknown chunks, so simply skip this + * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then + * the app has erroneously asked for unknown chunk saving when there + * is no support. + */ + if (keep > PNG_HANDLE_CHUNK_NEVER) + png_app_error(png_ptr, "no unknown chunk support available"); - if (ret < 0) - png_chunk_error(png_ptr, "error in user chunk"); + png_crc_finish(png_ptr, length); + } +# endif - if (ret == 0) +# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Now store the chunk in the chunk list if appropriate, and if the limits + * permit it. + */ + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { +# ifdef PNG_USER_LIMITS_SUPPORTED + switch (png_ptr->user_chunk_cache_max) { - if (PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) - { -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - } + case 2: + png_ptr->user_chunk_cache_max = 1; + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + /* FALL THROUGH */ + case 1: + /* NOTE: prior to 1.6.0 this case resulted in an unknown critical + * chunk being skipped, now there will be a hard error below. + */ + break; - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); + default: /* not at limit */ + --(png_ptr->user_chunk_cache_max); + /* FALL THROUGH */ + case 0: /* no limit */ +# endif /* USER_LIMITS */ + /* Here when the limit isn't reached or when limits are compiled + * out; store the chunk. + */ + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + handled = 1; +# ifdef PNG_USER_LIMITS_SUPPORTED + break; } +# endif } +# else /* no store support: the chunk must be handled by the user callback */ + PNG_UNUSED(info_ptr) +# endif - else -#endif - png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); - + /* Regardless of the error handling below the cached data (if any) can be + * freed now. Notice that the data is not freed if there is a png_error, but + * it will be freed by destroy_read_struct. + */ + if (png_ptr->unknown_chunk.data != NULL) png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - - else -#endif - skip = length; + png_ptr->unknown_chunk.data = NULL; - png_crc_finish(png_ptr, skip); +#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ + /* There is no support to read an unknown chunk, so just skip it. */ + png_crc_finish(png_ptr, length); + PNG_UNUSED(info_ptr) + PNG_UNUSED(keep) +#endif /* !READ_UNKNOWN_CHUNKS */ -#ifndef PNG_READ_USER_CHUNKS_SUPPORTED - PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */ -#endif + /* Check for unhandled critical chunks */ + if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) + png_chunk_error(png_ptr, "unhandled critical chunk"); } /* This function is called to verify that a chunk name is valid. @@ -2757,7 +2976,7 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) */ void /* PRIVATE */ -png_check_chunk_name(png_structp png_ptr, png_uint_32 chunk_name) +png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name) { int i; @@ -2782,11 +3001,11 @@ png_check_chunk_name(png_structp png_ptr, png_uint_32 chunk_name) * 'display' is false only those pixels present in the pass are filled in. */ void /* PRIVATE */ -png_combine_row(png_structp png_ptr, png_bytep dp, int display) +png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) { unsigned int pixel_depth = png_ptr->transformed_pixel_depth; png_const_bytep sp = png_ptr->row_buf + 1; - png_uint_32 row_width = png_ptr->width; + png_alloc_size_t row_width = png_ptr->width; unsigned int pass = png_ptr->pass; png_bytep end_ptr = 0; png_byte end_byte = 0; @@ -2823,7 +3042,8 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; end_byte = *end_ptr; # ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) /* little-endian byte */ + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + /* little-endian byte */ end_mask = 0xff << end_mask; else /* big-endian byte */ @@ -2832,17 +3052,18 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) /* end_mask is now the bits to *keep* from the destination row */ } - /* For non-interlaced images this reduces to a png_memcpy(). A png_memcpy() + /* For non-interlaced images this reduces to a memcpy(). A memcpy() * will also happen if interlacing isn't supported or if the application * does not call png_set_interlace_handling(). In the latter cases the * caller just gets a sequence of the unexpanded rows from each interlace * pass. */ #ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE) && - pass < 6 && (display == 0 || - /* The following copies everything for 'display' on passes 0, 2 and 4. */ - (display == 1 && (pass & 1) != 0))) + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0 && + pass < 6 && (display == 0 || + /* The following copies everything for 'display' on passes 0, 2 and 4. */ + (display == 1 && (pass & 1) != 0))) { /* Narrow images may have no bits in a pass; the caller should handle * this, but this test is cheap: @@ -2938,7 +3159,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) # define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } -# define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) } +# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) } # define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) @@ -2974,10 +3195,10 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) */ # define MASK(pass,depth,display,png)\ ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) -#endif /* !PNG_USE_COMPILE_TIME_MASKS */ +#endif /* !USE_COMPILE_TIME_MASKS */ /* Use the appropriate mask to copy the required bits. In some cases - * the byte mask will be 0 or 0xff, optimize these cases. row_width is + * the byte mask will be 0 or 0xff; optimize these cases. row_width is * the number of pixels, but the code copies bytes, so it is necessary * to special case the end. */ @@ -2985,7 +3206,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) png_uint_32 mask; # ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) mask = MASK(pass, pixel_depth, display, 0); else @@ -3049,7 +3270,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) } /* Work out the bytes to copy. */ - if (display) + if (display != 0) { /* When doing the 'block' algorithm the pixel in the pass gets * replicated to adjacent pixels. This is why the even (0,2,4,6) @@ -3059,7 +3280,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) /* But don't allow this number to exceed the actual row width. */ if (bytes_to_copy > row_width) - bytes_to_copy = row_width; + bytes_to_copy = (unsigned int)/*SAFE*/row_width; } else /* normal row; Adam7 only ever gives us one pixel to copy. */ @@ -3116,7 +3337,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) /* This can only be the RGB case, so each copy is exactly one * pixel and it is not necessary to check for a partial copy. */ - for(;;) + for (;;) { dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2]; @@ -3133,26 +3354,27 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) /* Check for double byte alignment and, if possible, use a * 16-bit copy. Don't attempt this for narrow images - ones that * are less than an interlace panel wide. Don't attempt it for - * wide bytes_to_copy either - use the png_memcpy there. + * wide bytes_to_copy either - use the memcpy there. */ - if (bytes_to_copy < 16 /*else use png_memcpy*/ && - png_isaligned(dp, png_uint_16) && - png_isaligned(sp, png_uint_16) && - bytes_to_copy % sizeof (png_uint_16) == 0 && - bytes_to_jump % sizeof (png_uint_16) == 0) + if (bytes_to_copy < 16 /*else use memcpy*/ && + png_isaligned(dp, png_uint_16) && + png_isaligned(sp, png_uint_16) && + bytes_to_copy % (sizeof (png_uint_16)) == 0 && + bytes_to_jump % (sizeof (png_uint_16)) == 0) { /* Everything is aligned for png_uint_16 copies, but try for * png_uint_32 first. */ - if (png_isaligned(dp, png_uint_32) && - png_isaligned(sp, png_uint_32) && - bytes_to_copy % sizeof (png_uint_32) == 0 && - bytes_to_jump % sizeof (png_uint_32) == 0) + if (png_isaligned(dp, png_uint_32) != 0 && + png_isaligned(sp, png_uint_32) != 0 && + bytes_to_copy % (sizeof (png_uint_32)) == 0 && + bytes_to_jump % (sizeof (png_uint_32)) == 0) { - png_uint_32p dp32 = (png_uint_32p)dp; - png_const_uint_32p sp32 = (png_const_uint_32p)sp; - unsigned int skip = (bytes_to_jump-bytes_to_copy) / - sizeof (png_uint_32); + png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); + png_const_uint_32p sp32 = png_aligncastconst( + png_const_uint_32p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_32)); do { @@ -3160,7 +3382,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) do { *dp32++ = *sp32++; - c -= sizeof (png_uint_32); + c -= (sizeof (png_uint_32)); } while (c > 0); @@ -3190,10 +3412,11 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) */ else { - png_uint_16p dp16 = (png_uint_16p)dp; - png_const_uint_16p sp16 = (png_const_uint_16p)sp; - unsigned int skip = (bytes_to_jump-bytes_to_copy) / - sizeof (png_uint_16); + png_uint_16p dp16 = png_aligncast(png_uint_16p, dp); + png_const_uint_16p sp16 = png_aligncastconst( + png_const_uint_16p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_16)); do { @@ -3201,7 +3424,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) do { *dp16++ = *sp16++; - c -= sizeof (png_uint_16); + c -= (sizeof (png_uint_16)); } while (c > 0); @@ -3223,12 +3446,12 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) return; } } -#endif /* PNG_ALIGN_ code */ +#endif /* ALIGN_TYPE code */ - /* The true default - use a png_memcpy: */ + /* The true default - use a memcpy: */ for (;;) { - png_memcpy(dp, sp, bytes_to_copy); + memcpy(dp, sp, bytes_to_copy); if (row_width <= bytes_to_jump) return; @@ -3237,7 +3460,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) dp += bytes_to_jump; row_width -= bytes_to_jump; if (bytes_to_copy > row_width) - bytes_to_copy = row_width; + bytes_to_copy = (unsigned int)/*SAFE*/row_width; } } @@ -3247,13 +3470,13 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display) /* Here if pixel_depth < 8 to check 'end_ptr' below. */ } else -#endif +#endif /* READ_INTERLACING */ - /* If here then the switch above wasn't used so just png_memcpy the whole row + /* If here then the switch above wasn't used so just memcpy the whole row * from the temporary row buffer (notice that this overwrites the end of the * destination row if it is a partial byte.) */ - png_memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); + memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); /* Restore the overwritten bits from the last byte if necessary. */ if (end_ptr != NULL) @@ -3290,7 +3513,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, int j; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)((row_info->width + 7) & 0x07); dshift = (int)((final_width + 7) & 0x07); @@ -3314,8 +3537,9 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, v = (png_byte)((*sp >> sshift) & 0x01); for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { @@ -3349,7 +3573,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, png_uint_32 i; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)(((row_info->width + 3) & 0x03) << 1); dshift = (int)(((final_width + 3) & 0x03) << 1); @@ -3376,8 +3600,9 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, v = (png_byte)((*sp >> sshift) & 0x03); for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { @@ -3411,7 +3636,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, int jstop = png_pass_inc[pass]; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)(((row_info->width + 1) & 0x01) << 2); dshift = (int)(((final_width + 1) & 0x01) << 2); @@ -3437,8 +3662,9 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { @@ -3476,14 +3702,14 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, for (i = 0; i < row_info->width; i++) { - png_byte v[8]; + png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */ int j; - png_memcpy(v, sp, pixel_bytes); + memcpy(v, sp, pixel_bytes); for (j = 0; j < jstop; j++) { - png_memcpy(dp, v, pixel_bytes); + memcpy(dp, v, pixel_bytes); dp -= pixel_bytes; } @@ -3500,7 +3726,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, PNG_UNUSED(transformations) /* Silence compiler warning */ #endif } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ +#endif /* READ_INTERLACING */ static void png_read_filter_row_sub(png_row_infop row_info, png_bytep row, @@ -3654,74 +3880,22 @@ png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, if (pb < pa) pa = pb, a = b; if (pc < pa) a = c; - c = b; a += *row; *row++ = (png_byte)a; } } -#ifdef PNG_ARM_NEON - -#ifdef __linux__ -#include -#include -#include - -static int png_have_hwcap(unsigned cap) -{ - FILE *f = fopen("/proc/self/auxv", "r"); - Elf32_auxv_t aux; - int have_cap = 0; - - if (!f) - return 0; - - while (fread(&aux, sizeof(aux), 1, f) > 0) - { - if (aux.a_type == AT_HWCAP && - aux.a_un.a_val & cap) - { - have_cap = 1; - break; - } - } - - fclose(f); - - return have_cap; -} -#endif /* __linux__ */ - -static void -png_init_filter_functions_neon(png_structp pp, unsigned int bpp) -{ -#ifdef __linux__ - if (!png_have_hwcap(HWCAP_NEON)) - return; -#endif - - pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon; - - if (bpp == 3) - { - pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon; - pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon; - pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = - png_read_filter_row_paeth3_neon; - } - - else if (bpp == 4) - { - pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon; - pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon; - pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = - png_read_filter_row_paeth4_neon; - } -} -#endif /* PNG_ARM_NEON */ - static void -png_init_filter_functions(png_structp pp) +png_init_filter_functions(png_structrp pp) + /* This function is called once for every PNG image (except for PNG images + * that only use PNG_FILTER_VALUE_NONE for all rows) to set the + * implementations required to reverse the filtering of PNG rows. Reversing + * the filter is the first transformation performed on the row data. It is + * performed in place, therefore an implementation can be selected based on + * the image pixel format. If the implementation depends on image width then + * take care to ensure that it works correctly if the image is interlaced - + * interlacing causes the actual row width to vary. + */ { unsigned int bpp = (pp->pixel_depth + 7) >> 3; @@ -3735,26 +3909,217 @@ png_init_filter_functions(png_structp pp) pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth_multibyte_pixel; -#ifdef PNG_ARM_NEON - png_init_filter_functions_neon(pp, bpp); +#ifdef PNG_FILTER_OPTIMIZATIONS + /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to + * call to install hardware optimizations for the above functions; simply + * replace whatever elements of the pp->read_filter[] array with a hardware + * specific (or, for that matter, generic) optimization. + * + * To see an example of this examine what configure.ac does when + * --enable-arm-neon is specified on the command line. + */ + PNG_FILTER_OPTIMIZATIONS(pp, bpp); #endif } void /* PRIVATE */ -png_read_filter_row(png_structp pp, png_row_infop row_info, png_bytep row, +png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, png_const_bytep prev_row, int filter) { - if (pp->read_filter[0] == NULL) - png_init_filter_functions(pp); + /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define + * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic + * implementations. See png_init_filter_functions above. + */ if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) + { + if (pp->read_filter[0] == NULL) + png_init_filter_functions(pp); + pp->read_filter[filter-1](row_info, row, prev_row); + } } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED void /* PRIVATE */ -png_read_finish_row(png_structp png_ptr) +png_read_IDAT_data(png_structrp png_ptr, png_bytep output, + png_alloc_size_t avail_out) +{ + /* Loop reading IDATs and decompressing the result into output[avail_out] */ + png_ptr->zstream.next_out = output; + png_ptr->zstream.avail_out = 0; /* safety: set below */ + + if (output == NULL) + avail_out = 0; + + do + { + int ret; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + if (png_ptr->zstream.avail_in == 0) + { + uInt avail_in; + png_bytep buffer; + + while (png_ptr->idat_size == 0) + { + png_crc_finish(png_ptr, 0); + + png_ptr->idat_size = png_read_chunk_header(png_ptr); + /* This is an error even in the 'check' case because the code just + * consumed a non-IDAT header. + */ + if (png_ptr->chunk_name != png_IDAT) + png_error(png_ptr, "Not enough image data"); + } + + avail_in = png_ptr->IDAT_read_size; + + if (avail_in > png_ptr->idat_size) + avail_in = (uInt)png_ptr->idat_size; + + /* A PNG with a gradually increasing IDAT size will defeat this attempt + * to minimize memory usage by causing lots of re-allocs, but + * realistically doing IDAT_read_size re-allocs is not likely to be a + * big problem. + */ + buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); + + png_crc_read(png_ptr, buffer, avail_in); + png_ptr->idat_size -= avail_in; + + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = avail_in; + } + + /* And set up the output side. */ + if (output != NULL) /* standard read */ + { + uInt out = ZLIB_IO_MAX; + + if (out > avail_out) + out = (uInt)avail_out; + + avail_out -= out; + png_ptr->zstream.avail_out = out; + } + + else /* after last row, checking for end */ + { + png_ptr->zstream.next_out = tmpbuf; + png_ptr->zstream.avail_out = (sizeof tmpbuf); + } + + /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the + * process. If the LZ stream is truncated the sequential reader will + * terminally damage the stream, above, by reading the chunk header of the + * following chunk (it then exits with png_error). + * + * TODO: deal more elegantly with truncated IDAT lists. + */ + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); + + /* Take the unconsumed output back. */ + if (output != NULL) + avail_out += png_ptr->zstream.avail_out; + + else /* avail_out counts the extra bytes */ + avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out; + + png_ptr->zstream.avail_out = 0; + + if (ret == Z_STREAM_END) + { + /* Do this for safety; we won't read any more into this row. */ + png_ptr->zstream.next_out = NULL; + + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + + if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) + png_chunk_benign_error(png_ptr, "Extra compressed data"); + break; + } + + if (ret != Z_OK) + { + png_zstream_error(png_ptr, ret); + + if (output != NULL) + png_chunk_error(png_ptr, png_ptr->zstream.msg); + + else /* checking */ + { + png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); + return; + } + } + } while (avail_out > 0); + + if (avail_out > 0) + { + /* The stream ended before the image; this is the same as too few IDATs so + * should be handled the same way. + */ + if (output != NULL) + png_error(png_ptr, "Not enough image data"); + + else /* the deflate stream contained extra data */ + png_chunk_benign_error(png_ptr, "Too much image data"); + } +} + +void /* PRIVATE */ +png_read_finish_IDAT(png_structrp png_ptr) +{ + /* We don't need any more data and the stream should have ended, however the + * LZ end code may actually not have been processed. In this case we must + * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk + * may still remain to be consumed. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in + * the compressed stream, but the stream may be damaged too, so even after + * this call we may need to terminate the zstream ownership. + */ + png_read_IDAT_data(png_ptr, NULL, 0); + png_ptr->zstream.next_out = NULL; /* safety */ + + /* Now clear everything out for safety; the following may not have been + * done. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + } + + /* If the zstream has not been released do it now *and* terminate the reading + * of the final IDAT chunk. + */ + if (png_ptr->zowner == png_IDAT) + { + /* Always do this; the pointers otherwise point into the read buffer. */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + + /* Now we no longer own the zstream. */ + png_ptr->zowner = 0; + + /* The slightly weird semantics of the sequential IDAT reading is that we + * are always in or at the end of an IDAT chunk, so we always need to do a + * crc_finish here. If idat_size is non-zero we also need to read the + * spurious bytes at the end of the chunk now. + */ + (void)png_crc_finish(png_ptr, png_ptr->idat_size); + } +} + +void /* PRIVATE */ +png_read_finish_row(png_structrp png_ptr) { -#ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ @@ -3768,22 +4133,20 @@ png_read_finish_row(png_structp png_ptr) /* Offset to next interlace block in the y direction */ static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif /* PNG_READ_INTERLACING_SUPPORTED */ png_debug(1, "in png_read_finish_row"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; /* TO DO: don't do this if prev_row isn't needed (requires * read-ahead of the next row's filter byte. */ - png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); do { @@ -3797,7 +4160,7 @@ png_read_finish_row(png_structp png_ptr) png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[png_ptr->pass] - 1 - @@ -3813,80 +4176,15 @@ png_read_finish_row(png_structp png_ptr) if (png_ptr->pass < 7) return; } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - { - char extra; - int ret; - - png_ptr->zstream.next_out = (Byte *)&extra; - png_ptr->zstream.avail_out = (uInt)1; - - for (;;) - { - if (!(png_ptr->zstream.avail_in)) - { - while (!png_ptr->idat_size) - { - png_crc_finish(png_ptr, 0); - png_ptr->idat_size = png_read_chunk_header(png_ptr); - if (png_ptr->chunk_name != png_IDAT) - png_error(png_ptr, "Not enough image data"); - } - - png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_in = png_ptr->zbuf; - - if (png_ptr->zbuf_size > png_ptr->idat_size) - png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; - - png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in); - png_ptr->idat_size -= png_ptr->zstream.avail_in; - } - - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - - if (ret == Z_STREAM_END) - { - if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || - png_ptr->idat_size) - png_warning(png_ptr, "Extra compressed data"); - - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - - if (ret != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : - "Decompression Error"); - - if (!(png_ptr->zstream.avail_out)) - { - png_warning(png_ptr, "Extra compressed data"); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - - } - png_ptr->zstream.avail_out = 0; - } - - if (png_ptr->idat_size || png_ptr->zstream.avail_in) - png_warning(png_ptr, "Extra compression data"); - inflateReset(&png_ptr->zstream); - - png_ptr->mode |= PNG_AFTER_IDAT; + /* Here after at the end of the last row of the last pass. */ + png_read_finish_IDAT(png_ptr); } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ void /* PRIVATE */ -png_read_start_row(png_structp png_ptr) +png_read_start_row(png_structrp png_ptr) { -#ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ @@ -3900,20 +4198,18 @@ png_read_start_row(png_structp png_ptr) /* Offset to next interlace block in the y direction */ static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif int max_pixel_depth; png_size_t row_bytes; png_debug(1, "in png_read_start_row"); - png_ptr->zstream.avail_in = 0; + #ifdef PNG_READ_TRANSFORMS_SUPPORTED png_init_read_transformations(png_ptr); #endif -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; @@ -3927,7 +4223,6 @@ png_read_start_row(png_structp png_ptr) } else -#endif /* PNG_READ_INTERLACING_SUPPORTED */ { png_ptr->num_rows = png_ptr->height; png_ptr->iwidth = png_ptr->width; @@ -3935,7 +4230,7 @@ png_read_start_row(png_structp png_ptr) max_pixel_depth = png_ptr->pixel_depth; - /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of + /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of * calculations to calculate the final pixel depth, then * png_do_read_transforms actually does the transforms. This means that the * code which effectively calculates this value is actually repeated in three @@ -3946,16 +4241,16 @@ png_read_start_row(png_structp png_ptr) * TODO: fix this. */ #ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) + if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8) max_pixel_depth = 8; #endif #ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) + if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) max_pixel_depth = 32; else @@ -3967,13 +4262,13 @@ png_read_start_row(png_structp png_ptr) if (max_pixel_depth < 8) max_pixel_depth = 8; - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) max_pixel_depth *= 2; } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) { max_pixel_depth *= 4; max_pixel_depth /= 3; @@ -3983,13 +4278,13 @@ png_read_start_row(png_structp png_ptr) #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND_16) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) { # ifdef PNG_READ_EXPAND_SUPPORTED /* In fact it is an error if it isn't supported, but checking is * the safe way. */ - if (png_ptr->transformations & PNG_EXPAND) + if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (png_ptr->bit_depth < 16) max_pixel_depth *= 2; @@ -4001,7 +4296,7 @@ png_read_start_row(png_structp png_ptr) #endif #ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & (PNG_FILLER)) + if ((png_ptr->transformations & (PNG_FILLER)) != 0) { if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) { @@ -4025,14 +4320,15 @@ png_read_start_row(png_structp png_ptr) #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) { if ( #ifdef PNG_READ_EXPAND_SUPPORTED - (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || + (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) || #endif #ifdef PNG_READ_FILLER_SUPPORTED - (png_ptr->transformations & (PNG_FILLER)) || + (png_ptr->transformations & (PNG_FILLER)) != 0 || #endif png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { @@ -4065,7 +4361,7 @@ png_read_start_row(png_structp png_ptr) #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) { int user_pixel_depth = png_ptr->user_transform_depth * png_ptr->user_transform_channels; @@ -4101,7 +4397,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) png_free(png_ptr, png_ptr->big_row_buf); png_free(png_ptr, png_ptr->big_prev_row); - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, row_bytes + 48); @@ -4144,7 +4440,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1)) png_error(png_ptr, "Row has too many bytes to allocate in memory"); - png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); png_debug1(3, "width = %u,", png_ptr->width); png_debug1(3, "height = %u,", png_ptr->height); @@ -4154,6 +4450,27 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) png_debug1(3, "irowbytes = %lu", (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + /* The sequential reader needs a buffer for IDAT, but the progressive reader + * does not, so free the read buffer now regardless; the sequential reader + * reallocates it on demand. + */ + if (png_ptr->read_buffer != 0) + { + png_bytep buffer = png_ptr->read_buffer; + + png_ptr->read_buffer_size = 0; + png_ptr->read_buffer = NULL; + png_free(png_ptr, buffer); + } + + /* Finally claim the zstream for the inflate of the IDAT data, use the bits + * value from the stream (note that this will result in a fatal error if the + * IDAT stream has a bogus deflate header window_bits value, but this should + * not be happening any longer!) + */ + if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + png_ptr->flags |= PNG_FLAG_ROW_INIT; } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ diff --git a/src/3rdparty/libpng/pngset.c b/src/3rdparty/libpng/pngset.c index e0118fa8c2..fce3039168 100644 --- a/src/3rdparty/libpng/pngset.c +++ b/src/3rdparty/libpng/pngset.c @@ -1,8 +1,8 @@ /* pngset.c - storage of image information into info struct * - * Last changed in libpng 1.5.10 [(PENDING RELEASE)] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -22,50 +22,51 @@ #ifdef PNG_bKGD_SUPPORTED void PNGAPI -png_set_bKGD(png_structp png_ptr, png_infop info_ptr, +png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, png_const_color_16p background) { png_debug1(1, "in %s storage function", "bKGD"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || background == NULL) return; - png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16)); + info_ptr->background = *background; info_ptr->valid |= PNG_INFO_bKGD; } #endif #ifdef PNG_cHRM_SUPPORTED void PNGFAPI -png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, +png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, png_fixed_point blue_y) { + png_xy xy; + png_debug1(1, "in %s storage function", "cHRM fixed"); if (png_ptr == NULL || info_ptr == NULL) return; -# ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, - white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y)) -# endif - { - info_ptr->x_white = white_x; - info_ptr->y_white = white_y; - info_ptr->x_red = red_x; - info_ptr->y_red = red_y; - info_ptr->x_green = green_x; - info_ptr->y_green = green_y; - info_ptr->x_blue = blue_x; - info_ptr->y_blue = blue_y; - info_ptr->valid |= PNG_INFO_cHRM; - } + xy.redx = red_x; + xy.redy = red_y; + xy.greenx = green_x; + xy.greeny = green_y; + xy.bluex = blue_x; + xy.bluey = blue_y; + xy.whitex = white_x; + xy.whitey = white_y; + + if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy, + 2/* override with app values*/) != 0) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); } void PNGFAPI -png_set_cHRM_XYZ_fixed(png_structp png_ptr, png_infop info_ptr, +png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, png_fixed_point int_red_Z, png_fixed_point int_green_X, png_fixed_point int_green_Y, png_fixed_point int_green_Z, @@ -73,33 +74,32 @@ png_set_cHRM_XYZ_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point int_blue_Z) { png_XYZ XYZ; - png_xy xy; png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); if (png_ptr == NULL || info_ptr == NULL) return; - XYZ.redX = int_red_X; - XYZ.redY = int_red_Y; - XYZ.redZ = int_red_Z; - XYZ.greenX = int_green_X; - XYZ.greenY = int_green_Y; - XYZ.greenZ = int_green_Z; - XYZ.blueX = int_blue_X; - XYZ.blueY = int_blue_Y; - XYZ.blueZ = int_blue_Z; - - if (png_xy_from_XYZ(&xy, XYZ)) - png_error(png_ptr, "XYZ values out of representable range"); - - png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy, - xy.greenx, xy.greeny, xy.bluex, xy.bluey); + XYZ.red_X = int_red_X; + XYZ.red_Y = int_red_Y; + XYZ.red_Z = int_red_Z; + XYZ.green_X = int_green_X; + XYZ.green_Y = int_green_Y; + XYZ.green_Z = int_green_Z; + XYZ.blue_X = int_blue_X; + XYZ.blue_Y = int_blue_Y; + XYZ.blue_Z = int_blue_Z; + + if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, + &XYZ, 2) != 0) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_cHRM(png_structp png_ptr, png_infop info_ptr, +png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, double green_y, double blue_x, double blue_y) { @@ -115,7 +115,7 @@ png_set_cHRM(png_structp png_ptr, png_infop info_ptr, } void PNGAPI -png_set_cHRM_XYZ(png_structp png_ptr, png_infop info_ptr, double red_X, +png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, double red_Y, double red_Z, double green_X, double green_Y, double green_Z, double blue_X, double blue_Y, double blue_Z) { @@ -130,41 +130,27 @@ png_set_cHRM_XYZ(png_structp png_ptr, png_infop info_ptr, double red_X, png_fixed(png_ptr, blue_Y, "cHRM Red Y"), png_fixed(png_ptr, blue_Z, "cHRM Red Z")); } -# endif /* PNG_FLOATING_POINT_SUPPORTED */ +# endif /* FLOATING_POINT */ -#endif /* PNG_cHRM_SUPPORTED */ +#endif /* cHRM */ #ifdef PNG_gAMA_SUPPORTED void PNGFAPI -png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point - file_gamma) +png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point file_gamma) { png_debug1(1, "in %s storage function", "gAMA"); if (png_ptr == NULL || info_ptr == NULL) return; - /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't - * occur. Since the fixed point representation is assymetrical it is - * possible for 1/gamma to overflow the limit of 21474 and this means the - * gamma value must be at least 5/100000 and hence at most 20000.0. For - * safety the limits here are a little narrower. The values are 0.00016 to - * 6250.0, which are truly ridiculous gammma values (and will produce - * displays that are all black or all white.) - */ - if (file_gamma < 16 || file_gamma > 625000000) - png_warning(png_ptr, "Out of range gamma value ignored"); - - else - { - info_ptr->gamma = file_gamma; - info_ptr->valid |= PNG_INFO_gAMA; - } + png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma); + png_colorspace_sync_info(png_ptr, info_ptr); } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) +png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) { png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, "png_set_gAMA")); @@ -174,7 +160,8 @@ png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) #ifdef PNG_hIST_SUPPORTED void PNGAPI -png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_const_uint_16p hist) +png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_uint_16p hist) { int i; @@ -197,26 +184,27 @@ png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_const_uint_16p hist) /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in * version 1.2.1 */ - png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr, - PNG_MAX_PALETTE_LENGTH * png_sizeof(png_uint_16)); + info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); - if (png_ptr->hist == NULL) + if (info_ptr->hist == NULL) { png_warning(png_ptr, "Insufficient memory for hIST chunk data"); + return; } + info_ptr->free_me |= PNG_FREE_HIST; + for (i = 0; i < info_ptr->num_palette; i++) - png_ptr->hist[i] = hist[i]; + info_ptr->hist[i] = hist[i]; - info_ptr->hist = png_ptr->hist; info_ptr->valid |= PNG_INFO_hIST; - info_ptr->free_me |= PNG_FREE_HIST; } #endif void PNGAPI -png_set_IHDR(png_structp png_ptr, png_infop info_ptr, +png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, int filter_type) @@ -241,32 +229,23 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr, if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_ptr->channels = 3; else info_ptr->channels = 1; - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) info_ptr->channels++; info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); - /* Check for potential overflow */ - if (width > - (PNG_UINT_32_MAX >> 3) /* 8-byte RRGGBBAA pixels */ - - 48 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - info_ptr->rowbytes = 0; - else - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); } #ifdef PNG_oFFs_SUPPORTED void PNGAPI -png_set_oFFs(png_structp png_ptr, png_infop info_ptr, +png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, int unit_type) { png_debug1(1, "in %s storage function", "oFFs"); @@ -283,7 +262,7 @@ png_set_oFFs(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_pCAL_SUPPORTED void PNGAPI -png_set_pCAL(png_structp png_ptr, png_infop info_ptr, +png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params) { @@ -292,10 +271,11 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, png_debug1(1, "in %s storage function", "pCAL"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL + || (nparams > 0 && params == NULL)) return; - length = png_strlen(purpose) + 1; + length = strlen(purpose) + 1; png_debug1(3, "allocating purpose for info (%lu bytes)", (unsigned long)length); @@ -305,20 +285,28 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, if (type < 0 || type > 3) png_error(png_ptr, "Invalid pCAL equation type"); + if (nparams < 0 || nparams > 255) + png_error(png_ptr, "Invalid pCAL parameter count"); + /* Validate params[nparams] */ for (i=0; ipcal_purpose = (png_charp)png_malloc_warn(png_ptr, length); + info_ptr->pcal_purpose = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); if (info_ptr->pcal_purpose == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL purpose"); + return; } - png_memcpy(info_ptr->pcal_purpose, purpose, length); + memcpy(info_ptr->pcal_purpose, purpose, length); png_debug(3, "storing X0, X1, type, and nparams in info"); info_ptr->pcal_X0 = X0; @@ -326,34 +314,37 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, info_ptr->pcal_type = (png_byte)type; info_ptr->pcal_nparams = (png_byte)nparams; - length = png_strlen(units) + 1; + length = strlen(units) + 1; png_debug1(3, "allocating units for info (%lu bytes)", (unsigned long)length); - info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length); + info_ptr->pcal_units = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); if (info_ptr->pcal_units == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL units"); + return; } - png_memcpy(info_ptr->pcal_units, units, length); + memcpy(info_ptr->pcal_units, units, length); - info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr, - (png_size_t)((nparams + 1) * png_sizeof(png_charp))); + info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + (png_size_t)((nparams + 1) * (sizeof (png_charp))))); if (info_ptr->pcal_params == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL params"); + return; } - png_memset(info_ptr->pcal_params, 0, (nparams + 1) * png_sizeof(png_charp)); + memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp))); for (i = 0; i < nparams; i++) { - length = png_strlen(params[i]) + 1; + length = strlen(params[i]) + 1; png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, (unsigned long)length); @@ -362,10 +353,11 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, if (info_ptr->pcal_params[i] == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL parameter"); + return; } - png_memcpy(info_ptr->pcal_params[i], params[i], length); + memcpy(info_ptr->pcal_params[i], params[i], length); } info_ptr->valid |= PNG_INFO_pCAL; @@ -375,7 +367,7 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_sCAL_SUPPORTED void PNGAPI -png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, +png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_const_charp swidth, png_const_charp sheight) { png_size_t lengthw = 0, lengthh = 0; @@ -391,11 +383,11 @@ png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, if (unit != 1 && unit != 2) png_error(png_ptr, "Invalid sCAL unit"); - if (swidth == NULL || (lengthw = png_strlen(swidth)) == 0 || + if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) png_error(png_ptr, "Invalid sCAL width"); - if (sheight == NULL || (lengthh = png_strlen(sheight)) == 0 || + if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) png_error(png_ptr, "Invalid sCAL height"); @@ -405,21 +397,24 @@ png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); - info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, lengthw); + info_ptr->scal_s_width = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthw)); if (info_ptr->scal_s_width == NULL) { png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; } - png_memcpy(info_ptr->scal_s_width, swidth, lengthw); + memcpy(info_ptr->scal_s_width, swidth, lengthw); ++lengthh; png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); - info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, lengthh); + info_ptr->scal_s_height = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthh)); if (info_ptr->scal_s_height == NULL) { @@ -427,10 +422,11 @@ png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, info_ptr->scal_s_width = NULL; png_warning(png_ptr, "Memory allocation failed while processing sCAL"); + return; } - png_memcpy(info_ptr->scal_s_height, sheight, lengthh); + memcpy(info_ptr->scal_s_height, sheight, lengthh); info_ptr->valid |= PNG_INFO_sCAL; info_ptr->free_me |= PNG_FREE_SCAL; @@ -438,8 +434,8 @@ png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_sCAL(png_structp png_ptr, png_infop info_ptr, int unit, double width, - double height) +png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + double width, double height) { png_debug1(1, "in %s storage function", "sCAL"); @@ -456,9 +452,9 @@ png_set_sCAL(png_structp png_ptr, png_infop info_ptr, int unit, double width, char swidth[PNG_sCAL_MAX_DIGITS+1]; char sheight[PNG_sCAL_MAX_DIGITS+1]; - png_ascii_from_fp(png_ptr, swidth, sizeof swidth, width, + png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, PNG_sCAL_PRECISION); - png_ascii_from_fp(png_ptr, sheight, sizeof sheight, height, + png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, PNG_sCAL_PRECISION); png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); @@ -468,7 +464,7 @@ png_set_sCAL(png_structp png_ptr, png_infop info_ptr, int unit, double width, # ifdef PNG_FIXED_POINT_SUPPORTED void PNGAPI -png_set_sCAL_fixed(png_structp png_ptr, png_infop info_ptr, int unit, +png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_fixed_point width, png_fixed_point height) { png_debug1(1, "in %s storage function", "sCAL"); @@ -486,8 +482,8 @@ png_set_sCAL_fixed(png_structp png_ptr, png_infop info_ptr, int unit, char swidth[PNG_sCAL_MAX_DIGITS+1]; char sheight[PNG_sCAL_MAX_DIGITS+1]; - png_ascii_from_fixed(png_ptr, swidth, sizeof swidth, width); - png_ascii_from_fixed(png_ptr, sheight, sizeof sheight, height); + png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); + png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); } @@ -497,7 +493,7 @@ png_set_sCAL_fixed(png_structp png_ptr, png_infop info_ptr, int unit, #ifdef PNG_pHYs_SUPPORTED void PNGAPI -png_set_pHYs(png_structp png_ptr, png_infop info_ptr, +png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type) { png_debug1(1, "in %s storage function", "pHYs"); @@ -513,7 +509,7 @@ png_set_pHYs(png_structp png_ptr, png_infop info_ptr, #endif void PNGAPI -png_set_PLTE(png_structp png_ptr, png_infop info_ptr, +png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_const_colorp palette, int num_palette) { @@ -530,13 +526,27 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, else { png_warning(png_ptr, "Invalid palette length"); + return; } } + if ((num_palette > 0 && palette == NULL) || + (num_palette == 0 +# ifdef PNG_MNG_FEATURES_SUPPORTED + && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 +# endif + )) + { + png_error(png_ptr, "Invalid palette"); + } + /* It may not actually be necessary to set png_ptr->palette here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. + * + * 1.6.0: the above statement appears to be incorrect; something has to set + * the palette inside png_struct on read. */ png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); @@ -544,10 +554,11 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, * of num_palette entries, in case of an invalid PNG file that has * too-large sample values. */ - png_ptr->palette = (png_colorp)png_calloc(png_ptr, - PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); + png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); - png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color)); + if (num_palette > 0) + memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color))); info_ptr->palette = png_ptr->palette; info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; @@ -558,34 +569,34 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_sBIT_SUPPORTED void PNGAPI -png_set_sBIT(png_structp png_ptr, png_infop info_ptr, +png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, png_const_color_8p sig_bit) { png_debug1(1, "in %s storage function", "sBIT"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) return; - png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof(png_color_8)); + info_ptr->sig_bit = *sig_bit; info_ptr->valid |= PNG_INFO_sBIT; } #endif #ifdef PNG_sRGB_SUPPORTED void PNGAPI -png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int srgb_intent) +png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) { png_debug1(1, "in %s storage function", "sRGB"); if (png_ptr == NULL || info_ptr == NULL) return; - info_ptr->srgb_intent = (png_byte)srgb_intent; - info_ptr->valid |= PNG_INFO_sRGB; + (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent); + png_colorspace_sync_info(png_ptr, info_ptr); } void PNGAPI -png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, +png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) { png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); @@ -593,28 +604,22 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, if (png_ptr == NULL || info_ptr == NULL) return; - png_set_sRGB(png_ptr, info_ptr, srgb_intent); - -# ifdef PNG_gAMA_SUPPORTED - png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); -# endif + if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, + srgb_intent) != 0) + { + /* This causes the gAMA and cHRM to be written too */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } -# ifdef PNG_cHRM_SUPPORTED - png_set_cHRM_fixed(png_ptr, info_ptr, - /* color x y */ - /* white */ 31270, 32900, - /* red */ 64000, 33000, - /* green */ 30000, 60000, - /* blue */ 15000, 6000 - ); -# endif /* cHRM */ + png_colorspace_sync_info(png_ptr, info_ptr); } #endif /* sRGB */ #ifdef PNG_iCCP_SUPPORTED void PNGAPI -png_set_iCCP(png_structp png_ptr, png_infop info_ptr, +png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp name, int compression_type, png_const_bytep profile, png_uint_32 proflen) { @@ -627,37 +632,61 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr, if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) return; - length = png_strlen(name)+1; - new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length); + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_app_error(png_ptr, "Invalid iCCP compression method"); + + /* Set the colorspace first because this validates the profile; do not + * override previously set app cHRM or gAMA here (because likely as not the + * application knows better than libpng what the correct values are.) Pass + * the info_ptr color_type field to png_colorspace_set_ICC because in the + * write case it has not yet been stored in png_ptr. + */ + { + int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name, + proflen, profile, info_ptr->color_type); + + png_colorspace_sync_info(png_ptr, info_ptr); + + /* Don't do any of the copying if the profile was bad, or inconsistent. */ + if (result == 0) + return; + + /* But do write the gAMA and cHRM chunks from the profile. */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } + + length = strlen(name)+1; + new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); if (new_iccp_name == NULL) { - png_warning(png_ptr, "Insufficient memory to process iCCP chunk"); + png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); + return; } - png_memcpy(new_iccp_name, name, length); - new_iccp_profile = (png_bytep)png_malloc_warn(png_ptr, proflen); + memcpy(new_iccp_name, name, length); + new_iccp_profile = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, proflen)); if (new_iccp_profile == NULL) { - png_free (png_ptr, new_iccp_name); - png_warning(png_ptr, + png_free(png_ptr, new_iccp_name); + new_iccp_name = NULL; + png_benign_error(png_ptr, "Insufficient memory to process iCCP profile"); + return; } - png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); + memcpy(new_iccp_profile, profile, proflen); png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); info_ptr->iccp_proflen = proflen; info_ptr->iccp_name = new_iccp_name; info_ptr->iccp_profile = new_iccp_profile; - /* Compression is always zero but is here so the API and info structure - * does not have to change if we introduce multiple compression types - */ - info_ptr->iccp_compression = (png_byte)compression_type; info_ptr->free_me |= PNG_FREE_ICCP; info_ptr->valid |= PNG_INFO_iCCP; } @@ -665,18 +694,18 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_TEXT_SUPPORTED void PNGAPI -png_set_text(png_structp png_ptr, png_infop info_ptr, png_const_textp text_ptr, - int num_text) +png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) { int ret; ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); - if (ret) + if (ret != 0) png_error(png_ptr, "Insufficient memory to store text"); } int /* PRIVATE */ -png_set_text_2(png_structp png_ptr, png_infop info_ptr, +png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, png_const_textp text_ptr, int num_text) { int i; @@ -684,63 +713,63 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" : (unsigned long)png_ptr->chunk_name); - if (png_ptr == NULL || info_ptr == NULL || num_text == 0) + if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) return(0); /* Make sure we have enough space in the "text" array in info_struct - * to hold all of the incoming text_ptr objects. + * to hold all of the incoming text_ptr objects. This compare can't overflow + * because max_text >= num_text (anyway, subtract of two positive integers + * can't overflow in any case.) */ - if (info_ptr->num_text + num_text > info_ptr->max_text) + if (num_text > info_ptr->max_text - info_ptr->num_text) { - int old_max_text = info_ptr->max_text; int old_num_text = info_ptr->num_text; + int max_text; + png_textp new_text = NULL; - if (info_ptr->text != NULL) + /* Calculate an appropriate max_text, checking for overflow. */ + max_text = old_num_text; + if (num_text <= INT_MAX - max_text) { - png_textp old_text; - - info_ptr->max_text = info_ptr->num_text + num_text + 8; - old_text = info_ptr->text; + max_text += num_text; - info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_size_t)(info_ptr->max_text * png_sizeof(png_text))); + /* Round up to a multiple of 8 */ + if (max_text < INT_MAX-8) + max_text = (max_text + 8) & ~0x7; - if (info_ptr->text == NULL) - { - /* Restore to previous condition */ - info_ptr->max_text = old_max_text; - info_ptr->text = old_text; - return(1); - } - - png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max_text * - png_sizeof(png_text))); - png_free(png_ptr, old_text); + else + max_text = INT_MAX; + + /* Now allocate a new array and copy the old members in; this does all + * the overflow checks. + */ + new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, + info_ptr->text, old_num_text, max_text-old_num_text, + sizeof *new_text)); } - else + if (new_text == NULL) { - info_ptr->max_text = num_text + 8; - info_ptr->num_text = 0; - info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_size_t)(info_ptr->max_text * png_sizeof(png_text))); - if (info_ptr->text == NULL) - { - /* Restore to previous condition */ - info_ptr->num_text = old_num_text; - info_ptr->max_text = old_max_text; - return(1); - } - info_ptr->free_me |= PNG_FREE_TEXT; + png_chunk_report(png_ptr, "too many text chunks", + PNG_CHUNK_WRITE_ERROR); + + return 1; } - png_debug1(3, "allocated %d entries for info_ptr->text", - info_ptr->max_text); + png_free(png_ptr, info_ptr->text); + + info_ptr->text = new_text; + info_ptr->free_me |= PNG_FREE_TEXT; + info_ptr->max_text = max_text; + /* num_text is adjusted below as the entries are copied in */ + + png_debug1(3, "allocated %d entries for info_ptr->text", max_text); } + for (i = 0; i < num_text; i++) { - png_size_t text_length, key_len; - png_size_t lang_len, lang_key_len; + size_t text_length, key_len; + size_t lang_len, lang_key_len; png_textp textp = &(info_ptr->text[info_ptr->num_text]); if (text_ptr[i].key == NULL) @@ -749,11 +778,12 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE || text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) { - png_warning(png_ptr, "text compression mode is out of range"); + png_chunk_report(png_ptr, "text compression mode is out of range", + PNG_CHUNK_WRITE_ERROR); continue; } - key_len = png_strlen(text_ptr[i].key); + key_len = strlen(text_ptr[i].key); if (text_ptr[i].compression <= 0) { @@ -767,20 +797,21 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, /* Set iTXt data */ if (text_ptr[i].lang != NULL) - lang_len = png_strlen(text_ptr[i].lang); + lang_len = strlen(text_ptr[i].lang); else lang_len = 0; if (text_ptr[i].lang_key != NULL) - lang_key_len = png_strlen(text_ptr[i].lang_key); + lang_key_len = strlen(text_ptr[i].lang_key); else lang_key_len = 0; } -# else /* PNG_iTXt_SUPPORTED */ +# else /* iTXt */ { - png_warning(png_ptr, "iTXt chunk not supported"); + png_chunk_report(png_ptr, "iTXt chunk not supported", + PNG_CHUNK_WRITE_ERROR); continue; } # endif @@ -799,32 +830,36 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, else { - text_length = png_strlen(text_ptr[i].text); + text_length = strlen(text_ptr[i].text); textp->compression = text_ptr[i].compression; } - textp->key = (png_charp)png_malloc_warn(png_ptr, - (png_size_t) - (key_len + text_length + lang_len + lang_key_len + 4)); + textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, + key_len + text_length + lang_len + lang_key_len + 4)); if (textp->key == NULL) - return(1); + { + png_chunk_report(png_ptr, "text chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + + return 1; + } png_debug2(2, "Allocated %lu bytes at %p in png_set_text", (unsigned long)(png_uint_32) (key_len + lang_len + lang_key_len + text_length + 4), textp->key); - png_memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len)); + memcpy(textp->key, text_ptr[i].key, key_len); *(textp->key + key_len) = '\0'; if (text_ptr[i].compression > 0) { textp->lang = textp->key + key_len + 1; - png_memcpy(textp->lang, text_ptr[i].lang, lang_len); + memcpy(textp->lang, text_ptr[i].lang, lang_len); *(textp->lang + lang_len) = '\0'; textp->lang_key = textp->lang + lang_len + 1; - png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); *(textp->lang_key + lang_key_len) = '\0'; textp->text = textp->lang_key + lang_key_len + 1; } @@ -836,9 +871,8 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, textp->text = textp->key + key_len + 1; } - if (text_length) - png_memcpy(textp->text, text_ptr[i].text, - (png_size_t)(text_length)); + if (text_length != 0) + memcpy(textp->text, text_ptr[i].text, text_length); *(textp->text + text_length) = '\0'; @@ -859,18 +893,20 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr, info_ptr->num_text++; png_debug1(3, "transferred text chunk %d", info_ptr->num_text); } + return(0); } #endif #ifdef PNG_tIME_SUPPORTED void PNGAPI -png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_const_timep mod_time) +png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_timep mod_time) { png_debug1(1, "in %s storage function", "tIME"); - if (png_ptr == NULL || info_ptr == NULL || - (png_ptr->mode & PNG_WROTE_tIME)) + if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || + (png_ptr->mode & PNG_WROTE_tIME) != 0) return; if (mod_time->month == 0 || mod_time->month > 12 || @@ -879,22 +915,24 @@ png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_const_timep mod_time) mod_time->second > 60) { png_warning(png_ptr, "Ignoring invalid time value"); + return; } - png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof(png_time)); + info_ptr->mod_time = *mod_time; info_ptr->valid |= PNG_INFO_tIME; } #endif #ifdef PNG_tRNS_SUPPORTED void PNGAPI -png_set_tRNS(png_structp png_ptr, png_infop info_ptr, +png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) { png_debug1(1, "in %s storage function", "tRNS"); if (png_ptr == NULL || info_ptr == NULL) + return; if (trans_alpha != NULL) @@ -902,33 +940,41 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr, /* It may not actually be necessary to set png_ptr->trans_alpha here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. + * + * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively + * relies on png_set_tRNS storing the information in png_struct + * (otherwise it won't be there for the code in pngrtran.c). */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ - png_ptr->trans_alpha = info_ptr->trans_alpha = - (png_bytep)png_malloc(png_ptr, (png_size_t)PNG_MAX_PALETTE_LENGTH); + png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) - png_memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); + memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); } if (trans_color != NULL) { - int sample_max = (1 << info_ptr->bit_depth); - - if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - (int)trans_color->gray > sample_max) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB && - ((int)trans_color->red > sample_max || - (int)trans_color->green > sample_max || - (int)trans_color->blue > sample_max))) - png_warning(png_ptr, - "tRNS chunk has out-of-range samples for bit_depth"); +#ifdef PNG_WARNINGS_SUPPORTED + if (info_ptr->bit_depth < 16) + { + int sample_max = (1 << info_ptr->bit_depth) - 1; + + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + trans_color->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + (trans_color->red > sample_max || + trans_color->green > sample_max || + trans_color->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); + } +#endif - png_memcpy(&(info_ptr->trans_color), trans_color, - png_sizeof(png_color_16)); + info_ptr->trans_color = *trans_color; if (num_trans == 0) num_trans = 1; @@ -946,8 +992,8 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr, #ifdef PNG_sPLT_SUPPORTED void PNGAPI -png_set_sPLT(png_structp png_ptr, - png_infop info_ptr, png_const_sPLT_tp entries, int nentries) +png_set_sPLT(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) /* * entries - array of png_sPLT_t structures * to be added to the list of palettes @@ -958,220 +1004,462 @@ png_set_sPLT(png_structp png_ptr, */ { png_sPLT_tp np; - int i; - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) return; - np = (png_sPLT_tp)png_malloc_warn(png_ptr, - (info_ptr->splt_palettes_num + nentries) * - (png_size_t)png_sizeof(png_sPLT_t)); + /* Use the internal realloc function, which checks for all the possible + * overflows. Notice that the parameters are (int) and (size_t) + */ + np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, + info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, + sizeof *np)); if (np == NULL) { - png_warning(png_ptr, "No memory for sPLT palettes"); + /* Out of memory or too many chunks */ + png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); + return; } - png_memcpy(np, info_ptr->splt_palettes, - info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t)); - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes=NULL; + info_ptr->splt_palettes = np; + info_ptr->free_me |= PNG_FREE_SPLT; - for (i = 0; i < nentries; i++) + np += info_ptr->splt_palettes_num; + + do { - png_sPLT_tp to = np + info_ptr->splt_palettes_num + i; - png_const_sPLT_tp from = entries + i; png_size_t length; - length = png_strlen(from->name) + 1; - to->name = (png_charp)png_malloc_warn(png_ptr, length); - - if (to->name == NULL) + /* Skip invalid input entries */ + if (entries->name == NULL || entries->entries == NULL) { - png_warning(png_ptr, - "Out of memory while processing sPLT chunk"); + /* png_handle_sPLT doesn't do this, so this is an app error */ + png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); + /* Just skip the invalid entry */ continue; } - png_memcpy(to->name, from->name, length); - to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, - from->nentries * png_sizeof(png_sPLT_entry)); + np->depth = entries->depth; + + /* In the event of out-of-memory just return - there's no point keeping + * on trying to add sPLT chunks. + */ + length = strlen(entries->name) + 1; + np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); + + if (np->name == NULL) + break; + + memcpy(np->name, entries->name, length); - if (to->entries == NULL) + /* IMPORTANT: we have memory now that won't get freed if something else + * goes wrong; this code must free it. png_malloc_array produces no + * warnings; use a png_chunk_report (below) if there is an error. + */ + np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, + entries->nentries, sizeof (png_sPLT_entry))); + + if (np->entries == NULL) { - png_warning(png_ptr, - "Out of memory while processing sPLT chunk"); - png_free(png_ptr, to->name); - to->name = NULL; - continue; + png_free(png_ptr, np->name); + np->name = NULL; + break; } - png_memcpy(to->entries, from->entries, - from->nentries * png_sizeof(png_sPLT_entry)); + np->nentries = entries->nentries; + /* This multiply can't overflow because png_malloc_array has already + * checked it when doing the allocation. + */ + memcpy(np->entries, entries->entries, + entries->nentries * sizeof (png_sPLT_entry)); + + /* Note that 'continue' skips the advance of the out pointer and out + * count, so an invalid entry is not added. + */ + info_ptr->valid |= PNG_INFO_sPLT; + ++(info_ptr->splt_palettes_num); + ++np; + } + while (++entries, --nentries); + + if (nentries > 0) + png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); +} +#endif /* sPLT */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +static png_byte +check_location(png_const_structrp png_ptr, int location) +{ + location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); - to->nentries = from->nentries; - to->depth = from->depth; + /* New in 1.6.0; copy the location and check it. This is an API + * change; previously the app had to use the + * png_set_unknown_chunk_location API below for each chunk. + */ + if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + /* Write struct, so unknown chunks come from the app */ + png_app_warning(png_ptr, + "png_set_unknown_chunks now expects a valid location"); + /* Use the old behavior */ + location = (png_byte)(png_ptr->mode & + (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); } - info_ptr->splt_palettes = np; - info_ptr->splt_palettes_num += nentries; - info_ptr->valid |= PNG_INFO_sPLT; - info_ptr->free_me |= PNG_FREE_SPLT; + /* This need not be an internal error - if the app calls + * png_set_unknown_chunks on a read pointer it must get the location right. + */ + if (location == 0) + png_error(png_ptr, "invalid location in png_set_unknown_chunks"); + + /* Now reduce the location to the top-most set bit by removing each least + * significant bit in turn. + */ + while (location != (location & -location)) + location &= ~(location & -location); + + /* The cast is safe because 'location' is a bit mask and only the low four + * bits are significant. + */ + return (png_byte)location; } -#endif /* PNG_sPLT_SUPPORTED */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED void PNGAPI -png_set_unknown_chunks(png_structp png_ptr, - png_infop info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) +png_set_unknown_chunks(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) { png_unknown_chunkp np; - int i; - if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) + if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || + unknowns == NULL) return; - np = (png_unknown_chunkp)png_malloc_warn(png_ptr, - (png_size_t)(info_ptr->unknown_chunks_num + num_unknowns) * - png_sizeof(png_unknown_chunk)); + /* Check for the failure cases where support has been disabled at compile + * time. This code is hardly ever compiled - it's here because + * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this + * code) but may be meaningless if the read or write handling of unknown + * chunks is not compiled in. + */ +# if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_app_error(png_ptr, "no unknown chunk support on read"); + + return; + } +# endif +# if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + png_app_error(png_ptr, "no unknown chunk support on write"); + + return; + } +# endif + + /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that + * unknown critical chunks could be lost with just a warning resulting in + * undefined behavior. Now png_chunk_report is used to provide behavior + * appropriate to read or write. + */ + np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, + info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, + sizeof *np)); if (np == NULL) { - png_warning(png_ptr, - "Out of memory while processing unknown chunk"); + png_chunk_report(png_ptr, "too many unknown chunks", + PNG_CHUNK_WRITE_ERROR); + return; } - png_memcpy(np, info_ptr->unknown_chunks, - (png_size_t)info_ptr->unknown_chunks_num * - png_sizeof(png_unknown_chunk)); - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - - for (i = 0; i < num_unknowns; i++) - { - png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; - png_const_unknown_chunkp from = unknowns + i; + info_ptr->unknown_chunks = np; /* safe because it is initialized */ + info_ptr->free_me |= PNG_FREE_UNKN; - png_memcpy(to->name, from->name, png_sizeof(from->name)); - to->name[png_sizeof(to->name)-1] = '\0'; - to->size = from->size; + np += info_ptr->unknown_chunks_num; - /* Note our location in the read or write sequence */ - to->location = (png_byte)(png_ptr->mode & 0xff); + /* Increment unknown_chunks_num each time round the loop to protect the + * just-allocated chunk data. + */ + for (; num_unknowns > 0; --num_unknowns, ++unknowns) + { + memcpy(np->name, unknowns->name, (sizeof np->name)); + np->name[(sizeof np->name)-1] = '\0'; + np->location = check_location(png_ptr, unknowns->location); - if (from->size == 0) - to->data=NULL; + if (unknowns->size == 0) + { + np->data = NULL; + np->size = 0; + } else { - to->data = (png_bytep)png_malloc_warn(png_ptr, - (png_size_t)from->size); + np->data = png_voidcast(png_bytep, + png_malloc_base(png_ptr, unknowns->size)); - if (to->data == NULL) + if (np->data == NULL) { - png_warning(png_ptr, - "Out of memory while processing unknown chunk"); - to->size = 0; + png_chunk_report(png_ptr, "unknown chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + /* But just skip storing the unknown chunk */ + continue; } - else - png_memcpy(to->data, from->data, from->size); + memcpy(np->data, unknowns->data, unknowns->size); + np->size = unknowns->size; } - } - info_ptr->unknown_chunks = np; - info_ptr->unknown_chunks_num += num_unknowns; - info_ptr->free_me |= PNG_FREE_UNKN; + /* These increments are skipped on out-of-memory for the data - the + * unknown chunk entry gets overwritten if the png_chunk_report returns. + * This is correct in the read case (the chunk is just dropped.) + */ + ++np; + ++(info_ptr->unknown_chunks_num); + } } void PNGAPI -png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, +png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location) { - if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk < - info_ptr->unknown_chunks_num) - info_ptr->unknown_chunks[chunk].location = (png_byte)location; -} -#endif + /* This API is pretty pointless in 1.6.0 because the location can be set + * before the call to png_set_unknown_chunks. + * + * TODO: add a png_app_warning in 1.7 + */ + if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && + chunk < info_ptr->unknown_chunks_num) + { + if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) + { + png_app_error(png_ptr, "invalid unknown chunk location"); + /* Fake out the pre 1.6.0 behavior: */ + if ((location & PNG_HAVE_IDAT) != 0) /* undocumented! */ + location = PNG_AFTER_IDAT; + + else + location = PNG_HAVE_IHDR; /* also undocumented */ + } + info_ptr->unknown_chunks[chunk].location = + check_location(png_ptr, location); + } +} +#endif /* STORE_UNKNOWN_CHUNKS */ #ifdef PNG_MNG_FEATURES_SUPPORTED png_uint_32 PNGAPI -png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features) +png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) { png_debug(1, "in png_permit_mng_features"); if (png_ptr == NULL) - return (png_uint_32)0; + return 0; - png_ptr->mng_features_permitted = - (png_byte)(mng_features & PNG_ALL_MNG_FEATURES); + png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; - return (png_uint_32)png_ptr->mng_features_permitted; + return png_ptr->mng_features_permitted; } #endif #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static unsigned int +add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) +{ + unsigned int i; + + /* Utility function: update the 'keep' state of a chunk if it is already in + * the list, otherwise add it to the list. + */ + for (i=0; i= PNG_HANDLE_CHUNK_LAST) { - if (keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE) - png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); - else - png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + return; + } - if (keep == PNG_HANDLE_CHUNK_ALWAYS) - png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; + if (num_chunks_in <= 0) + { + png_ptr->unknown_default = keep; - else - png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; + /* '0' means just set the flags, so stop here */ + if (num_chunks_in == 0) + return; + } - return; + if (num_chunks_in < 0) + { + /* Ignore all unknown chunks and all chunks recognized by + * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND + */ + static PNG_CONST png_byte chunks_to_ignore[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ + 104, 73, 83, 84, '\0', /* hIST */ + 105, 67, 67, 80, '\0', /* iCCP */ + 105, 84, 88, 116, '\0', /* iTXt */ + 111, 70, 70, 115, '\0', /* oFFs */ + 112, 67, 65, 76, '\0', /* pCAL */ + 112, 72, 89, 115, '\0', /* pHYs */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 67, 65, 76, '\0', /* sCAL */ + 115, 80, 76, 84, '\0', /* sPLT */ + 115, 84, 69, 82, '\0', /* sTER */ + 115, 82, 71, 66, '\0', /* sRGB */ + 116, 69, 88, 116, '\0', /* tEXt */ + 116, 73, 77, 69, '\0', /* tIME */ + 122, 84, 88, 116, '\0' /* zTXt */ + }; + + chunk_list = chunks_to_ignore; + num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U; } - if (chunk_list == NULL) - return; + else /* num_chunks_in > 0 */ + { + if (chunk_list == NULL) + { + /* Prior to 1.6.0 this was silently ignored, now it is an app_error + * which can be switched off. + */ + png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); + + return; + } + + num_chunks = num_chunks_in; + } old_num_chunks = png_ptr->num_chunk_list; - new_list=(png_bytep)png_malloc(png_ptr, - (png_size_t)(5*(num_chunks + old_num_chunks))); + if (png_ptr->chunk_list == NULL) + old_num_chunks = 0; + + /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. + */ + if (num_chunks + old_num_chunks > UINT_MAX/5) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); + + return; + } - if (png_ptr->chunk_list != NULL) + /* If these chunks are being reset to the default then no more memory is + * required because add_one_chunk above doesn't extend the list if the 'keep' + * parameter is the default. + */ + if (keep != 0) { - png_memcpy(new_list, png_ptr->chunk_list, - (png_size_t)(5*old_num_chunks)); - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list=NULL; + new_list = png_voidcast(png_bytep, png_malloc(png_ptr, + 5 * (num_chunks + old_num_chunks))); + + if (old_num_chunks > 0) + memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); } - png_memcpy(new_list + 5*old_num_chunks, chunk_list, - (png_size_t)(5*num_chunks)); + else if (old_num_chunks > 0) + new_list = png_ptr->chunk_list; + + else + new_list = NULL; + + /* Add the new chunks together with each one's handling code. If the chunk + * already exists the code is updated, otherwise the chunk is added to the + * end. (In libpng 1.6.0 order no longer matters because this code enforces + * the earlier convention that the last setting is the one that is used.) + */ + if (new_list != NULL) + { + png_const_bytep inlist; + png_bytep outlist; + unsigned int i; + + for (i=0; ichunk_list != new_list) + png_free(png_ptr, new_list); + + new_list = NULL; + } + } + + else + num_chunks = 0; + + png_ptr->num_chunk_list = num_chunks; + + if (png_ptr->chunk_list != new_list) + { + if (png_ptr->chunk_list != NULL) + png_free(png_ptr, png_ptr->chunk_list); - png_ptr->num_chunk_list = old_num_chunks + num_chunks; - png_ptr->chunk_list = new_list; - png_ptr->free_me |= PNG_FREE_LIST; + png_ptr->chunk_list = new_list; + } } #endif #ifdef PNG_READ_USER_CHUNKS_SUPPORTED void PNGAPI -png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, +png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn) { png_debug(1, "in png_set_read_user_chunk_fn"); @@ -1186,64 +1474,94 @@ png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI -png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) +png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytepp row_pointers) { png_debug1(1, "in %s storage function", "rows"); if (png_ptr == NULL || info_ptr == NULL) return; - if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) + if (info_ptr->row_pointers != NULL && + (info_ptr->row_pointers != row_pointers)) png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); info_ptr->row_pointers = row_pointers; - if (row_pointers) + if (row_pointers != NULL) info_ptr->valid |= PNG_INFO_IDAT; } #endif void PNGAPI -png_set_compression_buffer_size(png_structp png_ptr, png_size_t size) +png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) { if (png_ptr == NULL) return; - png_free(png_ptr, png_ptr->zbuf); + if (size == 0 || size > PNG_UINT_31_MAX) + png_error(png_ptr, "invalid compression buffer size"); - if (size > ZLIB_IO_MAX) - { - png_warning(png_ptr, "Attempt to set buffer size beyond max ignored"); - png_ptr->zbuf_size = ZLIB_IO_MAX; - size = ZLIB_IO_MAX; /* must fit */ - } +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ + return; + } +# endif - else - png_ptr->zbuf_size = (uInt)size; +# ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + if (png_ptr->zowner != 0) + { + png_warning(png_ptr, + "Compression buffer size cannot be changed because it is in use"); - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size); + return; + } - /* The following ensures a relatively safe failure if this gets called while - * the buffer is actually in use. - */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = 0; - png_ptr->zstream.avail_in = 0; +#ifndef __COVERITY__ + if (size > ZLIB_IO_MAX) + { + png_warning(png_ptr, + "Compression buffer size limited to system maximum"); + size = ZLIB_IO_MAX; /* must fit */ + } +#endif + + if (size < 6) + { + /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH + * if this is permitted. + */ + png_warning(png_ptr, + "Compression buffer size cannot be reduced below 6"); + + return; + } + + if (png_ptr->zbuffer_size != size) + { + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_ptr->zbuffer_size = (uInt)size; + } + } +# endif } void PNGAPI -png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) +png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) { - if (png_ptr && info_ptr) + if (png_ptr != NULL && info_ptr != NULL) info_ptr->valid &= ~mask; } - #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* This function was added to libpng 1.2.6 */ void PNGAPI -png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, +png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max) { /* Images with dimensions larger than these limits will be @@ -1259,51 +1577,64 @@ png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, /* This function was added to libpng 1.4.0 */ void PNGAPI -png_set_chunk_cache_max (png_structp png_ptr, - png_uint_32 user_chunk_cache_max) +png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) { - if (png_ptr) - png_ptr->user_chunk_cache_max = user_chunk_cache_max; + if (png_ptr != NULL) + png_ptr->user_chunk_cache_max = user_chunk_cache_max; } /* This function was added to libpng 1.4.1 */ void PNGAPI -png_set_chunk_malloc_max (png_structp png_ptr, +png_set_chunk_malloc_max (png_structrp png_ptr, png_alloc_size_t user_chunk_malloc_max) { - if (png_ptr) + if (png_ptr != NULL) png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; } -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ +#endif /* ?SET_USER_LIMITS */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI -png_set_benign_errors(png_structp png_ptr, int allowed) +png_set_benign_errors(png_structrp png_ptr, int allowed) { png_debug(1, "in png_set_benign_errors"); - if (allowed) - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + /* If allowed is 1, png_benign_error() is treated as a warning. + * + * If allowed is 0, png_benign_error() is treated as an error (which + * is the default behavior if png_set_benign_errors() is not called). + */ + + if (allowed != 0) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; else - png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN; + png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); } -#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ - -#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Do not report invalid palette index; added at libng-1.5.10 */ +#endif /* BENIGN_ERRORS */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Whether to report invalid palette index; added at libng-1.5.10. + * It is possible for an indexed (color-type==3) PNG file to contain + * pixels with invalid (out-of-range) indexes if the PLTE chunk has + * fewer entries than the image's bit-depth would allow. We recover + * from this gracefully by filling any incomplete palette with zeros + * (opaque black). By default, when this occurs libpng will issue + * a benign error. This API can be used to override that behavior. + */ void PNGAPI -png_set_check_for_invalid_index(png_structp png_ptr, int allowed) +png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) { png_debug(1, "in png_set_check_for_invalid_index"); - if (allowed) + if (allowed > 0) png_ptr->num_palette_max = 0; else png_ptr->num_palette_max = -1; } #endif - -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif /* READ || WRITE */ diff --git a/src/3rdparty/libpng/pngstruct.h b/src/3rdparty/libpng/pngstruct.h index 43a45cdec6..8420d09972 100644 --- a/src/3rdparty/libpng/pngstruct.h +++ b/src/3rdparty/libpng/pngstruct.h @@ -1,12 +1,11 @@ /* pngstruct.h - header file for PNG reference library * - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.9 [March 29, 2012] - * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h @@ -24,13 +23,130 @@ * in this structure and is required for decompressing the LZ compressed * data in PNG files. */ +#ifndef ZLIB_CONST + /* We must ensure that zlib uses 'const' in declarations. */ +# define ZLIB_CONST +#endif #include "zlib.h" +#ifdef const + /* zlib.h sometimes #defines const to nothing, undo this. */ +# undef const +#endif + +/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility + * with older builds. + */ +#if ZLIB_VERNUM < 0x1260 +# define PNGZ_MSG_CAST(s) png_constcast(char*,s) +# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) +#else +# define PNGZ_MSG_CAST(s) (s) +# define PNGZ_INPUT_CAST(b) (b) +#endif + +/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib + * can handle at once. This type need be no larger than 16 bits (so maximum of + * 65535), this define allows us to discover how big it is, but limited by the + * maximuum for png_size_t. The value can be overriden in a library build + * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably + * lower value (e.g. 255 works). A lower value may help memory usage (slightly) + * and may even improve performance on some systems (and degrade it on others.) + */ +#ifndef ZLIB_IO_MAX +# define ZLIB_IO_MAX ((uInt)-1) +#endif + +#ifdef PNG_WRITE_SUPPORTED +/* The type of a compression buffer list used by the write code. */ +typedef struct png_compression_buffer +{ + struct png_compression_buffer *next; + png_byte output[1]; /* actually zbuf_size */ +} png_compression_buffer, *png_compression_bufferp; + +#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ + (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) +#endif + +/* Colorspace support; structures used in png_struct, png_info and in internal + * functions to hold and communicate information about the color space. + * + * PNG_COLORSPACE_SUPPORTED is only required if the application will perform + * colorspace corrections, otherwise all the colorspace information can be + * skipped and the size of libpng can be reduced (significantly) by compiling + * out the colorspace support. + */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* The chromaticities of the red, green and blue colorants and the chromaticity + * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). + */ +typedef struct png_xy +{ + png_fixed_point redx, redy; + png_fixed_point greenx, greeny; + png_fixed_point bluex, bluey; + png_fixed_point whitex, whitey; +} png_xy; + +/* The same data as above but encoded as CIE XYZ values. When this data comes + * from chromaticities the sum of the Y values is assumed to be 1.0 + */ +typedef struct png_XYZ +{ + png_fixed_point red_X, red_Y, red_Z; + png_fixed_point green_X, green_Y, green_Z; + png_fixed_point blue_X, blue_Y, blue_Z; +} png_XYZ; +#endif /* COLORSPACE */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) +/* A colorspace is all the above plus, potentially, profile information; + * however at present libpng does not use the profile internally so it is only + * stored in the png_info struct (if iCCP is supported.) The rendering intent + * is retained here and is checked. + * + * The file gamma encoding information is also stored here and gamma correction + * is done by libpng, whereas color correction must currently be done by the + * application. + */ +typedef struct png_colorspace +{ +#ifdef PNG_GAMMA_SUPPORTED + png_fixed_point gamma; /* File gamma */ +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED + png_xy end_points_xy; /* End points as chromaticities */ + png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ + png_uint_16 rendering_intent; /* Rendering intent of a profile */ +#endif + + /* Flags are always defined to simplify the code. */ + png_uint_16 flags; /* As defined below */ +} png_colorspace, * PNG_RESTRICT png_colorspacerp; + +typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; + +/* General flags for the 'flags' field */ +#define PNG_COLORSPACE_HAVE_GAMMA 0x0001 +#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 +#define PNG_COLORSPACE_HAVE_INTENT 0x0004 +#define PNG_COLORSPACE_FROM_gAMA 0x0008 +#define PNG_COLORSPACE_FROM_cHRM 0x0010 +#define PNG_COLORSPACE_FROM_sRGB 0x0020 +#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 +#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ +#define PNG_COLORSPACE_INVALID 0x8000 +#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) +#endif /* COLORSPACE || GAMMA */ struct png_struct_def { #ifdef PNG_SETJMP_SUPPORTED - jmp_buf longjmp_buffer; /* used in png_error */ + jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ + jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ + size_t jmp_buf_size; /* size of the above, if allocated */ #endif png_error_ptr error_fn; /* function for printing errors and aborting */ #ifdef PNG_WARNINGS_SUPPORTED @@ -63,22 +179,12 @@ struct png_struct_def png_uint_32 flags; /* flags indicating various things to libpng */ png_uint_32 transformations; /* which transformations to perform */ - z_stream zstream; /* pointer to decompression structure (below) */ - png_bytep zbuf; /* buffer for zlib */ - uInt zbuf_size; /* size of zbuf (typically 65536) */ -#ifdef PNG_WRITE_SUPPORTED + png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ + z_stream zstream; /* decompression structure */ -/* Added in 1.5.4: state to keep track of whether the zstream has been - * initialized and if so whether it is for IDAT or some other chunk. - */ -#define PNG_ZLIB_UNINITIALIZED 0 -#define PNG_ZLIB_FOR_IDAT 1 -#define PNG_ZLIB_FOR_TEXT 2 /* anything other than IDAT */ -#define PNG_ZLIB_USE_MASK 3 /* bottom two bits */ -#define PNG_ZLIB_IN_USE 4 /* a flag value */ - - png_uint_32 zlib_state; /* State of zlib initialization */ -/* End of material added at libpng 1.5.4 */ +#ifdef PNG_WRITE_SUPPORTED + png_compression_bufferp zbuffer_list; /* Created on demand during write */ + uInt zbuffer_size; /* size of the actual buffer */ int zlib_level; /* holds zlib compression level */ int zlib_method; /* holds zlib compression method */ @@ -87,8 +193,7 @@ struct png_struct_def int zlib_strategy; /* holds zlib compression strategy */ #endif /* Added at libpng 1.5.4 */ -#if defined(PNG_WRITE_COMPRESSED_TEXT_SUPPORTED) || \ - defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED) +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED int zlib_text_level; /* holds zlib compression level */ int zlib_text_method; /* holds zlib compression method */ int zlib_text_window_bits; /* holds zlib compression window bits */ @@ -96,6 +201,14 @@ struct png_struct_def int zlib_text_strategy; /* holds zlib compression strategy */ #endif /* End of material added at libpng 1.5.4 */ +/* Added at libpng 1.6.0 */ +#ifdef PNG_WRITE_SUPPORTED + int zlib_set_level; /* Actual values set into the zstream on write */ + int zlib_set_method; + int zlib_set_window_bits; + int zlib_set_mem_level; + int zlib_set_strategy; +#endif png_uint_32 width; /* width of image in pixels */ png_uint_32 height; /* height of image in pixels */ @@ -111,10 +224,12 @@ struct png_struct_def png_bytep row_buf; /* buffer to save current (unfiltered) row. * This is a pointer into big_row_buf */ +#ifdef PNG_WRITE_SUPPORTED png_bytep sub_row; /* buffer to save "sub" row when filtering */ png_bytep up_row; /* buffer to save "up" row when filtering */ png_bytep avg_row; /* buffer to save "avg" row when filtering */ png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ +#endif png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ png_uint_32 idat_size; /* current IDAT size for read */ @@ -138,15 +253,14 @@ struct png_struct_def png_byte usr_bit_depth; /* bit depth of users row: write only */ png_byte pixel_depth; /* number of bits per pixel */ png_byte channels; /* number of channels in file */ +#ifdef PNG_WRITE_SUPPORTED png_byte usr_channels; /* channels at start of write: write only */ +#endif png_byte sig_bytes; /* magic bytes read/written from start of file */ png_byte maximum_pixel_depth; /* pixel depth used for the row buffers */ png_byte transformed_pixel_depth; /* pixel depth after read/write transforms */ - png_byte io_chunk_string[5]; - /* string name of chunk */ - #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) png_uint_16 filler; /* filler bytes for pixel expansion */ #endif @@ -159,7 +273,7 @@ struct png_struct_def #ifdef PNG_READ_GAMMA_SUPPORTED png_color_16 background_1; /* background normalized to gamma 1.0 */ #endif -#endif /* PNG_bKGD_SUPPORTED */ +#endif /* bKGD */ #ifdef PNG_WRITE_FLUSH_SUPPORTED png_flush_ptr output_flush_fn; /* Function for flushing output */ @@ -169,7 +283,6 @@ struct png_struct_def #ifdef PNG_READ_GAMMA_SUPPORTED int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ - png_fixed_point gamma; /* file gamma value */ png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ png_bytep gamma_table; /* gamma table for 8-bit depth files */ @@ -217,7 +330,7 @@ struct png_struct_def int process_mode; /* what push library is currently doing */ int cur_palette; /* current push library palette index */ -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PROGRESSIVE_READ */ #if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) /* For the Borland special 64K segment handler */ @@ -233,10 +346,6 @@ struct png_struct_def png_bytep quantize_index; /* index translation for palette files */ #endif -#if defined(PNG_READ_QUANTIZE_SUPPORTED) || defined(PNG_hIST_SUPPORTED) - png_uint_16p hist; /* histogram */ -#endif - #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED png_byte heuristic_method; /* heuristic for row filter selection */ png_byte num_prev_filters; /* number of weights for previous rows */ @@ -247,9 +356,17 @@ struct png_struct_def png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ #endif + /* Options */ +#ifdef PNG_SET_OPTION_SUPPORTED + png_byte options; /* On/off state (up to 4 options) */ +#endif + +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng-1.7 */ #ifdef PNG_TIME_RFC1123_SUPPORTED char time_buffer[29]; /* String to hold RFC 1123 time text */ #endif +#endif /* New members added in libpng-1.0.6 */ @@ -257,17 +374,16 @@ struct png_struct_def #ifdef PNG_USER_CHUNKS_SUPPORTED png_voidp user_chunk_ptr; +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ #endif - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - int num_chunk_list; - png_bytep chunk_list; #endif -#ifdef PNG_READ_sRGB_SUPPORTED - /* Added in 1.5.5 to record an sRGB chunk in the png. */ - png_byte is_sRGB; +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int unknown_default; /* As PNG_HANDLE_* */ + unsigned int num_chunk_list; /* Number of entries in the list */ + png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name + * followed by a PNG_HANDLE_* byte */ #endif /* New members added in libpng-1.0.3 */ @@ -332,16 +448,24 @@ struct png_struct_def #endif /* New member added in libpng-1.0.25 and 1.2.17 */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - /* Storage for unknown chunk that the library doesn't recognize. */ +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* Temporary storage for unknown chunk that the library doesn't recognize, + * used while reading the chunk. + */ png_unknown_chunk unknown_chunk; #endif /* New member added in libpng-1.2.26 */ png_size_t old_big_row_buf_size; +#ifdef PNG_READ_SUPPORTED /* New member added in libpng-1.2.30 */ - png_charp chunkdata; /* buffer for reading chunk data */ + png_bytep read_buffer; /* buffer for reading chunk data */ + png_alloc_size_t read_buffer_size; /* current size of the buffer */ +#endif +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + uInt IDAT_read_size; /* limit on read buffer size for IDAT */ +#endif #ifdef PNG_IO_STATE_SUPPORTED /* New member added in libpng-1.4.0 */ @@ -351,7 +475,14 @@ struct png_struct_def /* New member added in libpng-1.5.6 */ png_bytep big_prev_row; +/* New member added in libpng-1.5.7 */ void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, png_bytep row, png_const_bytep prev_row); + +#ifdef PNG_READ_SUPPORTED +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + png_colorspace colorspace; +#endif +#endif }; #endif /* PNGSTRUCT_H */ diff --git a/src/3rdparty/libpng/pngtrans.c b/src/3rdparty/libpng/pngtrans.c index fef12f1851..cd3a79b6fa 100644 --- a/src/3rdparty/libpng/pngtrans.c +++ b/src/3rdparty/libpng/pngtrans.c @@ -1,8 +1,8 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * Last changed in libpng 1.5.10 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -18,7 +18,7 @@ #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Turn on BGR-to-RGB mapping */ void PNGAPI -png_set_bgr(png_structp png_ptr) +png_set_bgr(png_structrp png_ptr) { png_debug(1, "in png_set_bgr"); @@ -32,7 +32,7 @@ png_set_bgr(png_structp png_ptr) #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Turn on 16 bit byte swapping */ void PNGAPI -png_set_swap(png_structp png_ptr) +png_set_swap(png_structrp png_ptr) { png_debug(1, "in png_set_swap"); @@ -47,7 +47,7 @@ png_set_swap(png_structp png_ptr) #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) /* Turn on pixel packing */ void PNGAPI -png_set_packing(png_structp png_ptr) +png_set_packing(png_structrp png_ptr) { png_debug(1, "in png_set_packing"); @@ -57,7 +57,9 @@ png_set_packing(png_structp png_ptr) if (png_ptr->bit_depth < 8) { png_ptr->transformations |= PNG_PACK; - png_ptr->usr_bit_depth = 8; +# ifdef PNG_WRITE_SUPPORTED + png_ptr->usr_bit_depth = 8; +# endif } } #endif @@ -65,7 +67,7 @@ png_set_packing(png_structp png_ptr) #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) /* Turn on packed pixel swapping */ void PNGAPI -png_set_packswap(png_structp png_ptr) +png_set_packswap(png_structrp png_ptr) { png_debug(1, "in png_set_packswap"); @@ -79,7 +81,7 @@ png_set_packswap(png_structp png_ptr) #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) void PNGAPI -png_set_shift(png_structp png_ptr, png_const_color_8p true_bits) +png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) { png_debug(1, "in png_set_shift"); @@ -94,11 +96,11 @@ png_set_shift(png_structp png_ptr, png_const_color_8p true_bits) #if defined(PNG_READ_INTERLACING_SUPPORTED) || \ defined(PNG_WRITE_INTERLACING_SUPPORTED) int PNGAPI -png_set_interlace_handling(png_structp png_ptr) +png_set_interlace_handling(png_structrp png_ptr) { png_debug(1, "in png_set_interlace handling"); - if (png_ptr && png_ptr->interlaced) + if (png_ptr != 0 && png_ptr->interlaced != 0) { png_ptr->transformations |= PNG_INTERLACE; return (7); @@ -115,44 +117,91 @@ png_set_interlace_handling(png_structp png_ptr) * that don't like bytes as parameters. */ void PNGAPI -png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) +png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) { png_debug(1, "in png_set_filler"); if (png_ptr == NULL) return; + /* In libpng 1.6 it is possible to determine whether this is a read or write + * operation and therefore to do more checking here for a valid call. + */ + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { +# ifdef PNG_READ_FILLER_SUPPORTED + /* On read png_set_filler is always valid, regardless of the base PNG + * format, because other transformations can give a format where the + * filler code can execute (basically an 8 or 16-bit component RGB or G + * format.) + * + * NOTE: usr_channels is not used by the read code! (This has led to + * confusion in the past.) The filler is only used in the read code. + */ + png_ptr->filler = (png_uint_16)filler; +# else + png_app_error(png_ptr, "png_set_filler not supported on read"); + PNG_UNUSED(filler) /* not used in the write case */ + return; +# endif + } + + else /* write */ + { +# ifdef PNG_WRITE_FILLER_SUPPORTED + /* On write the usr_channels parameter must be set correctly at the + * start to record the number of channels in the app-supplied data. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_RGB: + png_ptr->usr_channels = 4; + break; + + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + break; + } + + else + { + /* There simply isn't any code in libpng to strip out bits + * from bytes when the components are less than a byte in + * size! + */ + png_app_error(png_ptr, + "png_set_filler is invalid for low bit depth gray output"); + return; + } + + default: + png_app_error(png_ptr, + "png_set_filler: inappropriate color type"); + return; + } +# else + png_app_error(png_ptr, "png_set_filler not supported on write"); + return; +# endif + } + + /* Here on success - libpng supports the operation, set the transformation + * and the flag to say where the filler channel is. + */ png_ptr->transformations |= PNG_FILLER; - png_ptr->filler = (png_uint_16)filler; if (filler_loc == PNG_FILLER_AFTER) png_ptr->flags |= PNG_FLAG_FILLER_AFTER; else png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; - - /* This should probably go in the "do_read_filler" routine. - * I attempted to do that in libpng-1.0.1a but that caused problems - * so I restored it in libpng-1.0.2a - */ - - if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - png_ptr->usr_channels = 4; - } - - /* Also I added this in libpng-1.0.2a (what happens when we expand - * a less-than-8-bit grayscale to GA?) */ - - if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8) - { - png_ptr->usr_channels = 2; - } } /* Added to libpng-1.2.7 */ void PNGAPI -png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) +png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) { png_debug(1, "in png_set_add_alpha"); @@ -160,7 +209,9 @@ png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) return; png_set_filler(png_ptr, filler, filler_loc); - png_ptr->transformations |= PNG_ADD_ALPHA; + /* The above may fail to do anything. */ + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_ptr->transformations |= PNG_ADD_ALPHA; } #endif @@ -168,7 +219,7 @@ png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) void PNGAPI -png_set_swap_alpha(png_structp png_ptr) +png_set_swap_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_swap_alpha"); @@ -182,7 +233,7 @@ png_set_swap_alpha(png_structp png_ptr) #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) void PNGAPI -png_set_invert_alpha(png_structp png_ptr) +png_set_invert_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_invert_alpha"); @@ -195,7 +246,7 @@ png_set_invert_alpha(png_structp png_ptr) #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) void PNGAPI -png_set_invert_mono(png_structp png_ptr) +png_set_invert_mono(png_structrp png_ptr) { png_debug(1, "in png_set_invert_mono"); @@ -276,9 +327,16 @@ png_do_swap(png_row_infop row_info, png_bytep row) for (i = 0; i < istop; i++, rp += 2) { +#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED + /* Feature added to libpng-1.6.11 for testing purposes, not + * enabled by default. + */ + *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp); +#else png_byte t = *rp; *rp = *(rp + 1); *(rp + 1) = t; +#endif } } } @@ -420,7 +478,7 @@ png_do_packswap(png_row_infop row_info, png_bytep row) *rp = table[*rp]; } } -#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ +#endif /* PACKSWAP || WRITE_PACKSWAP */ #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) @@ -452,7 +510,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) { if (row_info->bit_depth == 8) { - if (at_start) /* Skip initial filler */ + if (at_start != 0) /* Skip initial filler */ ++sp; else /* Skip initial channel and, for sp, the filler */ sp += 2, ++dp; @@ -466,7 +524,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) else if (row_info->bit_depth == 16) { - if (at_start) /* Skip initial filler */ + if (at_start != 0) /* Skip initial filler */ sp += 2; else /* Skip initial channel and, for sp, the filler */ sp += 4, dp += 2; @@ -492,7 +550,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) { if (row_info->bit_depth == 8) { - if (at_start) /* Skip initial filler */ + if (at_start != 0) /* Skip initial filler */ ++sp; else /* Skip initial channels and, for sp, the filler */ sp += 4, dp += 3; @@ -506,7 +564,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) else if (row_info->bit_depth == 16) { - if (at_start) /* Skip initial filler */ + if (at_start != 0) /* Skip initial filler */ sp += 2; else /* Skip initial channels and, for sp, the filler */ sp += 8, dp += 6; @@ -547,7 +605,7 @@ png_do_bgr(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_bgr"); - if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { png_uint_32 row_width = row_info->width; if (row_info->bit_depth == 8) @@ -617,16 +675,16 @@ png_do_bgr(png_row_infop row_info, png_bytep row) #endif } } -#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ +#endif /* READ_BGR || WRITE_BGR */ #if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) /* Added at libpng-1.5.10 */ void /* PRIVATE */ -png_do_check_palette_indexes(png_structp png_ptr, png_row_infop row_info) +png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) { if (png_ptr->num_palette < (1 << row_info->bit_depth) && - png_ptr->num_palette_max >= 0) + png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ { /* Calculations moved outside switch in an attempt to stop different * compiler warnings. 'padding' is in *bits* within the last byte, it is @@ -708,7 +766,7 @@ png_do_check_palette_indexes(png_structp png_ptr, png_row_infop row_info) { for (; rp > png_ptr->row_buf; rp--) { - if (*rp >= png_ptr->num_palette_max) + if (*rp > png_ptr->num_palette_max) png_ptr->num_palette_max = (int) *rp; } @@ -720,19 +778,30 @@ png_do_check_palette_indexes(png_structp png_ptr, png_row_infop row_info) } } } -#endif /* PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED */ +#endif /* CHECK_FOR_INVALID_INDEX */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED void PNGAPI -png_set_user_transform_info(png_structp png_ptr, png_voidp +png_set_user_transform_info(png_structrp png_ptr, png_voidp user_transform_ptr, int user_transform_depth, int user_transform_channels) { png_debug(1, "in png_set_user_transform_info"); if (png_ptr == NULL) return; + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + { + png_app_error(png_ptr, + "info change after png_start_read_image or png_read_update_info"); + return; + } +#endif + png_ptr->user_transform_ptr = user_transform_ptr; png_ptr->user_transform_depth = (png_byte)user_transform_depth; png_ptr->user_transform_channels = (png_byte)user_transform_channels; @@ -746,20 +815,20 @@ png_set_user_transform_info(png_structp png_ptr, png_voidp */ #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED png_voidp PNGAPI -png_get_user_transform_ptr(png_const_structp png_ptr) +png_get_user_transform_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); - return ((png_voidp)png_ptr->user_transform_ptr); + return png_ptr->user_transform_ptr; } #endif #ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED png_uint_32 PNGAPI -png_get_current_row_number(png_const_structp png_ptr) +png_get_current_row_number(png_const_structrp png_ptr) { - /* See the comments in png.h - this is the sub-image row when reading and + /* See the comments in png.h - this is the sub-image row when reading an * interlaced image. */ if (png_ptr != NULL) @@ -769,13 +838,12 @@ png_get_current_row_number(png_const_structp png_ptr) } png_byte PNGAPI -png_get_current_pass_number(png_const_structp png_ptr) +png_get_current_pass_number(png_const_structrp png_ptr) { if (png_ptr != NULL) return png_ptr->pass; return 8; /* invalid */ } -#endif /* PNG_USER_TRANSFORM_INFO_SUPPORTED */ -#endif /* PNG_READ_USER_TRANSFORM_SUPPORTED || - PNG_WRITE_USER_TRANSFORM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif /* USER_TRANSFORM_INFO */ +#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */ +#endif /* READ || WRITE */ diff --git a/src/3rdparty/libpng/pngwio.c b/src/3rdparty/libpng/pngwio.c index 95ffb3429f..0a40948aab 100644 --- a/src/3rdparty/libpng/pngwio.c +++ b/src/3rdparty/libpng/pngwio.c @@ -1,8 +1,8 @@ /* pngwio.c - functions for data output * - * Last changed in libpng 1.5.0 [January 6, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -30,11 +30,12 @@ */ void /* PRIVATE */ -png_write_data(png_structp png_ptr, png_const_bytep data, png_size_t length) +png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) { /* NOTE: write_data_fn must not change the buffer! */ if (png_ptr->write_data_fn != NULL ) - (*(png_ptr->write_data_fn))(png_ptr, (png_bytep)data, length); + (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), + length); else png_error(png_ptr, "Call to NULL write function"); @@ -46,7 +47,6 @@ png_write_data(png_structp png_ptr, png_const_bytep data, png_size_t length) * write_data function and use it at run time with png_set_write_fn(), rather * than changing the library. */ -#ifndef USE_FAR_KEYWORD void PNGCBAPI png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { @@ -60,64 +60,6 @@ png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) if (check != length) png_error(png_ptr, "Write Error"); } -#else -/* This is the model-independent version. Since the standard I/O library - * can't handle far buffers in the medium and small models, we have to copy - * the data. - */ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -void PNGCBAPI -png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_uint_32 check; - png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ - png_FILE_p io_ptr; - - if (png_ptr == NULL) - return; - - /* Check if data really is near. If so, use usual code. */ - near_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - - if ((png_bytep)near_data == data) - { - check = fwrite(near_data, 1, length, io_ptr); - } - - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t written, remaining, err; - check = 0; - remaining = length; - - do - { - written = MIN(NEAR_BUF_SIZE, remaining); - png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ - err = fwrite(buf, 1, written, io_ptr); - - if (err != written) - break; - - else - check += err; - - data += written; - remaining -= written; - } - while (remaining != 0); - } - - if (check != length) - png_error(png_ptr, "Write Error"); -} - -#endif #endif /* This function is called to output any data pending writing (normally @@ -126,7 +68,7 @@ png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) */ #ifdef PNG_WRITE_FLUSH_SUPPORTED void /* PRIVATE */ -png_flush(png_structp png_ptr) +png_flush(png_structrp png_ptr) { if (png_ptr->output_flush_fn != NULL) (*(png_ptr->output_flush_fn))(png_ptr); @@ -141,7 +83,7 @@ png_default_flush(png_structp png_ptr) if (png_ptr == NULL) return; - io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr)); fflush(io_ptr); } # endif @@ -177,7 +119,7 @@ png_default_flush(png_structp png_ptr) * *FILE structure. */ void PNGAPI -png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, +png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) { if (png_ptr == NULL) @@ -207,8 +149,11 @@ png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, # else png_ptr->output_flush_fn = output_flush_fn; # endif -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ +#else + PNG_UNUSED(output_flush_fn) +#endif /* WRITE_FLUSH */ +#ifdef PNG_READ_SUPPORTED /* It is an error to read while writing a png file */ if (png_ptr->read_data_fn != NULL) { @@ -218,37 +163,6 @@ png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, "Can't set both read_data_fn and write_data_fn in the" " same structure"); } -} - -#ifdef USE_FAR_KEYWORD -# ifdef _MSC_VER -void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) -{ - void *near_ptr; - void FAR *far_ptr; - FP_OFF(near_ptr) = FP_OFF(ptr); - far_ptr = (void FAR *)near_ptr; - - if (check != 0) - if (FP_SEG(ptr) != FP_SEG(far_ptr)) - png_error(png_ptr, "segment lost in conversion"); - - return(near_ptr); -} -# else -void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) -{ - void *near_ptr; - void FAR *far_ptr; - near_ptr = (void FAR *)ptr; - far_ptr = (void FAR *)near_ptr; - - if (check != 0) - if (far_ptr != ptr) - png_error(png_ptr, "segment lost in conversion"); - - return(near_ptr); -} -# endif #endif -#endif /* PNG_WRITE_SUPPORTED */ +} +#endif /* WRITE */ diff --git a/src/3rdparty/libpng/pngwrite.c b/src/3rdparty/libpng/pngwrite.c index b587f1b999..e3c203496e 100644 --- a/src/3rdparty/libpng/pngwrite.c +++ b/src/3rdparty/libpng/pngwrite.c @@ -1,8 +1,8 @@ /* pngwrite.c - general routines to write a PNG file * - * Last changed in libpng 1.5.10 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -12,9 +12,65 @@ */ #include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif #ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +/* Write out all the unknown chunks for the current given location */ +static void +write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, + unsigned int where) +{ + if (info_ptr->unknown_chunks_num != 0) + { + png_const_unknown_chunkp up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + ++up) + if ((up->location & where) != 0) + { + /* If per-chunk unknown chunk handling is enabled use it, otherwise + * just write the chunks the application has set. + */ +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int keep = png_handle_as_unknown(png_ptr, up->name); + + /* NOTE: this code is radically different from the read side in the + * matter of handling an ancillary unknown chunk. In the read side + * the default behavior is to discard it, in the code below the default + * behavior is to write it. Critical chunks are, however, only + * written if explicitly listed or if the default is set to write all + * unknown chunks. + * + * The default handling is also slightly weird - it is not possible to + * stop the writing of all unsafe-to-copy chunks! + * + * TODO: REVIEW: this would seem to be a bug. + */ + if (keep != PNG_HANDLE_CHUNK_NEVER && + ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || + keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && + png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) +#endif + { + /* TODO: review, what is wrong with a zero length unknown chunk? */ + if (up->size == 0) + png_warning(png_ptr, "Writing zero-length unknown chunk"); + + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +} +#endif /* WRITE_UNKNOWN_CHUNKS */ + /* Writes all the PNG information. This is the suggested way to use the * library. If you have a new chunk to add, make a function to write it, * and put it in the correct location here. If you want the chunk written @@ -25,21 +81,21 @@ * them in png_write_end(), and compressing them. */ void PNGAPI -png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) +png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) { png_debug(1, "in png_write_info_before_PLTE"); if (png_ptr == NULL || info_ptr == NULL) return; - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) { /* Write PNG signature */ png_write_sig(png_ptr); #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ - (png_ptr->mng_features_permitted)) + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \ + png_ptr->mng_features_permitted != 0) { png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); png_ptr->mng_features_permitted = 0; @@ -51,75 +107,88 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, info_ptr->filter_type, #ifdef PNG_WRITE_INTERLACING_SUPPORTED - info_ptr->interlace_type); + info_ptr->interlace_type #else - 0); + 0 #endif + ); + /* The rest of these check to see if the valid field has the appropriate * flag set, and if it does, writes the chunk. + * + * 1.6.0: COLORSPACE support controls the writing of these chunks too, and + * the chunks will be written if the WRITE routine is there and information + * is available in the COLORSPACE. (See png_colorspace_sync_info in png.c + * for where the valid flags get set.) + * + * Under certain circumstances the colorspace can be invalidated without + * syncing the info_struct 'valid' flags; this happens if libpng detects and + * error and calls png_error while the color space is being set, yet the + * application continues writing the PNG. So check the 'invalid' flag here + * too. */ -#ifdef PNG_WRITE_gAMA_SUPPORTED - if (info_ptr->valid & PNG_INFO_gAMA) - png_write_gAMA_fixed(png_ptr, info_ptr->gamma); -#endif -#ifdef PNG_WRITE_sRGB_SUPPORTED - if (info_ptr->valid & PNG_INFO_sRGB) - png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); +#ifdef PNG_GAMMA_SUPPORTED +# ifdef PNG_WRITE_gAMA_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 && + (info_ptr->valid & PNG_INFO_gAMA) != 0) + png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); +# endif #endif -#ifdef PNG_WRITE_iCCP_SUPPORTED - if (info_ptr->valid & PNG_INFO_iCCP) - png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, - (png_charp)info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); -#endif +#ifdef PNG_COLORSPACE_SUPPORTED + /* Write only one of sRGB or an ICC profile. If a profile was supplied + * and it matches one of the known sRGB ones issue a warning. + */ +# ifdef PNG_WRITE_iCCP_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->valid & PNG_INFO_iCCP) != 0) + { +# ifdef PNG_WRITE_sRGB_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sRGB) != 0) + png_app_warning(png_ptr, + "profile matches sRGB but writing iCCP instead"); +# endif + + png_write_iCCP(png_ptr, info_ptr->iccp_name, + info_ptr->iccp_profile); + } +# ifdef PNG_WRITE_sRGB_SUPPORTED + else +# endif +# endif + +# ifdef PNG_WRITE_sRGB_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->valid & PNG_INFO_sRGB) != 0) + png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); +# endif /* WRITE_sRGB */ +#endif /* COLORSPACE */ + #ifdef PNG_WRITE_sBIT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sBIT) + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); #endif -#ifdef PNG_WRITE_cHRM_SUPPORTED - if (info_ptr->valid & PNG_INFO_cHRM) - png_write_cHRM_fixed(png_ptr, - info_ptr->x_white, info_ptr->y_white, - info_ptr->x_red, info_ptr->y_red, - info_ptr->x_green, info_ptr->y_green, - info_ptr->x_blue, info_ptr->y_blue); + +#ifdef PNG_COLORSPACE_SUPPORTED +# ifdef PNG_WRITE_cHRM_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 && + (info_ptr->valid & PNG_INFO_cHRM) != 0) + png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); +# endif #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); - - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && - !(up->location & PNG_HAVE_PLTE) && - !(up->location & PNG_HAVE_IDAT) && - !(up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - if (up->size == 0) - png_warning(png_ptr, "Writing zero-length unknown chunk"); - - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); #endif + png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; } } void PNGAPI -png_write_info(png_structp png_ptr, png_infop info_ptr) +png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) { #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) int i; @@ -132,19 +201,19 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) png_write_info_before_PLTE(png_ptr, info_ptr); - if (info_ptr->valid & PNG_INFO_PLTE) + if ((info_ptr->valid & PNG_INFO_PLTE) != 0) png_write_PLTE(png_ptr, info_ptr->palette, (png_uint_32)info_ptr->num_palette); - else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + else if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) !=0) png_error(png_ptr, "Valid palette required for paletted images"); #ifdef PNG_WRITE_tRNS_SUPPORTED - if (info_ptr->valid & PNG_INFO_tRNS) + if ((info_ptr->valid & PNG_INFO_tRNS) !=0) { #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel (in tRNS) */ - if ((png_ptr->transformations & PNG_INVERT_ALPHA) && + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int j; @@ -158,42 +227,42 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) } #endif #ifdef PNG_WRITE_bKGD_SUPPORTED - if (info_ptr->valid & PNG_INFO_bKGD) + if ((info_ptr->valid & PNG_INFO_bKGD) != 0) png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); #endif #ifdef PNG_WRITE_hIST_SUPPORTED - if (info_ptr->valid & PNG_INFO_hIST) + if ((info_ptr->valid & PNG_INFO_hIST) != 0) png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) + if ((info_ptr->valid & PNG_INFO_oFFs) != 0) png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, info_ptr->offset_unit_type); #endif #ifdef PNG_WRITE_pCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_pCAL) + if ((info_ptr->valid & PNG_INFO_pCAL) != 0) png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, info_ptr->pcal_units, info_ptr->pcal_params); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_sCAL) + if ((info_ptr->valid & PNG_INFO_sCAL) != 0) png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, info_ptr->scal_s_width, info_ptr->scal_s_height); #endif /* sCAL */ #ifdef PNG_WRITE_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) + if ((info_ptr->valid & PNG_INFO_pHYs) != 0) png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); #endif /* pHYs */ #ifdef PNG_WRITE_tIME_SUPPORTED - if (info_ptr->valid & PNG_INFO_tIME) + if ((info_ptr->valid & PNG_INFO_tIME) != 0) { png_write_tIME(png_ptr, &(info_ptr->mod_time)); png_ptr->mode |= PNG_WROTE_tIME; @@ -201,7 +270,7 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) #endif /* tIME */ #ifdef PNG_WRITE_sPLT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sPLT) + if ((info_ptr->valid & PNG_INFO_sPLT) != 0) for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); #endif /* sPLT */ @@ -223,11 +292,14 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else - png_warning(png_ptr, "Unable to write international text"); + png_warning(png_ptr, "Unable to write international text"); #endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } /* If we want a compressed text chunk */ @@ -236,13 +308,12 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0, - info_ptr->text[i].compression); + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) @@ -263,29 +334,7 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) #endif /* tEXt */ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && - (up->location & PNG_HAVE_PLTE) && - !(up->location & PNG_HAVE_IDAT) && - !(up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); #endif } @@ -295,14 +344,14 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) * comments, I suggest writing them here, and compressing them. */ void PNGAPI -png_write_end(png_structp png_ptr, png_infop info_ptr) +png_write_end(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_write_end"); if (png_ptr == NULL) return; - if (!(png_ptr->mode & PNG_HAVE_IDAT)) + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) png_error(png_ptr, "No IDATs written into file"); #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED @@ -318,8 +367,8 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) #endif #ifdef PNG_WRITE_tIME_SUPPORTED /* Check to see if user has supplied a time chunk */ - if ((info_ptr->valid & PNG_INFO_tIME) && - !(png_ptr->mode & PNG_WROTE_tIME)) + if ((info_ptr->valid & PNG_INFO_tIME) != 0 && + (png_ptr->mode & PNG_WROTE_tIME) == 0) png_write_tIME(png_ptr, &(info_ptr->mod_time)); #endif @@ -340,11 +389,14 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write international text"); #endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) @@ -352,13 +404,12 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0, - info_ptr->text[i].compression); + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) @@ -367,37 +418,16 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write uncompressed text"); #endif - - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } } #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && - (up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } + write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); #endif } @@ -405,6 +435,7 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) /* Write end of PNG file */ png_write_IEND(png_ptr); + /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, * and restored again in libpng-1.2.30, may cause some applications that * do not set png_ptr->output_flush_fn to crash. If your application @@ -420,9 +451,8 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) } #ifdef PNG_CONVERT_tIME_SUPPORTED -/* "tm" structure is not supported on WindowsCE */ void PNGAPI -png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm FAR * ttime) +png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) { png_debug(1, "in png_convert_from_struct_tm"); @@ -451,104 +481,75 @@ PNG_FUNCTION(png_structp,PNGAPI png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) { -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, NULL, NULL, NULL)); +#ifndef PNG_USER_MEM_SUPPORTED + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); } /* Alternate initialize png_ptr structure, and allocate any memory needed */ -static void png_reset_filter_heuristics(png_structp png_ptr); /* forward decl */ - PNG_FUNCTION(png_structp,PNGAPI png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { -#endif /* PNG_USER_MEM_SUPPORTED */ - volatile int png_cleanup_needed = 0; -#ifdef PNG_SETJMP_SUPPORTED - volatile -#endif - png_structp png_ptr; -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf tmp_jmpbuf; -#endif -#endif - - png_debug(1, "in png_create_write_struct"); - -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, - (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); -#else - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); -#endif /* PNG_USER_MEM_SUPPORTED */ - if (png_ptr == NULL) - return (NULL); + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ + if (png_ptr != NULL) + { + /* Set the zlib control values to defaults; they can be overridden by the + * application after the struct has been created. + */ + png_ptr->zbuffer_size = PNG_ZBUF_SIZE; - /* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; + /* The 'zlib_strategy' setting is irrelevant because png_default_claim in + * pngwutil.c defaults it according to whether or not filters will be + * used, and ignores this setting. + */ + png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; + png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_mem_level = 8; + png_ptr->zlib_window_bits = 15; + png_ptr->zlib_method = 8; + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED + png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; + png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_text_mem_level = 8; + png_ptr->zlib_text_window_bits = 15; + png_ptr->zlib_text_method = 8; +#endif /* WRITE_COMPRESSED_TEXT */ + + /* This is a highly dubious configuration option; by default it is off, + * but it may be appropriate for private builds that are testing + * extensions not conformant to the current specification, or of + * applications that must not fail to write at all costs! + */ +#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + /* In stable builds only warn if an application error can be completely + * handled. + */ + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; #endif -#ifdef PNG_SETJMP_SUPPORTED -/* Applications that neglect to set up their own setjmp() and then - * encounter a png_error() will longjmp here. Since the jmpbuf is - * then meaningless we abort instead of returning. - */ -#ifdef USE_FAR_KEYWORD - if (setjmp(tmp_jmpbuf)) -#else - if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */ -#endif -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf)); -#endif - PNG_ABORT(); + /* App warnings are warnings in release (or release candidate) builds but + * are errors during development. + */ +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; #endif -#ifdef PNG_USER_MEM_SUPPORTED - png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); -#endif /* PNG_USER_MEM_SUPPORTED */ - png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); - - if (!png_user_version_check(png_ptr, user_png_ver)) - png_cleanup_needed = 1; - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - - if (!png_cleanup_needed) - { - png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, - png_ptr->zbuf_size); - if (png_ptr->zbuf == NULL) - png_cleanup_needed = 1; - } - - if (png_cleanup_needed) - { - /* Clean up PNG structure and deallocate any memory. */ - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, - (png_free_ptr)free_fn, (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - return (NULL); + /* TODO: delay this, it can be done in png_init_io() (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_write_fn(png_ptr, NULL, NULL, NULL); } - png_set_write_fn(png_ptr, NULL, NULL, NULL); - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_reset_filter_heuristics(png_ptr); -#endif - - return (png_ptr); + return png_ptr; } @@ -558,7 +559,7 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, * "write" the image seven times. */ void PNGAPI -png_write_rows(png_structp png_ptr, png_bytepp row, +png_write_rows(png_structrp png_ptr, png_bytepp row, png_uint_32 num_rows) { png_uint_32 i; /* row counter */ @@ -580,7 +581,7 @@ png_write_rows(png_structp png_ptr, png_bytepp row, * if you are writing an interlaced image. */ void PNGAPI -png_write_image(png_structp png_ptr, png_bytepp image) +png_write_image(png_structrp png_ptr, png_bytepp image) { png_uint_32 i; /* row index */ int pass, num_pass; /* pass variables */ @@ -610,9 +611,74 @@ png_write_image(png_structp png_ptr, png_bytepp image) } } +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Performs intrapixel differencing */ +static void +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)(*rp - *(rp + 1)); + *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1)); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)(red >> 8); + *(rp + 1) = (png_byte)red; + *(rp + 4) = (png_byte)(blue >> 8); + *(rp + 5) = (png_byte)blue; + } + } +#endif /* WRITE_16BIT */ + } +} +#endif /* MNG_FEATURES */ + /* Called by user to write a row of image data */ void PNGAPI -png_write_row(png_structp png_ptr, png_const_bytep row) +png_write_row(png_structrp png_ptr, png_const_bytep row) { /* 1.5.6: moved from png_struct to be a local structure: */ png_row_info row_info; @@ -627,44 +693,44 @@ png_write_row(png_structp png_ptr, png_const_bytep row) if (png_ptr->row_number == 0 && png_ptr->pass == 0) { /* Make sure we wrote the header info */ - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) png_error(png_ptr, "png_write_info was never called before png_write_row"); /* Check for transforms that have been set but were defined out */ #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) + if ((png_ptr->transformations & PNG_FILLER) != 0) png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) + if ((png_ptr->transformations & PNG_PACK) != 0) png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) + if ((png_ptr->transformations & PNG_SHIFT) != 0) png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) + if ((png_ptr->transformations & PNG_BGR) != 0) png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); #endif @@ -673,12 +739,13 @@ png_write_row(png_structp png_ptr, png_const_bytep row) #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced and not interested in row, return */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { switch (png_ptr->pass) { case 0: - if (png_ptr->row_number & 0x07) + if ((png_ptr->row_number & 0x07) != 0) { png_write_finish_row(png_ptr); return; @@ -686,7 +753,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row) break; case 1: - if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5) { png_write_finish_row(png_ptr); return; @@ -702,7 +769,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row) break; case 3: - if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) + if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3) { png_write_finish_row(png_ptr); return; @@ -718,7 +785,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row) break; case 5: - if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) + if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2) { png_write_finish_row(png_ptr); return; @@ -726,7 +793,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row) break; case 6: - if (!(png_ptr->row_number & 0x01)) + if ((png_ptr->row_number & 0x01) == 0) { png_write_finish_row(png_ptr); return; @@ -755,16 +822,16 @@ png_write_row(png_structp png_ptr, png_const_bytep row) png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); /* Copy user's row into buffer, leaving room for filter byte. */ - png_memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); + memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Handle interlacing */ if (png_ptr->interlaced && png_ptr->pass < 6 && - (png_ptr->transformations & PNG_INTERLACE)) + (png_ptr->transformations & PNG_INTERLACE) != 0) { png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); /* This should always get caught above, but still ... */ - if (!(row_info.width)) + if (row_info.width == 0) { png_write_finish_row(png_ptr); return; @@ -774,7 +841,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row) #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* Handle other transformations */ - if (png_ptr->transformations) + if (png_ptr->transformations != 0) png_do_write_transformations(png_ptr, &row_info); #endif @@ -795,7 +862,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row) * 4. The filter_method is 64 and * 5. The color_type is RGB or RGBA */ - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ @@ -806,7 +873,8 @@ png_write_row(png_structp png_ptr, png_const_bytep row) /* Added at libpng-1.5.10 */ #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Check for out-of-range palette index */ - if(row_info.color_type == PNG_COLOR_TYPE_PALETTE) + if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) png_do_check_palette_indexes(png_ptr, &row_info); #endif @@ -820,7 +888,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row) #ifdef PNG_WRITE_FLUSH_SUPPORTED /* Set the automatic flush interval or 0 to turn flushing off */ void PNGAPI -png_set_flush(png_structp png_ptr, int nrows) +png_set_flush(png_structrp png_ptr, int nrows) { png_debug(1, "in png_set_flush"); @@ -832,10 +900,8 @@ png_set_flush(png_structp png_ptr, int nrows) /* Flush the current output buffers now */ void PNGAPI -png_write_flush(png_structp png_ptr) +png_write_flush(png_structrp png_ptr) { - int wrote_IDAT; - png_debug(1, "in png_write_flush"); if (png_ptr == NULL) @@ -845,140 +911,41 @@ png_write_flush(png_structp png_ptr) if (png_ptr->row_number >= png_ptr->num_rows) return; - do - { - int ret; - - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); - wrote_IDAT = 0; - - /* Check for compression errors */ - if (ret != Z_OK) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - - else - png_error(png_ptr, "zlib error"); - } - - if (!(png_ptr->zstream.avail_out)) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - wrote_IDAT = 1; - } - } while (wrote_IDAT == 1); - - /* If there is any data left to be output, write it into a new IDAT */ - if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, - png_ptr->zbuf_size - png_ptr->zstream.avail_out); - } + png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); png_ptr->flush_rows = 0; png_flush(png_ptr); } -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ - -/* Free all memory used by the write */ -void PNGAPI -png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) -{ - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn = NULL; - png_voidp mem_ptr = NULL; -#endif - - png_debug(1, "in png_destroy_write_struct"); +#endif /* WRITE_FLUSH */ - if (png_ptr_ptr != NULL) - png_ptr = *png_ptr_ptr; - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr != NULL) - { - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; - } -#endif - - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (info_ptr != NULL) - { - if (png_ptr != NULL) - { - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_ptr->num_chunk_list) - { - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->num_chunk_list = 0; - } -#endif - } - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif - *info_ptr_ptr = NULL; - } - - if (png_ptr != NULL) - { - png_write_destroy(png_ptr); -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */ #endif - *png_ptr_ptr = NULL; - } -} - -/* Free any memory used in png_ptr struct (old method) */ -void /* PRIVATE */ -png_write_destroy(png_structp png_ptr) +/* Free any memory used in png_ptr struct without freeing the struct itself. */ +static void +png_write_destroy(png_structrp png_ptr) { -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; /* Save jump buffer */ -#endif - png_error_ptr error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - png_error_ptr warning_fn; -#endif - png_voidp error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn; -#endif - png_debug(1, "in png_write_destroy"); /* Free any memory zlib uses */ - if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED) + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) deflateEnd(&png_ptr->zstream); /* Free our memory. png_free checks NULL for us. */ - png_free(png_ptr, png_ptr->zbuf); + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); png_free(png_ptr, png_ptr->row_buf); + png_ptr->row_buf = NULL; #ifdef PNG_WRITE_FILTER_SUPPORTED png_free(png_ptr, png_ptr->prev_row); png_free(png_ptr, png_ptr->sub_row); png_free(png_ptr, png_ptr->up_row); png_free(png_ptr, png_ptr->avg_row); png_free(png_ptr, png_ptr->paeth_row); + png_ptr->prev_row = NULL; + png_ptr->sub_row = NULL; + png_ptr->up_row = NULL; + png_ptr->avg_row = NULL; + png_ptr->paeth_row = NULL; #endif #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED @@ -986,41 +953,51 @@ png_write_destroy(png_structp png_ptr) png_reset_filter_heuristics(png_ptr); png_free(png_ptr, png_ptr->filter_costs); png_free(png_ptr, png_ptr->inv_filter_costs); + png_ptr->filter_costs = NULL; + png_ptr->inv_filter_costs = NULL; #endif -#ifdef PNG_SETJMP_SUPPORTED - /* Reset structure */ - png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf)); +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; #endif - error_fn = png_ptr->error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - warning_fn = png_ptr->warning_fn; -#endif - error_ptr = png_ptr->error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; -#endif + /* The error handling and memory handling information is left intact at this + * point: the jmp_buf may still have to be freed. See png_destroy_png_struct + * for how this happens. + */ +} - png_memset(png_ptr, 0, png_sizeof(png_struct)); +/* Free all memory used by the write. + * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for + * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free + * the passed in info_structs but it would quietly fail to free any of the data + * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it + * has no png_ptr.) + */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_debug(1, "in png_destroy_write_struct"); - png_ptr->error_fn = error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - png_ptr->warning_fn = warning_fn; -#endif - png_ptr->error_ptr = error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr->free_fn = free_fn; -#endif + if (png_ptr_ptr != NULL) + { + png_structrp png_ptr = *png_ptr_ptr; -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->longjmp_buffer, tmp_jmp, png_sizeof(jmp_buf)); -#endif + if (png_ptr != NULL) /* added in libpng 1.6.0 */ + { + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_write_destroy(png_ptr); + png_destroy_png_struct(png_ptr); + } + } } /* Allow the application to select one or more row filters to use. */ void PNGAPI -png_set_filter(png_structp png_ptr, int method, int filters) +png_set_filter(png_structrp png_ptr, int method, int filters) { png_debug(1, "in png_set_filter"); @@ -1028,7 +1005,7 @@ png_set_filter(png_structp png_ptr, int method, int filters) return; #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (method == PNG_INTRAPIXEL_DIFFERENCING)) method = PNG_FILTER_TYPE_BASE; @@ -1040,8 +1017,9 @@ png_set_filter(png_structp png_ptr, int method, int filters) #ifdef PNG_WRITE_FILTER_SUPPORTED case 5: case 6: - case 7: png_warning(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ + case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); + /* FALL THROUGH */ +#endif /* WRITE_FILTER */ case PNG_FILTER_VALUE_NONE: png_ptr->do_filter = PNG_FILTER_NONE; break; @@ -1062,8 +1040,8 @@ png_set_filter(png_structp png_ptr, int method, int filters) png_ptr->do_filter = (png_byte)filters; break; #else default: - png_warning(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ + png_app_error(png_ptr, "Unknown row filter for method 0"); +#endif /* WRITE_FILTER */ } /* If we have allocated the row_buf, this means we have already started @@ -1072,20 +1050,22 @@ png_set_filter(png_structp png_ptr, int method, int filters) * it is too late to start using the filters that need it, since we * will be missing the data in the previous row. If an application * wants to start and stop using particular filters during compression, - * it should start out with all of the filters, and then add and - * remove them after the start of compression. + * it should start out with all of the filters, and then remove them + * or add them back after the start of compression. */ if (png_ptr->row_buf != NULL) { #ifdef PNG_WRITE_FILTER_SUPPORTED - if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) + if ((png_ptr->do_filter & PNG_FILTER_SUB) != 0 && + png_ptr->sub_row == NULL) { png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, (png_ptr->rowbytes + 1)); png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; } - if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) + if ((png_ptr->do_filter & PNG_FILTER_UP) != 0 && + png_ptr->up_row == NULL) { if (png_ptr->prev_row == NULL) { @@ -1102,7 +1082,8 @@ png_set_filter(png_structp png_ptr, int method, int filters) } } - if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) + if ((png_ptr->do_filter & PNG_FILTER_AVG) != 0 && + png_ptr->avg_row == NULL) { if (png_ptr->prev_row == NULL) { @@ -1119,7 +1100,7 @@ png_set_filter(png_structp png_ptr, int method, int filters) } } - if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + if ((png_ptr->do_filter & PNG_FILTER_PAETH) != 0 && png_ptr->paeth_row == NULL) { if (png_ptr->prev_row == NULL) @@ -1137,7 +1118,7 @@ png_set_filter(png_structp png_ptr, int method, int filters) } if (png_ptr->do_filter == PNG_NO_FILTERS) -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ png_ptr->do_filter = PNG_FILTER_NONE; } } @@ -1155,7 +1136,7 @@ png_set_filter(png_structp png_ptr, int method, int filters) #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ /* Convenience reset API. */ static void -png_reset_filter_heuristics(png_structp png_ptr) +png_reset_filter_heuristics(png_structrp png_ptr) { /* Clear out any old values in the 'weights' - this must be done because if * the app calls set_filter_heuristics multiple times with different @@ -1188,7 +1169,7 @@ png_reset_filter_heuristics(png_structp png_ptr) } static int -png_init_filter_heuristics(png_structp png_ptr, int heuristic_method, +png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, int num_weights) { if (png_ptr == NULL) @@ -1208,7 +1189,7 @@ png_init_filter_heuristics(png_structp png_ptr, int heuristic_method, if (num_weights > 0) { png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_byte) * num_weights)); + (png_uint_32)((sizeof (png_byte)) * num_weights)); /* To make sure that the weighting starts out fairly */ for (i = 0; i < num_weights; i++) @@ -1217,10 +1198,10 @@ png_init_filter_heuristics(png_structp png_ptr, int heuristic_method, } png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); for (i = 0; i < num_weights; i++) { @@ -1238,10 +1219,10 @@ png_init_filter_heuristics(png_structp png_ptr, int heuristic_method, if (png_ptr->filter_costs == NULL) { png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); } for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) @@ -1271,7 +1252,7 @@ png_init_filter_heuristics(png_structp png_ptr, int heuristic_method, /* Provide floating and fixed point APIs */ #ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, +png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, int num_weights, png_const_doublep filter_weights, png_const_doublep filter_costs) { @@ -1280,7 +1261,7 @@ png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, /* The internal API allocates all the arrays and ensures that the elements of * those arrays are set to the default value. */ - if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) + if (png_init_filter_heuristics(png_ptr, heuristic_method, num_weights) == 0) return; /* If using the weighted method copy in the weights. */ @@ -1326,7 +1307,7 @@ png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, #ifdef PNG_FIXED_POINT_SUPPORTED void PNGAPI -png_set_filter_heuristics_fixed(png_structp png_ptr, int heuristic_method, +png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, int num_weights, png_const_fixed_point_p filter_weights, png_const_fixed_point_p filter_costs) { @@ -1335,7 +1316,7 @@ png_set_filter_heuristics_fixed(png_structp png_ptr, int heuristic_method, /* The internal API allocates all the arrays and ensures that the elements of * those arrays are set to the default value. */ - if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) + if (png_init_filter_heuristics(png_ptr, heuristic_method, num_weights) == 0) return; /* If using the weighted method copy in the weights. */ @@ -1389,40 +1370,41 @@ png_set_filter_heuristics_fixed(png_structp png_ptr, int heuristic_method, } } #endif /* FIXED_POINT */ -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ +#endif /* WRITE_WEIGHTED_FILTER */ +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED void PNGAPI -png_set_compression_level(png_structp png_ptr, int level) +png_set_compression_level(png_structrp png_ptr, int level) { png_debug(1, "in png_set_compression_level"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; png_ptr->zlib_level = level; } void PNGAPI -png_set_compression_mem_level(png_structp png_ptr, int mem_level) +png_set_compression_mem_level(png_structrp png_ptr, int mem_level) { png_debug(1, "in png_set_compression_mem_level"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; png_ptr->zlib_mem_level = mem_level; } void PNGAPI -png_set_compression_strategy(png_structp png_ptr, int strategy) +png_set_compression_strategy(png_structrp png_ptr, int strategy) { png_debug(1, "in png_set_compression_strategy"); if (png_ptr == NULL) return; + /* The flag setting here prevents the libpng dynamic selection of strategy. + */ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; png_ptr->zlib_strategy = strategy; } @@ -1431,80 +1413,82 @@ png_set_compression_strategy(png_structp png_ptr, int strategy) * smaller value of window_bits if it can do so safely. */ void PNGAPI -png_set_compression_window_bits(png_structp png_ptr, int window_bits) +png_set_compression_window_bits(png_structrp png_ptr, int window_bits) { if (png_ptr == NULL) return; + /* Prior to 1.6.0 this would warn but then set the window_bits value. This + * meant that negative window bits values could be selected that would cause + * libpng to write a non-standard PNG file with raw deflate or gzip + * compressed IDAT or ancillary chunks. Such files can be read and there is + * no warning on read, so this seems like a very bad idea. + */ if (window_bits > 15) + { png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } else if (window_bits < 8) + { png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } -#ifndef WBITS_8_OK - /* Avoid libpng bug with 256-byte windows */ - if (window_bits == 8) - { - png_warning(png_ptr, "Compression window is being reset to 512"); - window_bits = 9; - } - -#endif - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; png_ptr->zlib_window_bits = window_bits; } void PNGAPI -png_set_compression_method(png_structp png_ptr, int method) +png_set_compression_method(png_structrp png_ptr, int method) { png_debug(1, "in png_set_compression_method"); if (png_ptr == NULL) return; + /* This would produce an invalid PNG file if it worked, but it doesn't and + * deflate will fault it, so it is harmless to just warn here. + */ if (method != 8) png_warning(png_ptr, "Only compression method 8 is supported by PNG"); - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; png_ptr->zlib_method = method; } +#endif /* WRITE_CUSTOMIZE_COMPRESSION */ /* The following were added to libpng-1.5.4 */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED void PNGAPI -png_set_text_compression_level(png_structp png_ptr, int level) +png_set_text_compression_level(png_structrp png_ptr, int level) { png_debug(1, "in png_set_text_compression_level"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_LEVEL; png_ptr->zlib_text_level = level; } void PNGAPI -png_set_text_compression_mem_level(png_structp png_ptr, int mem_level) +png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) { png_debug(1, "in png_set_text_compression_mem_level"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL; png_ptr->zlib_text_mem_level = mem_level; } void PNGAPI -png_set_text_compression_strategy(png_structp png_ptr, int strategy) +png_set_text_compression_strategy(png_structrp png_ptr, int strategy) { png_debug(1, "in png_set_text_compression_strategy"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_STRATEGY; png_ptr->zlib_text_strategy = strategy; } @@ -1512,32 +1496,28 @@ png_set_text_compression_strategy(png_structp png_ptr, int strategy) * smaller value of window_bits if it can do so safely. */ void PNGAPI -png_set_text_compression_window_bits(png_structp png_ptr, int window_bits) +png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) { if (png_ptr == NULL) return; if (window_bits > 15) + { png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } else if (window_bits < 8) + { png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } -#ifndef WBITS_8_OK - /* Avoid libpng bug with 256-byte windows */ - if (window_bits == 8) - { - png_warning(png_ptr, "Text compression window is being reset to 512"); - window_bits = 9; - } - -#endif - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS; png_ptr->zlib_text_window_bits = window_bits; } void PNGAPI -png_set_text_compression_method(png_structp png_ptr, int method) +png_set_text_compression_method(png_structrp png_ptr, int method) { png_debug(1, "in png_set_text_compression_method"); @@ -1547,14 +1527,13 @@ png_set_text_compression_method(png_structp png_ptr, int method) if (method != 8) png_warning(png_ptr, "Only compression method 8 is supported by PNG"); - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_METHOD; png_ptr->zlib_text_method = method; } -#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ /* end of API added to libpng-1.5.4 */ void PNGAPI -png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) +png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) { if (png_ptr == NULL) return; @@ -1564,7 +1543,7 @@ png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED void PNGAPI -png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr +png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn) { png_debug(1, "in png_set_write_user_transform_fn"); @@ -1580,88 +1559,901 @@ png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI -png_write_png(png_structp png_ptr, png_infop info_ptr, +png_write_png(png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params) { if (png_ptr == NULL || info_ptr == NULL) return; + if ((info_ptr->valid & PNG_INFO_IDAT) == 0) + { + png_app_error(png_ptr, "no rows for png_write_image to write"); + return; + } + /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* ------ these transformations don't touch the info structure ------- */ -#ifdef PNG_WRITE_INVERT_SUPPORTED /* Invert monochrome pixels */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) +#ifdef PNG_WRITE_INVERT_SUPPORTED png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif -#ifdef PNG_WRITE_SHIFT_SUPPORTED /* Shift the pixels up to a legal bit depth and fill in * as appropriate to correctly scale the image. */ - if ((transforms & PNG_TRANSFORM_SHIFT) - && (info_ptr->valid & PNG_INFO_sBIT)) - png_set_shift(png_ptr, &info_ptr->sig_bit); + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); #endif -#ifdef PNG_WRITE_PACK_SUPPORTED /* Pack pixels into bytes */ - if (transforms & PNG_TRANSFORM_PACKING) - png_set_packing(png_ptr); + if ((transforms & PNG_TRANSFORM_PACKING) != 0) +#ifdef PNG_WRITE_PACK_SUPPORTED + png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); #endif -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED /* Swap location of alpha bytes from ARGB to RGBA */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif + /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into + * RGB, note that the code expects the input color type to be G or RGB; no + * alpha channel. + */ + if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER| + PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0) + { #ifdef PNG_WRITE_FILLER_SUPPORTED - /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ - if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) - png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0) + { + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_app_error(png_ptr, + "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported"); + + /* Continue if ignored - this is the pre-1.6.10 behavior */ + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + } - else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); + else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported"); #endif + } -#ifdef PNG_WRITE_BGR_SUPPORTED /* Flip BGR pixels to RGB */ - if (transforms & PNG_TRANSFORM_BGR) + if ((transforms & PNG_TRANSFORM_BGR) != 0) +#ifdef PNG_WRITE_BGR_SUPPORTED png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif -#ifdef PNG_WRITE_SWAP_SUPPORTED /* Swap bytes of 16-bit files to most significant byte first */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) +#ifdef PNG_WRITE_SWAP_SUPPORTED png_set_swap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED /* Swap bits of 1, 2, 4 bit packed pixel formats */ - if (transforms & PNG_TRANSFORM_PACKSWAP) + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel from opacity to transparency */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* ----------------------- end of transformations ------------------- */ /* Write the bits */ - if (info_ptr->valid & PNG_INFO_IDAT) - png_write_image(png_ptr, info_ptr->row_pointers); + png_write_image(png_ptr, info_ptr->row_pointers); /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); - PNG_UNUSED(transforms) /* Quiet compiler warnings */ PNG_UNUSED(params) } #endif -#endif /* PNG_WRITE_SUPPORTED */ + + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ +/* Initialize the write structure - general purpose utility. */ +static int +png_image_write_init(png_imagep image) +{ + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 1; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_write_struct(&png_ptr, NULL); + } + + return png_image_error(image, "png_image_write_: out of memory"); +} + +/* Arguments to png_image_write_main: */ +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_const_voidp buffer; + png_int_32 row_stride; + png_const_voidp colormap; + int convert_to_8bit; + /* Local variables: */ + png_const_voidp first_row; + ptrdiff_t row_bytes; + png_voidp local_row; +} png_image_write_control; + +/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to + * do any necessary byte swapping. The component order is defined by the + * png_image format value. + */ +static int +png_write_image_16bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); + png_uint_16p row_end; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + int aindex = 0; + png_uint_32 y = image->height; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else +# endif + aindex = channels; + } + + else + png_error(png_ptr, "png_write_image: internal call error"); + + /* Work out the output row end and count over this, note that the increment + * above to 'row' means that row_end can actually be beyond the end of the + * row; this is correct. + */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_uint_16p out_ptr = output_row; + + while (out_ptr < row_end) + { + const png_uint_16 alpha = in_ptr[aindex]; + png_uint_32 reciprocal = 0; + int c; + + out_ptr[aindex] = alpha; + + /* Calculate a reciprocal. The correct calculation is simply + * component/alpha*65535 << 15. (I.e. 15 bits of precision); this + * allows correct rounding by adding .5 before the shift. 'reciprocal' + * is only initialized when required. + */ + if (alpha > 0 && alpha < 65535) + reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; + + c = channels; + do /* always at least one channel */ + { + png_uint_16 component = *in_ptr++; + + /* The following gives 65535 for an alpha of 0, which is fine, + * otherwise if 0/0 is represented as some other value there is more + * likely to be a discontinuity which will probably damage + * compression when moving from a fully transparent area to a + * nearly transparent one. (The assumption here is that opaque + * areas tend not to be 0 intensity.) + */ + if (component >= alpha) + component = 65535; + + /* component 0 && alpha < 65535) + { + png_uint_32 calc = component * reciprocal; + calc += 16384; /* round to nearest */ + component = (png_uint_16)(calc >> 15); + } + + *out_ptr++ = component; + } + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } + + png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + + return 1; +} + +/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel + * is present it must be removed from the components, the components are then + * written in sRGB encoding. No components are added or removed. + * + * Calculate an alpha reciprocal to reverse pre-multiplication. As above the + * calculation can be done to 15 bits of accuracy; however, the output needs to + * be scaled in the range 0..255*65535, so include that scaling here. + */ +#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) + +static png_byte +png_unpremultiply(png_uint_32 component, png_uint_32 alpha, + png_uint_32 reciprocal/*from the above macro*/) +{ + /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 + * is represented as some other value there is more likely to be a + * discontinuity which will probably damage compression when moving from a + * fully transparent area to a nearly transparent one. (The assumption here + * is that opaque areas tend not to be 0 intensity.) + * + * There is a rounding problem here; if alpha is less than 128 it will end up + * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the + * output change for this too. + */ + if (component >= alpha || alpha < 128) + return 255; + + /* component 0) + { + /* The test is that alpha/257 (rounded) is less than 255, the first value + * that becomes 255 is 65407. + * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, + * be exact!) [Could also test reciprocal != 0] + */ + if (alpha < 65407) + { + component *= reciprocal; + component += 64; /* round to nearest */ + component >>= 7; + } + + else + component *= 255; + + /* Convert the component to sRGB. */ + return (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + else + return 0; +} + +static int +png_write_image_8bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_bytep output_row = png_voidcast(png_bytep, display->local_row); + png_uint_32 y = image->height; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_bytep row_end; + int aindex; + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else +# endif + aindex = channels; + + /* Use row_end in place of a loop counter: */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_16 alpha = in_ptr[aindex]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + int c; + + /* Scale and write the alpha channel. */ + out_ptr[aindex] = alphabyte; + + if (alphabyte > 0 && alphabyte < 255) + reciprocal = UNP_RECIPROCAL(alpha); + + c = channels; + do /* always at least one channel */ + *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } /* while out_ptr < row_end */ + + png_write_row(png_ptr, png_voidcast(png_const_bytep, + display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } /* while y */ + } + + else + { + /* No alpha channel, so the row_end really is the end of the row and it + * is sufficient to loop over the components one by one. + */ + png_bytep row_end = output_row + image->width * channels; + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_32 component = *in_ptr++; + + component *= 255; + *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + png_write_row(png_ptr, output_row); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + } + + return 1; +} + +static void +png_image_set_PLTE(png_image_write_control *display) +{ + const png_imagep image = display->image; + const void *cmap = display->colormap; + const int entries = image->colormap_entries > 256 ? 256 : + (int)image->colormap_entries; + + /* NOTE: the caller must check for cmap != NULL and entries != 0 */ + const png_uint_32 format = image->format; + const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); + +# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\ + defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED) + const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif + +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + int i, num_trans; + png_color palette[256]; + png_byte tRNS[256]; + + memset(tRNS, 255, (sizeof tRNS)); + memset(palette, 0, (sizeof palette)); + + for (i=num_trans=0; i= 3) /* RGB */ + { + palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[(2 ^ bgr)]); + palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[1]); + palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[bgr]); + } + + else /* Gray */ + palette[i].blue = palette[i].red = palette[i].green = + (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); + } + + else /* alpha */ + { + png_uint_16 alpha = entry[afirst ? 0 : channels-1]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + + /* Calculate a reciprocal, as in the png_write_image_8bit code above + * this is designed to produce a value scaled to 255*65535 when + * divided by 128 (i.e. asr 7). + */ + if (alphabyte > 0 && alphabyte < 255) + reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; + + tRNS[i] = alphabyte; + if (alphabyte < 255) + num_trans = i+1; + + if (channels >= 3) /* RGB */ + { + palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], + alpha, reciprocal); + palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, + reciprocal); + palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, + reciprocal); + } + + else /* gray */ + palette[i].blue = palette[i].red = palette[i].green = + png_unpremultiply(entry[afirst], alpha, reciprocal); + } + } + + else /* Color-map has sRGB values */ + { + png_const_bytep entry = png_voidcast(png_const_bytep, cmap); + + entry += i * channels; + + switch (channels) + { + case 4: + tRNS[i] = entry[afirst ? 0 : 3]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 3: + palette[i].blue = entry[afirst + (2 ^ bgr)]; + palette[i].green = entry[afirst + 1]; + palette[i].red = entry[afirst + bgr]; + break; + + case 2: + tRNS[i] = entry[1 ^ afirst]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 1: + palette[i].blue = palette[i].red = palette[i].green = + entry[afirst]; + break; + + default: + break; + } + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + + png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, + entries); + + if (num_trans > 0) + png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, + num_trans, NULL); + + image->colormap_entries = entries; +} + +static int +png_image_write_main(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 format = image->format; + + /* The following four ints are actually booleans */ + int colormap = (format & PNG_FORMAT_FLAG_COLORMAP); + int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */ + int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA); + int write_16bit = linear && !colormap && (display->convert_to_8bit == 0); + +# ifdef PNG_BENIGN_ERRORS_SUPPORTED + /* Make sure we error out on any bad situation */ + png_set_benign_errors(png_ptr, 0/*error*/); +# endif + + /* Default the 'row_stride' parameter if required. */ + if (display->row_stride == 0) + display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); + + /* Set the required transforms then write the rows in the correct order. */ + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) + { + if (display->colormap != NULL && image->colormap_entries > 0) + { + png_uint_32 entries = image->colormap_entries; + + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), + PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_image_set_PLTE(display); + } + + else + png_error(image->opaque->png_ptr, + "no color-map for color-mapped image"); + } + + else + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + write_16bit ? 16 : 8, + ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + + ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Counter-intuitively the data transformations must be called *after* + * png_write_info, not before as in the read code, but the 'set' functions + * must still be called before. Just set the color space information, never + * write an interlaced image. + */ + + if (write_16bit != 0) + { + /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); + + if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 + ); + } + + else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); + + /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit + * space must still be gamma encoded. + */ + else + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); + + /* Write the file header. */ + png_write_info(png_ptr, info_ptr); + + /* Now set up the data transformations (*after* the header is written), + * remove the handled transformations from the 'format' flags for checking. + * + * First check for a little endian system if writing 16 bit files. + */ + if (write_16bit != 0) + { + PNG_CONST png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + +# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED + if ((format & PNG_FORMAT_FLAG_BGR) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + format &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_set_swap_alpha(png_ptr); + format &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If there are 16 or fewer color-map entries we wrote a lower bit depth + * above, but the application data is still byte packed. + */ + if (colormap != 0 && image->colormap_entries <= 16) + png_set_packing(png_ptr); + + /* That should have handled all (both) the transforms. */ + if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | + PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) + png_error(png_ptr, "png_write_image: unsupported transformation"); + + { + png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= (sizeof (png_uint_16)); + + if (row_bytes < 0) + row += (image->height-1) * (-row_bytes); + + display->first_row = row; + display->row_bytes = row_bytes; + } + + /* Apply 'fast' options if the flag is set. */ + if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) + { + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); + /* NOTE: determined by experiment using pngstest, this reflects some + * balance between the time to write the image once and the time to read + * it about 50 times. The speed-up in pngstest was about 10-20% of the + * total (user) time on a heavily loaded system. + */ +#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED + png_set_compression_level(png_ptr, 3); +#endif + } + + /* Check for the cases that currently require a pre-transform on the row + * before it is written. This only applies when the input is 16-bit and + * either there is an alpha channel or it is converted to 8-bit. + */ + if ((linear != 0 && alpha != 0 ) || + (colormap == 0 && display->convert_to_8bit != 0)) + { + png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr))); + int result; + + display->local_row = row; + if (write_16bit != 0) + result = png_safe_execute(image, png_write_image_16bit, display); + else + result = png_safe_execute(image, png_write_image_8bit, display); + display->local_row = NULL; + + png_free(png_ptr, row); + + /* Skip the 'write_end' on error: */ + if (result == 0) + return 0; + } + + /* Otherwise this is the case where the input is in a format currently + * supported by the rest of the libpng write code; call it directly. + */ + else + { + png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); + ptrdiff_t row_bytes = display->row_bytes; + png_uint_32 y = image->height; + + while (y-- > 0) + { + png_write_row(png_ptr, row); + row += row_bytes; + } + } + + png_write_end(png_ptr, info_ptr); + return 1; +} + +int PNGAPI +png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given (FILE*). */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_write_init(image) != 0) + { + png_image_write_control display; + int result; + + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + + result = png_safe_execute(image, png_image_write_main, &display); + png_image_free(image); + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +int PNGAPI +png_image_write_to_file(png_imagep image, const char *file_name, + int convert_to_8bit, const void *buffer, png_int_32 row_stride, + const void *colormap) +{ + /* Write the image to the named file. */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "wb"); + + if (fp != NULL) + { + if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, + row_stride, colormap) != 0) + { + int error; /* from fflush/fclose */ + + /* Make sure the file is flushed correctly. */ + if (fflush(fp) == 0 && ferror(fp) == 0) + { + if (fclose(fp) == 0) + return 1; + + error = errno; /* from fclose */ + } + + else + { + error = errno; /* from fflush or ferror */ + (void)fclose(fp); + } + + (void)remove(file_name); + /* The image has already been cleaned up; this is just used to + * set the error (because the original write succeeded). + */ + return png_image_error(image, strerror(error)); + } + + else + { + /* Clean up: just the opened file. */ + (void)fclose(fp); + (void)remove(file_name); + return 0; + } + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_write_to_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} +#endif /* STDIO */ +#endif /* SIMPLIFIED_WRITE */ +#endif /* WRITE */ diff --git a/src/3rdparty/libpng/pngwtran.c b/src/3rdparty/libpng/pngwtran.c index 96608efcb4..db82e27bce 100644 --- a/src/3rdparty/libpng/pngwtran.c +++ b/src/3rdparty/libpng/pngwtran.c @@ -1,8 +1,8 @@ /* pngwtran.c - transforms the data in a row for PNG writers * - * Last changed in libpng 1.5.6 [November 3, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -14,90 +14,14 @@ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED - #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED -/* Transform the data according to the user's wishes. The order of - * transformations is significant. - */ -void /* PRIVATE */ -png_do_write_transformations(png_structp png_ptr, png_row_infop row_info) -{ - png_debug(1, "in png_do_write_transformations"); - - if (png_ptr == NULL) - return; - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - if (png_ptr->transformations & PNG_USER_TRANSFORM) - if (png_ptr->write_user_transform_fn != NULL) - (*(png_ptr->write_user_transform_fn)) /* User write transform - function */ - (png_ptr, /* png_ptr */ - row_info, /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_size_t rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#endif - -#ifdef PNG_WRITE_FILLER_SUPPORTED - if (png_ptr->transformations & PNG_FILLER) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); -#endif - -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_pack(row_info, png_ptr->row_buf + 1, - (png_uint_32)png_ptr->bit_depth); -#endif - -#ifdef PNG_WRITE_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED - if (png_ptr->transformations & PNG_SHIFT) - png_do_shift(row_info, png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(row_info, png_ptr->row_buf + 1); -#endif -} #ifdef PNG_WRITE_PACK_SUPPORTED /* Pack pixels into bytes. Pass the true bit depth in bit_depth. The * row_info bit depth should be 8 (one pixel per byte). The channels * should be 1 (this only happens on grayscale and paletted images). */ -void /* PRIVATE */ +static void png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) { png_debug(1, "in png_do_pack"); @@ -242,7 +166,7 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) * would pass 3 as bit_depth, and this routine would translate the * data to 0 to 15. */ -void /* PRIVATE */ +static void png_do_shift(png_row_infop row_info, png_bytep row, png_const_color_8p bit_depth) { @@ -253,7 +177,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, int shift_start[4], shift_dec[4]; int channels = 0; - if (row_info->color_type & PNG_COLOR_MASK_COLOR) + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { shift_start[channels] = row_info->bit_depth - bit_depth->red; shift_dec[channels] = bit_depth->red; @@ -275,7 +199,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, channels++; } - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) { shift_start[channels] = row_info->bit_depth - bit_depth->alpha; shift_dec[channels] = bit_depth->alpha; @@ -287,7 +211,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, { png_bytep bp = row; png_size_t i; - png_byte mask; + unsigned int mask; png_size_t row_bytes = row_info->rowbytes; if (bit_depth->gray == 1 && row_info->bit_depth == 2) @@ -301,20 +225,22 @@ png_do_shift(png_row_infop row_info, png_bytep row, for (i = 0; i < row_bytes; i++, bp++) { - png_uint_16 v; int j; + unsigned int v, out; v = *bp; - *bp = 0; + out = 0; for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) { if (j > 0) - *bp |= (png_byte)((v << j) & 0xff); + out |= v << j; else - *bp |= (png_byte)((v >> (-j)) & mask); + out |= (v >> (-j)) & mask; } + + *bp = (png_byte)(out & 0xff); } } @@ -327,21 +253,23 @@ png_do_shift(png_row_infop row_info, png_bytep row, for (i = 0; i < istop; i++, bp++) { - png_uint_16 v; + const unsigned int c = i%channels; int j; - int c = (int)(i%channels); + unsigned int v, out; v = *bp; - *bp = 0; + out = 0; for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) { if (j > 0) - *bp |= (png_byte)((v << j) & 0xff); + out |= v << j; else - *bp |= (png_byte)((v >> (-j)) & 0xff); + out |= v >> (-j); } + + *bp = (png_byte)(out & 0xff); } } @@ -353,22 +281,22 @@ png_do_shift(png_row_infop row_info, png_bytep row, for (bp = row, i = 0; i < istop; i++) { - int c = (int)(i%channels); - png_uint_16 value, v; + const unsigned int c = i%channels; int j; + unsigned int value, v; - v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1)); + v = png_get_uint_16(bp); value = 0; for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) { if (j > 0) - value |= (png_uint_16)((v << j) & (png_uint_16)0xffff); + value |= v << j; else - value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff); + value |= v >> (-j); } - *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)((value >> 8) & 0xff); *bp++ = (png_byte)(value & 0xff); } } @@ -377,7 +305,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, #endif #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_swap_alpha"); @@ -425,7 +353,7 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) *(dp++) = save[1]; } } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ +#endif /* WRITE_16BIT */ } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -464,14 +392,14 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) *(dp++) = save[1]; } } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ +#endif /* WRITE_16BIT */ } } } #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_invert_alpha"); @@ -521,7 +449,7 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) *(dp++) = (png_byte)(255 - *(sp++)); } } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ +#endif /* WRITE_16BIT */ } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -559,75 +487,88 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) *(dp++) = (png_byte)(255 - *(sp++)); } } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ +#endif /* WRITE_16BIT */ } } } #endif -#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ void /* PRIVATE */ -png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) { - png_debug(1, "in png_do_write_intrapixel"); + png_debug(1, "in png_do_write_transformations"); - if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; + if (png_ptr == NULL) + return; - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; +#ifdef PNG_WRITE_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); +#endif - else - return; +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff); - *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); - } - } +#ifdef PNG_WRITE_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_pack(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif -#ifdef PNG_WRITE_16BIT_SUPPORTED - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; +#ifdef PNG_WRITE_SWAP_SUPPORTED +# ifdef PNG_16BIT_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +# endif +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_shift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif - else - return; +#ifdef PNG_WRITE_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp + 1) = (png_byte)(red & 0xff); - *(rp + 4) = (png_byte)((blue >> 8) & 0xff); - *(rp + 5) = (png_byte)(blue & 0xff); - } - } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ - } +#ifdef PNG_WRITE_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif } -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_WRITE_SUPPORTED */ +#endif /* WRITE_TRANSFORMS */ +#endif /* WRITE */ diff --git a/src/3rdparty/libpng/pngwutil.c b/src/3rdparty/libpng/pngwutil.c index b49704f1a5..b289671d12 100644 --- a/src/3rdparty/libpng/pngwutil.c +++ b/src/3rdparty/libpng/pngwutil.c @@ -1,8 +1,8 @@ /* pngwutil.c - utilities to write a PNG file * - * Last changed in libpng 1.5.10 [March 8, 2012] - * Copyright (c) 1998-2012 Glenn Randers-Pehrson + * Last changed in libpng 1.6.17 [March 26, 2015] + * Copyright (c) 1998-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -23,29 +23,12 @@ void PNGAPI png_save_uint_32(png_bytep buf, png_uint_32 i) { - buf[0] = (png_byte)((i >> 24) & 0xff); - buf[1] = (png_byte)((i >> 16) & 0xff); - buf[2] = (png_byte)((i >> 8) & 0xff); - buf[3] = (png_byte)(i & 0xff); + buf[0] = (png_byte)(i >> 24); + buf[1] = (png_byte)(i >> 16); + buf[2] = (png_byte)(i >> 8); + buf[3] = (png_byte)(i ); } -#ifdef PNG_SAVE_INT_32_SUPPORTED -/* The png_save_int_32 function assumes integers are stored in two's - * complement format. If this isn't the case, then this routine needs to - * be modified to write data in two's complement format. Note that, - * the following works correctly even if png_int_32 has more than 32 bits - * (compare the more complex code required on read for sign extention.) - */ -void PNGAPI -png_save_int_32(png_bytep buf, png_int_32 i) -{ - buf[0] = (png_byte)((i >> 24) & 0xff); - buf[1] = (png_byte)((i >> 16) & 0xff); - buf[2] = (png_byte)((i >> 8) & 0xff); - buf[3] = (png_byte)(i & 0xff); -} -#endif - /* Place a 16-bit number into a buffer in PNG byte order. * The parameter is declared unsigned int, not png_uint_16, * just to avoid potential problems on pre-ANSI C compilers. @@ -53,8 +36,8 @@ png_save_int_32(png_bytep buf, png_int_32 i) void PNGAPI png_save_uint_16(png_bytep buf, unsigned int i) { - buf[0] = (png_byte)((i >> 8) & 0xff); - buf[1] = (png_byte)(i & 0xff); + buf[0] = (png_byte)(i >> 8); + buf[1] = (png_byte)(i ); } #endif @@ -65,7 +48,7 @@ png_save_uint_16(png_bytep buf, unsigned int i) * bytes have already been written. */ void PNGAPI -png_write_sig(png_structp png_ptr) +png_write_sig(png_structrp png_ptr) { png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; @@ -87,7 +70,7 @@ png_write_sig(png_structp png_ptr) * passing in png_write_chunk_data(). */ static void -png_write_chunk_header(png_structp png_ptr, png_uint_32 chunk_name, +png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, png_uint_32 length) { png_byte buf[8]; @@ -129,7 +112,7 @@ png_write_chunk_header(png_structp png_ptr, png_uint_32 chunk_name, } void PNGAPI -png_write_chunk_start(png_structp png_ptr, png_const_bytep chunk_string, +png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, png_uint_32 length) { png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length); @@ -141,7 +124,7 @@ png_write_chunk_start(png_structp png_ptr, png_const_bytep chunk_string, * given to png_write_chunk_header(). */ void PNGAPI -png_write_chunk_data(png_structp png_ptr, png_const_bytep data, +png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) { /* Write the data, and run the CRC over it */ @@ -153,7 +136,7 @@ png_write_chunk_data(png_structp png_ptr, png_const_bytep data, png_write_data(png_ptr, data, length); /* Update the CRC after writing the data, - * in case that the user I/O routine alters it. + * in case the user I/O routine alters it. */ png_calculate_crc(png_ptr, data, length); } @@ -161,7 +144,7 @@ png_write_chunk_data(png_structp png_ptr, png_const_bytep data, /* Finish a chunk started with png_write_chunk_header(). */ void PNGAPI -png_write_chunk_end(png_structp png_ptr) +png_write_chunk_end(png_structrp png_ptr) { png_byte buf[4]; @@ -190,15 +173,15 @@ png_write_chunk_end(png_structp png_ptr) * functions instead. */ static void -png_write_complete_chunk(png_structp png_ptr, png_uint_32 chunk_name, +png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, png_const_bytep data, png_size_t length) { if (png_ptr == NULL) return; /* On 64 bit architectures 'length' may not fit in a png_uint_32. */ - if (length > PNG_UINT_32_MAX) - png_error(png_ptr, "length exceeds PNG maxima"); + if (length > PNG_UINT_31_MAX) + png_error(png_ptr, "length exceeds PNG maximum"); png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); png_write_chunk_data(png_ptr, data, length); @@ -207,474 +190,571 @@ png_write_complete_chunk(png_structp png_ptr, png_uint_32 chunk_name, /* This is the API that calls the internal function above. */ void PNGAPI -png_write_chunk(png_structp png_ptr, png_const_bytep chunk_string, +png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, png_const_bytep data, png_size_t length) { png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, length); } -/* Initialize the compressor for the appropriate type of compression. */ -static void -png_zlib_claim(png_structp png_ptr, png_uint_32 state) +/* This is used below to find the size of an image to pass to png_deflate_claim, + * so it only needs to be accurate if the size is less than 16384 bytes (the + * point at which a lower LZ window size can be used.) + */ +static png_alloc_size_t +png_image_size(png_structrp png_ptr) { - if (!(png_ptr->zlib_state & PNG_ZLIB_IN_USE)) + /* Only return sizes up to the maximum of a png_uint_32; do this by limiting + * the width and height used to 15 bits. + */ + png_uint_32 h = png_ptr->height; + + if (png_ptr->rowbytes < 32768 && h < 32768) { - /* If already initialized for 'state' do not re-init. */ - if (png_ptr->zlib_state != state) + if (png_ptr->interlaced != 0) { - int ret = Z_OK; - png_const_charp who = "-"; + /* Interlacing makes the image larger because of the replication of + * both the filter byte and the padding to a byte boundary. + */ + png_uint_32 w = png_ptr->width; + unsigned int pd = png_ptr->pixel_depth; + png_alloc_size_t cb_base; + int pass; - /* If actually initialized for another state do a deflateEnd. */ - if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED) + for (cb_base=0, pass=0; pass<=6; ++pass) { - ret = deflateEnd(&png_ptr->zstream); - who = "end"; - png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED; + png_uint_32 pw = PNG_PASS_COLS(w, pass); + + if (pw > 0) + cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); } - /* zlib itself detects an incomplete state on deflateEnd */ - if (ret == Z_OK) switch (state) + return cb_base; + } + + else + return (png_ptr->rowbytes+1) * h; + } + + else + return 0xffffffffU; +} + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* This is the code to hack the first two bytes of the deflate stream (the + * deflate header) to correct the windowBits value to match the actual data + * size. Note that the second argument is the *uncompressed* size but the + * first argument is the *compressed* data (and it must be deflate + * compressed.) + */ +static void +optimize_cmf(png_bytep data, png_alloc_size_t data_size) +{ + /* Optimize the CMF field in the zlib stream. The resultant zlib stream is + * still compliant to the stream specification. + */ + if (data_size <= 16384) /* else windowBits must be 15 */ + { + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + unsigned int z_cinfo; + unsigned int half_z_window_size; + + z_cinfo = z_cmf >> 4; + half_z_window_size = 1U << (z_cinfo + 7); + + if (data_size <= half_z_window_size) /* else no change */ { -# ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED - case PNG_ZLIB_FOR_TEXT: - ret = deflateInit2(&png_ptr->zstream, - png_ptr->zlib_text_level, png_ptr->zlib_text_method, - png_ptr->zlib_text_window_bits, - png_ptr->zlib_text_mem_level, png_ptr->zlib_text_strategy); - who = "text"; - break; -# endif + unsigned int tmp; - case PNG_ZLIB_FOR_IDAT: - ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, - png_ptr->zlib_method, png_ptr->zlib_window_bits, - png_ptr->zlib_mem_level, png_ptr->zlib_strategy); - who = "IDAT"; - break; + do + { + half_z_window_size >>= 1; + --z_cinfo; + } + while (z_cinfo > 0 && data_size <= half_z_window_size); - default: - png_error(png_ptr, "invalid zlib state"); + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + + data[0] = (png_byte)z_cmf; + tmp = data[1] & 0xe0; + tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; + data[1] = (png_byte)tmp; } + } + } +} +#endif /* WRITE_OPTIMIZE_CMF */ - if (ret == Z_OK) - png_ptr->zlib_state = state; +/* Initialize the compressor for the appropriate type of compression. */ +static int +png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, + png_alloc_size_t data_size) +{ + if (png_ptr->zowner != 0) + { +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, owner); + msg[4] = ':'; + msg[5] = ' '; + PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); +#endif +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_warning(png_ptr, msg); - else /* an error in deflateEnd or deflateInit2 */ + /* Attempt sane error recovery */ + if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */ { - size_t pos = 0; - char msg[64]; + png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); + return Z_STREAM_ERROR; + } - pos = png_safecat(msg, sizeof msg, pos, - "zlib failed to initialize compressor ("); - pos = png_safecat(msg, sizeof msg, pos, who); + png_ptr->zowner = 0; +#else + png_error(png_ptr, msg); +#endif + } - switch (ret) - { - case Z_VERSION_ERROR: - pos = png_safecat(msg, sizeof msg, pos, ") version error"); - break; + { + int level = png_ptr->zlib_level; + int method = png_ptr->zlib_method; + int windowBits = png_ptr->zlib_window_bits; + int memLevel = png_ptr->zlib_mem_level; + int strategy; /* set below */ + int ret; /* zlib return code */ - case Z_STREAM_ERROR: - pos = png_safecat(msg, sizeof msg, pos, ") stream error"); - break; + if (owner == png_IDAT) + { + if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0) + strategy = png_ptr->zlib_strategy; - case Z_MEM_ERROR: - pos = png_safecat(msg, sizeof msg, pos, ") memory error"); - break; + else if (png_ptr->do_filter != PNG_FILTER_NONE) + strategy = PNG_Z_DEFAULT_STRATEGY; - default: - pos = png_safecat(msg, sizeof msg, pos, ") unknown error"); - break; - } + else + strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY; + } + + else + { +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + level = png_ptr->zlib_text_level; + method = png_ptr->zlib_text_method; + windowBits = png_ptr->zlib_text_window_bits; + memLevel = png_ptr->zlib_text_mem_level; + strategy = png_ptr->zlib_text_strategy; +#else + /* If customization is not supported the values all come from the + * IDAT values except for the strategy, which is fixed to the + * default. (This is the pre-1.6.0 behavior too, although it was + * implemented in a very different way.) + */ + strategy = Z_DEFAULT_STRATEGY; +#endif + } - png_error(png_ptr, msg); + /* Adjust 'windowBits' down if larger than 'data_size'; to stop this + * happening just pass 32768 as the data_size parameter. Notice that zlib + * requires an extra 262 bytes in the window in addition to the data to be + * able to see the whole of the data, so if data_size+262 takes us to the + * next windowBits size we need to fix up the value later. (Because even + * though deflate needs the extra window, inflate does not!) + */ + if (data_size <= 16384) + { + /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to + * work round a Microsoft Visual C misbehavior which, contrary to C-90, + * widens the result of the following shift to 64-bits if (and, + * apparently, only if) it is used in a test. + */ + unsigned int half_window_size = 1U << (windowBits-1); + + while (data_size + 262 <= half_window_size) + { + half_window_size >>= 1; + --windowBits; } } - /* Here on success, claim the zstream: */ - png_ptr->zlib_state |= PNG_ZLIB_IN_USE; - } + /* Check against the previous initialized values, if any. */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 && + (png_ptr->zlib_set_level != level || + png_ptr->zlib_set_method != method || + png_ptr->zlib_set_window_bits != windowBits || + png_ptr->zlib_set_mem_level != memLevel || + png_ptr->zlib_set_strategy != strategy)) + { + if (deflateEnd(&png_ptr->zstream) != Z_OK) + png_warning(png_ptr, "deflateEnd failed (ignored)"); - else - png_error(png_ptr, "zstream already in use (internal error)"); -} + png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED; + } -/* The opposite: release the stream. It is also reset, this API will warn on - * error but will not fail. - */ -static void -png_zlib_release(png_structp png_ptr) -{ - if (png_ptr->zlib_state & PNG_ZLIB_IN_USE) - { - int ret = deflateReset(&png_ptr->zstream); + /* For safety clear out the input and output pointers (currently zlib + * doesn't use them on Init, but it might in the future). + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; - png_ptr->zlib_state &= ~PNG_ZLIB_IN_USE; + /* Now initialize if required, setting the new parameters, otherwise just + * to a simple reset to the previous parameters. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + ret = deflateReset(&png_ptr->zstream); - if (ret != Z_OK) + else { - png_const_charp err; - PNG_WARNING_PARAMETERS(p) + ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, + memLevel, strategy); - switch (ret) - { - case Z_VERSION_ERROR: - err = "version"; - break; + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } - case Z_STREAM_ERROR: - err = "stream"; - break; + /* The return code is from either deflateReset or deflateInit2; they have + * pretty much the same set of error codes. + */ + if (ret == Z_OK) + png_ptr->zowner = owner; - case Z_MEM_ERROR: - err = "memory"; - break; + else + png_zstream_error(png_ptr, ret); - default: - err = "unknown"; - break; - } + return ret; + } +} - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, ret); - png_warning_parameter(p, 2, err); +/* Clean up (or trim) a linked list of compression buffers. */ +void /* PRIVATE */ +png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) +{ + png_compression_bufferp list = *listp; - if (png_ptr->zstream.msg) - err = png_ptr->zstream.msg; - else - err = "[no zlib message]"; + if (list != NULL) + { + *listp = NULL; - png_warning_parameter(p, 3, err); + do + { + png_compression_bufferp next = list->next; - png_formatted_warning(png_ptr, p, - "zlib failed to reset compressor: @1(@2): @3"); + png_free(png_ptr, list); + list = next; } + while (list != NULL); } - - else - png_warning(png_ptr, "zstream not in use (internal error)"); } #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED /* This pair of functions encapsulates the operation of (a) compressing a * text string, and (b) issuing it later as a series of chunk data writes. * The compression_state structure is shared context for these functions - * set up by the caller in order to make the whole mess thread-safe. + * set up by the caller to allow access to the relevant local variables. + * + * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size + * temporary buffers. From 1.6.0 it is retained in png_struct so that it will + * be correctly freed in the event of a write error (previous implementations + * just leaked memory.) */ - typedef struct { - png_const_bytep input; /* The uncompressed input data */ - png_size_t input_len; /* Its length */ - int num_output_ptr; /* Number of output pointers used */ - int max_output_ptr; /* Size of output_ptr */ - png_bytep *output_ptr; /* Array of pointers to output */ + png_const_bytep input; /* The uncompressed input data */ + png_alloc_size_t input_len; /* Its length */ + png_uint_32 output_len; /* Final compressed length */ + png_byte output[1024]; /* First block of output */ } compression_state; -/* Compress given text into storage in the png_ptr structure */ -static int /* PRIVATE */ -png_text_compress(png_structp png_ptr, - png_const_charp text, png_size_t text_len, int compression, - compression_state *comp) +static void +png_text_compress_init(compression_state *comp, png_const_bytep input, + png_alloc_size_t input_len) { - int ret; - - comp->num_output_ptr = 0; - comp->max_output_ptr = 0; - comp->output_ptr = NULL; - comp->input = NULL; - comp->input_len = text_len; - - /* We may just want to pass the text right through */ - if (compression == PNG_TEXT_COMPRESSION_NONE) - { - comp->input = (png_const_bytep)text; - return((int)text_len); - } - - if (compression >= PNG_TEXT_COMPRESSION_LAST) - { - PNG_WARNING_PARAMETERS(p) + comp->input = input; + comp->input_len = input_len; + comp->output_len = 0; +} - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, - compression); - png_formatted_warning(png_ptr, p, "Unknown compression type @1"); - } +/* Compress the data in the compression state input */ +static int +png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, + compression_state *comp, png_uint_32 prefix_len) +{ + int ret; - /* We can't write the chunk until we find out how much data we have, - * which means we need to run the compressor first and save the - * output. This shouldn't be a problem, as the vast majority of - * comments should be reasonable, but we will set up an array of - * malloc'd pointers to be sure. + /* To find the length of the output it is necessary to first compress the + * input. The result is buffered rather than using the two-pass algorithm + * that is used on the inflate side; deflate is assumed to be slower and a + * PNG writer is assumed to have more memory available than a PNG reader. * - * If we knew the application was well behaved, we could simplify this - * greatly by assuming we can always malloc an output buffer large - * enough to hold the compressed text ((1001 * text_len / 1000) + 12) - * and malloc this directly. The only time this would be a bad idea is - * if we can't malloc more than 64K and we have 64K of random input - * data, or if the input string is incredibly large (although this - * wouldn't cause a failure, just a slowdown due to swapping). + * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an + * upper limit on the output size, but it is always bigger than the input + * size so it is likely to be more efficient to use this linked-list + * approach. */ - png_zlib_claim(png_ptr, PNG_ZLIB_FOR_TEXT); + ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len); - /* Set up the compression buffers */ - /* TODO: the following cast hides a potential overflow problem. */ - png_ptr->zstream.avail_in = (uInt)text_len; + if (ret != Z_OK) + return ret; - /* NOTE: assume zlib doesn't overwrite the input */ - png_ptr->zstream.next_in = (Bytef *)text; - png_ptr->zstream.avail_out = png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; - - /* This is the same compression loop as in png_write_row() */ - do + /* Set up the compression buffers, we need a loop here to avoid overflowing a + * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited + * by the output buffer size, so there is no need to check that. Since this + * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits + * in size. + */ { - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); + png_compression_bufferp *end = &png_ptr->zbuffer_list; + png_alloc_size_t input_len = comp->input_len; /* may be zero! */ + png_uint_32 output_len; - if (ret != Z_OK) - { - /* Error */ - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); + /* zlib updates these for us: */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input); + png_ptr->zstream.avail_in = 0; /* Set below */ + png_ptr->zstream.next_out = comp->output; + png_ptr->zstream.avail_out = (sizeof comp->output); - else - png_error(png_ptr, "zlib error"); - } + output_len = png_ptr->zstream.avail_out; - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) + do { - /* Make sure the output array has room */ - if (comp->num_output_ptr >= comp->max_output_ptr) - { - int old_max; + uInt avail_in = ZLIB_IO_MAX; - old_max = comp->max_output_ptr; - comp->max_output_ptr = comp->num_output_ptr + 4; - if (comp->output_ptr != NULL) - { - png_bytepp old_ptr; + if (avail_in > input_len) + avail_in = (uInt)input_len; - old_ptr = comp->output_ptr; + input_len -= avail_in; - comp->output_ptr = (png_bytepp)png_malloc(png_ptr, - (png_alloc_size_t) - (comp->max_output_ptr * png_sizeof(png_charpp))); + png_ptr->zstream.avail_in = avail_in; - png_memcpy(comp->output_ptr, old_ptr, old_max - * png_sizeof(png_charp)); + if (png_ptr->zstream.avail_out == 0) + { + png_compression_buffer *next; - png_free(png_ptr, old_ptr); + /* Chunk data is limited to 2^31 bytes in length, so the prefix + * length must be counted here. + */ + if (output_len + prefix_len > PNG_UINT_31_MAX) + { + ret = Z_MEM_ERROR; + break; } - else - comp->output_ptr = (png_bytepp)png_malloc(png_ptr, - (png_alloc_size_t) - (comp->max_output_ptr * png_sizeof(png_charp))); - } - - /* Save the data */ - comp->output_ptr[comp->num_output_ptr] = - (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)png_ptr->zbuf_size); - - png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, - png_ptr->zbuf_size); - comp->num_output_ptr++; - - /* and reset the buffer */ - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; - } - /* Continue until we don't have any more to compress */ - } while (png_ptr->zstream.avail_in); - - /* Finish the compression */ - do - { - /* Tell zlib we are finished */ - ret = deflate(&png_ptr->zstream, Z_FINISH); - - if (ret == Z_OK) - { - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) - { - /* Check to make sure our output array has room */ - if (comp->num_output_ptr >= comp->max_output_ptr) + /* Need a new (malloc'ed) buffer, but there may be one present + * already. + */ + next = *end; + if (next == NULL) { - int old_max; + next = png_voidcast(png_compression_bufferp, png_malloc_base + (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); - old_max = comp->max_output_ptr; - comp->max_output_ptr = comp->num_output_ptr + 4; - if (comp->output_ptr != NULL) + if (next == NULL) { - png_bytepp old_ptr; - - old_ptr = comp->output_ptr; - - /* This could be optimized to realloc() */ - comp->output_ptr = (png_bytepp)png_malloc(png_ptr, - (png_alloc_size_t)(comp->max_output_ptr * - png_sizeof(png_charp))); - - png_memcpy(comp->output_ptr, old_ptr, - old_max * png_sizeof(png_charp)); - - png_free(png_ptr, old_ptr); + ret = Z_MEM_ERROR; + break; } - else - comp->output_ptr = (png_bytepp)png_malloc(png_ptr, - (png_alloc_size_t)(comp->max_output_ptr * - png_sizeof(png_charp))); + /* Link in this buffer (so that it will be freed later) */ + next->next = NULL; + *end = next; } - /* Save the data */ - comp->output_ptr[comp->num_output_ptr] = - (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)png_ptr->zbuf_size); + png_ptr->zstream.next_out = next->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + output_len += png_ptr->zstream.avail_out; - png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, - png_ptr->zbuf_size); + /* Move 'end' to the next buffer pointer. */ + end = &next->next; + } - comp->num_output_ptr++; + /* Compress the data */ + ret = deflate(&png_ptr->zstream, + input_len > 0 ? Z_NO_FLUSH : Z_FINISH); - /* and reset the buffer pointers */ - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; - } + /* Claw back input data that was not consumed (because avail_in is + * reset above every time round the loop). + */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; /* safety */ } - else if (ret != Z_STREAM_END) - { - /* We got an error */ - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); + while (ret == Z_OK); - else - png_error(png_ptr, "zlib error"); + /* There may be some space left in the last output buffer. This needs to + * be subtracted from output_len. + */ + output_len -= png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* safety */ + comp->output_len = output_len; + + /* Now double check the output length, put in a custom message if it is + * too long. Otherwise ensure the z_stream::msg pointer is set to + * something. + */ + if (output_len + prefix_len >= PNG_UINT_31_MAX) + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long"); + ret = Z_MEM_ERROR; } - } while (ret != Z_STREAM_END); - /* Text length is number of buffers plus last buffer */ - text_len = png_ptr->zbuf_size * comp->num_output_ptr; + else + png_zstream_error(png_ptr, ret); + + /* Reset zlib for another zTXt/iTXt or image data */ + png_ptr->zowner = 0; - if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) - text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; + /* The only success case is Z_STREAM_END, input_len must be 0; if not this + * is an internal error. + */ + if (ret == Z_STREAM_END && input_len == 0) + { +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* Fix up the deflate header, if required */ + optimize_cmf(comp->output, comp->input_len); +#endif + /* But Z_OK is returned, not Z_STREAM_END; this allows the claim + * function above to return Z_STREAM_END on an error (though it never + * does in the current versions of zlib.) + */ + return Z_OK; + } - return((int)text_len); + else + return ret; + } } /* Ship the compressed text out via chunk writes */ -static void /* PRIVATE */ -png_write_compressed_data_out(png_structp png_ptr, compression_state *comp, - png_size_t data_len) +static void +png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) { - int i; + png_uint_32 output_len = comp->output_len; + png_const_bytep output = comp->output; + png_uint_32 avail = (sizeof comp->output); + png_compression_buffer *next = png_ptr->zbuffer_list; - /* Handle the no-compression case */ - if (comp->input) + for (;;) { - png_write_chunk_data(png_ptr, comp->input, data_len); + if (avail > output_len) + avail = output_len; - return; - } + png_write_chunk_data(png_ptr, output, avail); -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - /* The zbuf_size test is because the code below doesn't work if zbuf_size is - * '1'; simply skip it to avoid memory overwrite. - */ - if (data_len >= 2 && comp->input_len < 16384 && png_ptr->zbuf_size > 1) - { - unsigned int z_cmf; /* zlib compression method and flags */ + output_len -= avail; - /* Optimize the CMF field in the zlib stream. This hack of the zlib - * stream is compliant to the stream specification. - */ + if (output_len == 0 || next == NULL) + break; - if (comp->num_output_ptr) - z_cmf = comp->output_ptr[0][0]; - else - z_cmf = png_ptr->zbuf[0]; + avail = png_ptr->zbuffer_size; + output = next->output; + next = next->next; + } - if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) - { - unsigned int z_cinfo; - unsigned int half_z_window_size; - png_size_t uncompressed_text_size = comp->input_len; + /* This is an internal error; 'next' must have been NULL! */ + if (output_len > 0) + png_error(png_ptr, "error writing ancillary chunked compressed data"); +} +#endif /* WRITE_COMPRESSED_TEXT */ - z_cinfo = z_cmf >> 4; - half_z_window_size = 1 << (z_cinfo + 7); +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The 'new_key' buffer must be 80 characters in size (for the keyword plus a + * trailing '\0'). If this routine returns 0 then there was no keyword, or a + * valid one could not be generated, and the caller must png_error. + */ +static png_uint_32 +png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) +{ + png_const_charp orig_key = key; + png_uint_32 key_len = 0; + int bad_character = 0; + int space = 1; - while (uncompressed_text_size <= half_z_window_size && - half_z_window_size >= 256) - { - z_cinfo--; - half_z_window_size >>= 1; - } + png_debug(1, "in png_check_keyword"); - z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + if (key == NULL) + { + *new_key = 0; + return 0; + } - if (comp->num_output_ptr) - { + while (*key && key_len < 79) + { + png_byte ch = (png_byte)*key++; - if (comp->output_ptr[0][0] != z_cmf) - { - int tmp; + if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) + *new_key++ = ch, ++key_len, space = 0; - comp->output_ptr[0][0] = (png_byte)z_cmf; - tmp = comp->output_ptr[0][1] & 0xe0; - tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; - comp->output_ptr[0][1] = (png_byte)tmp; - } - } - else - { - int tmp; + else if (space == 0) + { + /* A space or an invalid character when one wasn't seen immediately + * before; output just a space. + */ + *new_key++ = 32, ++key_len, space = 1; - png_ptr->zbuf[0] = (png_byte)z_cmf; - tmp = png_ptr->zbuf[1] & 0xe0; - tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; - png_ptr->zbuf[1] = (png_byte)tmp; - } + /* If the character was not a space then it is invalid. */ + if (ch != 32) + bad_character = ch; } - else - png_error(png_ptr, - "Invalid zlib compression method or flags in non-IDAT chunk"); + else if (bad_character == 0) + bad_character = ch; /* just skip it, record the first error */ } -#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ - /* Write saved output buffers, if any */ - for (i = 0; i < comp->num_output_ptr; i++) + if (key_len > 0 && space != 0) /* trailing space */ { - png_write_chunk_data(png_ptr, comp->output_ptr[i], - (png_size_t)png_ptr->zbuf_size); - - png_free(png_ptr, comp->output_ptr[i]); + --key_len, --new_key; + if (bad_character == 0) + bad_character = 32; } - if (comp->max_output_ptr != 0) - png_free(png_ptr, comp->output_ptr); + /* Terminate the keyword */ + *new_key = 0; + + if (key_len == 0) + return 0; - /* Write anything left in zbuf */ - if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) - png_write_chunk_data(png_ptr, png_ptr->zbuf, - (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); +#ifdef PNG_WARNINGS_SUPPORTED + /* Try to only output one warning per keyword: */ + if (*key != 0) /* keyword too long */ + png_warning(png_ptr, "keyword truncated"); - /* Reset zlib for another zTXt/iTXt or image data */ - png_zlib_release(png_ptr); + else if (bad_character != 0) + { + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter(p, 1, orig_key); + png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); + + png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); + } +#endif /* WARNINGS */ + + return key_len; } -#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ +#endif /* WRITE_TEXT || WRITE_pCAL || WRITE_iCCP || WRITE_sPLT */ /* Write the IHDR chunk, and update the png_struct with the necessary * information. Note that the rest of this code depends upon this * information being correct. */ void /* PRIVATE */ -png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, +png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int compression_type, int filter_type, int interlace_type) { @@ -768,8 +848,8 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, */ if ( #ifdef PNG_MNG_FEATURES_SUPPORTED - !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) && (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && @@ -791,7 +871,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, interlace_type=PNG_INTERLACE_NONE; #endif - /* Save the relevent information */ + /* Save the relevant information */ png_ptr->bit_depth = (png_byte)bit_depth; png_ptr->color_type = (png_byte)color_type; png_ptr->interlaced = (png_byte)interlace_type; @@ -821,12 +901,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, /* Write the chunk */ png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); - /* Initialize zlib with PNG info */ - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - - if (!(png_ptr->do_filter)) + if ((png_ptr->do_filter) == PNG_NO_FILTERS) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || png_ptr->bit_depth < 8) @@ -836,55 +911,6 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, png_ptr->do_filter = PNG_ALL_FILTERS; } - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) - { - if (png_ptr->do_filter != PNG_FILTER_NONE) - png_ptr->zlib_strategy = Z_FILTERED; - - else - png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; - } - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) - png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) - png_ptr->zlib_mem_level = 8; - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) - png_ptr->zlib_window_bits = 15; - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) - png_ptr->zlib_method = 8; - -#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_STRATEGY)) - png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY; - - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_LEVEL)) - png_ptr->zlib_text_level = png_ptr->zlib_level; - - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL)) - png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level; - - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS)) - png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits; - - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_METHOD)) - png_ptr->zlib_text_method = png_ptr->zlib_method; -#else - png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY; - png_ptr->zlib_text_level = png_ptr->zlib_level; - png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level; - png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits; - png_ptr->zlib_text_method = png_ptr->zlib_method; -#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ -#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ - - /* Record that the compressor has not yet been initialized. */ - png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED; - png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ } @@ -893,7 +919,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, * structure. */ void /* PRIVATE */ -png_write_PLTE(png_structp png_ptr, png_const_colorp palette, +png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, png_uint_32 num_pal) { png_uint_32 i; @@ -904,7 +930,7 @@ png_write_PLTE(png_structp png_ptr, png_const_colorp palette, if (( #ifdef PNG_MNG_FEATURES_SUPPORTED - !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 && #endif num_pal == 0) || num_pal > 256) { @@ -920,7 +946,7 @@ png_write_PLTE(png_structp png_ptr, png_const_colorp palette, } } - if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) { png_warning(png_ptr, "Ignoring request to write a PLTE chunk in grayscale PNG"); @@ -961,94 +987,165 @@ png_write_PLTE(png_structp png_ptr, png_const_colorp palette, png_ptr->mode |= PNG_HAVE_PLTE; } -/* Write an IDAT chunk */ +/* This is similar to png_text_compress, above, except that it does not require + * all of the data at once and, instead of buffering the compressed result, + * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out + * because it calls the write interface. As a result it does its own error + * reporting and does not return an error code. In the event of error it will + * just call png_error. The input data length may exceed 32-bits. The 'flush' + * parameter is exactly the same as that to deflate, with the following + * meanings: + * + * Z_NO_FLUSH: normal incremental output of compressed data + * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush + * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up + * + * The routine manages the acquire and release of the png_ptr->zstream by + * checking and (at the end) clearing png_ptr->zowner; it does some sanity + * checks on the 'mode' flags while doing this. + */ void /* PRIVATE */ -png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) +png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, + png_alloc_size_t input_len, int flush) { - png_debug(1, "in png_write_IDAT"); + if (png_ptr->zowner != png_IDAT) + { + /* First time. Ensure we have a temporary buffer for compression and + * trim the buffer list if it has more than one entry to free memory. + * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been + * created at this point, but the check here is quick and safe. + */ + if (png_ptr->zbuffer_list == NULL) + { + png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, + png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + png_ptr->zbuffer_list->next = NULL; + } -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if (!(png_ptr->mode & PNG_HAVE_IDAT) && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + else + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); + + /* It is a terminal error if we can't claim the zstream. */ + if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* The output state is maintained in png_ptr->zstream, so it must be + * initialized here after the claim. + */ + png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + } + + /* Now loop reading and writing until all the input is consumed or an error + * terminates the operation. The _out values are maintained across calls to + * this function, but the input must be reset each time. + */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + png_ptr->zstream.avail_in = 0; /* set below */ + for (;;) { - /* Optimize the CMF field in the zlib stream. This hack of the zlib - * stream is compliant to the stream specification. + int ret; + + /* INPUT: from the row data */ + uInt avail = ZLIB_IO_MAX; + + if (avail > input_len) + avail = (uInt)input_len; /* safe because of the check */ + + png_ptr->zstream.avail_in = avail; + input_len -= avail; + + ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); + + /* Include as-yet unconsumed input */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; + + /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note + * that these two zstream fields are preserved across the calls, therefore + * there is no need to set these up on entry to the loop. */ - unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + if (png_ptr->zstream.avail_out == 0) + { + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size; - if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + /* Write an IDAT containing the data then reset the buffer. The + * first IDAT may need deflate header optimization. + */ +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->mode |= PNG_HAVE_IDAT; + + png_ptr->zstream.next_out = data; + png_ptr->zstream.avail_out = size; + + /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with + * the same flush parameter until it has finished output, for NO_FLUSH + * it doesn't matter. + */ + if (ret == Z_OK && flush != Z_NO_FLUSH) + continue; + } + + /* The order of these checks doesn't matter much; it just affects which + * possible error might be detected if multiple things go wrong at once. + */ + if (ret == Z_OK) /* most likely return code! */ { - /* Avoid memory underflows and multiplication overflows. - * - * The conditions below are practically always satisfied; - * however, they still must be checked. + /* If all the input has been consumed then just return. If Z_FINISH + * was used as the flush parameter something has gone wrong if we get + * here. */ - if (length >= 2 && - png_ptr->height < 16384 && png_ptr->width < 16384) + if (input_len == 0) { - /* Compute the maximum possible length of the datastream */ + if (flush == Z_FINISH) + png_error(png_ptr, "Z_OK on Z_FINISH with output space"); - /* Number of pixels, plus for each row a filter byte - * and possibly a padding byte, so increase the maximum - * size to account for these. - */ - unsigned int z_cinfo; - unsigned int half_z_window_size; - png_uint_32 uncompressed_idat_size = png_ptr->height * - ((png_ptr->width * - png_ptr->channels * png_ptr->bit_depth + 15) >> 3); - - /* If it's interlaced, each block of 8 rows is sent as up to - * 14 rows, i.e., 6 additional rows, each with a filter byte - * and possibly a padding byte - */ - if (png_ptr->interlaced) - uncompressed_idat_size += ((png_ptr->height + 7)/8) * - (png_ptr->bit_depth < 8 ? 12 : 6); + return; + } + } - z_cinfo = z_cmf >> 4; - half_z_window_size = 1 << (z_cinfo + 7); + else if (ret == Z_STREAM_END && flush == Z_FINISH) + { + /* This is the end of the IDAT data; any pending output must be + * flushed. For small PNG files we may still be at the beginning. + */ + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; - while (uncompressed_idat_size <= half_z_window_size && - half_z_window_size >= 256) - { - z_cinfo--; - half_z_window_size >>= 1; - } +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif - z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->zstream.avail_out = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; - if (data[0] != z_cmf) - { - int tmp; - data[0] = (png_byte)z_cmf; - tmp = data[1] & 0xe0; - tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; - data[1] = (png_byte)tmp; - } - } + png_ptr->zowner = 0; /* Release the stream */ + return; } else - png_error(png_ptr, - "Invalid zlib compression method or flags in IDAT"); + { + /* This is an error condition. */ + png_zstream_error(png_ptr, ret); + png_error(png_ptr, png_ptr->zstream.msg); + } } -#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ - - png_write_complete_chunk(png_ptr, png_IDAT, data, length); - png_ptr->mode |= PNG_HAVE_IDAT; - - /* Prior to 1.5.4 this code was replicated in every caller (except at the - * end, where it isn't technically necessary). Since this function has - * flushed the data we can safely reset the zlib output buffer here. - */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; } /* Write an IEND chunk */ void /* PRIVATE */ -png_write_IEND(png_structp png_ptr) +png_write_IEND(png_structrp png_ptr) { png_debug(1, "in png_write_IEND"); @@ -1059,7 +1156,7 @@ png_write_IEND(png_structp png_ptr) #ifdef PNG_WRITE_gAMA_SUPPORTED /* Write a gAMA chunk */ void /* PRIVATE */ -png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) +png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) { png_byte buf[4]; @@ -1074,7 +1171,7 @@ png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) #ifdef PNG_WRITE_sRGB_SUPPORTED /* Write a sRGB chunk */ void /* PRIVATE */ -png_write_sRGB(png_structp png_ptr, int srgb_intent) +png_write_sRGB(png_structrp png_ptr, int srgb_intent) { png_byte buf[1]; @@ -1092,94 +1189,72 @@ png_write_sRGB(png_structp png_ptr, int srgb_intent) #ifdef PNG_WRITE_iCCP_SUPPORTED /* Write an iCCP chunk */ void /* PRIVATE */ -png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type, - png_const_charp profile, int profile_len) +png_write_iCCP(png_structrp png_ptr, png_const_charp name, + png_const_bytep profile) { - png_size_t name_len; - png_charp new_name; + png_uint_32 name_len; + png_uint_32 profile_len; + png_byte new_name[81]; /* 1 byte for the compression byte */ compression_state comp; - int embedded_profile_len = 0; + png_uint_32 temp; png_debug(1, "in png_write_iCCP"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - comp.input_len = 0; - - if ((name_len = png_check_keyword(png_ptr, name, &new_name)) == 0) - return; - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - png_warning(png_ptr, "Unknown compression type in iCCP chunk"); - + /* These are all internal problems: the profile should have been checked + * before when it was stored. + */ if (profile == NULL) - profile_len = 0; + png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ - if (profile_len > 3) - embedded_profile_len = - ((*( (png_const_bytep)profile ))<<24) | - ((*( (png_const_bytep)profile + 1))<<16) | - ((*( (png_const_bytep)profile + 2))<< 8) | - ((*( (png_const_bytep)profile + 3)) ); + profile_len = png_get_uint_32(profile); - if (embedded_profile_len < 0) - { - png_warning(png_ptr, - "Embedded profile length in iCCP chunk is negative"); + if (profile_len < 132) + png_error(png_ptr, "ICC profile too short"); - png_free(png_ptr, new_name); - return; - } + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_len & 0x03)) + png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); - if (profile_len < embedded_profile_len) { - png_warning(png_ptr, - "Embedded profile length too large in iCCP chunk"); + png_uint_32 embedded_profile_len = png_get_uint_32(profile); - png_free(png_ptr, new_name); - return; + if (profile_len != embedded_profile_len) + png_error(png_ptr, "Profile length does not match profile"); } - if (profile_len > embedded_profile_len) - { - png_warning(png_ptr, - "Truncating profile to actual length in iCCP chunk"); + name_len = png_check_keyword(png_ptr, name, new_name); - profile_len = embedded_profile_len; - } + if (name_len == 0) + png_error(png_ptr, "iCCP: invalid keyword"); - if (profile_len) - profile_len = png_text_compress(png_ptr, profile, - (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp); + new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE; /* Make sure we include the NULL after the name and the compression type */ - png_write_chunk_header(png_ptr, png_iCCP, - (png_uint_32)(name_len + profile_len + 2)); + ++name_len; - new_name[name_len + 1] = 0x00; + png_text_compress_init(&comp, profile, profile_len); - png_write_chunk_data(png_ptr, (png_bytep)new_name, - (png_size_t)(name_len + 2)); + /* Allow for keyword terminator and compression byte */ + if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); - if (profile_len) - { - png_write_compressed_data_out(png_ptr, &comp, profile_len); - } + png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len); + + png_write_chunk_data(png_ptr, new_name, name_len); + + png_write_compressed_data_out(png_ptr, &comp); png_write_chunk_end(png_ptr); - png_free(png_ptr, new_name); } #endif #ifdef PNG_WRITE_sPLT_SUPPORTED /* Write a sPLT chunk */ void /* PRIVATE */ -png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette) +png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) { - png_size_t name_len; - png_charp new_name; + png_uint_32 name_len; + png_byte new_name[80]; png_byte entrybuf[10]; png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); png_size_t palette_size = entry_size * spalette->nentries; @@ -1190,8 +1265,10 @@ png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette) png_debug(1, "in png_write_sPLT"); - if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0) - return; + name_len = png_check_keyword(png_ptr, spalette->name, new_name); + + if (name_len == 0) + png_error(png_ptr, "sPLT: invalid keyword"); /* Make sure we include the NULL after the name */ png_write_chunk_header(png_ptr, png_sPLT, @@ -1224,7 +1301,7 @@ png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette) png_save_uint_16(entrybuf + 8, ep->frequency); } - png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + png_write_chunk_data(png_ptr, entrybuf, entry_size); } #else ep=spalette->entries; @@ -1248,19 +1325,18 @@ png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette) png_save_uint_16(entrybuf + 8, ep[i].frequency); } - png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + png_write_chunk_data(png_ptr, entrybuf, entry_size); } #endif png_write_chunk_end(png_ptr); - png_free(png_ptr, new_name); } #endif #ifdef PNG_WRITE_sBIT_SUPPORTED /* Write the sBIT chunk */ void /* PRIVATE */ -png_write_sBIT(png_structp png_ptr, png_const_color_8p sbit, int color_type) +png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) { png_byte buf[4]; png_size_t size; @@ -1268,7 +1344,7 @@ png_write_sBIT(png_structp png_ptr, png_const_color_8p sbit, int color_type) png_debug(1, "in png_write_sBIT"); /* Make sure we don't depend upon the order of PNG_COLOR_8 */ - if (color_type & PNG_COLOR_MASK_COLOR) + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { png_byte maxbits; @@ -1301,7 +1377,7 @@ png_write_sBIT(png_structp png_ptr, png_const_color_8p sbit, int color_type) size = 1; } - if (color_type & PNG_COLOR_MASK_ALPHA) + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) { if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) { @@ -1319,42 +1395,33 @@ png_write_sBIT(png_structp png_ptr, png_const_color_8p sbit, int color_type) #ifdef PNG_WRITE_cHRM_SUPPORTED /* Write the cHRM chunk */ void /* PRIVATE */ -png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, - png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, - png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, - png_fixed_point blue_y) +png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy) { png_byte buf[32]; png_debug(1, "in png_write_cHRM"); /* Each value is saved in 1/100,000ths */ -#ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y, - green_x, green_y, blue_x, blue_y)) -#endif - { - png_save_uint_32(buf, (png_uint_32)white_x); - png_save_uint_32(buf + 4, (png_uint_32)white_y); + png_save_int_32(buf, xy->whitex); + png_save_int_32(buf + 4, xy->whitey); - png_save_uint_32(buf + 8, (png_uint_32)red_x); - png_save_uint_32(buf + 12, (png_uint_32)red_y); + png_save_int_32(buf + 8, xy->redx); + png_save_int_32(buf + 12, xy->redy); - png_save_uint_32(buf + 16, (png_uint_32)green_x); - png_save_uint_32(buf + 20, (png_uint_32)green_y); + png_save_int_32(buf + 16, xy->greenx); + png_save_int_32(buf + 20, xy->greeny); - png_save_uint_32(buf + 24, (png_uint_32)blue_x); - png_save_uint_32(buf + 28, (png_uint_32)blue_y); + png_save_int_32(buf + 24, xy->bluex); + png_save_int_32(buf + 28, xy->bluey); - png_write_complete_chunk(png_ptr, png_cHRM, buf, (png_size_t)32); - } + png_write_complete_chunk(png_ptr, png_cHRM, buf, 32); } #endif #ifdef PNG_WRITE_tRNS_SUPPORTED /* Write the tRNS chunk */ void /* PRIVATE */ -png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha, +png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, png_const_color_16p tran, int num_trans, int color_type) { png_byte buf[6]; @@ -1365,12 +1432,14 @@ png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha, { if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) { - png_warning(png_ptr, "Invalid number of transparent colors specified"); + png_app_warning(png_ptr, + "Invalid number of transparent colors specified"); return; } /* Write the chunk out as it is */ - png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, (png_size_t)num_trans); + png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, + (png_size_t)num_trans); } else if (color_type == PNG_COLOR_TYPE_GRAY) @@ -1378,7 +1447,7 @@ png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha, /* One 16 bit value */ if (tran->gray >= (1 << png_ptr->bit_depth)) { - png_warning(png_ptr, + png_app_warning(png_ptr, "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); return; @@ -1395,12 +1464,12 @@ png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha, png_save_uint_16(buf + 2, tran->green); png_save_uint_16(buf + 4, tran->blue); #ifdef PNG_WRITE_16BIT_SUPPORTED - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) #else - if (buf[0] | buf[2] | buf[4]) + if ((buf[0] | buf[2] | buf[4]) != 0) #endif { - png_warning(png_ptr, + png_app_warning(png_ptr, "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); return; } @@ -1410,7 +1479,7 @@ png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha, else { - png_warning(png_ptr, "Can't write tRNS with an alpha channel"); + png_app_warning(png_ptr, "Can't write tRNS with an alpha channel"); } } #endif @@ -1418,7 +1487,7 @@ png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha, #ifdef PNG_WRITE_bKGD_SUPPORTED /* Write the background chunk */ void /* PRIVATE */ -png_write_bKGD(png_structp png_ptr, png_const_color_16p back, int color_type) +png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) { png_byte buf[6]; @@ -1428,8 +1497,8 @@ png_write_bKGD(png_structp png_ptr, png_const_color_16p back, int color_type) { if ( #ifdef PNG_MNG_FEATURES_SUPPORTED - (png_ptr->num_palette || - (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && + (png_ptr->num_palette != 0 || + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) && #endif back->index >= png_ptr->num_palette) { @@ -1441,15 +1510,15 @@ png_write_bKGD(png_structp png_ptr, png_const_color_16p back, int color_type) png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); } - else if (color_type & PNG_COLOR_MASK_COLOR) + else if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { png_save_uint_16(buf, back->red); png_save_uint_16(buf + 2, back->green); png_save_uint_16(buf + 4, back->blue); #ifdef PNG_WRITE_16BIT_SUPPORTED - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) #else - if (buf[0] | buf[2] | buf[4]) + if ((buf[0] | buf[2] | buf[4]) != 0) #endif { png_warning(png_ptr, @@ -1480,7 +1549,7 @@ png_write_bKGD(png_structp png_ptr, png_const_color_16p back, int color_type) #ifdef PNG_WRITE_hIST_SUPPORTED /* Write the histogram */ void /* PRIVATE */ -png_write_hIST(png_structp png_ptr, png_const_uint_16p hist, int num_hist) +png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) { int i; png_byte buf[3]; @@ -1508,234 +1577,94 @@ png_write_hIST(png_structp png_ptr, png_const_uint_16p hist, int num_hist) } #endif -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ - defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) -/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, - * and if invalid, correct the keyword rather than discarding the entire - * chunk. The PNG 1.0 specification requires keywords 1-79 characters in - * length, forbids leading or trailing whitespace, multiple internal spaces, - * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. - * - * The new_key is allocated to hold the corrected keyword and must be freed - * by the calling routine. This avoids problems with trying to write to - * static keywords without having to have duplicate copies of the strings. - */ -png_size_t /* PRIVATE */ -png_check_keyword(png_structp png_ptr, png_const_charp key, png_charpp new_key) -{ - png_size_t key_len; - png_const_charp ikp; - png_charp kp, dp; - int kflag; - int kwarn=0; - - png_debug(1, "in png_check_keyword"); - - *new_key = NULL; - - if (key == NULL || (key_len = png_strlen(key)) == 0) - { - png_warning(png_ptr, "zero length keyword"); - return ((png_size_t)0); - } - - png_debug1(2, "Keyword to be checked is '%s'", key); - - *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); - - if (*new_key == NULL) - { - png_warning(png_ptr, "Out of memory while procesing keyword"); - return ((png_size_t)0); - } - - /* Replace non-printing characters with a blank and print a warning */ - for (ikp = key, dp = *new_key; *ikp != '\0'; ikp++, dp++) - { - if ((png_byte)*ikp < 0x20 || - ((png_byte)*ikp > 0x7E && (png_byte)*ikp < 0xA1)) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_02x, - (png_byte)*ikp); - png_formatted_warning(png_ptr, p, "invalid keyword character 0x@1"); - *dp = ' '; - } - - else - { - *dp = *ikp; - } - } - *dp = '\0'; - - /* Remove any trailing white space. */ - kp = *new_key + key_len - 1; - if (*kp == ' ') - { - png_warning(png_ptr, "trailing spaces removed from keyword"); - - while (*kp == ' ') - { - *(kp--) = '\0'; - key_len--; - } - } - - /* Remove any leading white space. */ - kp = *new_key; - if (*kp == ' ') - { - png_warning(png_ptr, "leading spaces removed from keyword"); - - while (*kp == ' ') - { - kp++; - key_len--; - } - } - - png_debug1(2, "Checking for multiple internal spaces in '%s'", kp); - - /* Remove multiple internal spaces. */ - for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) - { - if (*kp == ' ' && kflag == 0) - { - *(dp++) = *kp; - kflag = 1; - } - - else if (*kp == ' ') - { - key_len--; - kwarn = 1; - } - - else - { - *(dp++) = *kp; - kflag = 0; - } - } - *dp = '\0'; - if (kwarn) - png_warning(png_ptr, "extra interior spaces removed from keyword"); - - if (key_len == 0) - { - png_free(png_ptr, *new_key); - png_warning(png_ptr, "Zero length keyword"); - } - - if (key_len > 79) - { - png_warning(png_ptr, "keyword length must be 1 - 79 characters"); - (*new_key)[79] = '\0'; - key_len = 79; - } - - return (key_len); -} -#endif - #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write a tEXt chunk */ void /* PRIVATE */ -png_write_tEXt(png_structp png_ptr, png_const_charp key, png_const_charp text, +png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, png_size_t text_len) { - png_size_t key_len; - png_charp new_key; + png_uint_32 key_len; + png_byte new_key[80]; png_debug(1, "in png_write_tEXt"); - if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) - return; + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "tEXt: invalid keyword"); if (text == NULL || *text == '\0') text_len = 0; else - text_len = png_strlen(text); + text_len = strlen(text); + + if (text_len > PNG_UINT_31_MAX - (key_len+1)) + png_error(png_ptr, "tEXt: text too long"); /* Make sure we include the 0 after the key */ png_write_chunk_header(png_ptr, png_tEXt, - (png_uint_32)(key_len + text_len + 1)); + (png_uint_32)/*checked above*/(key_len + text_len + 1)); /* * We leave it to the application to meet PNG-1.0 requirements on the * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, - (png_size_t)(key_len + 1)); + png_write_chunk_data(png_ptr, new_key, key_len + 1); - if (text_len) - png_write_chunk_data(png_ptr, (png_const_bytep)text, - (png_size_t)text_len); + if (text_len != 0) + png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); png_write_chunk_end(png_ptr); - png_free(png_ptr, new_key); } #endif #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write a compressed text chunk */ void /* PRIVATE */ -png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text, - png_size_t text_len, int compression) +png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + int compression) { - png_size_t key_len; - png_byte buf; - png_charp new_key; + png_uint_32 key_len; + png_byte new_key[81]; compression_state comp; png_debug(1, "in png_write_zTXt"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - comp.input_len = 0; - - if ((key_len = png_check_keyword(png_ptr, key, &new_key)) == 0) + if (compression == PNG_TEXT_COMPRESSION_NONE) { - png_free(png_ptr, new_key); + png_write_tEXt(png_ptr, key, text, 0); return; } - if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) - { - png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); - png_free(png_ptr, new_key); - return; - } + if (compression != PNG_TEXT_COMPRESSION_zTXt) + png_error(png_ptr, "zTXt: invalid compression type"); - text_len = png_strlen(text); + key_len = png_check_keyword(png_ptr, key, new_key); - /* Compute the compressed data; do it now for the length */ - text_len = png_text_compress(png_ptr, text, text_len, compression, - &comp); + if (key_len == 0) + png_error(png_ptr, "zTXt: invalid keyword"); - /* Write start of chunk */ - png_write_chunk_header(png_ptr, png_zTXt, - (png_uint_32)(key_len+text_len + 2)); + /* Add the compression method and 1 for the keyword separator. */ + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; - /* Write key */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, - (png_size_t)(key_len + 1)); + /* Compute the compressed data; do it now for the length */ + png_text_compress_init(&comp, (png_const_bytep)text, + text == NULL ? 0 : strlen(text)); - png_free(png_ptr, new_key); + if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); - buf = (png_byte)compression; + /* Write start of chunk */ + png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len); - /* Write compression */ - png_write_chunk_data(png_ptr, &buf, (png_size_t)1); + /* Write key */ + png_write_chunk_data(png_ptr, new_key, key_len); /* Write the compressed data */ - png_write_compressed_data_out(png_ptr, &comp, text_len); + png_write_compressed_data_out(png_ptr, &comp); /* Close the chunk */ png_write_chunk_end(png_ptr); @@ -1745,100 +1674,107 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text, #ifdef PNG_WRITE_iTXt_SUPPORTED /* Write an iTXt chunk */ void /* PRIVATE */ -png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key, +png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, png_const_charp lang, png_const_charp lang_key, png_const_charp text) { - png_size_t lang_len, key_len, lang_key_len, text_len; - png_charp new_lang; - png_charp new_key = NULL; - png_byte cbuf[2]; + png_uint_32 key_len, prefix_len; + png_size_t lang_len, lang_key_len; + png_byte new_key[82]; compression_state comp; png_debug(1, "in png_write_iTXt"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; + key_len = png_check_keyword(png_ptr, key, new_key); - if ((key_len = png_check_keyword(png_ptr, key, &new_key)) == 0) - return; + if (key_len == 0) + png_error(png_ptr, "iTXt: invalid keyword"); - if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang)) == 0) + /* Set the compression flag */ + switch (compression) { - png_warning(png_ptr, "Empty language field in iTXt chunk"); - new_lang = NULL; - lang_len = 0; - } + case PNG_ITXT_COMPRESSION_NONE: + case PNG_TEXT_COMPRESSION_NONE: + compression = new_key[++key_len] = 0; /* no compression */ + break; - if (lang_key == NULL) - lang_key_len = 0; + case PNG_TEXT_COMPRESSION_zTXt: + case PNG_ITXT_COMPRESSION_zTXt: + compression = new_key[++key_len] = 1; /* compressed */ + break; - else - lang_key_len = png_strlen(lang_key); + default: + png_error(png_ptr, "iTXt: invalid compression"); + } - if (text == NULL) - text_len = 0; + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; /* for the keywod separator */ + /* We leave it to the application to meet PNG-1.0 requirements on the + * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of + * any non-Latin-1 characters except for NEWLINE. ISO PNG, however, + * specifies that the text is UTF-8 and this really doesn't require any + * checking. + * + * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + * + * TODO: validate the language tag correctly (see the spec.) + */ + if (lang == NULL) lang = ""; /* empty language is valid */ + lang_len = strlen(lang)+1; + if (lang_key == NULL) lang_key = ""; /* may be empty */ + lang_key_len = strlen(lang_key)+1; + if (text == NULL) text = ""; /* may be empty */ + + prefix_len = key_len; + if (lang_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; else - text_len = png_strlen(text); - - /* Compute the compressed data; do it now for the length */ - text_len = png_text_compress(png_ptr, text, text_len, compression - 2, - &comp); + prefix_len = (png_uint_32)(prefix_len + lang_len); + if (lang_key_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_key_len); - /* Make sure we include the compression flag, the compression byte, - * and the NULs after the key, lang, and lang_key parts - */ + png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); - png_write_chunk_header(png_ptr, png_iTXt, (png_uint_32)( - 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ - + key_len - + lang_len - + lang_key_len - + text_len)); + if (compression != 0) + { + if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + } - /* We leave it to the application to meet PNG-1.0 requirements on the - * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of - * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. - * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. - */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, (png_size_t)(key_len + 1)); + else + { + if (comp.input_len > PNG_UINT_31_MAX-prefix_len) + png_error(png_ptr, "iTXt: uncompressed text too long"); - /* Set the compression flag */ - if (compression == PNG_ITXT_COMPRESSION_NONE || - compression == PNG_TEXT_COMPRESSION_NONE) - cbuf[0] = 0; + /* So the string will fit in a chunk: */ + comp.output_len = (png_uint_32)/*SAFE*/comp.input_len; + } - else /* compression == PNG_ITXT_COMPRESSION_zTXt */ - cbuf[0] = 1; + png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len); - /* Set the compression method */ - cbuf[1] = 0; + png_write_chunk_data(png_ptr, new_key, key_len); - png_write_chunk_data(png_ptr, cbuf, (png_size_t)2); + png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len); - cbuf[0] = 0; - png_write_chunk_data(png_ptr, (new_lang ? (png_const_bytep)new_lang : cbuf), - (png_size_t)(lang_len + 1)); + png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); - png_write_chunk_data(png_ptr, (lang_key ? (png_const_bytep)lang_key : cbuf), - (png_size_t)(lang_key_len + 1)); + if (compression != 0) + png_write_compressed_data_out(png_ptr, &comp); - png_write_compressed_data_out(png_ptr, &comp, text_len); + else + png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len); png_write_chunk_end(png_ptr); - - png_free(png_ptr, new_key); - png_free(png_ptr, new_lang); } #endif #ifdef PNG_WRITE_oFFs_SUPPORTED /* Write the oFFs chunk */ void /* PRIVATE */ -png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, +png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, int unit_type) { png_byte buf[9]; @@ -1858,36 +1794,43 @@ png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, #ifdef PNG_WRITE_pCAL_SUPPORTED /* Write the pCAL chunk (described in the PNG extensions document) */ void /* PRIVATE */ -png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, +png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params) { - png_size_t purpose_len, units_len, total_len; + png_uint_32 purpose_len; + png_size_t units_len, total_len; png_size_tp params_len; png_byte buf[10]; - png_charp new_purpose; + png_byte new_purpose[80]; int i; png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); if (type >= PNG_EQUATION_LAST) - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + png_error(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, new_purpose); + + if (purpose_len == 0) + png_error(png_ptr, "pCAL: invalid keyword"); + + ++purpose_len; /* terminator */ - purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); - units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); + units_len = strlen(units) + (nparams == 0 ? 0 : 1); png_debug1(3, "pCAL units length = %d", (int)units_len); total_len = purpose_len + units_len + 10; params_len = (png_size_tp)png_malloc(png_ptr, - (png_alloc_size_t)(nparams * png_sizeof(png_size_t))); + (png_alloc_size_t)(nparams * (sizeof (png_size_t)))); /* Find the length of each parameter, making sure we don't count the * null terminator for the last parameter. */ for (i = 0; i < nparams; i++) { - params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1); png_debug2(3, "pCAL parameter %d length = %lu", i, (unsigned long)params_len[i]); total_len += params_len[i]; @@ -1895,7 +1838,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, png_debug1(3, "pCAL total length = %d", (int)total_len); png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len); - png_write_chunk_data(png_ptr, (png_const_bytep)new_purpose, purpose_len); + png_write_chunk_data(png_ptr, new_purpose, purpose_len); png_save_int_32(buf, X0); png_save_int_32(buf + 4, X1); buf[8] = (png_byte)type; @@ -1903,8 +1846,6 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, png_write_chunk_data(png_ptr, buf, (png_size_t)10); png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); - png_free(png_ptr, new_purpose); - for (i = 0; i < nparams; i++) { png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]); @@ -1918,7 +1859,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, #ifdef PNG_WRITE_sCAL_SUPPORTED /* Write the sCAL chunk */ void /* PRIVATE */ -png_write_sCAL_s(png_structp png_ptr, int unit, png_const_charp width, +png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, png_const_charp height) { png_byte buf[64]; @@ -1926,8 +1867,8 @@ png_write_sCAL_s(png_structp png_ptr, int unit, png_const_charp width, png_debug(1, "in png_write_sCAL_s"); - wlen = png_strlen(width); - hlen = png_strlen(height); + wlen = strlen(width); + hlen = strlen(height); total_len = wlen + hlen + 2; if (total_len > 64) @@ -1937,8 +1878,8 @@ png_write_sCAL_s(png_structp png_ptr, int unit, png_const_charp width, } buf[0] = (png_byte)unit; - png_memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ - png_memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ + memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ + memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len); @@ -1948,7 +1889,7 @@ png_write_sCAL_s(png_structp png_ptr, int unit, png_const_charp width, #ifdef PNG_WRITE_pHYs_SUPPORTED /* Write the pHYs chunk */ void /* PRIVATE */ -png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, +png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, int unit_type) { @@ -1972,7 +1913,7 @@ png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, * or png_convert_from_time_t(), or fill in the structure yourself. */ void /* PRIVATE */ -png_write_tIME(png_structp png_ptr, png_const_timep mod_time) +png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) { png_byte buf[7]; @@ -1999,7 +1940,7 @@ png_write_tIME(png_structp png_ptr, png_const_timep mod_time) /* Initializes the row writing capability of libpng */ void /* PRIVATE */ -png_write_start_row(png_structp png_ptr) +png_write_start_row(png_structrp png_ptr) { #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ @@ -2044,12 +1985,13 @@ png_write_start_row(png_structp png_ptr) } /* We only need to keep the previous row if we are using one of these. */ - if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + if ((png_ptr->do_filter & + (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0) { /* Set up previous row buffer */ png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size); - if (png_ptr->do_filter & PNG_FILTER_UP) + if ((png_ptr->do_filter & PNG_FILTER_UP) != 0) { png_ptr->up_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); @@ -2057,7 +1999,7 @@ png_write_start_row(png_structp png_ptr) png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; } - if (png_ptr->do_filter & PNG_FILTER_AVG) + if ((png_ptr->do_filter & PNG_FILTER_AVG) != 0) { png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); @@ -2065,7 +2007,7 @@ png_write_start_row(png_structp png_ptr) png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; } - if (png_ptr->do_filter & PNG_FILTER_PAETH) + if ((png_ptr->do_filter & PNG_FILTER_PAETH) != 0) { png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); @@ -2073,13 +2015,13 @@ png_write_start_row(png_structp png_ptr) png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; } } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, we need to set up width and height of pass */ - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; @@ -2101,15 +2043,11 @@ png_write_start_row(png_structp png_ptr) png_ptr->num_rows = png_ptr->height; png_ptr->usr_width = png_ptr->width; } - - png_zlib_claim(png_ptr, PNG_ZLIB_FOR_IDAT); - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; } /* Internal use only. Called when finished processing a row of data. */ void /* PRIVATE */ -png_write_finish_row(png_structp png_ptr) +png_write_finish_row(png_structrp png_ptr) { #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ @@ -2127,8 +2065,6 @@ png_write_finish_row(png_structp png_ptr) static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - int ret; - png_debug(1, "in png_write_finish_row"); /* Next row */ @@ -2140,10 +2076,10 @@ png_write_finish_row(png_structp png_ptr) #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, go to next pass */ - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; - if (png_ptr->transformations & PNG_INTERLACE) + if ((png_ptr->transformations & PNG_INTERLACE) != 0) { png_ptr->pass++; } @@ -2168,7 +2104,7 @@ png_write_finish_row(png_structp png_ptr) png_pass_ystart[png_ptr->pass]) / png_pass_yinc[png_ptr->pass]; - if (png_ptr->transformations & PNG_INTERLACE) + if ((png_ptr->transformations & PNG_INTERLACE) != 0) break; } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); @@ -2179,7 +2115,7 @@ png_write_finish_row(png_structp png_ptr) if (png_ptr->pass < 7) { if (png_ptr->prev_row != NULL) - png_memset(png_ptr->prev_row, 0, + memset(png_ptr->prev_row, 0, (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* png_ptr->usr_bit_depth, png_ptr->width)) + 1); @@ -2190,42 +2126,7 @@ png_write_finish_row(png_structp png_ptr) /* If we get here, we've just written the last row, so we need to flush the compressor */ - do - { - /* Tell the compressor we are done */ - ret = deflate(&png_ptr->zstream, Z_FINISH); - - /* Check for an error */ - if (ret == Z_OK) - { - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) - { - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - } - - else if (ret != Z_STREAM_END) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - - else - png_error(png_ptr, "zlib error"); - } - } while (ret != Z_STREAM_END); - - /* Write any extra space */ - if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) - { - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - - png_ptr->zstream.avail_out); - } - - png_zlib_release(png_ptr); - png_ptr->zstream.data_type = Z_BINARY; + png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH); } #ifdef PNG_WRITE_INTERLACING_SUPPORTED @@ -2389,7 +2290,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) /* Move the pixel */ if (dp != sp) - png_memcpy(dp, sp, pixel_bytes); + memcpy(dp, sp, pixel_bytes); /* Next pixel */ dp += pixel_bytes; @@ -2413,7 +2314,8 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) * been specified by the application, and then writes the row out with the * chosen filter. */ -static void png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row, +static void /* PRIVATE */ +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_size_t row_bytes); #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) @@ -2421,7 +2323,7 @@ static void png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row, #define PNG_LOMASK ((png_uint_32)0xffffL) #define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) void /* PRIVATE */ -png_write_find_filter(png_structp png_ptr, png_row_infop row_info) +png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) { png_bytep best_row; #ifdef PNG_WRITE_FILTER_SUPPORTED @@ -2481,7 +2383,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) /* We don't need to test the 'no filter' case if this is the only filter * that has been chosen, as it doesn't actually do anything to the data. */ - if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE) + if ((filter_to_do & PNG_FILTER_NONE) != 0 && filter_to_do != PNG_FILTER_NONE) { png_bytep rp; png_uint_32 sum = 0; @@ -2551,13 +2453,13 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) for (lp = row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { - *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + *dp = (png_byte)((int)*rp - (int)*lp); } best_row = png_ptr->sub_row; } - else if (filter_to_do & PNG_FILTER_SUB) + else if ((filter_to_do & PNG_FILTER_SUB) != 0) { png_bytep rp, dp, lp; png_uint_32 sum = 0, lmins = mins; @@ -2613,7 +2515,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) for (lp = row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { - v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + v = *dp = (png_byte)((int)*rp - (int)*lp); sum += (v < 128) ? v : 256 - v; @@ -2672,13 +2574,13 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) pp = prev_row + 1; i < row_bytes; i++, rp++, pp++, dp++) { - *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + *dp = (png_byte)((int)*rp - (int)*pp); } best_row = png_ptr->up_row; } - else if (filter_to_do & PNG_FILTER_UP) + else if ((filter_to_do & PNG_FILTER_UP) != 0) { png_bytep rp, dp, pp; png_uint_32 sum = 0, lmins = mins; @@ -2723,7 +2625,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, pp = prev_row + 1; i < row_bytes; i++) { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - (int)*pp++); sum += (v < 128) ? v : 256 - v; @@ -2781,18 +2683,18 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, pp = prev_row + 1; i < bpp; i++) { - *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + *dp++ = (png_byte)((int)*rp++ - ((int)*pp++ / 2)); } for (lp = row_buf + 1; i < row_bytes; i++) { - *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) - & 0xff); + *dp++ = + (png_byte)((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)); } best_row = png_ptr->avg_row; } - else if (filter_to_do & PNG_FILTER_AVG) + else if ((filter_to_do & PNG_FILTER_AVG) != 0) { png_bytep rp, dp, pp, lp; png_uint_32 sum = 0, lmins = mins; @@ -2836,7 +2738,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, pp = prev_row + 1; i < bpp; i++) { - v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - ((int)*pp++ / 2)); sum += (v < 128) ? v : 256 - v; } @@ -2844,7 +2746,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) for (lp = row_buf + 1; i < row_bytes; i++) { v = *dp++ = - (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); + (png_byte)(((int)*rp++ - ((int)*pp++ + (int)*lp++) / 2)); sum += (v < 128) ? v : 256 - v; @@ -2894,7 +2796,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) } /* Paeth filter */ - if (filter_to_do == PNG_FILTER_PAETH) + if ((filter_to_do == PNG_FILTER_PAETH) != 0) { png_bytep rp, dp, pp, cp, lp; png_size_t i; @@ -2902,7 +2804,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, pp = prev_row + 1; i < bpp; i++) { - *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + *dp++ = (png_byte)((int)*rp++ - (int)*pp++); } for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) @@ -2928,12 +2830,12 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; - *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + *dp++ = (png_byte)((int)*rp++ - p); } best_row = png_ptr->paeth_row; } - else if (filter_to_do & PNG_FILTER_PAETH) + else if ((filter_to_do & PNG_FILTER_PAETH) != 0) { png_bytep rp, dp, pp, cp, lp; png_uint_32 sum = 0, lmins = mins; @@ -2977,7 +2879,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, pp = prev_row + 1; i < bpp; i++) { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - (int)*pp++); sum += (v < 128) ? v : 256 - v; } @@ -3003,7 +2905,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) pc = (p + pc) < 0 ? -(p + pc) : p + pc; #endif p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; -#else /* PNG_SLOW_PAETH */ +#else /* SLOW_PAETH */ p = a + b - c; pa = abs(p - a); pb = abs(p - b); @@ -3017,9 +2919,9 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) else p = c; -#endif /* PNG_SLOW_PAETH */ +#endif /* SLOW_PAETH */ - v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + v = *dp++ = (png_byte)((int)*rp++ - p); sum += (v < 128) ? v : 256 - v; @@ -3066,7 +2968,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) best_row = png_ptr->paeth_row; } } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ /* Do the actual writing of the filtered row data from the chosen filter. */ png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); @@ -3086,73 +2988,22 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) png_ptr->prev_filters[j] = best_row[0]; } #endif -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ } /* Do the actual writing of a previously filtered row. */ static void -png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row, - png_size_t avail/*includes filter byte*/) +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t full_row_length/*includes filter byte*/) { png_debug(1, "in png_write_filtered_row"); png_debug1(2, "filter = %d", filtered_row[0]); - /* Set up the zlib input buffer */ - - png_ptr->zstream.next_in = filtered_row; - png_ptr->zstream.avail_in = 0; - /* Repeat until we have compressed all the data */ - do - { - int ret; /* Return of zlib */ - - /* Record the number of bytes available - zlib supports at least 65535 - * bytes at one step, depending on the size of the zlib type 'uInt', the - * maximum size zlib can write at once is ZLIB_IO_MAX (from pngpriv.h). - * Use this because on 16 bit systems 'rowbytes' can be up to 65536 (i.e. - * one more than 16 bits) and, in this case 'rowbytes+1' can overflow a - * uInt. ZLIB_IO_MAX can be safely reduced to cause zlib to be called - * with smaller chunks of data. - */ - if (png_ptr->zstream.avail_in == 0) - { - if (avail > ZLIB_IO_MAX) - { - png_ptr->zstream.avail_in = ZLIB_IO_MAX; - avail -= ZLIB_IO_MAX; - } - else - { - /* So this will fit in the available uInt space: */ - png_ptr->zstream.avail_in = (uInt)avail; - avail = 0; - } - } - - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); - - /* Check for compression errors */ - if (ret != Z_OK) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - - else - png_error(png_ptr, "zlib error"); - } - - /* See if it is time to write another IDAT */ - if (!(png_ptr->zstream.avail_out)) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - } - /* Repeat until all data has been compressed */ - } while (avail > 0 || png_ptr->zstream.avail_in > 0); + png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); +#ifdef PNG_WRITE_FILTER_SUPPORTED /* Swap the current and previous rows */ if (png_ptr->prev_row != NULL) { @@ -3162,6 +3013,7 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row, png_ptr->prev_row = png_ptr->row_buf; png_ptr->row_buf = tptr; } +#endif /* WRITE_FILTER */ /* Finish row - updates counters and flushes zlib if last row */ png_write_finish_row(png_ptr); @@ -3174,6 +3026,6 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row, { png_write_flush(png_ptr); } -#endif +#endif /* WRITE_FLUSH */ } -#endif /* PNG_WRITE_SUPPORTED */ +#endif /* WRITE */ diff --git a/src/3rdparty/libpng/qtpatches.diff b/src/3rdparty/libpng/qtpatches.diff new file mode 100644 index 0000000000..1fb9b3f0c0 --- /dev/null +++ b/src/3rdparty/libpng/qtpatches.diff @@ -0,0 +1,77 @@ +diff --git a/src/3rdparty/libpng/pnglibconf.h b/src/3rdparty/libpng/pnglibconf.h +index b4ec3c3..f0fdcf8 100644 +--- a/src/3rdparty/libpng/pnglibconf.h ++++ b/src/3rdparty/libpng/pnglibconf.h +@@ -27,7 +27,9 @@ + #define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + #define PNG_COLORSPACE_SUPPORTED + #define PNG_CONSOLE_IO_SUPPORTED ++#ifndef _WIN32_WCE + #define PNG_CONVERT_tIME_SUPPORTED ++#endif + #define PNG_EASY_ACCESS_SUPPORTED + /*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ + #define PNG_ERROR_TEXT_SUPPORTED +@@ -106,12 +108,14 @@ + #define PNG_SET_OPTION_SUPPORTED + #define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + #define PNG_SET_USER_LIMITS_SUPPORTED ++#ifndef _WIN32_WCE + #define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED + #define PNG_SIMPLIFIED_READ_BGR_SUPPORTED + #define PNG_SIMPLIFIED_READ_SUPPORTED + #define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + #define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED + #define PNG_SIMPLIFIED_WRITE_SUPPORTED ++#endif + #define PNG_STDIO_SUPPORTED + #define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + #define PNG_TEXT_SUPPORTED +diff --git a/src/3rdparty/libpng/pngpriv.h b/src/3rdparty/libpng/pngpriv.h +index 5980a3f..7185444 100644 +--- a/src/3rdparty/libpng/pngpriv.h ++++ b/src/3rdparty/libpng/pngpriv.h +@@ -23,6 +23,12 @@ + #ifndef PNGPRIV_H + #define PNGPRIV_H + ++#ifdef _MSC_VER ++# ifndef _CRT_SECURE_NO_DEPRECATE ++# define _CRT_SECURE_NO_DEPRECATE ++# endif ++#endif ++ + /* Feature Test Macros. The following are defined here to ensure that correctly + * implemented libraries reveal the APIs libpng needs to build and hide those + * that are not needed and potentially damaging to the compilation. +@@ -215,6 +221,11 @@ + # endif + #endif /* Setting PNG_BUILD_DLL if required */ + ++/* Modfied for usage in Qt: Do not export the libpng APIs */ ++#ifdef PNG_BUILD_DLL ++#undef PNG_BUILD_DLL ++#endif ++ + /* See pngconf.h for more details: the builder of the library may set this on + * the command line to the right thing for the specific compilation system or it + * may be automagically set above (at present we know of no system where it does +@@ -426,6 +437,9 @@ + #if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ + defined(_WIN32) || defined(__WIN32__) + # include /* defines _WINDOWS_ macro */ ++# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) ++# define _WINRT_ /* Define a macro for Windows Runtime builds */ ++# endif + #endif + #endif /* PNG_VERSION_INFO_ONLY */ + +@@ -436,7 +450,7 @@ + + /* Memory model/platform independent fns */ + #ifndef PNG_ABORT +-# ifdef _WINDOWS_ ++# if (defined(_WINDOWS_) || defined(_WIN32_WCE)) && !defined(_WINRT_) + # define PNG_ABORT() ExitProcess(0) + # else + # define PNG_ABORT() abort() -- cgit v1.2.3 From c52bcf733742837f7fbeedbb788c3c9285a24bb6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 9 Mar 2015 17:32:15 +0100 Subject: Support gradients natively in the PDF generator Add native support for linear and radial gradients to our PDF generator. This fixes a couple of issues with both the quality of the generated PDFs as well as sizes of the files. Task-number: QTBUG-42758 Change-Id: Ib905457e11e4dc52443c76b3761bca8d1fbe9bfc Reviewed-by: Stephen Chu Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qpdf.cpp | 490 +++++++++++++++++++++++++--------------------- src/gui/painting/qpdf_p.h | 13 +- 2 files changed, 270 insertions(+), 233 deletions(-) (limited to 'src') diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index cc1ad02eee..3f2ebb92a0 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -66,12 +66,9 @@ QT_BEGIN_NAMESPACE inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features() { QPaintEngine::PaintEngineFeatures f = QPaintEngine::AllFeatures; - f &= ~(QPaintEngine::PorterDuff | QPaintEngine::PerspectiveTransform + f &= ~(QPaintEngine::PorterDuff + | QPaintEngine::PerspectiveTransform | QPaintEngine::ObjectBoundingModeGradients -#ifndef USE_NATIVE_GRADIENTS - | QPaintEngine::LinearGradientFill -#endif - | QPaintEngine::RadialGradientFill | QPaintEngine::ConicalGradientFill); return f; } @@ -548,189 +545,6 @@ QByteArray QPdf::patternForBrush(const QBrush &b) return pattern_for_brush[style]; } -#ifdef USE_NATIVE_GRADIENTS -static void writeTriangleLine(uchar *&data, int xpos, int ypos, int xoff, int yoff, uint rgb, uchar flag, bool alpha) -{ - data[0] = flag; - data[1] = (uchar)(xpos >> 16); - data[2] = (uchar)(xpos >> 8); - data[3] = (uchar)(xpos >> 0); - data[4] = (uchar)(ypos >> 16); - data[5] = (uchar)(ypos >> 8); - data[6] = (uchar)(ypos >> 0); - data += 7; - if (alpha) { - *data++ = (uchar)qAlpha(rgb); - } else { - *data++ = (uchar)qRed(rgb); - *data++ = (uchar)qGreen(rgb); - *data++ = (uchar)qBlue(rgb); - } - xpos += xoff; - ypos += yoff; - data[0] = flag; - data[1] = (uchar)(xpos >> 16); - data[2] = (uchar)(xpos >> 8); - data[3] = (uchar)(xpos >> 0); - data[4] = (uchar)(ypos >> 16); - data[5] = (uchar)(ypos >> 8); - data[6] = (uchar)(ypos >> 0); - data += 7; - if (alpha) { - *data++ = (uchar)qAlpha(rgb); - } else { - *data++ = (uchar)qRed(rgb); - *data++ = (uchar)qGreen(rgb); - *data++ = (uchar)qBlue(rgb); - } -} - - -QByteArray QPdf::generateLinearGradientShader(const QLinearGradient *gradient, const QPointF *page_rect, bool alpha) -{ - // generate list of triangles with colors - QPointF start = gradient->start(); - QPointF stop = gradient->finalStop(); - QGradientStops stops = gradient->stops(); - QPointF offset = stop - start; - QGradient::Spread spread = gradient->spread(); - - if (gradient->spread() == QGradient::ReflectSpread) { - offset *= 2; - for (int i = stops.size() - 2; i >= 0; --i) { - QGradientStop stop = stops.at(i); - stop.first = 2. - stop.first; - stops.append(stop); - } - for (int i = 0 ; i < stops.size(); ++i) - stops[i].first /= 2.; - } - - QPointF orthogonal(offset.y(), -offset.x()); - qreal length = offset.x()*offset.x() + offset.y()*offset.y(); - - // find the max and min values in offset and orth direction that are needed to cover - // the whole page - int off_min = INT_MAX; - int off_max = INT_MIN; - qreal ort_min = INT_MAX; - qreal ort_max = INT_MIN; - for (int i = 0; i < 4; ++i) { - qreal off = ((page_rect[i].x() - start.x()) * offset.x() + (page_rect[i].y() - start.y()) * offset.y())/length; - qreal ort = ((page_rect[i].x() - start.x()) * orthogonal.x() + (page_rect[i].y() - start.y()) * orthogonal.y())/length; - off_min = qMin(off_min, qFloor(off)); - off_max = qMax(off_max, qCeil(off)); - ort_min = qMin(ort_min, ort); - ort_max = qMax(ort_max, ort); - } - ort_min -= 1; - ort_max += 1; - - start += off_min * offset + ort_min * orthogonal; - orthogonal *= (ort_max - ort_min); - int num = off_max - off_min; - - QPointF gradient_rect[4] = { start, - start + orthogonal, - start + num*offset, - start + num*offset + orthogonal }; - qreal xmin = gradient_rect[0].x(); - qreal xmax = gradient_rect[0].x(); - qreal ymin = gradient_rect[0].y(); - qreal ymax = gradient_rect[0].y(); - for (int i = 1; i < 4; ++i) { - xmin = qMin(xmin, gradient_rect[i].x()); - xmax = qMax(xmax, gradient_rect[i].x()); - ymin = qMin(ymin, gradient_rect[i].y()); - ymax = qMax(ymax, gradient_rect[i].y()); - } - xmin -= 1000; - xmax += 1000; - ymin -= 1000; - ymax += 1000; - start -= QPointF(xmin, ymin); - qreal factor_x = qreal(1<<24)/(xmax - xmin); - qreal factor_y = qreal(1<<24)/(ymax - ymin); - int xoff = (int)(orthogonal.x()*factor_x); - int yoff = (int)(orthogonal.y()*factor_y); - - QByteArray triangles; - triangles.resize(spread == QGradient::PadSpread ? 20*(stops.size()+2) : 20*num*stops.size()); - uchar *data = (uchar *) triangles.data(); - if (spread == QGradient::PadSpread) { - if (off_min > 0 || off_max < 1) { - // linear gradient outside of page - const QGradientStop ¤t_stop = off_min > 0 ? stops.at(stops.size()-1) : stops.at(0); - uint rgb = current_stop.second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, 0, alpha); - start += num*offset; - xpos = (int)(start.x()*factor_x); - ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, 1, alpha); - } else { - int flag = 0; - if (off_min < 0) { - uint rgb = stops.at(0).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - start -= off_min*offset; - flag = 1; - } - for (int s = 0; s < stops.size(); ++s) { - const QGradientStop ¤t_stop = stops.at(s); - uint rgb = current_stop.second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - if (s < stops.size()-1) - start += offset*(stops.at(s+1).first - stops.at(s).first); - flag = 1; - } - if (off_max > 1) { - start += (off_max - 1)*offset; - uint rgb = stops.at(stops.size()-1).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - } - } - } else { - for (int i = 0; i < num; ++i) { - uchar flag = 0; - for (int s = 0; s < stops.size(); ++s) { - uint rgb = stops.at(s).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - if (s < stops.size()-1) - start += offset*(stops.at(s+1).first - stops.at(s).first); - flag = 1; - } - } - } - triangles.resize((char *)data - triangles.constData()); - - QByteArray shader; - QPdf::ByteStream s(&shader); - s << "<<\n" - "/ShadingType 4\n" - "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << - "/AntiAlias true\n" - "/BitsPerCoordinate 24\n" - "/BitsPerComponent 8\n" - "/BitsPerFlag 8\n" - "/Decode [" << xmin << xmax << ymin << ymax << (alpha ? "0 1]\n" : "0 1 0 1 0 1]\n") << - "/AntiAlias true\n" - "/Length " << triangles.length() << "\n" - ">>\n" - "stream\n" << triangles << "endstream\n" - "endobj\n"; - return shader; -} -#endif static void moveToHook(qfixed x, qfixed y, void *data) { @@ -1381,6 +1195,8 @@ void QPdfEngine::setBrush() bool specifyColor; int gStateObject = 0; int patternObject = d->addBrushPattern(d->stroker.matrix, &specifyColor, &gStateObject); + if (!patternObject && !specifyColor) + return; *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs "); if (specifyColor) { @@ -2116,34 +1932,263 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, return image; } -#ifdef USE_NATIVE_GRADIENTS -int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject) +struct QGradientBound { + qreal start; + qreal stop; + int function; + bool reverse; +}; + +int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha) { - const QGradient *gradient = b.gradient(); - if (!gradient) - return 0; + QGradientStops stops = gradient->stops(); + if (stops.isEmpty()) { + stops << QGradientStop(0, Qt::black); + stops << QGradientStop(1, Qt::white); + } + if (stops.at(0).first > 0) + stops.prepend(QGradientStop(0, stops.at(0).second)); + if (stops.at(stops.size() - 1).first < 1) + stops.append(QGradientStop(1, stops.at(stops.size() - 1).second)); + + QVector functions; + for (int i = 0; i < stops.size() - 1; ++i) { + int f = addXrefEntry(-1); + QByteArray data; + QPdf::ByteStream s(&data); + s << "<<\n" + "/FunctionType 2\n" + "/Domain [0 1]\n" + "/N 1\n"; + if (alpha) { + s << "/C0 [" << stops.at(i).second.alphaF() << "]\n" + "/C1 [" << stops.at(i + 1).second.alphaF() << "]\n"; + } else { + s << "/C0 [" << stops.at(i).second.redF() << stops.at(i).second.greenF() << stops.at(i).second.blueF() << "]\n" + "/C1 [" << stops.at(i + 1).second.redF() << stops.at(i + 1).second.greenF() << stops.at(i + 1).second.blueF() << "]\n"; + } + s << ">>\n" + "endobj\n"; + write(data); + functions << f; + } + + QVector gradientBounds; - QTransform inv = matrix.inverted(); - QPointF page_rect[4] = { inv.map(QPointF(0, 0)), - inv.map(QPointF(width_, 0)), - inv.map(QPointF(0, height_)), - inv.map(QPointF(width_, height_)) }; + for (int step = from; step < to; ++step) { + if (reflect && step % 2) { + for (int i = stops.size() - 1; i > 0; --i) { + QGradientBound b; + b.start = step + 1 - qBound(0., stops.at(i).first, 1.); + b.stop = step + 1 - qBound(0., stops.at(i - 1).first, 1.); + b.function = functions.at(i - 1); + b.reverse = true; + gradientBounds << b; + } + } else { + for (int i = 0; i < stops.size() - 1; ++i) { + QGradientBound b; + b.start = step + qBound(0., stops.at(i).first, 1.); + b.stop = step + qBound(0., stops.at(i + 1).first, 1.); + b.function = functions.at(i); + b.reverse = false; + gradientBounds << b; + } + } + } - bool opaque = b.isOpaque(); + // normalize bounds to [0..1] + qreal bstart = gradientBounds.at(0).start; + qreal bend = gradientBounds.at(gradientBounds.size() - 1).stop; + qreal norm = 1./(bend - bstart); + for (int i = 0; i < gradientBounds.size(); ++i) { + gradientBounds[i].start = (gradientBounds[i].start - bstart)*norm; + gradientBounds[i].stop = (gradientBounds[i].stop - bstart)*norm; + } - QByteArray shader; - QByteArray alphaShader; - if (gradient->type() == QGradient::LinearGradient) { - const QLinearGradient *lg = static_cast(gradient); - shader = QPdf::generateLinearGradientShader(lg, page_rect); - if (!opaque) - alphaShader = QPdf::generateLinearGradientShader(lg, page_rect, true); + int function; + if (gradientBounds.size() > 1) { + function = addXrefEntry(-1); + QByteArray data; + QPdf::ByteStream s(&data); + s << "<<\n" + "/FunctionType 3\n" + "/Domain [0 1]\n" + "/Bounds ["; + for (int i = 1; i < gradientBounds.size(); ++i) + s << gradientBounds.at(i).start; + s << "]\n" + "/Encode ["; + for (int i = 0; i < gradientBounds.size(); ++i) + s << (gradientBounds.at(i).reverse ? "1 0 " : "0 1 "); + s << "]\n" + "/Functions ["; + for (int i = 0; i < gradientBounds.size(); ++i) + s << gradientBounds.at(i).function << "0 R "; + s << "]\n" + ">>\n"; + write(data); } else { - // ############# - return 0; + function = functions.at(0); + } + return function; +} + +int QPdfEnginePrivate::generateLinearGradientShader(const QLinearGradient *gradient, const QTransform &matrix, bool alpha) +{ + QPointF start = gradient->start(); + QPointF stop = gradient->finalStop(); + QPointF offset = stop - start; + Q_ASSERT(gradient->coordinateMode() == QGradient::LogicalMode); + + int from = 0; + int to = 1; + bool reflect = false; + switch (gradient->spread()) { + case QGradient::PadSpread: + break; + case QGradient::ReflectSpread: + reflect = true; + // fall through + case QGradient::RepeatSpread: { + // calculate required bounds + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + QTransform inv = matrix.inverted(); + QPointF page_rect[4] = { inv.map(pageRect.topLeft()), + inv.map(pageRect.topRight()), + inv.map(pageRect.bottomLeft()), + inv.map(pageRect.bottomRight()) }; + + qreal length = offset.x()*offset.x() + offset.y()*offset.y(); + + // find the max and min values in offset and orth direction that are needed to cover + // the whole page + from = INT_MAX; + to = INT_MIN; + for (int i = 0; i < 4; ++i) { + qreal off = ((page_rect[i].x() - start.x()) * offset.x() + (page_rect[i].y() - start.y()) * offset.y())/length; + from = qMin(from, qFloor(off)); + to = qMax(to, qCeil(off)); + } + + stop = start + to * offset; + start = start + from * offset;\ + break; + } + } + + int function = createShadingFunction(gradient, from, to, reflect, alpha); + + QByteArray shader; + QPdf::ByteStream s(&shader); + s << "<<\n" + "/ShadingType 2\n" + "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << + "/AntiAlias true\n" + "/Coords [" << start.x() << start.y() << stop.x() << stop.y() << "]\n" + "/Extend [true true]\n" + "/Function " << function << "0 R\n" + ">>\n" + "endobj\n"; + int shaderObject = addXrefEntry(-1); + write(shader); + return shaderObject; +} + +int QPdfEnginePrivate::generateRadialGradientShader(const QRadialGradient *gradient, const QTransform &matrix, bool alpha) +{ + QPointF p1 = gradient->center(); + double r1 = gradient->centerRadius(); + QPointF p0 = gradient->focalPoint(); + double r0 = gradient->focalRadius(); + + Q_ASSERT(gradient->coordinateMode() == QGradient::LogicalMode); + + int from = 0; + int to = 1; + bool reflect = false; + switch (gradient->spread()) { + case QGradient::PadSpread: + break; + case QGradient::ReflectSpread: + reflect = true; + // fall through + case QGradient::RepeatSpread: { + Q_ASSERT(qFuzzyIsNull(r0)); // QPainter emulates if this is not 0 + + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + QTransform inv = matrix.inverted(); + QPointF page_rect[4] = { inv.map(pageRect.topLeft()), + inv.map(pageRect.topRight()), + inv.map(pageRect.bottomLeft()), + inv.map(pageRect.bottomRight()) }; + + // increase to until the whole page fits into it + bool done = false; + while (!done) { + QPointF center = QPointF(p0.x() + to*(p1.x() - p0.x()), p0.y() + to*(p1.y() - p0.y())); + double radius = r0 + to*(r1 - r0); + double r2 = radius*radius; + done = true; + for (int i = 0; i < 4; ++i) { + QPointF off = page_rect[i] - center; + if (off.x()*off.x() + off.y()*off.y() > r2) { + ++to; + done = false; + break; + } + } + } + p1 = QPointF(p0.x() + to*(p1.x() - p0.x()), p0.y() + to*(p1.y() - p0.y())); + r1 = r0 + to*(r1 - r0); + break; + } } + + int function = createShadingFunction(gradient, from, to, reflect, alpha); + + QByteArray shader; + QPdf::ByteStream s(&shader); + s << "<<\n" + "/ShadingType 3\n" + "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << + "/AntiAlias true\n" + "/Domain [0 1]\n" + "/Coords [" << p0.x() << p0.y() << r0 << p1.x() << p1.y() << r1 << "]\n" + "/Extend [true true]\n" + "/Function " << function << "0 R\n" + ">>\n" + "endobj\n"; int shaderObject = addXrefEntry(-1); write(shader); + return shaderObject; +} + +int QPdfEnginePrivate::generateGradientShader(const QGradient *gradient, const QTransform &matrix, bool alpha) +{ + switch (gradient->type()) { + case QGradient::LinearGradient: + return generateLinearGradientShader(static_cast(gradient), matrix, alpha); + case QGradient::RadialGradient: + return generateRadialGradientShader(static_cast(gradient), matrix, alpha); + case QGradient::ConicalGradient: + default: + qWarning() << "Implement me!"; + } + return 0; +} + +int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QTransform &matrix, int *gStateObject) +{ + const QGradient *gradient = b.gradient(); + + if (!gradient || gradient->coordinateMode() != QGradient::LogicalMode) + return 0; + + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + + QTransform m = b.transform() * matrix; + int shaderObject = generateGradientShader(gradient, m); QByteArray str; QPdf::ByteStream s(&str); @@ -2152,12 +2197,12 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int "/PatternType 2\n" "/Shading " << shaderObject << "0 R\n" "/Matrix [" - << matrix.m11() - << matrix.m12() - << matrix.m21() - << matrix.m22() - << matrix.dx() - << matrix.dy() << "]\n"; + << m.m11() + << m.m12() + << m.m21() + << m.m22() + << m.dx() + << m.dy() << "]\n"; s << ">>\n" "endobj\n"; @@ -2165,7 +2210,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int write(str); currentPage->patterns.append(patternObj); - if (!opaque) { + if (!b.isOpaque()) { bool ca = true; QGradientStops stops = gradient->stops(); int a = stops.at(0).second.alpha(); @@ -2178,8 +2223,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int if (ca) { *gStateObject = addConstantAlphaObject(stops.at(0).second.alpha()); } else { - int alphaShaderObject = addXrefEntry(-1); - write(alphaShader); + int alphaShaderObject = generateGradientShader(gradient, m, true); QByteArray content; QPdf::ByteStream c(&content); @@ -2190,7 +2234,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int f << "<<\n" "/Type /XObject\n" "/Subtype /Form\n" - "/BBox [0 0 " << width_ << height_ << "]\n" + "/BBox [0 0 " << pageRect.width() << pageRect.height() << "]\n" "/Group <>\n" "/Resources <<\n" "/Shading << /Shader" << alphaShaderObject << alphaShaderObject << "0 R >>\n" @@ -2214,7 +2258,6 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int return patternObj; } -#endif int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha) { @@ -2236,6 +2279,7 @@ int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha) return object; } + int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, int *gStateObject) { int paintType = 2; // Uncolored tiling @@ -2251,13 +2295,9 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, //qDebug() << brushOrigin << matrix; Qt::BrushStyle style = brush.style(); - if (style == Qt::LinearGradientPattern) {// && style <= Qt::ConicalGradientPattern) { -#ifdef USE_NATIVE_GRADIENTS + if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern) {// && style <= Qt::ConicalGradientPattern) { *specifyColor = false; - return gradientBrush(b, matrix, gStateObject); -#else - return 0; -#endif + return gradientBrush(brush, matrix, gStateObject); } if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0) diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h index e7ff09cd3b..94e74f30b9 100644 --- a/src/gui/painting/qpdf_p.h +++ b/src/gui/painting/qpdf_p.h @@ -58,8 +58,6 @@ #include "private/qfontsubset_p.h" #include "qpagelayout.h" -// #define USE_NATIVE_GRADIENTS - QT_BEGIN_NAMESPACE const char *qt_real_to_string(qreal val, char *buf); @@ -116,9 +114,6 @@ namespace QPdf { QByteArray generateMatrix(const QTransform &matrix); QByteArray generateDashes(const QPen &pen); QByteArray patternForBrush(const QBrush &b); -#ifdef USE_NATIVE_GRADIENTS - QByteArray generateLinearGradientShader(const QLinearGradient *lg, const QPointF *page_rect, bool alpha = false); -#endif struct Stroker { Stroker(); @@ -276,9 +271,11 @@ public: QPageLayout m_pageLayout; private: -#ifdef USE_NATIVE_GRADIENTS - int gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject); -#endif + int gradientBrush(const QBrush &b, const QTransform &matrix, int *gStateObject); + int generateGradientShader(const QGradient *gradient, const QTransform &matrix, bool alpha = false); + int generateLinearGradientShader(const QLinearGradient *lg, const QTransform &matrix, bool alpha); + int generateRadialGradientShader(const QRadialGradient *gradient, const QTransform &matrix, bool alpha); + int createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha); void writeInfo(); void writePageRoot(); -- cgit v1.2.3 From b59521f2a40fab1205e7cec1c99c8c109f98021a Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 10 Apr 2015 10:42:54 +0200 Subject: Add FIXME comments to make Q[]Validator::setRange() non-virtual. There is no apparent reason why these functions should be virtual. The virtual keyword originates from the CVS import. Change-Id: I4f8051cd4e89ca3037a78d12f17c93265c755b8e Reviewed-by: Marc Mutz Reviewed-by: Jarek Kobus --- src/gui/util/qvalidator.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index 6b1e20c844..31dfd20d1a 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -448,6 +448,8 @@ void QIntValidator::fixup(QString &input) const input = locale().toString(entered); } +// FIXME: Qt 6: Make QIntValidator::setRange() non-virtual + /*! Sets the range of the validator to only accept integers between \a bottom and \a top inclusive. @@ -696,6 +698,7 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL return QValidator::Intermediate; } +// FIXME: Qt 6: Make QDoubleValidator::setRange() non-virtual /*! Sets the validator to accept doubles from \a minimum to \a maximum -- cgit v1.2.3 From 34ec0713bb5a2bc12782ab17ceabfead37c4b584 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 8 Apr 2015 13:09:10 +0200 Subject: Add a means to set the application icon where supported On OS X the application icon can be changed at runtime, so this adds a way to set this via the QPlatformIntegration. [ChangeLog][OS X] QApplication::setWindowIcon now changes the icon for the application in the dock. Task-number: QTBUG-43999 Change-Id: Ice298c0bd52f10f4866f37c6d3f20cf5419b7a1b Reviewed-by: Gabriel de Dietrich Reviewed-by: Jake Petroules --- src/gui/kernel/qguiapplication.cpp | 3 +++ src/gui/kernel/qplatformintegration.cpp | 14 ++++++++++++++ src/gui/kernel/qplatformintegration.h | 5 +++-- src/plugins/platforms/cocoa/qcocoaintegration.h | 2 ++ src/plugins/platforms/cocoa/qcocoaintegration.mm | 13 +++++++++++++ 5 files changed, 35 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 47c20a71fc..3e2b692cd0 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2840,6 +2840,9 @@ void QGuiApplication::setWindowIcon(const QIcon &icon) if (!QGuiApplicationPrivate::app_icon) QGuiApplicationPrivate::app_icon = new QIcon(); *QGuiApplicationPrivate::app_icon = icon; + if (QGuiApplicationPrivate::platform_integration + && QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::ApplicationIcon)) + QGuiApplicationPrivate::platform_integration->setApplicationIcon(icon); if (QGuiApplicationPrivate::is_app_running && !QGuiApplicationPrivate::is_app_closing) QGuiApplicationPrivate::self->notifyWindowIconChanged(); } diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index f2a92e10df..f917c09f6d 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -231,6 +231,8 @@ QPlatformServices *QPlatformIntegration::services() const implementation for QOpenGLContext::getProcAddress() and support returning a function pointer also for the standard, non-extension functions. This capability is a prerequisite for dynamic OpenGL loading. + + \value ApplicationIcon The platform supports setting the application icon. (since 5.5) */ /*! @@ -544,4 +546,16 @@ QOpenGLContext::OpenGLModuleType QPlatformIntegration::openGLModuleType() } #endif +/*! + \since 5.5 + + Platform integration function for setting the application icon. + + \sa QGuiApplication::setWindowIcon() +*/ +void QPlatformIntegration::setApplicationIcon(const QIcon &icon) const +{ + Q_UNUSED(icon); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index 34639e6929..473c75a9e0 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -90,7 +90,8 @@ public: WindowManagement, SyncState, RasterGLSurface, - AllGLFunctionsQueryable + AllGLFunctionsQueryable, + ApplicationIcon }; virtual ~QPlatformIntegration() { } @@ -169,7 +170,7 @@ public: #ifndef QT_NO_OPENGL virtual QOpenGLContext::OpenGLModuleType openGLModuleType(); #endif - + virtual void setApplicationIcon(const QIcon &icon) const; protected: void screenAdded(QPlatformScreen *screen, bool isPrimary = false); void destroyScreen(QPlatformScreen *screen); diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index dc9140d990..ee42a83446 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -138,6 +138,8 @@ public: QCocoaWindow *popPopupWindow(); QCocoaWindow *activePopupWindow() const; QList *popupWindowStack(); + + void setApplicationIcon(const QIcon &icon) const; private: static QCocoaIntegration *mInstance; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index aa33cfd8bc..c8f6dd05db 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -420,6 +420,7 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons case ForeignWindows: case RasterGLSurface: case ApplicationState: + case ApplicationIcon: return true; default: return QPlatformIntegration::hasCapability(cap); @@ -569,4 +570,16 @@ QList *QCocoaIntegration::popupWindowStack() return &m_popupWindowStack; } +void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const +{ + NSImage *image = nil; + if (!icon.isNull()) { + NSSize size = [[[NSApplication sharedApplication] dockTile] size]; + QPixmap pixmap = icon.pixmap(size.width, size.height); + image = static_cast(qt_mac_create_nsimage(pixmap)); + } + [[NSApplication sharedApplication] setApplicationIconImage:image]; + [image release]; +} + QT_END_NAMESPACE -- cgit v1.2.3 From 417a2210725f4aad83688b494fbc9d45342c134a Mon Sep 17 00:00:00 2001 From: Eike Hein Date: Thu, 9 Apr 2015 23:36:38 +0200 Subject: Expose ItemViewActivateItemOnSingleClick in QStyleHints This completes support for ItemViewActivateItemOnSingleClick in QPlatformIntegration and exposes the setting in QStyleHints. Based on the review process, the public name used is 'singleClickActivation' for brevity, as well as to avoid con- fusion over alluding to "item views" in the Qt Quick context. KDE Plasma intends to use this via Qt.styleHints to have Qt Quick-based UI correctly implement the global single vs. double click user preference for item activation. [ChangeLog][QtGui] Added QStyleHints::singleClickActivation to access whether the platform expects item activation to occur on single clicks rather than double clicks. Change-Id: I0916e9e68c3a157f95053da8227b2612803653f7 Reviewed-by: Friedemann Kleint --- src/gui/kernel/qplatformintegration.cpp | 2 ++ src/gui/kernel/qplatformintegration.h | 3 ++- src/gui/kernel/qplatformtheme.cpp | 2 ++ src/gui/kernel/qstylehints.cpp | 12 ++++++++++++ src/gui/kernel/qstylehints.h | 2 ++ 5 files changed, 20 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index f917c09f6d..4d973d47a5 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -396,6 +396,8 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const return QPlatformTheme::defaultThemeHint(QPlatformTheme::TabFocusBehavior); case ReplayMousePressOutsidePopup: return true; + case ItemViewActivateItemOnSingleClick: + return QPlatformTheme::defaultThemeHint(QPlatformTheme::ItemViewActivateItemOnSingleClick); } return 0; diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index 473c75a9e0..2aa502b3d2 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -147,7 +147,8 @@ public: ShowIsMaximized, MousePressAndHoldInterval, TabFocusBehavior, - ReplayMousePressOutsidePopup + ReplayMousePressOutsidePopup, + ItemViewActivateItemOnSingleClick }; virtual QVariant styleHint(StyleHint hint) const; diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index aa49d64309..36a71fe2da 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -434,6 +434,8 @@ QVariant QPlatformTheme::themeHint(ThemeHint hint) const return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::PasswordMaskCharacter); case QPlatformTheme::MousePressAndHoldInterval: return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::MousePressAndHoldInterval); + case QPlatformTheme::ItemViewActivateItemOnSingleClick: + return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::ItemViewActivateItemOnSingleClick); default: return QPlatformTheme::defaultThemeHint(hint); } diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp index b7af2e759f..7ff0f9f860 100644 --- a/src/gui/kernel/qstylehints.cpp +++ b/src/gui/kernel/qstylehints.cpp @@ -377,4 +377,16 @@ Qt::TabFocusBehavior QStyleHints::tabFocusBehavior() const return Qt::TabFocusBehavior(themeableHint(QPlatformTheme::TabFocusBehavior, QPlatformIntegration::TabFocusBehavior).toInt()); } +/*! + \property QStyleHints::singleClickActivation + \brief \c true if items should be activated by single click, \b false + if they should be activated by double click instead. + + \since 5.5 +*/ +bool QStyleHints::singleClickActivation() const +{ + return themeableHint(QPlatformTheme::ItemViewActivateItemOnSingleClick, QPlatformIntegration::ItemViewActivateItemOnSingleClick).toBool(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h index 5fbc851ee9..82eb8a6f7d 100644 --- a/src/gui/kernel/qstylehints.h +++ b/src/gui/kernel/qstylehints.h @@ -61,6 +61,7 @@ class Q_GUI_EXPORT QStyleHints : public QObject Q_PROPERTY(int startDragVelocity READ startDragVelocity STORED false CONSTANT FINAL) Q_PROPERTY(bool useRtlExtensions READ useRtlExtensions STORED false CONSTANT FINAL) Q_PROPERTY(Qt::TabFocusBehavior tabFocusBehavior READ tabFocusBehavior STORED false CONSTANT FINAL) + Q_PROPERTY(bool singleClickActivation READ singleClickActivation STORED false CONSTANT FINAL) public: void setMouseDoubleClickInterval(int mouseDoubleClickInterval); @@ -83,6 +84,7 @@ public: bool useRtlExtensions() const; bool setFocusOnTouchRelease() const; Qt::TabFocusBehavior tabFocusBehavior() const; + bool singleClickActivation() const; Q_SIGNALS: void cursorFlashTimeChanged(int cursorFlashTime); -- cgit v1.2.3 From ab8d20532039674ac749186c1773bc0d33cf19cf Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 16 Mar 2015 11:20:55 +0100 Subject: QStateMachine: move methods out of Private class. Also rename them to match the names in the scxml standard, and add the relevant description from the standard to the methods. Change-Id: I495832358f5836ed6ea04bf43061d42e29f4f743 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/statemachine/qstatemachine.cpp | 88 ++++++++++++++++++------------ src/corelib/statemachine/qstatemachine_p.h | 2 - 2 files changed, 54 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 375fe6c8e8..2fff03d8c1 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -177,6 +177,47 @@ QT_BEGIN_NAMESPACE // #define QSTATEMACHINE_DEBUG // #define QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG +/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : + +function isDescendant(state1, state2) + +Returns 'true' if state1 is a descendant of state2 (a child, or a child of a child, or a child of a +child of a child, etc.) Otherwise returns 'false'. +*/ +static inline bool isDescendant(const QAbstractState *state1, const QAbstractState *state2) +{ + Q_ASSERT(state1 != 0); + + for (QAbstractState *it = state1->parentState(); it != 0; it = it->parentState()) { + if (it == state2) + return true; + } + + return false; +} + +/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : + +function getProperAncestors(state1, state2) + +If state2 is null, returns the set of all ancestors of state1 in ancestry order (state1's parent +followed by the parent's parent, etc. up to an including the element). If state2 is +non-null, returns in ancestry order the set of all ancestors of state1, up to but not including +state2. (A "proper ancestor" of a state is its parent, or the parent's parent, or the parent's +parent's parent, etc.))If state2 is state1's parent, or equal to state1, or a descendant of state1, +this returns the empty set. +*/ +static QVector getProperAncestors(const QAbstractState *state, const QAbstractState *upperBound) +{ + Q_ASSERT(state != 0); + QVector result; + result.reserve(16); + for (QState *it = state->parentState(); it && it != upperBound; it = it->parentState()) { + result.append(it); + } + return result; +} + template static uint qHash(const QPointer &p) { return qHash(p.data()); } @@ -246,7 +287,7 @@ static int indexOfDescendant(QState *s, QAbstractState *desc) QList childStates = QStatePrivate::get(s)->childStates(); for (int i = 0; i < childStates.size(); ++i) { QAbstractState *c = childStates.at(i); - if ((c == desc) || QStateMachinePrivate::isDescendantOf(desc, c)) { + if ((c == desc) || isDescendant(desc, c)) { return i; } } @@ -258,9 +299,9 @@ bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState if (s1->parent() == s2->parent()) { return s1->parent()->children().indexOf(s1) < s2->parent()->children().indexOf(s2); - } else if (isDescendantOf(s1, s2)) { + } else if (isDescendant(s1, s2)) { return false; - } else if (isDescendantOf(s2, s1)) { + } else if (isDescendant(s2, s1)) { return true; } else { Q_ASSERT(s1->machine() != 0); @@ -276,9 +317,9 @@ bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState if (s1->parent() == s2->parent()) { return s2->parent()->children().indexOf(s2) < s1->parent()->children().indexOf(s1); - } else if (isDescendantOf(s1, s2)) { + } else if (isDescendant(s1, s2)) { return true; - } else if (isDescendantOf(s2, s1)) { + } else if (isDescendant(s2, s1)) { return false; } else { Q_ASSERT(s1->machine() != 0); @@ -293,13 +334,13 @@ QState *QStateMachinePrivate::findLCA(const QList &states) cons { if (states.isEmpty()) return 0; - QList ancestors = properAncestors(states.at(0), rootState()->parentState()); + QVector ancestors = getProperAncestors(states.at(0), rootState()->parentState()); for (int i = 0; i < ancestors.size(); ++i) { QState *anc = ancestors.at(i); bool ok = true; for (int j = states.size() - 1; (j > 0) && ok; --j) { const QAbstractState *s = states.at(j); - if (!isDescendantOf(s, anc)) + if (!isDescendant(s, anc)) ok = false; } if (ok) @@ -317,7 +358,7 @@ bool QStateMachinePrivate::isPreempted(const QAbstractState *s, const QSetsourceState()); QAbstractState *lca = findLCA(lst); - if (isDescendantOf(s, lca)) { + if (isDescendant(s, lca)) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ':' << transitions << "preempts selection of a transition from" << s << "because" << s << "is a descendant of" << lca; @@ -341,7 +382,7 @@ QSet QStateMachinePrivate::selectTransitions(QEvent *event continue; if (isPreempted(state, enabledTransitions)) continue; - QList lst = properAncestors(state, rootState()->parentState()); + QVector lst = getProperAncestors(state, rootState()->parentState()); if (QState *grp = toStandardState(state)) lst.prepend(grp); bool found = false; @@ -433,7 +474,7 @@ QList QStateMachinePrivate::computeStatesToExit(const QList::const_iterator it; for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { QAbstractState *s = *it; - if (isDescendantOf(s, lca)) + if (isDescendant(s, lca)) statesToExit.insert(s); } } @@ -457,7 +498,7 @@ void QStateMachinePrivate::exitStates(QEvent *event, const QListhistoryType == QHistoryState::DeepHistory) { - if (isAtomic(s0) && isDescendantOf(s0, s)) + if (isAtomic(s0) && isDescendant(s0, s)) QHistoryStatePrivate::get(h)->configuration.append(s0); } else if (s0->parentState() == s) { QHistoryStatePrivate::get(h)->configuration.append(s0); @@ -721,7 +762,7 @@ void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QState *r QSet &statesToEnter, QSet &statesForDefaultEntry) { - QList ancs = properAncestors(s, root); + QVector ancs = getProperAncestors(s, root); for (int i = 0; i < ancs.size(); ++i) { QState *anc = ancs.at(i); if (!anc->parentState()) @@ -734,7 +775,7 @@ void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QState *r bool hasDescendantInList = false; QSet::const_iterator it; for (it = statesToEnter.constBegin(); it != statesToEnter.constEnd(); ++it) { - if (isDescendantOf(*it, child)) { + if (isDescendant(*it, child)) { hasDescendantInList = true; break; } @@ -778,27 +819,6 @@ bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const || (ss && QStatePrivate::get(ss)->isMachine && (ss != rootState())); } - -bool QStateMachinePrivate::isDescendantOf(const QAbstractState *state, const QAbstractState *other) -{ - Q_ASSERT(state != 0); - for (QAbstractState *s = state->parentState(); s != 0; s = s->parentState()) { - if (s == other) - return true; - } - return false; -} - -QList QStateMachinePrivate::properAncestors(const QAbstractState *state, const QState *upperBound) -{ - Q_ASSERT(state != 0); - QList result; - for (QState *s = state->parentState(); s && s != upperBound; s = s->parentState()) { - result.append(s); - } - return result; -} - QState *QStateMachinePrivate::toStandardState(QAbstractState *state) { if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::StandardState)) diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index 1c885d1a36..d0cc56bc2a 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -156,8 +156,6 @@ public: static bool isParallel(const QAbstractState *s); bool isCompound(const QAbstractState *s) const; bool isAtomic(const QAbstractState *s) const; - static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other); - static QList properAncestors(const QAbstractState *s, const QState *upperBound); void goToState(QAbstractState *targetState); -- cgit v1.2.3 From e616bd2641b9cf6a18cabeae3f9c425f91bfc4b3 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 17 Mar 2015 13:23:51 +0100 Subject: QStateMachine: fix history state restoration. When a history state is entered that has an actual saved history (so not the initial state), the entry set was calculated wrongly in some cases. See the bug report for the specific case. The fix is to fully implement the standard, so method names in the private class are updated to reflect the names as used in the standard. Note that, as mentioned in the bug report, the algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ has a bug. What is implemented is the fixed algorithm as described in the current working draft as of Friday March 13, 2015. This draft can be found at: http://www.w3.org/Voice/2013/scxml-irp/SCXML.htm [ChangeLog][QtCore] Fixed an issue where a history state restore would activate too many states, possibly putting the state machine in an invalid state. Change-Id: Ibb5491b2fdcf3a167c223fa8c9c4aad302dbb795 Task-number: QTBUG-44963 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/statemachine/qstatemachine.cpp | 266 ++++++++++++++++++++++++----- src/corelib/statemachine/qstatemachine_p.h | 14 +- 2 files changed, 235 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 2fff03d8c1..477fa83705 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -196,6 +196,15 @@ static inline bool isDescendant(const QAbstractState *state1, const QAbstractSta return false; } +static bool containsDecendantOf(const QSet &states, const QAbstractState *node) +{ + Q_FOREACH (QAbstractState *s, states) + if (isDescendant(s, node)) + return true; + + return false; +} + /* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : function getProperAncestors(state1, state2) @@ -218,6 +227,41 @@ static QVector getProperAncestors(const QAbstractState *state, const QA return result; } +/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : + +function getEffectiveTargetStates(transition) + +Returns the states that will be the target when 'transition' is taken, dereferencing any history states. + +function getEffectiveTargetStates(transition) + targets = new OrderedSet() + for s in transition.target + if isHistoryState(s): + if historyValue[s.id]: + targets.union(historyValue[s.id]) + else: + targets.union(getEffectiveTargetStates(s.transition)) + else: + targets.add(s) + return targets +*/ +static QSet getEffectiveTargetStates(QAbstractTransition *transition) +{ + QSet targets; + foreach (QAbstractState *s, transition->targetStates()) { + if (QHistoryState *historyState = QStateMachinePrivate::toHistoryState(s)) { + QList historyConfiguration = QHistoryStatePrivate::get(historyState)->configuration; + if (!historyConfiguration.isEmpty()) + targets.unite(historyConfiguration.toSet()); + else if (QAbstractState *defaultState = historyState->defaultState()) + targets.insert(defaultState); // Qt does not support initial transitions, but uses the default state of the history state for this. + } else { + targets.insert(s); + } + } + return targets; +} + template static uint qHash(const QPointer &p) { return qHash(p.data()); } @@ -330,13 +374,16 @@ bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState } } -QState *QStateMachinePrivate::findLCA(const QList &states) const +QState *QStateMachinePrivate::findLCA(const QList &states, bool onlyCompound) const { if (states.isEmpty()) return 0; QVector ancestors = getProperAncestors(states.at(0), rootState()->parentState()); for (int i = 0; i < ancestors.size(); ++i) { QState *anc = ancestors.at(i); + if (onlyCompound && !isCompound(anc)) + continue; + bool ok = true; for (int j = states.size() - 1; (j > 0) && ok; --j) { const QAbstractState *s = states.at(j); @@ -349,6 +396,11 @@ QState *QStateMachinePrivate::findLCA(const QList &states) cons return 0; } +QState *QStateMachinePrivate::findLCCA(const QList &states) const +{ + return findLCA(states, true); +} + bool QStateMachinePrivate::isPreempted(const QAbstractState *s, const QSet &transitions) const { QSet::const_iterator it; @@ -416,7 +468,7 @@ void QStateMachinePrivate::microstep(QEvent *event, const QList pendingRestorables = computePendingRestorables(exitedStates); QSet statesForDefaultEntry; - QList enteredStates = computeStatesToEnter(enabledTransitions, statesForDefaultEntry); + QList enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry); QHash > assignmentsForEnteredStates = computePropertyAssignments(enteredStates, pendingRestorables); @@ -541,30 +593,22 @@ void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList QStateMachinePrivate::computeStatesToEnter(const QList &enabledTransitions, - QSet &statesForDefaultEntry) +QList QStateMachinePrivate::computeEntrySet(const QList &enabledTransitions, + QSet &statesForDefaultEntry) { QSet statesToEnter; if (pendingErrorStates.isEmpty()) { - for (int i = 0; i < enabledTransitions.size(); ++i) { - QAbstractTransition *t = enabledTransitions.at(i); - QList lst = t->targetStates(); - if (lst.isEmpty()) - continue; - QAbstractState *src = t->sourceState(); - if (src) - lst.prepend(src); - QState *lca = findLCA(lst); - for (int j = src ? 1 : 0; j < lst.size(); ++j) { - QAbstractState *s = lst.at(j); - addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry); + Q_FOREACH (QAbstractTransition *t, enabledTransitions) { + Q_FOREACH (QAbstractState *s, t->targetStates()) { + addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry); } - if (isParallel(lca)) { - QList lcac = QStatePrivate::get(lca)->childStates(); - foreach (QAbstractState* child,lcac) { - if (!statesToEnter.contains(child)) - addStatesToEnter(child,lca,statesToEnter,statesForDefaultEntry); - } +#ifdef QSTATEMACHINE_DEBUG + qDebug() << "computed entry set after descendants:" << statesToEnter; +#endif + QList effectiveTargetStates = getEffectiveTargetStates(t).toList(); + QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates); + Q_FOREACH (QAbstractState *s, effectiveTargetStates) { + addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry); } } } @@ -583,6 +627,51 @@ QList QStateMachinePrivate::computeStatesToEnter(const QList &effectiveTargetStates) +{ + if (effectiveTargetStates.isEmpty()) + return 0; + +#if 0 + // Qt only has external transitions, so skip the special case for the internal transitions + if (QState *tSource = t->sourceState()) { + if (isCompound(tSource)) { + bool allDescendants = true; + Q_FOREACH (QAbstractState *s, effectiveTargetStates) { + if (!isDescendant(s, tSource)) { + allDescendants = false; + break; + } + } + + if (allDescendants) + return tSource; + } + } +#endif + + QList states(effectiveTargetStates); + if (QAbstractState *src = t->sourceState()) + states.prepend(src); + return findLCCA(states); +} + void QStateMachinePrivate::enterStates(QEvent *event, const QList &exitedStates_sorted, const QList &statesToEnter_sorted, const QSet &statesForDefaultEntry, @@ -758,30 +847,126 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, } } -void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QState *root, +/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ has a bug. See + * QTBUG-44963 for details. The algorithm here is as described in + * http://www.w3.org/Voice/2013/scxml-irp/SCXML.htm as of Friday March 13, 2015. + +procedure addDescendantStatesToEnter(state,statesToEnter,statesForDefaultEntry, defaultHistoryContent): + if isHistoryState(state): + if historyValue[state.id]: + for s in historyValue[state.id]: + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent) + for s in historyValue[state.id]: + addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent) + else: + defaultHistoryContent[state.parent.id] = state.transition.content + for s in state.transition.target: + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent) + for s in state.transition.target: + addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent) + else: + statesToEnter.add(state) + if isCompoundState(state): + statesForDefaultEntry.add(state) + for s in state.initial.transition.target: + addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent) + for s in state.initial.transition.target: + addAncestorStatesToEnter(s, state, statesToEnter, statesForDefaultEntry, defaultHistoryContent) + else: + if isParallelState(state): + for child in getChildStates(state): + if not statesToEnter.some(lambda s: isDescendant(s,child)): + addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent) +*/ +void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state, + QSet &statesToEnter, + QSet &statesForDefaultEntry) +{ + if (QHistoryState *h = toHistoryState(state)) { + QList historyConfiguration = QHistoryStatePrivate::get(h)->configuration; + if (!historyConfiguration.isEmpty()) { + Q_FOREACH (QAbstractState *s, historyConfiguration) + addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry); + Q_FOREACH (QAbstractState *s, historyConfiguration) + addAncestorStatesToEnter(s, state->parentState(), statesToEnter, statesForDefaultEntry); + +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": restoring" + << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow") + << "history from" << state << ':' << historyConfiguration; +#endif + } else { + QList defaultHistoryContent; + if (QHistoryStatePrivate::get(h)->defaultState) + defaultHistoryContent.append(QHistoryStatePrivate::get(h)->defaultState); + + if (defaultHistoryContent.isEmpty()) { + setError(QStateMachine::NoDefaultStateInHistoryStateError, h); + } else { + Q_FOREACH (QAbstractState *s, defaultHistoryContent) + addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry); + Q_FOREACH (QAbstractState *s, defaultHistoryContent) + addAncestorStatesToEnter(s, state->parentState(), statesToEnter, statesForDefaultEntry); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": initial history targets for" << state << ':' << defaultHistoryContent; +#endif + } + } + } else { + if (state == rootState()) { + // Error has already been set by exitStates(). + Q_ASSERT(error != QStateMachine::NoError); + return; + } + statesToEnter.insert(state); + if (isCompound(state)) { + statesForDefaultEntry.insert(state); + if (QAbstractState *initial = toStandardState(state)->initialState()) { + Q_ASSERT(initial->machine() == q_func()); + + // Qt does not support initial transitions (which is a problem for parallel states). + // The way it simulates this for other states, is by having a single initial state. + statesForDefaultEntry.insert(initial); + + addDescendantStatesToEnter(initial, statesToEnter, statesForDefaultEntry); + addAncestorStatesToEnter(initial, state, statesToEnter, statesForDefaultEntry); + } else { + setError(QStateMachine::NoInitialStateError, state); + return; + } + } else if (isParallel(state)) { + QState *grp = toStandardState(state); + Q_FOREACH (QAbstractState *child, QStatePrivate::get(grp)->childStates()) { + if (!containsDecendantOf(statesToEnter, child)) + addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry); + } + } + } +} + + +/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : + +procedure addAncestorStatesToEnter(state, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent) + for anc in getProperAncestors(state,ancestor): + statesToEnter.add(anc) + if isParallelState(anc): + for child in getChildStates(anc): + if not statesToEnter.some(lambda s: isDescendant(s,child)): + addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent) +*/ +void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QAbstractState *ancestor, QSet &statesToEnter, QSet &statesForDefaultEntry) { - QVector ancs = getProperAncestors(s, root); - for (int i = 0; i < ancs.size(); ++i) { - QState *anc = ancs.at(i); + Q_FOREACH (QState *anc, getProperAncestors(s, ancestor)) { if (!anc->parentState()) continue; statesToEnter.insert(anc); if (isParallel(anc)) { - QList lst = QStatePrivate::get(anc)->childStates(); - for (int j = 0; j < lst.size(); ++j) { - QAbstractState *child = lst.at(j); - bool hasDescendantInList = false; - QSet::const_iterator it; - for (it = statesToEnter.constBegin(); it != statesToEnter.constEnd(); ++it) { - if (isDescendant(*it, child)) { - hasDescendantInList = true; - break; - } - } - if (!hasDescendantInList) - addStatesToEnter(child, anc, statesToEnter, statesForDefaultEntry); + Q_FOREACH (QAbstractState *child, QStatePrivate::get(anc)->childStates()) { + if (!containsDecendantOf(statesToEnter, child)) + addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry); } } } @@ -1403,8 +1588,7 @@ void QStateMachinePrivate::_q_start() executeTransitionContent(&nullEvent, transitions); QList exitedStates = QList(); QSet statesForDefaultEntry; - QList enteredStates = computeStatesToEnter(transitions, - statesForDefaultEntry); + QList enteredStates = computeEntrySet(transitions, statesForDefaultEntry); QHash pendingRestorables; QHash > assignmentsForEnteredStates = computePropertyAssignments(enteredStates, pendingRestorables); diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index d0cc56bc2a..a8f0745730 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -100,7 +100,8 @@ public: static QStateMachinePrivate *get(QStateMachine *q); - QState *findLCA(const QList &states) const; + QState *findLCA(const QList &states, bool onlyCompound = false) const; + QState *findLCCA(const QList &states) const; static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2); static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2); @@ -137,12 +138,17 @@ public: , const QList &selectedAnimations #endif ); - QList computeStatesToEnter(const QList &enabledTransitions, - QSet &statesForDefaultEntry); + QList computeEntrySet(const QList &enabledTransitions, + QSet &statesForDefaultEntry); + QAbstractState *getTransitionDomain(QAbstractTransition *t, + const QList &effectiveTargetStates); + void addDescendantStatesToEnter(QAbstractState *state, + QSet &statesToEnter, + QSet &statesForDefaultEntry); void addStatesToEnter(QAbstractState *s, QState *root, QSet &statesToEnter, QSet &statesForDefaultEntry); - void addAncestorStatesToEnter(QAbstractState *s, QState *root, + void addAncestorStatesToEnter(QAbstractState *s, QAbstractState *ancestor, QSet &statesToEnter, QSet &statesForDefaultEntry); -- cgit v1.2.3 From b2f6406b6f3c6374df2751a4669fbe51f04d09e7 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 18 Mar 2015 12:44:22 +0100 Subject: QStateMachine: remove conflicting transitions after selection. After selecting all (enabled) transitions for a microstep, filter out any conflicting transition. The actual conflict resulution is done by ordering the transitions in order of the states that selected them. For example: if an event would trigger two transitions in a parallel state where one would exit that state and the other would not, this filtering prevents the state machine from selecting both states (as this case is an invalid state of the whole machine). This also fixes the exit set calculation for parallel states when one of its substates is exited and subsequently re-entered in the same transition. Previously, the parallel state was not exited, and subsequent re-entry was ignored (because it was still active). Now it is correctly exited and re-entered. A side-effect of the transition ordering mentioned above is it also fixes the non-deterministic behavior of which of the conflicting transitions is taken. [ChangeLog][QtCore] Fixed an issue where the state machine could end up in an invalid state when transitions from a parallel state were not checked for conflicts. [ChangeLog][QtCore] Fixed a case where a parallel state was not exited and re-entered when one of its substates was exited and subsequently re-entered. [ChangeLog][QtCore] Fixed the non-deterministic behavior of picking a transition from a set of conflicting transitions. Task-number: QTBUG-44783 Change-Id: I2ee72b6a2f552077bfa7aa4d369474ab62f4c2f0 Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Kevin Funk --- src/corelib/statemachine/qstatemachine.cpp | 214 ++++++++++++++++++++--------- src/corelib/statemachine/qstatemachine_p.h | 10 +- 2 files changed, 157 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 477fa83705..eec3febbfe 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -251,10 +251,17 @@ static QSet getEffectiveTargetStates(QAbstractTransition *tran foreach (QAbstractState *s, transition->targetStates()) { if (QHistoryState *historyState = QStateMachinePrivate::toHistoryState(s)) { QList historyConfiguration = QHistoryStatePrivate::get(historyState)->configuration; - if (!historyConfiguration.isEmpty()) + if (!historyConfiguration.isEmpty()) { + // There is a saved history, so apply that. targets.unite(historyConfiguration.toSet()); - else if (QAbstractState *defaultState = historyState->defaultState()) - targets.insert(defaultState); // Qt does not support initial transitions, but uses the default state of the history state for this. + } else if (QAbstractState *defaultState = historyState->defaultState()) { + // Qt does not support initial transitions, but uses the default state of the history state for this. + targets.insert(defaultState); + } else { + // Woops, we found a history state without a default state. That's not valid! + QStateMachinePrivate *m = QStateMachinePrivate::get(historyState->machine()); + m->setError(QStateMachine::NoDefaultStateInHistoryStateError, historyState); + } } else { targets.insert(s); } @@ -338,6 +345,15 @@ static int indexOfDescendant(QState *s, QAbstractState *desc) return -1; } +bool QStateMachinePrivate::transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2) +{ + QState *s1 = t1->sourceState(), *s2 = t2->sourceState(); + if (s1 == s2) + return QStatePrivate::get(s1)->transitions().indexOf(t1) < QStatePrivate::get(s2)->transitions().indexOf(t2); + else + return stateEntryLessThan(t1->sourceState(), t2->sourceState()); +} + bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2) { if (s1->parent() == s2->parent()) { @@ -401,40 +417,21 @@ QState *QStateMachinePrivate::findLCCA(const QList &states) con return findLCA(states, true); } -bool QStateMachinePrivate::isPreempted(const QAbstractState *s, const QSet &transitions) const +QList QStateMachinePrivate::selectTransitions(QEvent *event) { - QSet::const_iterator it; - for (it = transitions.constBegin(); it != transitions.constEnd(); ++it) { - QAbstractTransition *t = *it; - QList lst = t->targetStates(); - if (!lst.isEmpty()) { - lst.prepend(t->sourceState()); - QAbstractState *lca = findLCA(lst); - if (isDescendant(s, lca)) { -#ifdef QSTATEMACHINE_DEBUG - qDebug() << q_func() << ':' << transitions << "preempts selection of a transition from" - << s << "because" << s << "is a descendant of" << lca; -#endif - return true; - } - } + Q_Q(const QStateMachine); + + QVarLengthArray configuration_sorted; + foreach (QAbstractState *s, configuration) { + if (isAtomic(s)) + configuration_sorted.append(s); } - return false; -} + std::sort(configuration_sorted.begin(), configuration_sorted.end(), stateEntryLessThan); -QSet QStateMachinePrivate::selectTransitions(QEvent *event) const -{ - Q_Q(const QStateMachine); - QSet enabledTransitions; - QSet::const_iterator it; + QList enabledTransitions; const_cast(q)->beginSelectTransitions(event); - for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { - QAbstractState *state = *it; - if (!isAtomic(state)) - continue; - if (isPreempted(state, enabledTransitions)) - continue; - QVector lst = getProperAncestors(state, rootState()->parentState()); + foreach (QAbstractState *state, configuration_sorted) { + QVector lst = getProperAncestors(state, Q_NULLPTR); if (QState *grp = toStandardState(state)) lst.prepend(grp); bool found = false; @@ -447,29 +444,94 @@ QSet QStateMachinePrivate::selectTransitions(QEvent *event #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": selecting transition" << t; #endif - enabledTransitions.insert(t); + enabledTransitions.append(t); found = true; break; } } } } + + if (!enabledTransitions.isEmpty()) { + removeConflictingTransitions(enabledTransitions); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": enabled transitions after removing conflicts:" << enabledTransitions; +#endif + } const_cast(q)->endSelectTransitions(event); return enabledTransitions; } +/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : + +function removeConflictingTransitions(enabledTransitions): + filteredTransitions = new OrderedSet() + // toList sorts the transitions in the order of the states that selected them + for t1 in enabledTransitions.toList(): + t1Preempted = false; + transitionsToRemove = new OrderedSet() + for t2 in filteredTransitions.toList(): + if computeExitSet([t1]).hasIntersection(computeExitSet([t2])): + if isDescendant(t1.source, t2.source): + transitionsToRemove.add(t2) + else: + t1Preempted = true + break + if not t1Preempted: + for t3 in transitionsToRemove.toList(): + filteredTransitions.delete(t3) + filteredTransitions.add(t1) + + return filteredTransitions +*/ +void QStateMachinePrivate::removeConflictingTransitions(QList &enabledTransitions) +{ + QList filteredTransitions; + filteredTransitions.reserve(enabledTransitions.size()); + std::sort(enabledTransitions.begin(), enabledTransitions.end(), transitionStateEntryLessThan); + + Q_FOREACH (QAbstractTransition *t1, enabledTransitions) { + bool t1Preempted = false; + QVarLengthArray transitionsToRemove; + QSet exitSetT1 = computeExitSet_Unordered(QList() << t1); + Q_FOREACH (QAbstractTransition *t2, filteredTransitions) { + QSet exitSetT2 = computeExitSet_Unordered(QList() << t2); + if (!exitSetT1.intersect(exitSetT2).isEmpty()) { + if (isDescendant(t1->sourceState(), t2->sourceState())) { + transitionsToRemove.append(t2); + } else { + t1Preempted = true; + break; + } + } + } + if (!t1Preempted) { + Q_FOREACH (QAbstractTransition *t3, transitionsToRemove) + filteredTransitions.removeAll(t3); + filteredTransitions.append(t1); + } + } + + enabledTransitions = filteredTransitions; +} + void QStateMachinePrivate::microstep(QEvent *event, const QList &enabledTransitions) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ')'; qDebug() << q_func() << ": configuration before exiting states:" << configuration; #endif - QList exitedStates = computeStatesToExit(enabledTransitions); + QList exitedStates = computeExitSet(enabledTransitions); QHash pendingRestorables = computePendingRestorables(exitedStates); QSet statesForDefaultEntry; QList enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry); +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q_func() << ": computed exit set:" << exitedStates; + qDebug() << q_func() << ": computed entry set:" << enteredStates; +#endif + QHash > assignmentsForEnteredStates = computePropertyAssignments(enteredStates, pendingRestorables); if (!pendingRestorables.isEmpty()) { @@ -502,38 +564,63 @@ void QStateMachinePrivate::microstep(QEvent *event, const QList QStateMachinePrivate::computeStatesToExit(const QList &enabledTransitions) +/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : + +procedure computeExitSet(enabledTransitions) + +For each transition t in enabledTransitions, if t is targetless then do nothing, else compute the +transition's domain. (This will be the source state in the case of internal transitions) or the +least common compound ancestor state of the source state and target states of t (in the case of +external transitions. Add to the statesToExit set all states in the configuration that are +descendants of the domain. + +function computeExitSet(transitions) + statesToExit = new OrderedSet + for t in transitions: + if (t.target): + domain = getTransitionDomain(t) + for s in configuration: + if isDescendant(s,domain): + statesToExit.add(s) + return statesToExit +*/ +QList QStateMachinePrivate::computeExitSet(const QList &enabledTransitions) +{ + QList statesToExit_sorted = computeExitSet_Unordered(enabledTransitions).toList(); + std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan); + return statesToExit_sorted; +} + +QSet QStateMachinePrivate::computeExitSet_Unordered(const QList &enabledTransitions) { QSet statesToExit; -// QSet statesToSnapshot; for (int i = 0; i < enabledTransitions.size(); ++i) { QAbstractTransition *t = enabledTransitions.at(i); - QList lst = t->targetStates(); - if (lst.isEmpty()) - continue; - lst.prepend(t->sourceState()); - QAbstractState *lca = findLCA(lst); - if (lca == 0) { - setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState()); - lst = pendingErrorStates.toList(); + QList effectiveTargetStates = getEffectiveTargetStates(t).toList(); + QAbstractState *domain = getTransitionDomain(t, effectiveTargetStates); + if (domain == Q_NULLPTR && !t->targetStates().isEmpty()) { + // So we didn't find the least common ancestor for the source and target states of the + // transition. If there were not target states, that would be fine: then the transition + // will fire any events or signals, but not exit the state. + // + // However, there are target states, so it's either a node without a parent (or parent's + // parent, etc), or the state belongs to a different state machine. Either way, this + // makes the state machine invalid. + if (error == QStateMachine::NoError) + setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState()); + QList lst = pendingErrorStates.toList(); lst.prepend(t->sourceState()); - lca = findLCA(lst); - Q_ASSERT(lca != 0); + domain = findLCCA(lst); + Q_ASSERT(domain != 0); } - { - QSet::const_iterator it; - for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { - QAbstractState *s = *it; - if (isDescendant(s, lca)) - statesToExit.insert(s); - } + Q_FOREACH (QAbstractState* s, configuration) { + if (isDescendant(s, domain)) + statesToExit.insert(s); } } - QList statesToExit_sorted = statesToExit.toList(); - std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan); - return statesToExit_sorted; + return statesToExit; } void QStateMachinePrivate::exitStates(QEvent *event, const QList &statesToExit_sorted, @@ -602,9 +689,7 @@ QList QStateMachinePrivate::computeEntrySet(const QListtargetStates()) { addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry); } -#ifdef QSTATEMACHINE_DEBUG - qDebug() << "computed entry set after descendants:" << statesToEnter; -#endif + QList effectiveTargetStates = getEffectiveTargetStates(t).toList(); QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates); Q_FOREACH (QAbstractState *s, effectiveTargetStates) { @@ -643,7 +728,7 @@ function getTransitionDomain(t) else: return findLCCA([t.source].append(tstates)) */ -QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t, const QList &effectiveTargetStates) +QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t, const QList &effectiveTargetStates) const { if (effectiveTargetStates.isEmpty()) return 0; @@ -1285,6 +1370,9 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta Q_ASSERT(currentErrorState != rootState()); if (currentErrorState != 0) { +#ifdef QSTATEMACHINE_DEBUG + qDebug() << q << ": entering error state" << currentErrorState << "from" << currentContext; +#endif QState *lca = findLCA(QList() << currentErrorState << currentContext); addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry); } else { @@ -1640,7 +1728,7 @@ void QStateMachinePrivate::_q_process() processing = false; break; } - QSet enabledTransitions; + QList enabledTransitions; QEvent *e = new QEvent(QEvent::None); enabledTransitions = selectTransitions(e); if (enabledTransitions.isEmpty()) { @@ -1676,7 +1764,7 @@ void QStateMachinePrivate::_q_process() } if (!enabledTransitions.isEmpty()) { q->beginMicrostep(e); - microstep(e, enabledTransitions.toList()); + microstep(e, enabledTransitions); q->endMicrostep(e); } #ifdef QSTATEMACHINE_DEBUG diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index a8f0745730..a88f95f1f5 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -103,6 +103,7 @@ public: QState *findLCA(const QList &states, bool onlyCompound = false) const; QState *findLCCA(const QList &states) const; + static bool transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2); static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2); static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2); @@ -123,12 +124,13 @@ public: void clearHistory(); QAbstractTransition *createInitialTransition() const; + void removeConflictingTransitions(QList &enabledTransitions); void microstep(QEvent *event, const QList &transitionList); - bool isPreempted(const QAbstractState *s, const QSet &transitions) const; - QSet selectTransitions(QEvent *event) const; + QList selectTransitions(QEvent *event); void exitStates(QEvent *event, const QList &statesToExit_sorted, const QHash > &assignmentsForEnteredStates); - QList computeStatesToExit(const QList &enabledTransitions); + QList computeExitSet(const QList &enabledTransitions); + QSet computeExitSet_Unordered(const QList &enabledTransitions); void executeTransitionContent(QEvent *event, const QList &transitionList); void enterStates(QEvent *event, const QList &exitedStates_sorted, const QList &statesToEnter_sorted, @@ -141,7 +143,7 @@ public: QList computeEntrySet(const QList &enabledTransitions, QSet &statesForDefaultEntry); QAbstractState *getTransitionDomain(QAbstractTransition *t, - const QList &effectiveTargetStates); + const QList &effectiveTargetStates) const; void addDescendantStatesToEnter(QAbstractState *state, QSet &statesToEnter, QSet &statesForDefaultEntry); -- cgit v1.2.3 From 7e721d24d7828097ad5cdabcf8371edb3b0ca969 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Thu, 2 Apr 2015 01:15:34 +0400 Subject: [QWin32PrintEngine] Do not do any language-specific processing ...and simply use the glyph indices provided by the QTextItemInt (since we always provide the glyph indices, even for non-TTFs). Task-number: QTBUG-40683 Change-Id: I276e9c6831a770e888f9ba0640353d20711a3d02 Reviewed-by: Lars Knoll --- src/printsupport/kernel/qprintengine_win.cpp | 36 +++++++--------------------- 1 file changed, 8 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index 910c6c1514..731e923b2b 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -69,7 +69,7 @@ extern QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit f // #define QT_DEBUG_METRICS static void draw_text_item_win(const QPointF &_pos, const QTextItemInt &ti, HDC hdc, - bool convertToText, const QTransform &xform, const QPointF &topLeft); + const QTransform &xform, const QPointF &topLeft); QWin32PrintEngine::QWin32PrintEngine(QPrinter::PrinterMode mode) : QAlphaPaintEngine(*(new QWin32PrintEnginePrivate), @@ -309,27 +309,12 @@ void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem return ; } - // We only want to convert the glyphs to text if the entire string is compatible with ASCII - // and if we actually have access to the chars. - bool convertToText = ti.chars != 0; - for (int i=0; i < ti.num_chars; ++i) { - if (ti.chars[i].unicode() >= 0x80) { - convertToText = false; - break; - } - - if (ti.logClusters[i] != i) { - convertToText = false; - break; - } - } - COLORREF cf = RGB(qRed(brushColor), qGreen(brushColor), qBlue(brushColor)); SelectObject(d->hdc, CreateSolidBrush(cf)); SelectObject(d->hdc, CreatePen(PS_SOLID, 1, cf)); SetTextColor(d->hdc, cf); - draw_text_item_win(p, ti, d->hdc, convertToText, d->matrix, QPointF(0.0, 0.0)); + draw_text_item_win(p, ti, d->hdc, d->matrix, QPointF(0.0, 0.0)); DeleteObject(SelectObject(d->hdc,GetStockObject(HOLLOW_BRUSH))); DeleteObject(SelectObject(d->hdc,GetStockObject(BLACK_PEN))); } @@ -1682,7 +1667,7 @@ void QWin32PrintEnginePrivate::debugMetrics() const } static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc, - bool convertToText, const QTransform &xform, const QPointF &topLeft) + const QTransform &xform, const QPointF &topLeft) { QPointF baseline_pos = xform.inverted().map(xform.map(pos) - topLeft); @@ -1692,24 +1677,20 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h const bool has_kerning = ti.f && ti.f->kerning(); HFONT hfont = 0; - bool ttf = false; if (ti.fontEngine->type() == QFontEngine::Win) { const QVariantMap userData = ti.fontEngine->userData().toMap(); const QVariant hfontV = userData.value(QStringLiteral("hFont")); const QVariant ttfV = userData.value(QStringLiteral("trueType")); - if (ttfV.type() == QVariant::Bool && hfontV.canConvert()) { + if (ttfV.toBool() && hfontV.canConvert()) hfont = hfontV.value(); - ttf = ttfV.toBool(); - } } if (!hfont) hfont = (HFONT)GetStockObject(ANSI_VAR_FONT); HGDIOBJ old_font = SelectObject(hdc, hfont); - unsigned int options = (ttf && !convertToText) ? ETO_GLYPH_INDEX : 0; - wchar_t *convertedGlyphs = (wchar_t *)ti.chars; + unsigned int options = ETO_GLYPH_INDEX; QGlyphLayout glyphs = ti.glyphs; bool fast = !has_kerning && !(ti.flags & QTextItem::RightToLeft); @@ -1743,7 +1724,7 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h ExtTextOut(hdc, qRound(baseline_pos.x() + glyphs.offsets[0].x.toReal()), qRound(baseline_pos.y() + glyphs.offsets[0].y.toReal()), - options, 0, convertToText ? convertedGlyphs : g.data(), glyphs.numGlyphs, 0); + options, 0, g.constData(), glyphs.numGlyphs, 0); } else { QVarLengthArray positions; QVarLengthArray _glyphs; @@ -1756,7 +1737,6 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h return; } - convertToText = convertToText && glyphs.numGlyphs == _glyphs.size(); bool outputEntireItem = _glyphs.size() > 0; if (outputEntireItem) { @@ -1772,7 +1752,7 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0; g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1]; ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0, - convertToText ? convertedGlyphs : g.data(), _glyphs.size(), + g.constData(), _glyphs.size(), glyphDistances.data()); } else { int i = 0; @@ -1781,7 +1761,7 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h ExtTextOut(hdc, qRound(positions[i].x), qRound(positions[i].y), options, 0, - convertToText ? convertedGlyphs + i : &g, 1, 0); + &g, 1, 0); ++i; } } -- cgit v1.2.3 From 6c6fe766a84214b5dfaaff06ce44610fdf4b098f Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 10 Apr 2015 10:47:34 +0200 Subject: Improve QTextDocument::toPlainText doc related to inline images "Embedded objects, such as images, are represented by a Unicode value U+FFFC (OBJECT REPLACEMENT CHARACTER)." Also updated the QTextImageFormat docs with the same wording. Task-number: QTBUG-44538 Change-Id: I64dd5f5be4a0ecc64b30758a72f8b4281c17924b Reviewed-by: Lars Knoll Reviewed-by: Konstantin Ritt --- src/gui/text/qtextdocument.cpp | 3 +++ src/gui/text/qtextformat.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index e8dd663354..d3b70aaf26 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -1142,6 +1142,9 @@ void QTextDocument::setMetaInformation(MetaInformation info, const QString &stri Returns the plain text contained in the document. If you want formatting information use a QTextCursor instead. + \note Embedded objects, such as images, are represented by a + Unicode value U+FFFC (OBJECT REPLACEMENT CHARACTER). + \sa toHtml() */ QString QTextDocument::toPlainText() const diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index c60d0cc775..598a22d9c6 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -3027,8 +3027,8 @@ QTextTableFormat::QTextTableFormat(const QTextFormat &fmt) \ingroup richtext-processing \ingroup shared - Inline images are represented by an object replacement character - (0xFFFC in Unicode) which has an associated QTextImageFormat. The + Inline images are represented by a Unicode value U+FFFC (OBJECT + REPLACEMENT CHARACTER) which has an associated QTextImageFormat. The image format specifies a name with setName() that is used to locate the image. The size of the rectangle that the image will occupy is specified using setWidth() and setHeight(). -- cgit v1.2.3 From 4ecae86e4b44c564e0f9b0e869e85f1c9febbdb4 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Fri, 3 Apr 2015 16:40:15 +0300 Subject: xcb: Handle XSettings for a virtual desktop rather than for an output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtual desktop may be composed of several outputs which are represented by the QXcbScreen class. XSettings are related to the virtual desktop, so introduce a QXcbVirtualDesktop class and store QXcbXSettings in it. Change-Id: Ib2261675ef8e5136592d4b856bc84646db3a3af4 Reviewed-by: Uli Schlachter Reviewed-by: Jørgen Lind --- src/plugins/platforms/xcb/qxcbconnection.cpp | 44 ++++++++++++++-------------- src/plugins/platforms/xcb/qxcbconnection.h | 6 ++-- src/plugins/platforms/xcb/qxcbcursor.cpp | 2 +- src/plugins/platforms/xcb/qxcbcursor.h | 2 +- src/plugins/platforms/xcb/qxcbscreen.cpp | 44 +++++++++++++++++++--------- src/plugins/platforms/xcb/qxcbscreen.h | 36 +++++++++++++++++------ src/plugins/platforms/xcb/qxcbxsettings.cpp | 10 +++---- src/plugins/platforms/xcb/qxcbxsettings.h | 4 +-- 8 files changed, 92 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index f0cd4c8484..3d65b789a4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -143,7 +143,7 @@ QXcbScreen* QXcbConnection::findScreenForOutput(xcb_window_t rootWindow, xcb_ran return 0; } -QXcbScreen* QXcbConnection::createScreen(int screenNumber, xcb_screen_t* xcbScreen, +QXcbScreen* QXcbConnection::createScreen(QXcbVirtualDesktop* virtualDesktop, xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output) { @@ -156,10 +156,10 @@ QXcbScreen* QXcbConnection::createScreen(int screenNumber, xcb_screen_t* xcbScre int dotPos = displayName.lastIndexOf('.'); if (dotPos != -1) displayName.truncate(dotPos); - name = QString::fromLocal8Bit(displayName) + QLatin1Char('.') + QString::number(screenNumber); + name = QString::fromLocal8Bit(displayName) + QLatin1Char('.') + QString::number(virtualDesktop->number()); } - return new QXcbScreen(this, xcbScreen, outputId, output, name, screenNumber); + return new QXcbScreen(this, virtualDesktop, outputId, output, name); } bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output) @@ -179,15 +179,11 @@ bool QXcbConnection::checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_out return isPrimary; } -xcb_screen_t* QXcbConnection::xcbScreenForRootWindow(xcb_window_t rootWindow, int *xcbScreenNumber) +QXcbVirtualDesktop* QXcbConnection::virtualDesktopForRootWindow(xcb_window_t rootWindow) { - xcb_screen_iterator_t xcbScreenIter = xcb_setup_roots_iterator(m_setup); - for (; xcbScreenIter.rem; xcb_screen_next(&xcbScreenIter)) { - if (xcbScreenIter.data->root == rootWindow) { - if (xcbScreenNumber) - *xcbScreenNumber = xcb_setup_roots_length(m_setup) - xcbScreenIter.rem; - return xcbScreenIter.data; - } + foreach (QXcbVirtualDesktop *virtualDesktop, m_virtualDesktops) { + if (virtualDesktop->screen()->root == rootWindow) + return virtualDesktop; } return 0; @@ -200,8 +196,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) { if (event->subCode == XCB_RANDR_NOTIFY_CRTC_CHANGE) { xcb_randr_crtc_change_t crtc = event->u.cc; - xcb_screen_t *xcbScreen = xcbScreenForRootWindow(crtc.window); - if (!xcbScreen) + QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(crtc.window); + if (!virtualDesktop) // Not for us return; @@ -218,9 +214,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) } else if (event->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) { xcb_randr_output_change_t output = event->u.oc; - int xcbScreenNumber = 0; - xcb_screen_t *xcbScreen = xcbScreenForRootWindow(output.window, &xcbScreenNumber); - if (!xcbScreen) + QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(output.window); + if (!virtualDesktop) // Not for us return; @@ -248,7 +243,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) QScopedPointer outputInfo( xcb_randr_get_output_info_reply(xcb_connection(), outputInfoCookie, NULL)); - screen = createScreen(xcbScreenNumber, xcbScreen, output.output, outputInfo.data()); + screen = createScreen(virtualDesktop, output.output, outputInfo.data()); qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled"; screen->setPrimary(checkOutputIsPrimary(output.window, output.output)); @@ -299,14 +294,15 @@ void QXcbConnection::initializeScreens() xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); int xcbScreenNumber = 0; // screen number in the xcb sense QXcbScreen* primaryScreen = Q_NULLPTR; - xcb_screen_t *xcbScreen = Q_NULLPTR; bool hasOutputs = false; while (it.rem) { // Each "screen" in xcb terminology is a virtual desktop, // potentially a collection of separate juxtaposed monitors. // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.) // which will become virtual siblings. - xcbScreen = it.data; + xcb_screen_t *xcbScreen = it.data; + QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber); + m_virtualDesktops.append(virtualDesktop); QList siblings; int outputCount = 0; int connectedOutputCount = 0; @@ -376,7 +372,7 @@ void QXcbConnection::initializeScreens() continue; } - QXcbScreen *screen = createScreen(xcbScreenNumber, xcbScreen, outputs[i], output.data()); + QXcbScreen *screen = createScreen(virtualDesktop, outputs[i], output.data()); siblings << screen; ++connectedOutputCount; hasOutputs = true; @@ -411,8 +407,9 @@ void QXcbConnection::initializeScreens() // but the dimensions are known anyway, and we don't already have any lingering // (possibly disconnected) screens, then showing windows should be possible, // so create one screen. (QTBUG-31389) - if (xcbScreen && !hasOutputs && xcbScreen->width_in_pixels > 0 && xcbScreen->height_in_pixels > 0 && m_screens.isEmpty()) { - QXcbScreen *screen = createScreen(0, xcbScreen, 0, Q_NULLPTR); + QXcbVirtualDesktop *virtualDesktop = m_virtualDesktops.value(0); + if (virtualDesktop && !hasOutputs && !virtualDesktop->size().isEmpty() && m_screens.isEmpty()) { + QXcbScreen *screen = createScreen(virtualDesktop, 0, Q_NULLPTR); screen->setVirtualSiblings(QList() << screen); m_screens << screen; primaryScreen = screen; @@ -583,6 +580,9 @@ QXcbConnection::~QXcbConnection() while (!m_screens.isEmpty()) integration->destroyScreen(m_screens.takeLast()); + while (!m_virtualDesktops.isEmpty()) + delete m_virtualDesktops.takeLast(); + delete m_glIntegration; #ifdef XCB_USE_XLIB diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index f479c1bc80..91547dd697 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -80,6 +80,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaXInput) Q_DECLARE_LOGGING_CATEGORY(lcQpaXInputDevices) Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen) +class QXcbVirtualDesktop; class QXcbScreen; class QXcbWindow; class QXcbDrag; @@ -494,12 +495,12 @@ private: void initializeXShape(); void initializeXKB(); void handleClientMessageEvent(const xcb_client_message_event_t *event); - QXcbScreen* createScreen(int screenNumber, xcb_screen_t* xcbScreen, + QXcbScreen* createScreen(QXcbVirtualDesktop *virtualDesktop, xcb_randr_output_t outputId = XCB_NONE, xcb_randr_get_output_info_reply_t *output = 0); QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc); QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output); - xcb_screen_t* xcbScreenForRootWindow(xcb_window_t rootWindow, int *xcbScreenNumber = 0); + QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow); bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output); void initializeScreens(); void updateScreens(const xcb_randr_notify_event_t *event); @@ -564,6 +565,7 @@ private: const xcb_setup_t *m_setup; bool m_canGrabServer; + QList m_virtualDesktops; QList m_screens; int m_primaryScreenNumber; diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 8dd27ec9c5..e30cc26313 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -502,7 +502,7 @@ bool updateCursorTheme(void *dpy, const QByteArray &theme) { return setTheme; } - void QXcbCursor::cursorThemePropertyChanged(QXcbScreen *screen, const QByteArray &name, const QVariant &property, void *handle) + void QXcbCursor::cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle) { Q_UNUSED(screen); Q_UNUSED(name); diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h index 1280c7e042..7e5cdc6870 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.h +++ b/src/plugins/platforms/xcb/qxcbcursor.h @@ -91,7 +91,7 @@ private: CursorHash m_cursorHash; #endif #ifdef XCB_USE_XLIB - static void cursorThemePropertyChanged(QXcbScreen *screen, + static void cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle); diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 6f1fc08167..fcf70f3c51 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -47,11 +47,33 @@ QT_BEGIN_NAMESPACE -QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, +QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t *screen, int number) + : QXcbObject(connection) + , m_screen(screen) + , m_number(number) + , m_xSettings(Q_NULLPTR) +{ +} + +QXcbVirtualDesktop::~QXcbVirtualDesktop() +{ + delete m_xSettings; +} + +QXcbXSettings *QXcbVirtualDesktop::xSettings() const +{ + if (!m_xSettings) { + QXcbVirtualDesktop *self = const_cast(this); + self->m_xSettings = new QXcbXSettings(self); + } + return m_xSettings; +} + +QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop, xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output, - QString outputName, int number) + QString outputName) : QXcbObject(connection) - , m_screen(scr) + , m_virtualDesktop(virtualDesktop) , m_output(outputId) , m_crtc(output ? output->crtc : 0) , m_mode(XCB_NONE) @@ -59,10 +81,9 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, , m_rotation(XCB_RANDR_ROTATION_ROTATE_0) , m_outputName(outputName) , m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize()) - , m_virtualSize(scr->width_in_pixels, scr->height_in_pixels) - , m_virtualSizeMillimeters(scr->width_in_millimeters, scr->height_in_millimeters) + , m_virtualSize(virtualDesktop->size()) + , m_virtualSizeMillimeters(virtualDesktop->physicalSize()) , m_orientation(Qt::PrimaryOrientation) - , m_number(number) , m_refreshRate(60) , m_forcedDpi(-1) , m_devicePixelRatio(1) @@ -70,7 +91,6 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, , m_noFontHinting(false) , m_subpixelType(QFontEngine::SubpixelAntialiasingType(-1)) , m_antialiasingEnabled(-1) - , m_xSettings(0) { if (connection->hasXRandr()) { xcb_randr_select_input(xcb_connection(), screen()->root, true); @@ -215,7 +235,7 @@ QXcbScreen::~QXcbScreen() QWindow *QXcbScreen::topLevelAt(const QPoint &p) const { - xcb_window_t root = m_screen->root; + xcb_window_t root = screen()->root; int dpr = int(devicePixelRatio()); int x = p.x() / dpr; @@ -496,7 +516,7 @@ void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode) // we can safely use get_screen_resources_current here, because in order to // get here, we must have called get_screen_resources before xcb_randr_get_screen_resources_current_cookie_t resourcesCookie = - xcb_randr_get_screen_resources_current_unchecked(xcb_connection(), m_screen->root); + xcb_randr_get_screen_resources_current_unchecked(xcb_connection(), screen()->root); xcb_randr_get_screen_resources_current_reply_t *resources = xcb_randr_get_screen_resources_current_reply(xcb_connection(), resourcesCookie, NULL); if (resources) { @@ -707,11 +727,7 @@ void QXcbScreen::readXResources() QXcbXSettings *QXcbScreen::xSettings() const { - if (!m_xSettings) { - QXcbScreen *self = const_cast(this); - self->m_xSettings = new QXcbXSettings(self); - } - return m_xSettings; + return m_virtualDesktop->xSettings(); } static inline void formatRect(QDebug &debug, const QRect r) diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 3f228465f2..6b60ea9bb1 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -54,12 +54,32 @@ class QXcbXSettings; class QDebug; #endif +class QXcbVirtualDesktop : public QXcbObject +{ +public: + QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t *screen, int number); + ~QXcbVirtualDesktop(); + + xcb_screen_t *screen() const { return m_screen; } + int number() const { return m_number; } + QSize size() const { return QSize(m_screen->width_in_pixels, m_screen->height_in_pixels); } + QSize physicalSize() const { return QSize(m_screen->width_in_millimeters, m_screen->height_in_millimeters); } + + QXcbXSettings *xSettings() const; + +private: + xcb_screen_t *m_screen; + int m_number; + + QXcbXSettings *m_xSettings; +}; + class Q_XCB_EXPORT QXcbScreen : public QXcbObject, public QPlatformScreen { public: - QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, + QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop, xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output, - QString outputName, int number); + QString outputName); ~QXcbScreen(); QPixmap grabWindow(WId window, int x, int y, int width, int height) const Q_DECL_OVERRIDE; @@ -69,7 +89,7 @@ public: QRect geometry() const Q_DECL_OVERRIDE { return m_geometry; } QRect nativeGeometry() const { return m_nativeGeometry; } QRect availableGeometry() const Q_DECL_OVERRIDE {return m_availableGeometry;} - int depth() const Q_DECL_OVERRIDE { return m_screen->root_depth; } + int depth() const Q_DECL_OVERRIDE { return screen()->root_depth; } QImage::Format format() const Q_DECL_OVERRIDE; QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_sizeMillimeters; } QSize virtualSize() const { return m_virtualSize; } @@ -87,10 +107,10 @@ public: void setPrimary(bool primary) { m_primary = primary; } bool isPrimary() const { return m_primary; } - int screenNumber() const { return m_number; } + int screenNumber() const { return m_virtualDesktop->number(); } - xcb_screen_t *screen() const { return m_screen; } - xcb_window_t root() const { return m_screen->root; } + xcb_screen_t *screen() const { return m_virtualDesktop->screen(); } + xcb_window_t root() const { return screen()->root; } xcb_randr_output_t output() const { return m_output; } xcb_randr_crtc_t crtc() const { return m_crtc; } xcb_randr_mode_t mode() const { return m_mode; } @@ -126,7 +146,7 @@ private: QByteArray &stringValue); void sendStartupMessage(const QByteArray &message) const; - xcb_screen_t *m_screen; + QXcbVirtualDesktop *m_virtualDesktop; xcb_randr_output_t m_output; xcb_randr_crtc_t m_crtc; xcb_randr_mode_t m_mode; @@ -143,7 +163,6 @@ private: QSizeF m_virtualSizeMillimeters; QList m_siblings; Qt::ScreenOrientation m_orientation; - int m_number; QString m_windowManagerName; bool m_syncRequestSupported; xcb_window_t m_clientLeader; @@ -157,7 +176,6 @@ private: bool m_noFontHinting; QFontEngine::SubpixelAntialiasingType m_subpixelType; int m_antialiasingEnabled; - QXcbXSettings *m_xSettings; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp index c83edd506d..46cee5d6d0 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.cpp +++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp @@ -63,7 +63,7 @@ public: : last_change_serial(-1) {} - void updateValue(QXcbScreen *screen, const QByteArray &name, const QVariant &value, int last_change_serial) + void updateValue(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &value, int last_change_serial) { if (last_change_serial <= this->last_change_serial) return; @@ -92,7 +92,7 @@ public: class QXcbXSettingsPrivate { public: - QXcbXSettingsPrivate(QXcbScreen *screen) + QXcbXSettingsPrivate(QXcbVirtualDesktop *screen) : screen(screen) , initialized(false) { @@ -217,18 +217,18 @@ public: } #endif //XCB_USE_XLIB - QXcbScreen *screen; + QXcbVirtualDesktop *screen; xcb_window_t x_settings_window; QMap settings; bool initialized; }; -QXcbXSettings::QXcbXSettings(QXcbScreen *screen) +QXcbXSettings::QXcbXSettings(QXcbVirtualDesktop *screen) : d_ptr(new QXcbXSettingsPrivate(screen)) { QByteArray settings_atom_for_screen("_XSETTINGS_S"); - settings_atom_for_screen.append(QByteArray::number(screen->screenNumber())); + settings_atom_for_screen.append(QByteArray::number(screen->number())); xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(screen->xcb_connection(), true, settings_atom_for_screen.length(), diff --git a/src/plugins/platforms/xcb/qxcbxsettings.h b/src/plugins/platforms/xcb/qxcbxsettings.h index 4022f0a2c4..3f1d175336 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.h +++ b/src/plugins/platforms/xcb/qxcbxsettings.h @@ -44,13 +44,13 @@ class QXcbXSettings : public QXcbWindowEventListener { Q_DECLARE_PRIVATE(QXcbXSettings) public: - QXcbXSettings(QXcbScreen *screen); + QXcbXSettings(QXcbVirtualDesktop *screen); ~QXcbXSettings(); bool initialized() const; QVariant setting(const QByteArray &property) const; - typedef void (*PropertyChangeFunc)(QXcbScreen *screen, const QByteArray &name, const QVariant &property, void *handle); + typedef void (*PropertyChangeFunc)(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, void *handle); void registerCallbackForProperty(const QByteArray &property, PropertyChangeFunc func, void *handle); void removeCallbackForHandle(const QByteArray &property, void *handle); void removeCallbackForHandle(void *handle); -- cgit v1.2.3 From 364905b59242084ba468d7fc52ab8ee4f889654c Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Thu, 9 Apr 2015 14:50:36 +0300 Subject: xcb: Fix getting of virtual roots Update QXcbWMSupport::net_virtual_roots instead of QXcbWMSupport::net_wm_atoms. It's a copy/paste error. Change-Id: If146955d954850f02980f473ad2318d67f193ec9 Reviewed-by: Lars Knoll Reviewed-by: Uli Schlachter --- src/plugins/platforms/xcb/qxcbwmsupport.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp index bcdfde2ef9..7d31ac7118 100644 --- a/src/plugins/platforms/xcb/qxcbwmsupport.cpp +++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp @@ -68,7 +68,7 @@ void QXcbWMSupport::updateNetWMAtoms() remaining = 0; if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { - int len = xcb_get_property_value_length(reply)/4; + int len = xcb_get_property_value_length(reply)/sizeof(xcb_atom_t); xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); int s = net_wm_atoms.size(); net_wm_atoms.resize(s + len); @@ -102,11 +102,11 @@ void QXcbWMSupport::updateVirtualRoots() remaining = 0; if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { - int len = xcb_get_property_value_length(reply)/4; - xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); - int s = net_wm_atoms.size(); - net_wm_atoms.resize(s + len); - memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t)); + int len = xcb_get_property_value_length(reply)/sizeof(xcb_window_t); + xcb_window_t *roots = (xcb_window_t *)xcb_get_property_value(reply); + int s = net_virtual_roots.size(); + net_virtual_roots.resize(s + len); + memcpy(net_virtual_roots.data() + s, roots, len*sizeof(xcb_window_t)); remaining = reply->bytes_after; offset += len; -- cgit v1.2.3 From 1aab68648d3aa38811be38b5bbd3a0704e17ccf8 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 10 Apr 2015 08:46:37 +0200 Subject: Speed up compose file parsing in the X11 composition input method plugin There's no need to decode the string until the end of the line, it's sufficient to stop at the end of the quotes. Change-Id: Ie617d2538511e91d0e0146f98b7e5ea3213b8db2 Reviewed-by: Lars Knoll --- src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index 4784a6e828..120b228f79 100644 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -399,7 +399,7 @@ void TableGenerator::parseKeySequence(char *line) // handle direct text encoded in the locale if (*composeValue == '\\') ++composeValue; - elem.value = QString::fromLocal8Bit(composeValue).at(0).unicode(); + elem.value = QString::fromLocal8Bit(composeValue, composeValueEnd - composeValue).at(0).unicode(); ++composeValue; } -- cgit v1.2.3 From d11665b27ce3357fb30bff6ffc1379a4756ec8d1 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 10 Apr 2015 09:01:47 +0200 Subject: Speed up application startup on X11 Avoid parsing the composition tables on application startup. Instead let's do that on-demand the first time a composition key is pressed. Change-Id: I52feb36246a091b9a84d46e479ba2ad1f5cd1556 Reviewed-by: Lars Knoll --- .../compose/qcomposeplatforminputcontext.cpp | 32 ++++++++++++---------- .../compose/qcomposeplatforminputcontext.h | 1 + 2 files changed, 19 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp index 49fa32004e..d1bea9af23 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp @@ -80,37 +80,32 @@ static const int composingKeys[] = { }; QComposeInputContext::QComposeInputContext() + : m_tableState(TableGenerator::EmptyTable) + , m_compositionTableInitialized(false) { - TableGenerator reader; - m_tableState = reader.tableState(); - - if ((m_tableState & TableGenerator::NoErrors) == TableGenerator::NoErrors) { - m_composeTable = reader.composeTable(); - clearComposeBuffer(); - } + clearComposeBuffer(); } bool QComposeInputContext::filterEvent(const QEvent *event) { - // if there were errors when generating the compose table input - // context should not try to filter anything, simply return false - if ((m_tableState & TableGenerator::NoErrors) != TableGenerator::NoErrors) - return false; - const QKeyEvent *keyEvent = (const QKeyEvent *)event; // should pass only the key presses if (keyEvent->type() != QEvent::KeyPress) { return false; } + // if there were errors when generating the compose table input + // context should not try to filter anything, simply return false + if (m_compositionTableInitialized && (m_tableState & TableGenerator::NoErrors) != TableGenerator::NoErrors) + return false; + int keyval = keyEvent->key(); int keysym = 0; if (ignoreKey(keyval)) return false; - QString text = keyEvent->text(); - if (!composeKey(keyval) && text.isEmpty()) + if (!composeKey(keyval) && keyEvent->text().isEmpty()) return false; keysym = keyEvent->nativeVirtualKey(); @@ -163,6 +158,15 @@ static bool isDuplicate(const QComposeTableElement &lhs, const QComposeTableElem bool QComposeInputContext::checkComposeTable() { + if (!m_compositionTableInitialized) { + TableGenerator reader; + m_tableState = reader.tableState(); + + if ((m_tableState & TableGenerator::NoErrors) == TableGenerator::NoErrors) + m_composeTable = reader.composeTable(); + + m_compositionTableInitialized = true; + } QVector::const_iterator it = std::lower_bound(m_composeTable.constBegin(), m_composeTable.constEnd(), m_composeBuffer, Compare()); diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h index 643b93c32d..bdf5a91335 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h @@ -70,6 +70,7 @@ private: QVector m_composeTable; uint m_composeBuffer[QT_KEYSEQUENCE_MAX_LEN + 1]; TableGenerator::TableState m_tableState; + bool m_compositionTableInitialized; }; QT_END_NAMESPACE -- cgit v1.2.3 From 4fab4d2e806ee5aff112a0ef194cf0974e229eaa Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Thu, 9 Apr 2015 12:21:12 +0200 Subject: qiostextresponder: Use UIKeyboardTypePhonePad for ImhDialableCharactersOnly Change-Id: I8123199da51a0b840c068bea4ba089c0fec9697b Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiostextresponder.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 5d2a675f90..0b5ff11b47 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -196,7 +196,7 @@ else if (hints & Qt::ImhFormattedNumbersOnly) self.keyboardType = UIKeyboardTypeDecimalPad; else if (hints & Qt::ImhDialableCharactersOnly) - self.keyboardType = UIKeyboardTypeNumberPad; + self.keyboardType = UIKeyboardTypePhonePad; else self.keyboardType = UIKeyboardTypeDefault; -- cgit v1.2.3 From 95b481ea6dfa901c23b012085527769f9b5823c9 Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Thu, 9 Apr 2015 12:27:31 +0200 Subject: qiostextresponder: Add support for ImhLatinOnly Change-Id: I38f43cd644d3c26c834cf60019c4db1fa0b8d61f Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiostextresponder.mm | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 0b5ff11b47..52336a4e69 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -197,6 +197,8 @@ self.keyboardType = UIKeyboardTypeDecimalPad; else if (hints & Qt::ImhDialableCharactersOnly) self.keyboardType = UIKeyboardTypePhonePad; + else if (hints & Qt::ImhLatinOnly) + self.keyboardType = UIKeyboardTypeASCIICapable; else self.keyboardType = UIKeyboardTypeDefault; -- cgit v1.2.3 From a36adfc73ee0085313712dfe1c8c37454dd9380e Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Sun, 12 Apr 2015 10:56:13 +0200 Subject: Upgrade PCRE to r1546 Thanks to LLVM's libFuzzer a dozen of assorted buffer overflows has been discovered, see [1, 2] [1] http://vcs.pcre.org/viewvc/code/trunk/ChangeLog?view=markup [2] http://blog.llvm.org/2015/04/fuzz-all-clangs.html Change-Id: Ib9fd8dfaee8dc50e1899ebac83a74ac1107a0bd2 Reviewed-by: Konstantin Ritt --- src/3rdparty/pcre/pcre_compile.c | 142 +++++++++++++++++++++++------------ src/3rdparty/pcre/pcre_dfa_exec.c | 5 +- src/3rdparty/pcre/pcre_exec.c | 20 +++-- src/3rdparty/pcre/pcre_jit_compile.c | 8 +- src/3rdparty/pcre/sljit/sljitLir.c | 6 ++ src/3rdparty/pcre/sljit/sljitLir.h | 12 +-- 6 files changed, 126 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/3rdparty/pcre/pcre_compile.c b/src/3rdparty/pcre/pcre_compile.c index 7df7fef4bd..3f8174fbd4 100644 --- a/src/3rdparty/pcre/pcre_compile.c +++ b/src/3rdparty/pcre/pcre_compile.c @@ -866,6 +866,14 @@ static const pcre_uint8 opcode_possessify[] = { }; +/* Structure for mutual recursion detection. */ + +typedef struct recurse_check { + struct recurse_check *prev; + const pcre_uchar *group; +} recurse_check; + + /************************************************* * Find an error text * @@ -1704,6 +1712,7 @@ Arguments: utf TRUE in UTF-8 / UTF-16 / UTF-32 mode atend TRUE if called when the pattern is complete cd the "compile data" structure + recurses chain of recurse_check to catch mutual recursion Returns: the fixed length, or -1 if there is no fixed length, @@ -1713,10 +1722,11 @@ Returns: the fixed length, */ static int -find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd) +find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd, + recurse_check *recurses) { int length = -1; - +recurse_check this_recurse; register int branchlength = 0; register pcre_uchar *cc = code + 1 + LINK_SIZE; @@ -1741,7 +1751,8 @@ for (;;) case OP_ONCE: case OP_ONCE_NC: case OP_COND: - d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd); + d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd, + recurses); if (d < 0) return d; branchlength += d; do cc += GET(cc, 1); while (*cc == OP_ALT); @@ -1775,7 +1786,15 @@ for (;;) cs = ce = (pcre_uchar *)cd->start_code + GET(cc, 1); /* Start subpattern */ do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */ if (cc > cs && cc < ce) return -1; /* Recursion */ - d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd); + else /* Check for mutual recursion */ + { + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; + if (r != NULL) return -1; /* Mutual recursion */ + } + this_recurse.prev = recurses; + this_recurse.group = cs; + d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd, &this_recurse); if (d < 0) return d; branchlength += d; cc += 1 + LINK_SIZE; @@ -2362,11 +2381,6 @@ Arguments: Returns: TRUE if what is matched could be empty */ -typedef struct recurse_check { - struct recurse_check *prev; - const pcre_uchar *group; -} recurse_check; - static BOOL could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode, BOOL utf, compile_data *cd, recurse_check *recurses) @@ -2497,8 +2511,8 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); empty_branch = FALSE; do { - if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd, NULL)) - empty_branch = TRUE; + if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd, + recurses)) empty_branch = TRUE; code += GET(code, 1); } while (*code == OP_ALT); @@ -3093,7 +3107,7 @@ Returns: TRUE if the auto-possessification is possible static BOOL compare_opcodes(const pcre_uchar *code, BOOL utf, const compile_data *cd, - const pcre_uint32 *base_list, const pcre_uchar *base_end) + const pcre_uint32 *base_list, const pcre_uchar *base_end, int *rec_limit) { pcre_uchar c; pcre_uint32 list[8]; @@ -3110,6 +3124,9 @@ pcre_uint32 chr; BOOL accepted, invert_bits; BOOL entered_a_group = FALSE; +if (*rec_limit == 0) return FALSE; +--(*rec_limit); + /* Note: the base_list[1] contains whether the current opcode has greedy (represented by a non-zero value) quantifier. This is a different from other character type lists, which stores here that the character iterator @@ -3180,7 +3197,8 @@ for(;;) while (*next_code == OP_ALT) { - if (!compare_opcodes(code, utf, cd, base_list, base_end)) return FALSE; + if (!compare_opcodes(code, utf, cd, base_list, base_end, rec_limit)) + return FALSE; code = next_code + 1 + LINK_SIZE; next_code += GET(next_code, 1); } @@ -3200,7 +3218,7 @@ for(;;) /* The bracket content will be checked by the OP_BRA/OP_CBRA case above. */ next_code += 1 + LINK_SIZE; - if (!compare_opcodes(next_code, utf, cd, base_list, base_end)) + if (!compare_opcodes(next_code, utf, cd, base_list, base_end, rec_limit)) return FALSE; code += PRIV(OP_lengths)[c]; @@ -3633,6 +3651,7 @@ register pcre_uchar c; const pcre_uchar *end; pcre_uchar *repeat_opcode; pcre_uint32 list[8]; +int rec_limit; for (;;) { @@ -3653,7 +3672,8 @@ for (;;) get_chr_property_list(code, utf, cd->fcc, list) : NULL; list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO; - if (end != NULL && compare_opcodes(end, utf, cd, list, end)) + rec_limit = 1000; + if (end != NULL && compare_opcodes(end, utf, cd, list, end, &rec_limit)) { switch(c) { @@ -3709,7 +3729,8 @@ for (;;) list[1] = (c & 1) == 0; - if (compare_opcodes(end, utf, cd, list, end)) + rec_limit = 1000; + if (compare_opcodes(end, utf, cd, list, end, &rec_limit)) { switch (c) { @@ -4002,7 +4023,7 @@ while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL) /* See if this recursion is on the forward reference list. If so, adjust the reference. */ - for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm; + for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm; hc += LINK_SIZE) { offset = (int)GET(hc, 0); @@ -4208,7 +4229,11 @@ if ((options & PCRE_CASELESS) != 0) range. Otherwise, use a recursive call to add the additional range. */ else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */ - else if (od > end && oc <= end + 1) end = od; /* Extend upwards */ + else if (od > end && oc <= end + 1) + { + end = od; /* Extend upwards */ + if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff); + } else n8 += add_to_class(classbits, uchardptr, options, cd, oc, od); } } @@ -5509,6 +5534,12 @@ for (;; ptr++) } #endif + /* Even though any XCLASS list is now discarded, we must allow for + its memory. */ + + if (lengthptr != NULL) + *lengthptr += (int)(class_uchardata - class_uchardata_base); + /* If there are no characters > 255, or they are all to be included or excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the whole class was negated and whether there were negative specials such as \S @@ -5907,6 +5938,7 @@ for (;; ptr++) { register int i; int len = (int)(code - previous); + size_t base_hwm_offset = save_hwm_offset; pcre_uchar *bralink = NULL; pcre_uchar *brazeroptr = NULL; @@ -6052,21 +6084,21 @@ for (;; ptr++) memcpy(code, previous, IN_UCHARS(len)); while (cd->hwm > cd->start_workspace + cd->workspace_size - - WORK_SIZE_SAFETY_MARGIN - - (this_hwm_offset - save_hwm_offset)) + WORK_SIZE_SAFETY_MARGIN - + (this_hwm_offset - base_hwm_offset)) { *errorcodeptr = expand_workspace(cd); if (*errorcodeptr != 0) goto FAILED; } - for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; - hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset; + for (hc = (pcre_uchar *)cd->start_workspace + base_hwm_offset; + hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset; hc += LINK_SIZE) { PUT(cd->hwm, 0, GET(hc, 0) + len); cd->hwm += LINK_SIZE; } - save_hwm_offset = this_hwm_offset; + base_hwm_offset = this_hwm_offset; code += len; } } @@ -6133,21 +6165,21 @@ for (;; ptr++) copying them. */ while (cd->hwm > cd->start_workspace + cd->workspace_size - - WORK_SIZE_SAFETY_MARGIN - - (this_hwm_offset - save_hwm_offset)) + WORK_SIZE_SAFETY_MARGIN - + (this_hwm_offset - base_hwm_offset)) { *errorcodeptr = expand_workspace(cd); if (*errorcodeptr != 0) goto FAILED; } - for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; - hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset; + for (hc = (pcre_uchar *)cd->start_workspace + base_hwm_offset; + hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset; hc += LINK_SIZE) { PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1)); cd->hwm += LINK_SIZE; } - save_hwm_offset = this_hwm_offset; + base_hwm_offset = this_hwm_offset; code += len; } @@ -6455,15 +6487,25 @@ for (;; ptr++) parenthesis forms. */ case CHAR_LEFT_PARENTHESIS: - newoptions = options; - skipbytes = 0; - bravalue = OP_CBRA; - save_hwm_offset = cd->hwm - cd->start_workspace; - reset_bracount = FALSE; + ptr++; - /* First deal with various "verbs" that can be introduced by '*'. */ + /* First deal with comments. Putting this code right at the start ensures + that comments have no bad side effects. */ + + if (ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN) + { + ptr += 2; + while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; + if (*ptr == CHAR_NULL) + { + *errorcodeptr = ERR18; + goto FAILED; + } + continue; + } + + /* Now deal with various "verbs" that can be introduced by '*'. */ - ptr++; if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':' || (MAX_255(ptr[1]) && ((cd->ctypes[ptr[1]] & ctype_letter) != 0)))) { @@ -6584,10 +6626,18 @@ for (;; ptr++) goto FAILED; } + /* Initialize for "real" parentheses */ + + newoptions = options; + skipbytes = 0; + bravalue = OP_CBRA; + save_hwm_offset = cd->hwm - cd->start_workspace; + reset_bracount = FALSE; + /* Deal with the extended parentheses; all are introduced by '?', and the appearance of any of them means that this is not a capturing group. */ - else if (*ptr == CHAR_QUESTION_MARK) + if (*ptr == CHAR_QUESTION_MARK) { int i, set, unset, namelen; int *optset; @@ -6596,17 +6646,6 @@ for (;; ptr++) switch (*(++ptr)) { - case CHAR_NUMBER_SIGN: /* Comment; skip to ket */ - ptr++; - while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; - if (*ptr == CHAR_NULL) - { - *errorcodeptr = ERR18; - goto FAILED; - } - continue; - - /* ------------------------------------------------------------ */ case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ reset_bracount = TRUE; @@ -6655,7 +6694,9 @@ for (;; ptr++) if (tempptr[1] == CHAR_QUESTION_MARK && (tempptr[2] == CHAR_EQUALS_SIGN || tempptr[2] == CHAR_EXCLAMATION_MARK || - tempptr[2] == CHAR_LESS_THAN_SIGN)) + (tempptr[2] == CHAR_LESS_THAN_SIGN && + (tempptr[3] == CHAR_EQUALS_SIGN || + tempptr[3] == CHAR_EXCLAMATION_MARK)))) { cd->iscondassert = TRUE; break; @@ -8264,7 +8305,7 @@ for (;;) int fixed_length; *code = OP_END; fixed_length = find_fixedlength(last_branch, (options & PCRE_UTF8) != 0, - FALSE, cd); + FALSE, cd, NULL); DPRINTF(("fixed length = %d\n", fixed_length)); if (fixed_length == -3) { @@ -8549,6 +8590,7 @@ do { case OP_RREF: case OP_DNRREF: case OP_DEF: + case OP_FAIL: return FALSE; default: /* Assertion */ @@ -9366,7 +9408,7 @@ if (cd->check_lookbehind) int end_op = *be; *be = OP_END; fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE, - cd); + cd, NULL); *be = end_op; DPRINTF(("fixed length = %d\n", fixed_length)); if (fixed_length < 0) diff --git a/src/3rdparty/pcre/pcre_dfa_exec.c b/src/3rdparty/pcre/pcre_dfa_exec.c index 64a495cc04..2d99787631 100644 --- a/src/3rdparty/pcre/pcre_dfa_exec.c +++ b/src/3rdparty/pcre/pcre_dfa_exec.c @@ -2736,9 +2736,10 @@ for (;;) condcode == OP_DNRREF) return PCRE_ERROR_DFA_UCOND; - /* The DEFINE condition is always false */ + /* The DEFINE condition is always false, and the assertion (?!) is + converted to OP_FAIL. */ - if (condcode == OP_DEF) + if (condcode == OP_DEF || condcode == OP_FAIL) { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); } /* The only supported version of OP_RREF is for the value RREF_ANY, diff --git a/src/3rdparty/pcre/pcre_exec.c b/src/3rdparty/pcre/pcre_exec.c index 75fa2a7329..b639a28b69 100644 --- a/src/3rdparty/pcre/pcre_exec.c +++ b/src/3rdparty/pcre/pcre_exec.c @@ -1376,6 +1376,7 @@ for (;;) break; case OP_DEF: /* DEFINE - always false */ + case OP_FAIL: /* From optimized (?!) condition */ break; /* The condition is an assertion. Call match() to evaluate it - setting @@ -3482,7 +3483,7 @@ for (;;) if (possessive) continue; /* No backtracking */ for(;;) { - if (eptr == pp) goto TAIL_RECURSE; + if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM23); if (rrc != MATCH_NOMATCH) RRETURN(rrc); #ifdef SUPPORT_UCP @@ -3903,7 +3904,7 @@ for (;;) if (possessive) continue; /* No backtracking */ for(;;) { - if (eptr == pp) goto TAIL_RECURSE; + if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM30); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; @@ -4038,7 +4039,7 @@ for (;;) if (possessive) continue; /* No backtracking */ for(;;) { - if (eptr == pp) goto TAIL_RECURSE; + if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM34); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; @@ -5609,7 +5610,7 @@ for (;;) if (possessive) continue; /* No backtracking */ for(;;) { - if (eptr == pp) goto TAIL_RECURSE; + if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM44); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; @@ -5651,12 +5652,17 @@ for (;;) if (possessive) continue; /* No backtracking */ + /* We use <= pp rather than == pp to detect the start of the run while + backtracking because the use of \C in UTF mode can cause BACKCHAR to + move back past pp. This is just palliative; the use of \C in UTF mode + is fraught with danger. */ + for(;;) { int lgb, rgb; PCRE_PUCHAR fptr; - if (eptr == pp) goto TAIL_RECURSE; /* At start of char run */ + if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */ RMATCH(eptr, ecode, offset_top, md, eptrb, RM45); if (rrc != MATCH_NOMATCH) RRETURN(rrc); @@ -5674,7 +5680,7 @@ for (;;) for (;;) { - if (eptr == pp) goto TAIL_RECURSE; /* At start of char run */ + if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */ fptr = eptr - 1; if (!utf) c = *fptr; else { @@ -5924,7 +5930,7 @@ for (;;) if (possessive) continue; /* No backtracking */ for(;;) { - if (eptr == pp) goto TAIL_RECURSE; + if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM46); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; diff --git a/src/3rdparty/pcre/pcre_jit_compile.c b/src/3rdparty/pcre/pcre_jit_compile.c index 795a5d2b47..0901c1bd53 100644 --- a/src/3rdparty/pcre/pcre_jit_compile.c +++ b/src/3rdparty/pcre/pcre_jit_compile.c @@ -2108,7 +2108,7 @@ sljit_uw *result; if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; -result = (sljit_uw *)SLJIT_MALLOC(size + sizeof(sljit_uw), common->allocator_data); +result = (sljit_uw *)SLJIT_MALLOC(size + sizeof(sljit_uw), compiler->allocator_data); if (SLJIT_UNLIKELY(result == NULL)) { sljit_set_compiler_memory_error(compiler); @@ -6997,7 +6997,7 @@ cc += GET(cc, 1); has_alternatives = *cc == OP_ALT; if (SLJIT_UNLIKELY(opcode == OP_COND || opcode == OP_SCOND)) - has_alternatives = (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF) ? FALSE : TRUE; + has_alternatives = (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF || *matchingpath == OP_FAIL) ? FALSE : TRUE; if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN)) opcode = OP_SCOND; @@ -7255,12 +7255,14 @@ if (opcode == OP_COND || opcode == OP_SCOND) add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), JUMP(SLJIT_ZERO)); matchingpath += 1 + 2 * IMM2_SIZE; } - else if (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF) + else if (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF || *matchingpath == OP_FAIL) { /* Never has other case. */ BACKTRACK_AS(bracket_backtrack)->u.condfailed = NULL; SLJIT_ASSERT(!has_alternatives); + if (*matchingpath == OP_FAIL) + stacksize = 0; if (*matchingpath == OP_RREF) { stacksize = GET2(matchingpath, 1); diff --git a/src/3rdparty/pcre/sljit/sljitLir.c b/src/3rdparty/pcre/sljit/sljitLir.c index 8112e8da6e..5039a7e04e 100644 --- a/src/3rdparty/pcre/sljit/sljitLir.c +++ b/src/3rdparty/pcre/sljit/sljitLir.c @@ -435,6 +435,12 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compile SLJIT_FREE(compiler, allocator_data); } +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler) +{ + if (compiler->error == SLJIT_SUCCESS) + compiler->error = SLJIT_ERR_ALLOC_FAILED; +} + #if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code) { diff --git a/src/3rdparty/pcre/sljit/sljitLir.h b/src/3rdparty/pcre/sljit/sljitLir.h index 79f1d102c1..24c0f60399 100644 --- a/src/3rdparty/pcre/sljit/sljitLir.h +++ b/src/3rdparty/pcre/sljit/sljitLir.h @@ -429,11 +429,13 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compile these checks increases the performance of the compiling process. */ static SLJIT_INLINE sljit_si sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; } -/* Sets the compiler error code to SLJIT_ERR_ALLOC_FAILED. After - the error code is set, the compiler behaves as if itself detected - an allocation failure. This can greatly simplify error management, - since only the compiler needs to be checked after compilation. */ -static SLJIT_INLINE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler) { compiler->error = SLJIT_ERR_ALLOC_FAILED; } +/* Sets the compiler error code to SLJIT_ERR_ALLOC_FAILED except + if an error was detected before. After the error code is set + the compiler behaves as if the allocation failure happened + during an sljit function call. This can greatly simplify error + checking, since only the compiler status needs to be checked + after the compilation. */ +SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler); /* Allocate a small amount of memory. The size must be <= 64 bytes on 32 bit, -- cgit v1.2.3 From 96cc8eec9b32f4e80c2d748687c485bc79133d39 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 9 Apr 2015 11:24:15 +0200 Subject: remove the "wonderful Windows notifier" from QProcess Remove the 100 ms timer that was used to nudge QProcess to write data to the child's stdin. Instead, react on the canWrite() signal of QWindowsPipeWriter. QProcess::writeData needs to call _q_canWrite via the event loop to start the write operation. The socket notifier code was never in use on Windows. Task-number: QTBUG-45457 Change-Id: I99c956ba5f2169f80068eee206543ceb9788b2e0 Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qprocess.cpp | 34 +++++++++++++++++++++++++++------- src/corelib/io/qprocess.h | 1 - src/corelib/io/qprocess_p.h | 4 +--- src/corelib/io/qprocess_unix.cpp | 4 ---- src/corelib/io/qprocess_win.cpp | 19 ++----------------- src/corelib/io/qprocess_wince.cpp | 4 ---- 6 files changed, 30 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 7d7cdef203..ead04791e5 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -36,6 +36,9 @@ #include #include +#if defined(Q_OS_WIN) +#include +#endif #if defined QPROCESS_DEBUG #include #include @@ -819,7 +822,7 @@ QProcessPrivate::QProcessPrivate() emittedReadyRead = false; emittedBytesWritten = false; #ifdef Q_OS_WIN - notifier = 0; + stdinWriteTrigger = 0; processFinishedNotifier = 0; #endif // Q_OS_WIN } @@ -848,6 +851,10 @@ void QProcessPrivate::cleanup() delete pid; pid = 0; } + if (stdinWriteTrigger) { + delete stdinWriteTrigger; + stdinWriteTrigger = 0; + } if (processFinishedNotifier) { delete processFinishedNotifier; processFinishedNotifier = 0; @@ -878,12 +885,6 @@ void QProcessPrivate::cleanup() delete deathNotifier; deathNotifier = 0; } -#ifdef Q_OS_WIN - if (notifier) { - delete notifier; - notifier = 0; - } -#endif closeChannel(&stdoutChannel); closeChannel(&stderrChannel); closeChannel(&stdinChannel); @@ -1953,10 +1954,24 @@ qint64 QProcess::writeData(const char *data, qint64 len) return 0; } +#if defined(Q_OS_WIN) + if (!d->stdinWriteTrigger) { + d->stdinWriteTrigger = new QTimer; + d->stdinWriteTrigger->setSingleShot(true); + QObjectPrivate::connect(d->stdinWriteTrigger, &QTimer::timeout, + d, &QProcessPrivate::_q_canWrite); + } +#endif + if (len == 1) { d->stdinChannel.buffer.putChar(*data); +#ifdef Q_OS_WIN + if (!d->stdinWriteTrigger->isActive()) + d->stdinWriteTrigger->start(); +#else if (d->stdinChannel.notifier) d->stdinChannel.notifier->setEnabled(true); +#endif #if defined QPROCESS_DEBUG qDebug("QProcess::writeData(%p \"%s\", %lld) == 1 (written to buffer)", data, qt_prettyDebug(data, len, 16).constData(), len); @@ -1966,8 +1981,13 @@ qint64 QProcess::writeData(const char *data, qint64 len) char *dest = d->stdinChannel.buffer.reserve(len); memcpy(dest, data, len); +#ifdef Q_OS_WIN + if (!d->stdinWriteTrigger->isActive()) + d->stdinWriteTrigger->start(); +#else if (d->stdinChannel.notifier) d->stdinChannel.notifier->setEnabled(true); +#endif #if defined QPROCESS_DEBUG qDebug("QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)", data, qt_prettyDebug(data, len, 16).constData(), len, len); diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 65af469c18..54cf37b717 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -266,7 +266,6 @@ private: Q_PRIVATE_SLOT(d_func(), bool _q_canWrite()) Q_PRIVATE_SLOT(d_func(), bool _q_startupNotification()) Q_PRIVATE_SLOT(d_func(), bool _q_processDied()) - Q_PRIVATE_SLOT(d_func(), void _q_notified()) friend class QProcessManager; }; diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 5654b404fe..f6bd64fb87 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -303,7 +303,6 @@ public: bool _q_canWrite(); bool _q_startupNotification(); bool _q_processDied(); - void _q_notified(); QProcess::ProcessChannel processChannel; QProcess::ProcessChannelMode processChannelMode; @@ -342,8 +341,7 @@ public: int forkfd; #ifdef Q_OS_WIN - // the wonderful windows notifier - QTimer *notifier; + QTimer *stdinWriteTrigger; QWinEventNotifier *processFinishedNotifier; #endif diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 46b557d6e0..69b631f7e7 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -1111,10 +1111,6 @@ bool QProcessPrivate::waitForDeadChild() return true; } -void QProcessPrivate::_q_notified() -{ -} - #if defined(QPROCESS_USE_SPAWN) bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) { diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 563286e3e9..cef961ecbd 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -58,8 +57,6 @@ QT_BEGIN_NAMESPACE //#define QPROCESS_DEBUG -#define NOTIFYTIMEOUT 100 - static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe) { // Anomymous pipes do not support asynchronous I/O. Thus we @@ -543,9 +540,6 @@ void QProcessPrivate::startProcess() processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q); QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied())); processFinishedNotifier->setEnabled(true); - notifier = new QTimer(q); - QObject::connect(notifier, SIGNAL(timeout()), q, SLOT(_q_notified())); - notifier->start(NOTIFYTIMEOUT); } _q_startupNotification(); @@ -810,6 +804,8 @@ qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) if (!stdinChannel.writer) { stdinChannel.writer = new QWindowsPipeWriter(stdinChannel.pipe[1], q); + QObjectPrivate::connect(stdinChannel.writer, &QWindowsPipeWriter::canWrite, + this, &QProcessPrivate::_q_canWrite); stdinChannel.writer->start(); } @@ -828,17 +824,6 @@ bool QProcessPrivate::waitForWrite(int msecs) return false; } -void QProcessPrivate::_q_notified() -{ - notifier->stop(); - - if (!stdinChannel.buffer.isEmpty() && (!stdinChannel.writer || stdinChannel.writer->waitForWrite(0))) - _q_canWrite(); - - if (processState != QProcess::NotRunning) - notifier->start(NOTIFYTIMEOUT); -} - bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) { QString args = qt_create_commandline(program, arguments); diff --git a/src/corelib/io/qprocess_wince.cpp b/src/corelib/io/qprocess_wince.cpp index bf19c81f25..53767758c2 100644 --- a/src/corelib/io/qprocess_wince.cpp +++ b/src/corelib/io/qprocess_wince.cpp @@ -288,10 +288,6 @@ bool QProcessPrivate::waitForWrite(int msecs) return false; } -void QProcessPrivate::_q_notified() -{ -} - bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) { Q_UNUSED(workingDir); -- cgit v1.2.3 From a02c04a51b34fc780fa680383f2aee3b3f37fa51 Mon Sep 17 00:00:00 2001 From: Niclas Rosenvik Date: Mon, 13 Apr 2015 13:03:53 +0200 Subject: qstorageinfo_unix.cpp: fixes for NetBSD and solaris NetBSD uses struct statvfs ** as first argument to getmntinfo. see: http://netbsd.gw.com/cgi-bin/man-cgi?getmntinfo getmntent on solaris and sunos returns an integer not a pointer. see: http://www.unix.com/man-page/opensolaris/3c/getmntent/ see: https://smartos.org/man/3C/getmntent Change-Id: Ic01da0edcf1f55617294e5a86b8459669e82c1b1 Reviewed-by: Thiago Macieira --- src/corelib/io/qstorageinfo_unix.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 45b32830cd..7b8f608050 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -122,7 +122,11 @@ public: inline QByteArray device() const; private: #if defined(Q_OS_BSD4) +# if defined(Q_OS_NETBSD) + struct statvfs *stat_buf; +# else struct statfs *stat_buf; +# endif int entryCount; int currentIndex; #elif defined(Q_OS_SOLARIS) @@ -206,7 +210,7 @@ inline bool QStorageIterator::isValid() const inline bool QStorageIterator::next() { - return ::getmntent(fp, &mnt) == Q_NULLPTR; + return ::getmntent(fp, &mnt) == 0; } inline QString QStorageIterator::rootPath() const -- cgit v1.2.3 From 4e1b09fa8ff1a9ab42c0a29a2efe1ae7f4700d71 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Fri, 20 Mar 2015 17:30:26 +0100 Subject: Keep screen geometries from overlapping The simple mapping of dividing each position by the devicePixelRatio does not work when screens have different DPR. If the low-DPR screen above or to the left of the high-DPR screen, the geometries will overlap in the Qt coordinate system. This change introduces a new mapping where the origin of each screen does not move. This mapping is not perfect: it will have gaps between contiguous screens. However, it will keep non-overlapping screens non-overlapping in the Qt coordinate system. Since there is no longer a simple linear coordinate transform, we have to add screen-dependent mapping functions, and distinguish between local and non-local coordinates. A side benefit is that the code is now easier to read, since we remove most manual coordinate transformation. We also have to cache the screen of each window: since we send resize events before screen change events, we cannot rely on QPlatformWindow::screen() (which is set from the screen change event). Task-number: QTBUG-45076 Change-Id: Ie95a0b71ae274e02903caa102a98af2050a44129 Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbcursor.cpp | 7 +- src/plugins/platforms/xcb/qxcbscreen.cpp | 29 ++++++- src/plugins/platforms/xcb/qxcbscreen.h | 5 ++ src/plugins/platforms/xcb/qxcbwindow.cpp | 143 ++++++++++++++++++++----------- src/plugins/platforms/xcb/qxcbwindow.h | 10 ++- 5 files changed, 138 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index e30cc26313..e51ab85e30 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -633,18 +633,17 @@ void QXcbCursor::queryPointer(QXcbConnection *c, xcb_window_t *rootWin, QPoint * QPoint QXcbCursor::pos() const { - const int dpr = int(m_screen->devicePixelRatio()); QPoint p; queryPointer(connection(), 0, &p); - return p / dpr; + return m_screen->mapFromNative(p); } void QXcbCursor::setPos(const QPoint &pos) { - const int dpr = int(m_screen->devicePixelRatio()); + const QPoint xPos = m_screen->mapToNative(pos); xcb_window_t root = 0; queryPointer(connection(), &root, 0); - xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x()*dpr, pos.y()*dpr); + xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, xPos.x(), xPos.y()); xcb_flush(xcb_connection()); } diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index fcf70f3c51..bcaa13eb1e 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -273,6 +273,31 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const return 0; } + +QPoint QXcbScreen::mapToNative(const QPoint &pos) const +{ + const int dpr = int(devicePixelRatio()); + return (pos - m_geometry.topLeft()) * dpr + m_nativeGeometry.topLeft(); +} + +QPoint QXcbScreen::mapFromNative(const QPoint &pos) const +{ + const int dpr = int(devicePixelRatio()); + return (pos - m_nativeGeometry.topLeft()) / dpr + m_geometry.topLeft(); +} + +QRect QXcbScreen::mapToNative(const QRect &rect) const +{ + const int dpr = int(devicePixelRatio()); + return QRect(mapToNative(rect.topLeft()), rect.size() * dpr); +} + +QRect QXcbScreen::mapFromNative(const QRect &rect) const +{ + const int dpr = int(devicePixelRatio()); + return QRect(mapFromNative(rect.topLeft()), rect.size() / dpr); +} + void QXcbScreen::windowShown(QXcbWindow *window) { // Freedesktop.org Startup Notification @@ -499,9 +524,9 @@ void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation) qreal dpi = xGeometry.width() / physicalSize().width() * qreal(25.4); m_devicePixelRatio = qRound(dpi/96); const int dpr = int(devicePixelRatio()); // we may override m_devicePixelRatio - m_geometry = QRect(xGeometry.topLeft()/dpr, xGeometry.size()/dpr); + m_geometry = QRect(xGeometry.topLeft(), xGeometry.size()/dpr); m_nativeGeometry = QRect(xGeometry.topLeft(), xGeometry.size()); - m_availableGeometry = QRect(xAvailableGeometry.topLeft()/dpr, xAvailableGeometry.size()/dpr); + m_availableGeometry = QRect(mapFromNative(xAvailableGeometry.topLeft()), xAvailableGeometry.size()/dpr); QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); } diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 6b60ea9bb1..a29efc1e79 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -140,6 +140,11 @@ public: QXcbXSettings *xSettings() const; + QPoint mapToNative(const QPoint &pos) const; + QPoint mapFromNative(const QPoint &pos) const; + QRect mapToNative(const QRect &rect) const; + QRect mapFromNative(const QRect &rect) const; + private: static bool xResource(const QByteArray &identifier, const QByteArray &expectedIdentifier, diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index b06b41a77b..b5d0741fa6 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -138,7 +138,7 @@ enum QX11EmbedMessageType { const quint32 XEMBED_VERSION = 0; -static inline QRect mapToNative(const QRect &qtRect, int dpr) +static inline QRect mapLocalGeometryToNative(const QRect &qtRect, int dpr) { return QRect(qtRect.x() * dpr, qtRect.y() * dpr, qtRect.width() * dpr, qtRect.height() * dpr); } @@ -166,11 +166,45 @@ static inline QRect mapExposeFromNative(const QRect &xRect, int dpr) return QRect(dpr_floor(xRect.topLeft(), dpr), dpr_ceil(xRect.bottomRight(), dpr)); } -static inline QRect mapGeometryFromNative(const QRect &xRect, int dpr) +static inline QRect mapLocalGeometryFromNative(const QRect &xRect, int dpr) { return QRect(xRect.topLeft() / dpr, dpr_ceil(xRect.size(), dpr)); } +QXcbScreen *QXcbWindow::parentScreen() +{ + return parent() ? static_cast(parent())->parentScreen() : m_xcbScreen; +} + +QPoint QXcbWindow::mapToNative(const QPoint &pos, const QXcbScreen *screen) const +{ + if (parent()) + return pos * int(screen->devicePixelRatio()); + else + return screen->mapToNative(pos); +} +QPoint QXcbWindow::mapFromNative(const QPoint &pos, const QXcbScreen *screen) const +{ + if (parent()) + return pos / int(screen->devicePixelRatio()); + else + return screen->mapFromNative(pos); +} +QRect QXcbWindow::mapToNative(const QRect &rect, const QXcbScreen *screen) const +{ + if (parent()) + return mapLocalGeometryToNative(rect, int(screen->devicePixelRatio())); + else + return screen->mapToNative(rect); +} +QRect QXcbWindow::mapFromNative(const QRect &rect, const QXcbScreen *screen) const +{ + if (parent()) + return mapLocalGeometryFromNative(rect, int(screen->devicePixelRatio())); + else + return screen->mapFromNative(rect); +} + // Returns \c true if we should set WM_TRANSIENT_FOR on \a w static inline bool isTransient(const QWindow *w) { @@ -291,6 +325,7 @@ static const char *wm_window_type_property_id = "_q_xcb_wm_window_type"; QXcbWindow::QXcbWindow(QWindow *window) : QPlatformWindow(window) , m_window(0) + , m_xcbScreen(0) , m_syncCounter(0) , m_gravity(XCB_GRAVITY_STATIC) , m_mapped(false) @@ -344,8 +379,11 @@ void QXcbWindow::create() Qt::WindowType type = window()->type(); - QXcbScreen *platformScreen = xcbScreen(); + QXcbScreen *currentScreen = xcbScreen(); + QRect rect = window()->geometry(); + QXcbScreen *platformScreen = parent() ? parentScreen() : static_cast(screenForGeometry(rect)); + m_xcbScreen = platformScreen; if (type == Qt::Desktop) { m_window = platformScreen->root(); m_depth = platformScreen->screen()->root_depth; @@ -371,13 +409,10 @@ void QXcbWindow::create() // Parameters to XCreateWindow() are frame corner + inner size. // This fits in case position policy is frame inclusive. There is // currently no way to implement it for frame-exclusive geometries. - QRect rect = window()->geometry(); QPlatformWindow::setGeometry(rect); - QXcbScreen *currentScreen = xcbScreen(); - QPlatformScreen *newScreen = screenForGeometry(rect); - if (newScreen != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + if (platformScreen != currentScreen) + QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen()); const int dpr = int(devicePixelRatio()); @@ -428,7 +463,7 @@ void QXcbWindow::create() m_visualId = visualInfo->visualid; - const QRect xRect = mapToNative(rect, dpr); + const QRect xRect = mapToNative(rect, platformScreen); m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, xRect.x(), xRect.y(), xRect.width(), xRect.height(), 0, visualInfo->depth, InputOutput, visualInfo->visual, @@ -472,15 +507,16 @@ void QXcbWindow::create() const xcb_visualtype_t *visual = platformScreen->visualForId(m_visualId); m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap); + const QRect xRect = mapToNative(rect, platformScreen); Q_XCB_CALL(xcb_create_window(xcb_connection(), m_depth, m_window, // window id xcb_parent_id, // parent window id - rect.x(), - rect.y(), - rect.width(), - rect.height(), + xRect.x(), + xRect.y(), + xRect.width(), + xRect.height(), 0, // border width XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class m_visualId, // visual @@ -631,7 +667,7 @@ void QXcbWindow::destroy() void QXcbWindow::maybeSetScreen(QXcbScreen *screen) { - if (!window()->screen() && screen->geometry().contains(geometry().topLeft() * int(devicePixelRatio()))) { + if (!window()->screen() && screen->geometry().contains(geometry().topLeft())) { QWindowSystemInterface::handleWindowScreenChanged(window(), static_cast(screen)->screen()); QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(0, 0), window()->size()))); } @@ -644,16 +680,17 @@ void QXcbWindow::setGeometry(const QRect &rect) propagateSizeHints(); QXcbScreen *currentScreen = xcbScreen(); - QPlatformScreen *newScreen = screenForGeometry(rect); + QXcbScreen *newScreen = parent() ? parentScreen() : static_cast(screenForGeometry(rect)); + if (!newScreen) newScreen = currentScreen; - const QRect xRect = mapToNative(rect, int(newScreen->devicePixelRatio())); + m_xcbScreen = newScreen; + const QRect xRect = mapToNative(rect, newScreen); const QRect wmGeometry = windowToWmGeometry(xRect); - if (newScreen != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); if (qt_window_private(window())->positionAutomatic) { const quint32 mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; @@ -1160,6 +1197,8 @@ void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) event.data.data32[3] = 0; event.data.data32[4] = 0; + if (!xcbScreen()) + return; Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, xcbScreen()->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); } @@ -1554,7 +1593,7 @@ void QXcbWindow::propagateSizeHints() memset(&hints, 0, sizeof(hints)); const int dpr = int(devicePixelRatio()); - const QRect xRect = mapToNative(windowToWmGeometry(geometry()), dpr); + const QRect xRect = windowToWmGeometry(mapToNative(geometry(), xcbScreen())); QWindow *win = window(); @@ -1892,20 +1931,21 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } } -// Temporary workaround for bug in QPlatformScreen::screenForNativeGeometry +// Temporary workaround for bug in QPlatformScreen::screenForGeometry // we need the native geometries to detect our screen, but that's not // available in cross-platform code. Will be fixed properly when highDPI // support is refactored to expose the native coordinate system. -QPlatformScreen *QXcbWindow::screenForNativeGeometry(const QRect &newGeometry) const +QXcbScreen *QXcbWindow::screenForNativeGeometry(const QRect &newGeometry) const { - QXcbScreen *currentScreen = static_cast(screen()); + QXcbScreen *currentScreen = xcbScreen(); if (!currentScreen && QGuiApplication::primaryScreen()) currentScreen = static_cast(QGuiApplication::primaryScreen()->handle()); if (currentScreen && !parent() && !currentScreen->nativeGeometry().intersects(newGeometry)) { Q_FOREACH (QPlatformScreen* screen, currentScreen->virtualSiblings()) { - if (static_cast(screen)->nativeGeometry().intersects(newGeometry)) - return screen; + QXcbScreen *xcbScreen = static_cast(screen); + if (xcbScreen->nativeGeometry().intersects(newGeometry)) + return xcbScreen; } } return currentScreen; @@ -1927,23 +1967,18 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } } - const int dpr = devicePixelRatio(); const QRect nativeRect = QRect(pos, QSize(event->width, event->height)); - const QRect rect = mapGeometryFromNative(nativeRect, dpr); + QXcbScreen *newScreen = parent() ? parentScreen() : screenForNativeGeometry(nativeRect); + + m_xcbScreen = newScreen; + if (!newScreen) + return; + const QRect rect = mapFromNative(nativeRect, newScreen); QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); - QPlatformScreen *newScreen = screenForNativeGeometry(nativeRect); - if (newScreen != screen()) { - if (newScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); - int newDpr = newScreen->devicePixelRatio(); - if (newDpr != dpr) { - QRect newRect = mapGeometryFromNative(nativeRect, newDpr); - QPlatformWindow::setGeometry(newRect); - QWindowSystemInterface::handleGeometryChange(window(), newRect); - } - } + if (newScreen != screen()) + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); m_configureNotifyPending = false; @@ -1984,12 +2019,12 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { - ret.setX(reply->dst_x / dpr); - ret.setY(reply->dst_y / dpr); + ret.setX(reply->dst_x); + ret.setY(reply->dst_y); free(reply); } - return ret; + return mapFromNative(ret, xcbScreen()); } QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const @@ -1999,9 +2034,10 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const const int dpr = int(devicePixelRatio()); QPoint ret; + QPoint xPos = mapToNative(pos, xcbScreen()); xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcbScreen()->root(), xcb_window(), - pos.x() *dpr, pos.y() * dpr); + xPos.x(), xPos.y()); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { @@ -2055,7 +2091,7 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) } const int dpr = int(devicePixelRatio()); QPoint local(event->event_x/dpr, event->event_y/dpr); - QPoint global(event->root_x/dpr, event->root_y/dpr); + QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); @@ -2080,7 +2116,7 @@ void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *even { const int dpr = int(devicePixelRatio()); QPoint local(event->event_x/dpr, event->event_y/dpr); - QPoint global(event->root_x/dpr, event->root_y/dpr); + QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); if (event->detail >= 4 && event->detail <= 7) { @@ -2095,7 +2131,9 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) { const int dpr = int(devicePixelRatio()); QPoint local(event->event_x/dpr, event->event_y/dpr); - QPoint global(event->root_x/dpr, event->root_y/dpr); + if (!xcbScreen()) + return; + QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); handleMouseEvent(event->time, local, global, modifiers); @@ -2152,7 +2190,9 @@ void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) const int dpr = int(devicePixelRatio()); const QPoint local(event->event_x/dpr, event->event_y/dpr); - const QPoint global(event->root_x/dpr, event->root_y/dpr); + if (!xcbScreen()) + return; + QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); QWindowSystemInterface::handleEnterEvent(window(), local, global); } @@ -2170,7 +2210,9 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) if (enterWindow) { const int dpr = int(devicePixelRatio()); QPoint local(enter->event_x/dpr, enter->event_y/dpr); - QPoint global(enter->root_x/dpr, enter->root_y/dpr); + if (!xcbScreen()) + return; + QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global); } else { @@ -2185,6 +2227,8 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev connection()->setTime(event->time); const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE; + if (!xcbScreen()) + return; if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) { if (propertyDeleted) @@ -2333,7 +2377,6 @@ void QXcbWindow::windowEvent(QEvent *event) bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) { - const int dpr = int(devicePixelRatio()); const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); if (!connection()->wmSupport()->isSupportedByWM(moveResize)) return false; @@ -2342,7 +2385,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) xev.type = moveResize; xev.window = xcb_window(); xev.format = 32; - const QPoint globalPos = window()->mapToGlobal(pos) * dpr; + const QPoint globalPos = mapToNative(window()->mapToGlobal(pos), xcbScreen()); xev.data.data32[0] = globalPos.x(); xev.data.data32[1] = globalPos.y(); const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner; @@ -2471,7 +2514,7 @@ void QXcbWindow::setMask(const QRegion ®ion) const int dpr = devicePixelRatio(); QVector rects; foreach (const QRect &r, region.rects()) - rects.push_back(qRectToXCBRectangle(mapToNative(r, dpr))); + rects.push_back(qRectToXCBRectangle(mapLocalGeometryToNative(r, dpr))); xcb_shape_rectangles(connection()->xcb_connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, xcb_window(), 0, 0, rects.size(), &rects[0]); @@ -2495,6 +2538,8 @@ bool QXcbWindow::needsSync() const void QXcbWindow::postSyncWindowRequest() { + if (!xcbScreen()) + return; if (!m_pendingSyncRequest) { QXcbSyncWindowRequest *e = new QXcbSyncWindowRequest(this); m_pendingSyncRequest = e; diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index c08408a1ca..fbf3cfe172 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -155,7 +155,7 @@ public: virtual void create(); virtual void destroy(); void maybeSetScreen(QXcbScreen *screen); - QPlatformScreen *screenForNativeGeometry(const QRect &newGeometry) const; + QXcbScreen *screenForNativeGeometry(const QRect &newGeometry) const; public Q_SLOTS: void updateSyncRequestCounter(); @@ -165,6 +165,12 @@ protected: virtual void *createVisual() { return Q_NULLPTR; } virtual bool supportsSyncProtocol() { return !window()->supportsOpenGL(); } + QPoint mapToNative(const QPoint &pos, const QXcbScreen *screen) const; + QPoint mapFromNative(const QPoint &pos, const QXcbScreen *screen) const; + QRect mapToNative(const QRect &rect, const QXcbScreen *screen) const; + QRect mapFromNative(const QRect &rect, const QXcbScreen *screen) const; + QXcbScreen *parentScreen(); + void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); NetWmStates netWmStates(); void setNetWmStates(NetWmStates); @@ -192,6 +198,8 @@ protected: xcb_window_t m_window; + QXcbScreen *m_xcbScreen; + uint m_depth; QImage::Format m_imageFormat; bool m_imageRgbSwap; -- cgit v1.2.3 From 666486b3efec871301b82244ec661e1eaa6cca9c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 10 Apr 2015 10:07:51 +0200 Subject: Fix performance of recursive read-write locks The implementation used an expensive QHash to keep track of reading threads, for seemingly no good reason. Change-Id: Iffa5b18d80f56b8ff22d39aa6bc3d52c2e3ed0ef Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Lars Knoll Reviewed-by: Thiago Macieira --- src/corelib/thread/qreadwritelock.cpp | 57 ----------------------------------- src/corelib/thread/qreadwritelock_p.h | 1 - 2 files changed, 58 deletions(-) (limited to 'src') diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp index 0ea8c4c00f..e6477bf5e0 100644 --- a/src/corelib/thread/qreadwritelock.cpp +++ b/src/corelib/thread/qreadwritelock.cpp @@ -136,27 +136,11 @@ void QReadWriteLock::lockForRead() { QMutexLocker lock(&d->mutex); - Qt::HANDLE self = 0; - if (d->recursive) { - self = QThread::currentThreadId(); - - QHash::iterator it = d->currentReaders.find(self); - if (it != d->currentReaders.end()) { - ++it.value(); - ++d->accessCount; - Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::lockForRead()", - "Overflow in lock counter"); - return; - } - } - while (d->accessCount < 0 || d->waitingWriters) { ++d->waitingReaders; d->readerWait.wait(&d->mutex); --d->waitingReaders; } - if (d->recursive) - d->currentReaders.insert(self, 1); ++d->accessCount; Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::lockForRead()", "Overflow in lock counter"); @@ -182,24 +166,8 @@ bool QReadWriteLock::tryLockForRead() { QMutexLocker lock(&d->mutex); - Qt::HANDLE self = 0; - if (d->recursive) { - self = QThread::currentThreadId(); - - QHash::iterator it = d->currentReaders.find(self); - if (it != d->currentReaders.end()) { - ++it.value(); - ++d->accessCount; - Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()", - "Overflow in lock counter"); - return true; - } - } - if (d->accessCount < 0) return false; - if (d->recursive) - d->currentReaders.insert(self, 1); ++d->accessCount; Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()", "Overflow in lock counter"); @@ -230,20 +198,6 @@ bool QReadWriteLock::tryLockForRead(int timeout) { QMutexLocker lock(&d->mutex); - Qt::HANDLE self = 0; - if (d->recursive) { - self = QThread::currentThreadId(); - - QHash::iterator it = d->currentReaders.find(self); - if (it != d->currentReaders.end()) { - ++it.value(); - ++d->accessCount; - Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()", - "Overflow in lock counter"); - return true; - } - } - while (d->accessCount < 0 || d->waitingWriters) { ++d->waitingReaders; bool success = d->readerWait.wait(&d->mutex, timeout < 0 ? ULONG_MAX : ulong(timeout)); @@ -251,8 +205,6 @@ bool QReadWriteLock::tryLockForRead(int timeout) if (!success) return false; } - if (d->recursive) - d->currentReaders.insert(self, 1); ++d->accessCount; Q_ASSERT_X(d->accessCount > 0, "QReadWriteLock::tryLockForRead()", "Overflow in lock counter"); @@ -412,15 +364,6 @@ void QReadWriteLock::unlock() bool unlocked = false; if (d->accessCount > 0) { // releasing a read lock - if (d->recursive) { - Qt::HANDLE self = QThread::currentThreadId(); - QHash::iterator it = d->currentReaders.find(self); - if (it != d->currentReaders.end()) { - if (--it.value() <= 0) - d->currentReaders.erase(it); - } - } - unlocked = --d->accessCount == 0; } else if (d->accessCount < 0 && ++d->accessCount == 0) { // released a write lock diff --git a/src/corelib/thread/qreadwritelock_p.h b/src/corelib/thread/qreadwritelock_p.h index e57c0e403f..15a6d1f57e 100644 --- a/src/corelib/thread/qreadwritelock_p.h +++ b/src/corelib/thread/qreadwritelock_p.h @@ -69,7 +69,6 @@ struct QReadWriteLockPrivate bool recursive; Qt::HANDLE currentWriter; - QHash currentReaders; }; QT_END_NAMESPACE -- cgit v1.2.3 From 472216da2d3e88472df3594cbc9eccc6d6b1b44b Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 13 Apr 2015 15:52:51 +0200 Subject: Defer Q(OpenGL|Raster)Window updates when non-exposed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is similar to how widgets work. On platforms like OS X this becomes essential since in non-exposed state SwapBuffers does not block so continuing to update continuously leads to undesirable effects. Task-number: QTBUG-45524 Change-Id: I80f4c00b218561b9e62c3cad1e66f61f4debd4af Reviewed-by: Jørgen Lind --- src/gui/kernel/qpaintdevicewindow.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qpaintdevicewindow.cpp b/src/gui/kernel/qpaintdevicewindow.cpp index b32ab3b34d..ff661d017d 100644 --- a/src/gui/kernel/qpaintdevicewindow.cpp +++ b/src/gui/kernel/qpaintdevicewindow.cpp @@ -60,6 +60,9 @@ QT_BEGIN_NAMESPACE \note Subsequent calls to this function before the next paint event will get ignored. + + \note For non-exposed windows the update is deferred until the + window becomes exposed again. */ void QPaintDeviceWindow::update() { @@ -70,26 +73,34 @@ void QPaintDeviceWindow::update() Marks the \a rect of the window as dirty and schedules a repaint. \note Subsequent calls to this function before the next paint - event will get ignored. + event will get ignored, but \a rect is added to the region to update. + + \note For non-exposed windows the update is deferred until the + window becomes exposed again. */ void QPaintDeviceWindow::update(const QRect &rect) { Q_D(QPaintDeviceWindow); d->dirtyRegion += rect; - requestUpdate(); + if (isExposed()) + requestUpdate(); } /*! Marks the \a region of the window as dirty and schedules a repaint. \note Subsequent calls to this function before the next paint - event will get ignored. + event will get ignored, but \a region is added to the region to update. + + \note For non-exposed windows the update is deferred until the + window becomes exposed again. */ void QPaintDeviceWindow::update(const QRegion ®ion) { Q_D(QPaintDeviceWindow); d->dirtyRegion += region; - requestUpdate(); + if (isExposed()) + requestUpdate(); } /*! @@ -168,6 +179,9 @@ void QPaintDeviceWindow::exposeEvent(QExposeEvent *exposeEvent) // sometimes relative to the parent, depending on the platform plugin. // We require local coords here. d->doFlush(QRect(QPoint(0, 0), size())); + } else if (!d->dirtyRegion.isEmpty()) { + // Updates while non-exposed were ignored. Schedule an update now. + requestUpdate(); } } -- cgit v1.2.3 From 91dfab223a64385f6c0d010deafbdc8b2eb69968 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Tue, 24 Mar 2015 22:20:48 +0100 Subject: Add support for unregistering of custom meta types. This patch addresses a specific Qml problem, where the meta types list will grow indefinitely when unloading and reloading Qml components over and over (in an failed effort to save memory). The implementation is not specific to Qml though, but will cater to all use-cases where registered types may not live until the application's termination. Change-Id: Ic0224dcd19aeb559715ef088b22a30509be2456b Reviewed-by: Simon Hausmann --- src/corelib/kernel/qmetatype.cpp | 63 ++++++++++++++++++++++++++++++++++++---- src/corelib/kernel/qmetatype.h | 1 + 2 files changed, 58 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index d4a69ee4b9..3b70ef92ed 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -872,13 +872,17 @@ static inline int qMetaTypeStaticType(const char *typeName, int length) \internal Similar to QMetaType::type(), but only looks in the custom set of types, and doesn't lock the mutex. + The extra \a firstInvalidIndex parameter is an easy way to avoid + iterating over customTypes() a second time in registerNormalizedType(). */ -static int qMetaTypeCustomType_unlocked(const char *typeName, int length) +static int qMetaTypeCustomType_unlocked(const char *typeName, int length, int *firstInvalidIndex = 0) { const QVector * const ct = customTypes(); if (!ct) return QMetaType::UnknownType; + if (firstInvalidIndex) + *firstInvalidIndex = -1; for (int v = 0; v < ct->count(); ++v) { const QCustomTypeInfo &customInfo = ct->at(v); if ((length == customInfo.typeName.size()) @@ -887,6 +891,8 @@ static int qMetaTypeCustomType_unlocked(const char *typeName, int length) return customInfo.alias; return v + QMetaType::User; } + if (firstInvalidIndex && (*firstInvalidIndex < 0) && customInfo.typeName.isEmpty()) + *firstInvalidIndex = v; } return QMetaType::UnknownType; } @@ -905,6 +911,39 @@ int QMetaType::registerType(const char *typeName, Deleter deleter, QtMetaTypePrivate::QMetaTypeFunctionHelper::Construct, 0, TypeFlags(), 0); } +/*! + \internal + \since 5.5 + + Unregisters the user type with the given \a typeId and all its aliases. + Returns \c true if the type was unregistered or \c false otherwise. + + This function was added for QML to be able to deregister types after + they are unloaded to prevent an infinite increase in custom types for + applications that are unloading/reloading components often. + */ +bool QMetaType::unregisterType(int type) +{ + QWriteLocker locker(customTypesLock()); + QVector *ct = customTypes(); + + // check if user type + if ((type < User) || ((type - User) >= ct->size())) + return false; + + // only types without Q_DECLARE_METATYPE can be unregistered + if (ct->data()[type - User].flags & WasDeclaredAsMetaType) + return false; + + // invalidate type and all its alias entries + for (int v = 0; v < ct->count(); ++v) { + if (((v + User) == type) || (ct->at(v).alias == type)) + ct->data()[v].typeName.clear(); + } + return true; +} + + /*! \internal \since 5.0 @@ -977,8 +1016,10 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, int previousFlags = 0; if (idx == UnknownType) { QWriteLocker locker(customTypesLock()); + int posInVector = -1; idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), - normalizedTypeName.size()); + normalizedTypeName.size(), + &posInVector); if (idx == UnknownType) { QCustomTypeInfo inf; inf.typeName = normalizedTypeName; @@ -992,8 +1033,13 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName, inf.size = size; inf.flags = flags; inf.metaObject = metaObject; - idx = ct->size() + User; - ct->append(inf); + if (posInVector == -1) { + idx = ct->size() + User; + ct->append(inf); + } else { + idx = posInVector + User; + ct->data()[posInVector] = inf; + } return idx; } @@ -1075,14 +1121,19 @@ int QMetaType::registerNormalizedTypedef(const NS(QByteArray) &normalizedTypeNam if (idx == UnknownType) { QWriteLocker locker(customTypesLock()); + int posInVector = -1; idx = qMetaTypeCustomType_unlocked(normalizedTypeName.constData(), - normalizedTypeName.size()); + normalizedTypeName.size(), + &posInVector); if (idx == UnknownType) { QCustomTypeInfo inf; inf.typeName = normalizedTypeName; inf.alias = aliasId; - ct->append(inf); + if (posInVector == -1) + ct->append(inf); + else + ct->data()[posInVector] = inf; return aliasId; } } diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index aa8d826ed9..1e2a860d8c 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -484,6 +484,7 @@ public: int size, QMetaType::TypeFlags flags, const QMetaObject *metaObject); + static bool unregisterType(int type); static int registerNormalizedType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, Deleter deleter, Creator creator, Destructor destructor, -- cgit v1.2.3 From 2bcbe227bdcfded9ae01b289e78aa9e117613056 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 13 Apr 2015 22:22:10 -0700 Subject: Fix crashes on shutdown when the D-Bus spy list has been destroyed The QDBusConnection spy hook is most often created after the QDBusConnectionManager global, which means it will get destroyed before. That means we'll almost surely going to get a null pointer dereference if we handle the socket close to shutdown. Change-Id: I27eaacb532114dd188c4ffff13d4c9dc865b8c02 Reviewed-by: Alex Blasche --- src/dbus/qdbusintegrator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 9eac1ed933..d05703d34d 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -554,7 +554,7 @@ qDBusSignalFilter(DBusConnection *connection, DBusMessage *message, void *data) bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg) { const QDBusSpyHookList *list = qDBusSpyHookList(); - for (int i = 0; i < list->size(); ++i) { + for (int i = 0; list && i < list->size(); ++i) { qDBusDebug() << "calling the message spy hook"; (*(*list)[i])(amsg); } -- cgit v1.2.3 From d370878aa0510e1e51eb9014965f505e395f3f81 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 3 Apr 2015 22:21:08 -0700 Subject: Fix undefined behavior: accessing an object after destruction QDBusConnectionPrivate keeps a pointer to a QDBusConnectionInterface, which in turn holds a reference back to that QDBusConnectionPrivate. During the interface object's destruction, the QDBusAbstractInterface's destructor checks if the interface is still valid. That access is undefined behavior, but has so far been benign in all our uses since the memory had not yet been freed (just destroyed) and the reference count went from 0 to -1. To be on the safe side, we destroy now the QDBusConnectionInterface object while the Private is still valid. It will bring the reference count down from 0 to a negative number, but won't cause any other effects. Change-Id: I9a75ad8521ae4e5cbbe5ffff13d1b80057e13809 Reviewed-by: Alex Blasche --- src/dbus/qdbusintegrator.cpp | 9 +++++++++ src/dbus/qdbusserver.cpp | 1 + 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index d05703d34d..cce8b9c28d 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1038,6 +1038,15 @@ QDBusConnectionPrivate::~QDBusConnectionPrivate() "Timer and socket errors will follow and the program will probably crash", qPrintable(name)); + if (mode == ClientMode) { + // the bus service object holds a reference back to us; + // we need to destroy it before we finish destroying ourselves + Q_ASSERT(ref.load() == 0); + QObject *obj = (QObject *)busService; + disconnect(obj, Q_NULLPTR, this, Q_NULLPTR); + delete obj; + } + closeConnection(); rootNode.children.clear(); // free resources qDeleteAll(cachedMetaObjects); diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp index 2fc7c75d83..cf1b6e9665 100644 --- a/src/dbus/qdbusserver.cpp +++ b/src/dbus/qdbusserver.cpp @@ -111,6 +111,7 @@ QDBusServer::~QDBusServer() } d->serverConnectionNames.clear(); } + d->ref.store(0); d->deleteLater(); } -- cgit v1.2.3 From 939f21be53efabc37b7682a72effab716d8b9410 Mon Sep 17 00:00:00 2001 From: Filipe Azevedo Date: Mon, 16 Mar 2015 14:07:17 +0100 Subject: QNSView: Implement custom cursors for drag and drop. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The change has been made so it support possible future change for QTBUG-26724 Task-number: QTBUG-40346 Change-Id: Ia52835f1a882289a2a22a0b755c943a12b8d3aa3 Reviewed-by: Christoph Schleifenbaum Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qnsview.mm | 42 ++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'src') diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 3a3a17a474..7896fffaad 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1883,6 +1883,48 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); } + QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); + const QPixmap pixmapCursor = nativeDrag->currentDrag()->dragCursor(response.acceptedAction()); + NSCursor *nativeCursor = nil; + + if (pixmapCursor.isNull()) { + switch (response.acceptedAction()) { + case Qt::CopyAction: + nativeCursor = [NSCursor dragCopyCursor]; + break; + case Qt::LinkAction: + nativeCursor = [NSCursor dragLinkCursor]; + break; + case Qt::IgnoreAction: + // Uncomment the next lines if forbiden cursor wanted on non droppable targets. + /*nativeCursor = [NSCursor operationNotAllowedCursor]; + break;*/ + case Qt::MoveAction: + default: + nativeCursor = [NSCursor arrowCursor]; + break; + } + } + else { + NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor); + nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint]; + [nsimage release]; + } + + // change the cursor + [nativeCursor set]; + + // Make sure the cursor is updated correctly if the mouse does not move and window is under cursor + // by creating a fake move event + const QPoint mousePos(QCursor::pos()); + CGEventRef moveEvent(CGEventCreateMouseEvent( + NULL, kCGEventMouseMoved, + CGPointMake(mousePos.x(), mousePos.y()), + kCGMouseButtonLeft // ignored + )); + CGEventPost(kCGHIDEventTap, moveEvent); + CFRelease(moveEvent); + return qt_mac_mapDropAction(response.acceptedAction()); } -- cgit v1.2.3 From 2748661ddd3033ca3e6bcf3fe16633ab75a598aa Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 13 Apr 2015 15:52:56 +0200 Subject: Work around MSVC warnings about unused variables in moc output Change 8836a4d5f0fbbb already added Q_UNUSED in one place, but that was not enough. Change-Id: Ib98ba3fe47c0903cc01c56fd3eb8461c8938c75e Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Thiago Macieira --- src/tools/moc/generator.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 46acbc608b..8b6a0519c5 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1310,6 +1310,7 @@ void Generator::generateStaticMetacall() } else { fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); } + fprintf(out, " Q_UNUSED(_t)\n"); if (needTempVarForGet) fprintf(out, " void *_v = _a[0];\n"); fprintf(out, " switch (_id) {\n"); @@ -1355,6 +1356,7 @@ void Generator::generateStaticMetacall() } else { fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); } + fprintf(out, " Q_UNUSED(_t)\n"); fprintf(out, " void *_v = _a[0];\n"); fprintf(out, " switch (_id) {\n"); for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { @@ -1408,6 +1410,7 @@ void Generator::generateStaticMetacall() } else { fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); } + fprintf(out, " Q_UNUSED(_t)\n"); fprintf(out, " switch (_id) {\n"); for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { const PropertyDef &p = cdef->propertyList.at(propindex); -- cgit v1.2.3 From c586f958b30c32176487133e76d5cf65b15d6166 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 14 Apr 2015 16:40:26 +0400 Subject: Fix trivial copy-paste typo in QTextBlock::previous() docu Change-Id: Ia5d260af00aecf40400653e41248b5dd5f074b74 Reviewed-by: Simon Hausmann --- src/gui/text/qtextobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index 425126d474..df7c8b9c71 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -1561,7 +1561,7 @@ QTextBlock QTextBlock::next() const Returns the text block in the document before this block, or an empty text block if this is the first one. - Note that the next block may be in a different frame or table to this block. + Note that the previous block may be in a different frame or table to this block. \sa next(), begin(), end() */ -- cgit v1.2.3 From ba5af03a5a505d4ef19ccea1c0170e50abf3db8c Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 14 Apr 2015 15:34:08 +0400 Subject: [QTextCursor] Better use of the cached whiteSpace attribute In compare to QTextEngine::atSpace(), this also handles the less-common "white spaces" and the exceptional control codes. Change-Id: I52878932926b7f9fe36c9dd01007963b9691fbf0 Reviewed-by: Simon Hausmann --- src/gui/text/qtextcursor.cpp | 8 ++++---- src/gui/text/qtextengine.cpp | 15 --------------- src/gui/text/qtextengine_p.h | 1 - src/gui/text/qtextlayout.cpp | 8 ++++---- 4 files changed, 8 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index a151c515a3..eb51447105 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -424,9 +424,9 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor // skip if already at word start QTextEngine *engine = layout->engine(); - engine->attributes(); + const QCharAttributes *attributes = engine->attributes(); if ((relativePos == blockIt.length() - 1) - && (engine->atSpace(relativePos - 1) || engine->atWordSeparator(relativePos - 1))) + && (attributes[relativePos - 1].whiteSpace || engine->atWordSeparator(relativePos - 1))) return false; if (relativePos < blockIt.length()-1) @@ -499,7 +499,7 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor } case QTextCursor::EndOfWord: { QTextEngine *engine = layout->engine(); - engine->attributes(); + const QCharAttributes *attributes = engine->attributes(); const int len = blockIt.length() - 1; if (relativePos >= len) return false; @@ -508,7 +508,7 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor while (relativePos < len && engine->atWordSeparator(relativePos)) ++relativePos; } else { - while (relativePos < len && !engine->atSpace(relativePos) && !engine->atWordSeparator(relativePos)) + while (relativePos < len && !attributes[relativePos].whiteSpace && !engine->atWordSeparator(relativePos)) ++relativePos; } newPosition = blockIt.position() + relativePos; diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 10a61d3c84..67a19804a3 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2549,21 +2549,6 @@ bool QTextEngine::atWordSeparator(int position) const return false; } -bool QTextEngine::atSpace(int position) const -{ - const QChar c = layoutData->string.at(position); - switch (c.unicode()) { - case QChar::Tabulation: - case QChar::Space: - case QChar::Nbsp: - case QChar::LineSeparator: - return true; - default: - break; - } - return false; -} - void QTextEngine::setPreeditArea(int position, const QString &preeditText) { if (preeditText.isEmpty()) { diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 8037fd5f6d..39b9e0cb5a 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -592,7 +592,6 @@ private: public: bool atWordSeparator(int position) const; - bool atSpace(int position) const; QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0, int from = 0, int count = -1) const; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index cab9f6ae61..7da3e84041 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -648,10 +648,10 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const while (oldPos < len && d->atWordSeparator(oldPos)) oldPos++; } else { - while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos)) + while (oldPos < len && !attributes[oldPos].whiteSpace && !d->atWordSeparator(oldPos)) oldPos++; } - while (oldPos < len && d->atSpace(oldPos)) + while (oldPos < len && attributes[oldPos].whiteSpace) oldPos++; } @@ -679,7 +679,7 @@ int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const while (oldPos && !attributes[oldPos].graphemeBoundary) oldPos--; } else { - while (oldPos && d->atSpace(oldPos-1)) + while (oldPos > 0 && attributes[oldPos - 1].whiteSpace) oldPos--; if (oldPos && d->atWordSeparator(oldPos-1)) { @@ -687,7 +687,7 @@ int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const while (oldPos && d->atWordSeparator(oldPos-1)) oldPos--; } else { - while (oldPos && !d->atSpace(oldPos-1) && !d->atWordSeparator(oldPos-1)) + while (oldPos > 0 && !attributes[oldPos - 1].whiteSpace && !d->atWordSeparator(oldPos-1)) oldPos--; } } -- cgit v1.2.3 From 7432c7c08a6709a12a143d48fbaa9927962edae8 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 7 Apr 2015 11:20:08 +0200 Subject: Cleanup and optimization of qimage smoothscale Cleaning up smoothscale code. Upscaling is improved using existing optimized interpolation methods, and downscale is given SSE4.1 optimized versions. Change-Id: I7cdc256c26850948aef7dae26fda1622be6b8179 Reviewed-by: Gunnar Sletta --- src/gui/image/qimage.cpp | 10 +- src/gui/painting/painting.pri | 3 +- src/gui/painting/qdrawhelper.cpp | 38 -- src/gui/painting/qdrawhelper_p.h | 36 + src/gui/painting/qimagescale.cpp | 1155 +++++++++++++-------------------- src/gui/painting/qimagescale_p.h | 9 + src/gui/painting/qimagescale_sse4.cpp | 247 +++++++ 7 files changed, 769 insertions(+), 729 deletions(-) create mode 100644 src/gui/painting/qimagescale_sse4.cpp (limited to 'src') diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 5cc1cf760f..f20800440d 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -4248,11 +4248,15 @@ int QImage::bitPlaneCount() const static QImage smoothScaled(const QImage &source, int w, int h) { QImage src = source; - bool canSkipConversion = (src.format() == QImage::Format_RGB32 || src.format() == QImage::Format_ARGB32_Premultiplied); + switch (src.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32_Premultiplied: #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - canSkipConversion = canSkipConversion || (src.format() == QImage::Format_RGBX8888 || src.format() == QImage::Format_RGBA8888_Premultiplied); + case QImage::Format_RGBX8888: #endif - if (!canSkipConversion) { + case QImage::Format_RGBA8888_Premultiplied: + break; + default: if (src.hasAlphaChannel()) src = src.convertToFormat(QImage::Format_ARGB32_Premultiplied); else diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 2f2d3daaf8..a861516821 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -93,7 +93,8 @@ SOURCES += \ SSE2_SOURCES += painting/qdrawhelper_sse2.cpp SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp -SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp +SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ + painting/qimagescale_sse4.cpp AVX2_SOURCES += painting/qdrawhelper_avx2.cpp !ios { diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 57bb111538..b75018452a 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -1245,44 +1245,6 @@ static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, i } #endif -#if defined(__SSE2__) -static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) -{ - // First interpolate right and left pixels in parallel. - __m128i vl = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tl), _mm_cvtsi32_si128(bl)); - __m128i vr = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tr), _mm_cvtsi32_si128(br)); - vl = _mm_unpacklo_epi8(vl, _mm_setzero_si128()); - vr = _mm_unpacklo_epi8(vr, _mm_setzero_si128()); - vl = _mm_mullo_epi16(vl, _mm_set1_epi16(256 - distx)); - vr = _mm_mullo_epi16(vr, _mm_set1_epi16(distx)); - __m128i vtb = _mm_add_epi16(vl, vr); - vtb = _mm_srli_epi16(vtb, 8); - // vtb now contains the result of the first two interpolate calls vtb = unpacked((xbot << 64) | xtop) - - // Now the last interpolate between top and bottom interpolations. - const __m128i vidisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(256 - disty), _MM_SHUFFLE(0, 0, 0, 0)); - const __m128i vdisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(disty), _MM_SHUFFLE(0, 0, 0, 0)); - const __m128i vmuly = _mm_unpacklo_epi16(vidisty, vdisty); - vtb = _mm_unpacklo_epi16(vtb, _mm_srli_si128(vtb, 8)); - // vtb now contains the colors of top and bottom interleaved { ta, ba, tr, br, tg, bg, tb, bb } - vtb = _mm_madd_epi16(vtb, vmuly); // Multiply and horizontal add. - vtb = _mm_srli_epi32(vtb, 8); - vtb = _mm_packs_epi32(vtb, _mm_setzero_si128()); - vtb = _mm_packus_epi16(vtb, _mm_setzero_si128()); - return _mm_cvtsi128_si32(vtb); -} -#else -static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) -{ - uint idistx = 256 - distx; - uint idisty = 256 - disty; - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - return INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); -} -#endif - - template void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2); diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 480ba4c97b..0d391b2cec 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -605,6 +605,42 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) { } #endif +#ifdef __SSE2__ +static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +{ + // First interpolate right and left pixels in parallel. + __m128i vl = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tl), _mm_cvtsi32_si128(bl)); + __m128i vr = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tr), _mm_cvtsi32_si128(br)); + vl = _mm_unpacklo_epi8(vl, _mm_setzero_si128()); + vr = _mm_unpacklo_epi8(vr, _mm_setzero_si128()); + vl = _mm_mullo_epi16(vl, _mm_set1_epi16(256 - distx)); + vr = _mm_mullo_epi16(vr, _mm_set1_epi16(distx)); + __m128i vtb = _mm_add_epi16(vl, vr); + vtb = _mm_srli_epi16(vtb, 8); + // vtb now contains the result of the first two interpolate calls vtb = unpacked((xbot << 64) | xtop) + + // Now the last interpolate between top and bottom interpolations. + const __m128i vidisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(256 - disty), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vdisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(disty), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vmuly = _mm_unpacklo_epi16(vidisty, vdisty); + vtb = _mm_unpacklo_epi16(vtb, _mm_srli_si128(vtb, 8)); + // vtb now contains the colors of top and bottom interleaved { ta, ba, tr, br, tg, bg, tb, bb } + vtb = _mm_madd_epi16(vtb, vmuly); // Multiply and horizontal add. + vtb = _mm_srli_epi32(vtb, 8); + vtb = _mm_packs_epi32(vtb, _mm_setzero_si128()); + vtb = _mm_packus_epi16(vtb, _mm_setzero_si128()); + return _mm_cvtsi128_si32(vtb); +} +#else +static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +{ + uint idistx = 256 - distx; + uint idisty = 256 - disty; + uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); + uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); + return INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); +} +#endif #if Q_BYTE_ORDER == Q_BIG_ENDIAN static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 58e9112dd6..5f1b25e189 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -38,10 +38,6 @@ QT_BEGIN_NAMESPACE -namespace QImageScale { - struct QImageScaleInfo; -} - typedef void (*qt_qimageScaleFunc)(QImageScale::QImageScaleInfo *isi, unsigned int *dest, int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow); @@ -105,15 +101,7 @@ qt_qimageScaleFunc qt_qimageScaleRgb = qt_qimageScaleAARGB; namespace QImageScale { - struct QImageScaleInfo { - int *xpoints; - const unsigned int **ypoints; - int *xapoints, *yapoints; - int xup_yup; - }; - - const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, - int dh); + const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh); int* qimageCalcXPoints(int sw, int dw); int* qimageCalcApoints(int s, int d, int up); QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi); @@ -134,16 +122,11 @@ using namespace QImageScale; #define G_VAL(p) (qGreen(*p)) #define B_VAL(p) (qBlue(*p)) -#define INV_XAP (256 - xapoints[x]) -#define XAP (xapoints[x]) -#define INV_YAP (256 - yapoints[dyy + y]) -#define YAP (yapoints[dyy + y]) - const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh) { const unsigned int **p; - int i, j = 0, rv = 0; + int j = 0, rv = 0; qint64 val, inc; if(dh < 0){ @@ -155,12 +138,12 @@ const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int up = qAbs(dh) >= sh; val = up ? 0x8000 * sh / dh - 0x8000 : 0; inc = (((qint64)sh) << 16) / dh; - for(i = 0; i < dh; i++){ + for (int i = 0; i < dh; i++) { p[j++] = src + qMax(0LL, val >> 16) * sw; val += inc; } - if(rv){ - for(i = dh / 2; --i >= 0; ){ + if (rv) { + for (int i = dh / 2; --i >= 0; ) { const unsigned int *tmp = p[i]; p[i] = p[dh - i - 1]; p[dh - i - 1] = tmp; @@ -171,7 +154,7 @@ const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int* QImageScale::qimageCalcXPoints(int sw, int dw) { - int *p, i, j = 0, rv = 0; + int *p, j = 0, rv = 0; qint64 val, inc; if(dw < 0){ @@ -183,13 +166,13 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) int up = qAbs(dw) >= sw; val = up ? 0x8000 * sw / dw - 0x8000 : 0; inc = (((qint64)sw) << 16) / dw; - for(i = 0; i < dw; i++){ + for (int i = 0; i < dw; i++) { p[j++] = qMax(0LL, val >> 16); val += inc; } - if(rv){ - for(i = dw / 2; --i >= 0; ){ + if (rv) { + for (int i = dw / 2; --i >= 0; ) { int tmp = p[i]; p[i] = p[dw - i - 1]; p[dw - i - 1] = tmp; @@ -200,7 +183,7 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) int* QImageScale::qimageCalcApoints(int s, int d, int up) { - int *p, i, j = 0, rv = 0; + int *p, j = 0, rv = 0; if(d < 0){ rv = 1; @@ -214,7 +197,7 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) val = 0x8000 * s / d - 0x8000; inc = (((qint64)s) << 16) / d; - for(i = 0; i < d; i++){ + for (int i = 0; i < d; i++) { int pos = val >> 16; if (pos < 0) p[j++] = 0; @@ -226,14 +209,12 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) } } /* scaling down */ - else{ - qint64 val, inc; - int ap, Cp; - val = 0; - inc = (((qint64)s) << 16) / d; - Cp = ((d << 14) / s) + 1; - for(i = 0; i < d; i++){ - ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8; + else { + qint64 val = 0; + qint64 inc = (((qint64)s) << 16) / d; + int Cp = (((d << 14) + s - 1) / s); + for (int i = 0; i < d; i++) { + int ap = ((0x10000 - (val & 0xffff)) * Cp) >> 16; p[j] = ap | (Cp << 16); j++; val += inc; @@ -241,13 +222,13 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) } if(rv){ int tmp; - for(i = d / 2; --i >= 0; ){ + for (int i = d / 2; --i >= 0; ) { tmp = p[i]; p[i] = p[d - i - 1]; p[d - i - 1] = tmp; } } - return(p); + return p; } QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi) @@ -297,700 +278,500 @@ QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, return(isi); } -/* FIXME: NEED to optimize ScaleAARGBA - currently its "ok" but needs work*/ -/* scale by area sampling */ -static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) +template +void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +template +void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +template +void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +#endif + +static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) { - const unsigned int *sptr; - unsigned int *dptr; - int x, y, end; const unsigned int **ypoints = isi->ypoints; int *xpoints = isi->xpoints; int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - end = dxx + dw; - /* scaling up both ways */ - if(isi->xup_yup == 3){ - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - /* calculate the source line we'll scan from */ - dptr = dest + dx + ((y + dy) * dow); - sptr = ypoints[dyy + y]; - if(YAP > 0){ - for(x = dxx; x < end; x++){ - int r, g, b, a; - int rr, gg, bb, aa; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - a = A_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - a += A_VAL(pix) * XAP; - pix += sow; - rr = R_VAL(pix) * XAP; - gg = G_VAL(pix) * XAP; - bb = B_VAL(pix) * XAP; - aa = A_VAL(pix) * XAP; - pix--; - rr += R_VAL(pix) * INV_XAP; - gg += G_VAL(pix) * INV_XAP; - bb += B_VAL(pix) * INV_XAP; - aa += A_VAL(pix) * INV_XAP; - r = ((rr * YAP) + (r * INV_YAP)) >> 16; - g = ((gg * YAP) + (g * INV_YAP)) >> 16; - b = ((bb * YAP) + (b * INV_YAP)) >> 16; - a = ((aa * YAP) + (a * INV_YAP)) >> 16; - *dptr++ = qRgba(r, g, b, a); - } - else{ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_YAP; - g = G_VAL(pix) * INV_YAP; - b = B_VAL(pix) * INV_YAP; - a = A_VAL(pix) * INV_YAP; - pix += sow; - r += R_VAL(pix) * YAP; - g += G_VAL(pix) * YAP; - b += B_VAL(pix) * YAP; - a += A_VAL(pix) * YAP; - r >>= 8; - g >>= 8; - b >>= 8; - a >>= 8; - *dptr++ = qRgba(r, g, b, a); - } - } + int end = dxx + dw; + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + /* calculate the source line we'll scan from */ + const unsigned int *sptr = ypoints[dyy + y]; + unsigned int *dptr = dest + dx + ((y + dy) * dow); + const int yap = yapoints[dyy + y]; + if (yap > 0) { + for (int x = dxx; x < end; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate_4_pixels(pix[0], pix[1], pix[sow], pix[sow + 1], xap, yap); + else + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap); + dptr++; } - else{ - for(x = dxx; x < end; x++){ - int r, g, b, a; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - a = A_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - a += A_VAL(pix) * XAP; - r >>= 8; - g >>= 8; - b >>= 8; - a >>= 8; - *dptr++ = qRgba(r, g, b, a); - } - else - *dptr++ = sptr[xpoints[x] ]; - } + } else { + for (int x = dxx; x < end; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); + dptr++; } } } +} + +/* scale by area sampling */ +static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + /* scaling up both ways */ + if (isi->xup_yup == 3){ + qt_qimageScaleAARGBA_up_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } /* if we're scaling down vertically */ - else if(isi->xup_yup == 1){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cy, j; - const unsigned int *pix; - int r, g, b, a, rr, gg, bb, aa; - int yap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * yap; - g = G_VAL(pix) * yap; - b = B_VAL(pix) * yap; - a = A_VAL(pix) * yap; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix += sow; - r += R_VAL(pix) * Cy; - g += G_VAL(pix) * Cy; - b += B_VAL(pix) * Cy; - a += A_VAL(pix) * Cy; - } - if(j > 0){ - pix += sow; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - a += A_VAL(pix) * j; - } - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + 1; - rr = R_VAL(pix) * yap; - gg = G_VAL(pix) * yap; - bb = B_VAL(pix) * yap; - aa = A_VAL(pix) * yap; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix += sow; - rr += R_VAL(pix) * Cy; - gg += G_VAL(pix) * Cy; - bb += B_VAL(pix) * Cy; - aa += A_VAL(pix) * Cy; - } - if(j > 0){ - pix += sow; - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - aa += A_VAL(pix) * j; - } - r = r * INV_XAP; - g = g * INV_XAP; - b = b * INV_XAP; - a = a * INV_XAP; - r = (r + ((rr * XAP))) >> 12; - g = (g + ((gg * XAP))) >> 12; - b = (b + ((bb * XAP))) >> 12; - a = (a + ((aa * XAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - a >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10); - dptr++; - } - } + else if (isi->xup_yup == 1) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_up_x_down_y_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_up_x_down_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } /* if we're scaling down horizontally */ - else if(isi->xup_yup == 2){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, j; - const unsigned int *pix; - int r, g, b, a, rr, gg, bb, aa; - int xap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * xap; - g = G_VAL(pix) * xap; - b = B_VAL(pix) * xap; - a = A_VAL(pix) * xap; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - pix++; - r += R_VAL(pix) * Cx; - g += G_VAL(pix) * Cx; - b += B_VAL(pix) * Cx; - a += A_VAL(pix) * Cx; - } - if(j > 0){ - pix++; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - a += A_VAL(pix) * j; - } - if(YAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + sow; - rr = R_VAL(pix) * xap; - gg = G_VAL(pix) * xap; - bb = B_VAL(pix) * xap; - aa = A_VAL(pix) * xap; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - pix++; - rr += R_VAL(pix) * Cx; - gg += G_VAL(pix) * Cx; - bb += B_VAL(pix) * Cx; - aa += A_VAL(pix) * Cx; - } - if(j > 0){ - pix++; - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - aa += A_VAL(pix) * j; - } - r = r * INV_YAP; - g = g * INV_YAP; - b = b * INV_YAP; - a = a * INV_YAP; - r = (r + ((rr * YAP))) >> 12; - g = (g + ((gg * YAP))) >> 12; - b = (b + ((bb * YAP))) >> 12; - a = (a + ((aa * YAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - a >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10); - dptr++; - } - } + else if (isi->xup_yup == 2) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_x_up_y_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_down_x_up_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } /* if we're scaling down horizontally & vertically */ - else{ - /*\ 'Correct' version, with math units prepared for MMXification: - |*| The operation 'b = (b * c) >> 16' translates to pmulhw, - |*| so the operation 'b = (b * c) >> d' would translate to - |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb - \*/ - int Cx, Cy, i, j; - const unsigned int *pix; - int a, r, g, b, ax, rx, gx, bx; - int xap, yap; - - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - sptr = ypoints[dyy + y] + xpoints[x]; - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r = (rx >> 5) * yap; - g = (gx >> 5) * yap; - b = (bx >> 5) * yap; - a = (ax >> 5) * yap; - - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r += (rx >> 5) * Cy; - g += (gx >> 5) * Cy; - b += (bx >> 5) * Cy; - a += (ax >> 5) * Cy; - } - if(j > 0){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r += (rx >> 5) * j; - g += (gx >> 5) * j; - b += (bx >> 5) * j; - a += (ax >> 5) * j; - } - - *dptr = qRgba(r >> 23, g >> 23, b >> 23, a >> 23); - dptr++; + else { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_xy_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_down_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } +} + +inline static void qt_qimageScaleAARGBA_helper_x(const unsigned int *pix, int xap, int Cx, int &r, int &g, int &b, int &a) +{ + r = R_VAL(pix) * xap; + g = G_VAL(pix) * xap; + b = B_VAL(pix) * xap; + a = A_VAL(pix) * xap; + int j; + for (j = (1 << 14) - xap; j > Cx; j -= Cx ){ + pix++; + r += R_VAL(pix) * Cx; + g += G_VAL(pix) * Cx; + b += B_VAL(pix) * Cx; + a += A_VAL(pix) * Cx; + } + pix++; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; + a += A_VAL(pix) * j; +} + +inline static void qt_qimageScaleAARGBA_helper_y(const unsigned int *pix, int yap, int Cy, int sow, int &r, int &g, int &b, int &a) +{ + r = R_VAL(pix) * yap; + g = G_VAL(pix) * yap; + b = B_VAL(pix) * yap; + a = A_VAL(pix) * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy ){ + pix += sow; + r += R_VAL(pix) * Cy; + g += G_VAL(pix) * Cy; + b += B_VAL(pix) * Cy; + a += A_VAL(pix) * Cy; + } + pix += sow; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; + a += A_VAL(pix) * j; +} + +static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper_y(sptr, yap, Cy, sow, r, g, b, a); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper_y(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + a = a * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + a = (a + (aa * xap)) >> 8; } + *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); } } } -/* scale by area sampling - IGNORE the ALPHA byte*/ -static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) { - const unsigned int *sptr; - unsigned int *dptr; - int x, y, end; const unsigned int **ypoints = isi->ypoints; int *xpoints = isi->xpoints; int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - end = dxx + dw; - /* scaling up both ways */ - if(isi->xup_yup == 3){ - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - /* calculate the source line we'll scan from */ - dptr = dest + dx + ((y + dy) * dow); - sptr = ypoints[dyy + y]; - if(YAP > 0){ - for(x = dxx; x < end; x++){ - int r = 0, g = 0, b = 0; - int rr = 0, gg = 0, bb = 0; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - pix += sow; - rr = R_VAL(pix) * XAP; - gg = G_VAL(pix) * XAP; - bb = B_VAL(pix) * XAP; - pix --; - rr += R_VAL(pix) * INV_XAP; - gg += G_VAL(pix) * INV_XAP; - bb += B_VAL(pix) * INV_XAP; - r = ((rr * YAP) + (r * INV_YAP)) >> 16; - g = ((gg * YAP) + (g * INV_YAP)) >> 16; - b = ((bb * YAP) + (b * INV_YAP)) >> 16; - *dptr++ = qRgba(r, g, b, 0xff); - } - else{ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_YAP; - g = G_VAL(pix) * INV_YAP; - b = B_VAL(pix) * INV_YAP; - pix += sow; - r += R_VAL(pix) * YAP; - g += G_VAL(pix) * YAP; - b += B_VAL(pix) * YAP; - r >>= 8; - g >>= 8; - b >>= 8; - *dptr++ = qRgba(r, g, b, 0xff); - } - } - } - else{ - for(x = dxx; x < end; x++){ - int r = 0, g = 0, b = 0; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - r >>= 8; - g >>= 8; - b >>= 8; - *dptr++ = qRgba(r, g, b, 0xff); - } - else - *dptr++ = sptr[xpoints[x] ]; - } + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, r, g, b, a); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper_x(sptr + sow, xap, Cx, rr, gg, bb, aa); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + a = a * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + a = (a + (aa * yap)) >> 8; } + *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); + dptr++; } } - /* if we're scaling down vertically */ - else if(isi->xup_yup == 1){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cy, j; - const unsigned int *pix; - int r, g, b, rr, gg, bb; - int yap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * yap; - g = G_VAL(pix) * yap; - b = B_VAL(pix) * yap; - pix += sow; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - r += R_VAL(pix) * Cy; - g += G_VAL(pix) * Cy; - b += B_VAL(pix) * Cy; - pix += sow; - } - if(j > 0){ - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - } - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + 1; - rr = R_VAL(pix) * yap; - gg = G_VAL(pix) * yap; - bb = B_VAL(pix) * yap; - pix += sow; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - rr += R_VAL(pix) * Cy; - gg += G_VAL(pix) * Cy; - bb += B_VAL(pix) * Cy; - pix += sow; - } - if(j > 0){ - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - } - r = r * INV_XAP; - g = g * INV_XAP; - b = b * INV_XAP; - r = (r + ((rr * XAP))) >> 12; - g = (g + ((gg * XAP))) >> 12; - b = (b + ((bb * XAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff); - dptr++; +} + +static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int rx, gx, bx, ax; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + + int r = ((rx>>4) * yap); + int g = ((gx>>4) * yap); + int b = ((bx>>4) * yap); + int a = ((ax>>4) * yap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + r += ((rx>>4) * Cy); + g += ((gx>>4) * Cy); + b += ((bx>>4) * Cy); + a += ((ax>>4) * Cy); } + sptr += sow; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + + r += ((rx>>4) * j); + g += ((gx>>4) * j); + b += ((bx>>4) * j); + a += ((ax>>4) * j); + + *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24); + dptr++; } } +} + +static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +/* scale by area sampling - IGNORE the ALPHA byte*/ +static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + /* scaling up both ways */ + if (isi->xup_yup == 3) { + qt_qimageScaleAARGBA_up_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } + /* if we're scaling down vertically */ + else if (isi->xup_yup == 1) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_up_x_down_y_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_up_x_down_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } /* if we're scaling down horizontally */ - else if(isi->xup_yup == 2){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, j; - const unsigned int *pix; - int r, g, b, rr, gg, bb; - int xap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * xap; - g = G_VAL(pix) * xap; - b = B_VAL(pix) * xap; - pix++; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - r += R_VAL(pix) * Cx; - g += G_VAL(pix) * Cx; - b += B_VAL(pix) * Cx; - pix++; - } - if(j > 0){ - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - } - if(YAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + sow; - rr = R_VAL(pix) * xap; - gg = G_VAL(pix) * xap; - bb = B_VAL(pix) * xap; - pix++; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - rr += R_VAL(pix) * Cx; - gg += G_VAL(pix) * Cx; - bb += B_VAL(pix) * Cx; - pix++; - } - if(j > 0){ - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - } - r = r * INV_YAP; - g = g * INV_YAP; - b = b * INV_YAP; - r = (r + ((rr * YAP))) >> 12; - g = (g + ((gg * YAP))) >> 12; - b = (b + ((bb * YAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff); - dptr++; - } - } + else if (isi->xup_yup == 2) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_x_up_y_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_down_x_up_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } - /* fully optimized (i think) - onyl change of algorithm can help */ /* if we're scaling down horizontally & vertically */ - else{ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, Cy, i, j; - const unsigned int *pix; - int r, g, b, rx, gx, bx; - int xap, yap; - - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - sptr = ypoints[dyy + y] + xpoints[x]; - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r = (rx >> 5) * yap; - g = (gx >> 5) * yap; - b = (bx >> 5) * yap; - - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r += (rx >> 5) * Cy; - g += (gx >> 5) * Cy; - b += (bx >> 5) * Cy; - } - if(j > 0){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r += (rx >> 5) * j; - g += (gx >> 5) * j; - b += (bx >> 5) * j; - } - - *dptr = qRgb(r >> 23, g >> 23, b >> 23); - dptr++; + else { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_xy_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_down_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } +} + + +inline static void qt_qimageScaleAARGB_helper_x(const unsigned int *pix, int xap, int Cx, int &r, int &g, int &b) +{ + r = R_VAL(pix) * xap; + g = G_VAL(pix) * xap; + b = B_VAL(pix) * xap; + int j; + for (j = (1 << 14) - xap; j > Cx; j -= Cx ){ + pix++; + r += R_VAL(pix) * Cx; + g += G_VAL(pix) * Cx; + b += B_VAL(pix) * Cx; + } + pix++; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; +} + +inline static void qt_qimageScaleAARGB_helper_y(const unsigned int *pix, int yap, int Cy, int sow, int &r, int &g, int &b) +{ + r = R_VAL(pix) * yap; + g = G_VAL(pix) * yap; + b = B_VAL(pix) * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy ){ + pix += sow; + r += R_VAL(pix) * Cy; + g += G_VAL(pix) * Cy; + b += B_VAL(pix) * Cy; + } + pix += sow; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; +} + +static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper_y(sptr, yap, Cy, sow, r, g, b); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper_y(sptr + 1, yap, Cy, sow, rr, gg, bb); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } } } -#if 0 -static void qt_qimageScaleAARGBASetup(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) { - qInitDrawhelperAsm(); - qt_qimageScaleAARGBA(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, r, g, b); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper_x(sptr + sow, xap, Cx, rr, gg, bb); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); + } + } } -static void qt_qimageScaleAARGBSetup(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) { - qInitDrawhelperAsm(); - qt_qimageScaleAARGB(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int rx, gx, bx; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + int r = (rx >> 4) * yap; + int g = (gx >> 4) * yap; + int b = (bx >> 4) * yap; + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + r += (rx >> 4) * Cy; + g += (gx >> 4) * Cy; + b += (bx >> 4) * Cy; + } + sptr += sow; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + r += (rx >> 4) * j; + g += (gx >> 4) * j; + b += (bx >> 4) * j; + + *dptr = qRgb(r >> 24, g >> 24, b >> 24); + dptr++; + } + } } -#endif QImage qSmoothScaleImage(const QImage &src, int dw, int dh) { @@ -1012,7 +793,7 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh) return QImage(); } - if (src.format() == QImage::Format_ARGB32_Premultiplied || src.format() == QImage::Format_RGBA8888_Premultiplied) + if (src.hasAlphaChannel()) qt_qimageScaleArgb(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4); else diff --git a/src/gui/painting/qimagescale_p.h b/src/gui/painting/qimagescale_p.h index 512ec6488e..c35aea451a 100644 --- a/src/gui/painting/qimagescale_p.h +++ b/src/gui/painting/qimagescale_p.h @@ -53,6 +53,15 @@ QT_BEGIN_NAMESPACE */ QImage qSmoothScaleImage(const QImage &img, int w, int h); +namespace QImageScale { + struct QImageScaleInfo { + int *xpoints; + const unsigned int **ypoints; + int *xapoints, *yapoints; + int xup_yup; + }; +} + QT_END_NAMESPACE #endif diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp new file mode 100644 index 0000000000..565ea4daa1 --- /dev/null +++ b/src/gui/painting/qimagescale_sse4.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qimagescale_p.h" +#include "qimage.h" +#include + +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) + +QT_BEGIN_NAMESPACE + +using namespace QImageScale; + +inline static __m128i qt_qimageScaleAARGBA_helper_x(const unsigned int *pix, int xap, int Cx, const __m128i vxap, const __m128i vCx) +{ + __m128i vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + __m128i vx = _mm_mullo_epi32(vpix, vxap); + int i; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) { + pix++; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCx)); + } + pix++; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, _mm_set1_epi32(i))); + return vx; +} + +inline static __m128i qt_qimageScaleAARGBA_helper_y(const unsigned int *pix, int yap, int Cy, int sow, const __m128i vyap, const __m128i vCy) +{ + __m128i vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + __m128i vx = _mm_mullo_epi32(vpix, vyap); + int i; + for (i = (1 << 14) - yap; i > Cy; i -= Cy) { + pix += sow; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCy)); + } + pix += sow; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, _mm_set1_epi32(i))); + return vx; +} + +template +void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + const __m128i v256 = _mm_set1_epi32(256); + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + const __m128i vCy = _mm_set1_epi32(Cy); + const __m128i vyap = _mm_set1_epi32(yap); + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_y(sptr, yap, Cy, sow, vyap, vCy); + + int xap = xapoints[x]; + if (xap > 0) { + const __m128i vxap = _mm_set1_epi32(xap); + const __m128i vinvxap = _mm_sub_epi32(v256, vxap); + __m128i vr = qt_qimageScaleAARGBA_helper_y(sptr + 1, yap, Cy, sow, vyap, vCy); + + vx = _mm_mullo_epi32(vx, vinvxap); + vr = _mm_mullo_epi32(vr, vxap); + vx = _mm_add_epi32(vx, vr); + vx = _mm_srli_epi32(vx, 8); + } + vx = _mm_srli_epi32(vx, 14); + vx = _mm_packus_epi32(vx, _mm_setzero_si128()); + vx = _mm_packus_epi16(vx, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vx); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template +void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + const __m128i v256 = _mm_set1_epi32(256); + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + const __m128i vCx = _mm_set1_epi32(Cx); + const __m128i vxap = _mm_set1_epi32(xap); + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + const __m128i vyap = _mm_set1_epi32(yap); + const __m128i vinvyap = _mm_sub_epi32(v256, vyap); + __m128i vr = qt_qimageScaleAARGBA_helper_x(sptr + sow, xap, Cx, vxap, vCx); + + vx = _mm_mullo_epi32(vx, vinvyap); + vr = _mm_mullo_epi32(vr, vyap); + vx = _mm_add_epi32(vx, vr); + vx = _mm_srli_epi32(vx, 8); + } + vx = _mm_srli_epi32(vx, 14); + vx = _mm_packus_epi32(vx, _mm_setzero_si128()); + vx = _mm_packus_epi16(vx, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vx); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template +void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + const __m128i vCy = _mm_set1_epi32(Cy); + const __m128i vyap = _mm_set1_epi32(yap); + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + int end = dxx + dw; + for (int x = dxx; x < end; x++) { + const int Cx = xapoints[x] >> 16; + const int xap = xapoints[x] & 0xffff; + const __m128i vCx = _mm_set1_epi32(Cx); + const __m128i vxap = _mm_set1_epi32(xap); + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy)); + } + sptr += sow; + vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j))); + + vr = _mm_srli_epi32(vr, 24); + vr = _mm_packus_epi32(vr, _mm_setzero_si128()); + vr = _mm_packus_epi16(vr, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vr); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +QT_END_NAMESPACE + +#endif -- cgit v1.2.3 From d605883b5e8e8cb272fab760cd4896d006ce0719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Fri, 10 Apr 2015 12:57:02 +0200 Subject: Make it possible to use the -visual argument for xcb applications to use a specific visual id when creating windows. Also make it possible to retrieve the visual id of a specific window with QXcbWindowFunctions::visualId(QWindow *window). UINT_MAX is used as an invalid visualId. Change-Id: If62ada119ce8f9174cc211f53bbf1ce1bb7d021a Reviewed-by: Andy Shaw --- .../xcbfunctions/qxcbwindowfunctions.h | 11 +++ src/plugins/platforms/xcb/qxcbconnection.cpp | 19 ++++- src/plugins/platforms/xcb/qxcbconnection.h | 9 ++- src/plugins/platforms/xcb/qxcbintegration.cpp | 11 ++- src/plugins/platforms/xcb/qxcbintegration.h | 3 + src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 3 + src/plugins/platforms/xcb/qxcbwindow.cpp | 82 ++++++++++++++++------ src/plugins/platforms/xcb/qxcbwindow.h | 3 + 8 files changed, 116 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/platformheaders/xcbfunctions/qxcbwindowfunctions.h b/src/platformheaders/xcbfunctions/qxcbwindowfunctions.h index f9008039a1..ae05cf52a9 100644 --- a/src/platformheaders/xcbfunctions/qxcbwindowfunctions.h +++ b/src/platformheaders/xcbfunctions/qxcbwindowfunctions.h @@ -72,6 +72,17 @@ public: if (func) func(window, type); } + + typedef uint (*VisualId)(QWindow *window); + static const QByteArray visualIdIdentifier() { return QByteArrayLiteral("XcbVisualId"); } + + static uint visualId(QWindow *window) + { + QXcbWindowFunctions::VisualId func = reinterpret_cast(QGuiApplication::platformFunction(visualIdIdentifier())); + if (func) + return func(window); + return UINT_MAX; + } }; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 3d65b789a4..94f4c2a2d3 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #endif #if defined(XCB_USE_XINPUT2) @@ -437,9 +438,10 @@ void QXcbConnection::initializeScreens() qCDebug(lcQpaScreen) << "primary output is" << m_screens.first()->name(); } -QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName) +QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName) : m_connection(0) , m_canGrabServer(canGrabServer) + , m_defaultVisualId(defaultVisualId) , m_primaryScreenNumber(0) , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) , m_nativeInterface(nativeInterface) @@ -1351,6 +1353,21 @@ void *QXcbConnection::xlib_display() const { return m_xlib_display; } + +void *QXcbConnection::createVisualInfoForDefaultVisualId() const +{ + if (m_defaultVisualId == UINT_MAX) + return 0; + XVisualInfo info; + memset(&info, 0, sizeof info); + info.visualid = m_defaultVisualId; + + int count = 0; + XVisualInfo *retVisual = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &info, &count); + Q_ASSERT(count < 2); + return retVisual; +} + #endif void QXcbConnection::processXcbEvents() diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 91547dd697..e4274eca4d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -370,7 +370,7 @@ class Q_XCB_EXPORT QXcbConnection : public QObject { Q_OBJECT public: - QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName = 0); + QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName = 0); ~QXcbConnection(); QXcbConnection *connection() const { return const_cast(this); } @@ -400,8 +400,13 @@ public: QXcbWMSupport *wmSupport() const { return m_wmSupport.data(); } xcb_window_t rootWindow(); + + bool hasDefaultVisualId() const { return m_defaultVisualId != UINT_MAX; } + xcb_visualid_t defaultVisualId() const { return m_defaultVisualId; } + #ifdef XCB_USE_XLIB void *xlib_display() const; + void *createVisualInfoForDefaultVisualId() const; #endif #if defined(XCB_USE_XINPUT2) @@ -564,6 +569,7 @@ private: xcb_connection_t *m_connection; const xcb_setup_t *m_setup; bool m_canGrabServer; + xcb_visualid_t m_defaultVisualId; QList m_virtualDesktops; QList m_screens; @@ -632,6 +638,7 @@ private: }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) +#define CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(object) ((XVisualInfo *)(object->connection()->createVisualInfoForDefaultVisualId())) template xcb_generic_event_t *QXcbConnection::checkEvent(T &checker) diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 2547e537a7..fc06f1a7b0 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -116,6 +116,7 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char : m_services(new QGenericUnixServices) , m_instanceName(0) , m_canGrab(true) + , m_defaultVisualId(UINT_MAX) { m_instance = this; @@ -143,6 +144,12 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char noGrabArg = true; else if (arg == "-dograb") doGrabArg = true; + else if (arg == "-visual" && i < argc - 1) { + bool ok = false; + m_defaultVisualId = QByteArray(argv[++i]).toUInt(&ok, 0); + if (!ok) + m_defaultVisualId = UINT_MAX; + } else argv[j++] = argv[i]; } @@ -167,12 +174,12 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char if (canNotGrabEnv) m_canGrab = false; - m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, displayName); + m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, displayName); for (int i = 0; i < parameters.size() - 1; i += 2) { qCDebug(lcQpaScreen) << "connecting to additional display: " << parameters.at(i) << parameters.at(i+1); QString display = parameters.at(i) + QLatin1Char(':') + parameters.at(i+1); - m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, display.toLatin1().constData()); + m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, m_defaultVisualId, display.toLatin1().constData()); } m_fontDatabase.reset(new QGenericUnixFontDatabase()); diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 4212d53810..4e2a3c2bbd 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -39,6 +39,8 @@ #include "qxcbexport.h" +#include + QT_BEGIN_NAMESPACE class QXcbConnection; @@ -123,6 +125,7 @@ private: mutable QByteArray m_wmClass; const char *m_instanceName; bool m_canGrab; + xcb_visualid_t m_defaultVisualId; static QXcbIntegration *m_instance; }; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index bfba7f2b6a..8bf9003af7 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -392,6 +392,9 @@ QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &functio if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier()) { return QFunctionPointer(QXcbWindow::setWmWindowTypeStatic); } + if (function == QXcbWindowFunctions::visualIdIdentifier()) { + return QFunctionPointer(QXcbWindowFunctions::VisualId(QXcbWindow::visualIdStatic)); + } return Q_NULLPTR; } diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index b5d0741fa6..77c431edb2 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -388,7 +388,16 @@ void QXcbWindow::create() m_window = platformScreen->root(); m_depth = platformScreen->screen()->root_depth; m_visualId = platformScreen->screen()->root_visual; - const xcb_visualtype_t *visual = platformScreen->visualForId(m_visualId); + const xcb_visualtype_t *visual = 0; + if (connection()->hasDefaultVisualId()) { + visual = platformScreen->visualForId(connection()->defaultVisualId()); + if (visual) + m_visualId = connection()->defaultVisualId(); + if (!visual) + qWarning() << "Could not use default visual id. Falling back to root_visual for screen."; + } + if (!visual) + visual = platformScreen->visualForId(m_visualId); m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap); connection()->addWindowEventListener(m_window, this); return; @@ -442,7 +451,12 @@ void QXcbWindow::create() #ifdef XCB_USE_XLIB if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { - XVisualInfo *visualInfo = static_cast(createVisual()); + XVisualInfo *visualInfo = Q_NULLPTR; + if (connection()->hasDefaultVisualId()) + visualInfo = CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(this); + if (!visualInfo) + visualInfo = static_cast(createVisual()); + if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface) qFatal("Could not initialize OpenGL"); @@ -477,35 +491,49 @@ void QXcbWindow::create() if (!m_window) { m_window = xcb_generate_id(xcb_connection()); - m_visualId = platformScreen->screen()->root_visual; + m_visualId = UINT_MAX; + const xcb_visualtype_t *visual = Q_NULLPTR; m_depth = platformScreen->screen()->root_depth; uint32_t mask = 0; uint32_t values[3]; - if (m_format.alphaBufferSize() == 8) { - xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(platformScreen->screen()); - while (depthIter.rem) { - if (depthIter.data->depth == 32) { - xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data); - if (visualIter.rem) { - m_visualId = visualIter.data->visual_id; - m_depth = 32; - uint32_t colormap = xcb_generate_id(xcb_connection()); - xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap, - xcb_parent_id, m_visualId); - mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP; - values[0] = platformScreen->screen()->white_pixel; - values[1] = platformScreen->screen()->black_pixel; - values[2] = colormap; - break; + if (connection()->hasDefaultVisualId()) { + m_visualId = connection()->defaultVisualId(); + visual = platformScreen->visualForId(m_visualId); + } + + if (!visual) { + if (connection()->hasDefaultVisualId()) + qWarning("Failed to use default visual id. Falling back to using screens root_visual"); + + m_visualId = platformScreen->screen()->root_visual; + + if (m_format.alphaBufferSize() == 8) { + xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(platformScreen->screen()); + while (depthIter.rem) { + if (depthIter.data->depth == 32) { + xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data); + if (visualIter.rem) { + m_visualId = visualIter.data->visual_id; + m_depth = 32; + uint32_t colormap = xcb_generate_id(xcb_connection()); + xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap, + xcb_parent_id, m_visualId); + mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP; + values[0] = platformScreen->screen()->white_pixel; + values[1] = platformScreen->screen()->black_pixel; + values[2] = colormap; + break; + } } + xcb_depth_next(&depthIter); } - xcb_depth_next(&depthIter); } + + visual = platformScreen->visualForId(m_visualId); } - const xcb_visualtype_t *visual = platformScreen->visualForId(m_visualId); m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap); const QRect xRect = mapToNative(rect, platformScreen); @@ -1680,6 +1708,13 @@ void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmW window->setProperty(wm_window_type_property_id, QVariant::fromValue(static_cast(windowTypes))); } +uint QXcbWindow::visualIdStatic(QWindow *window) +{ + if (window && window->handle()) + return static_cast(window->handle())->visualId(); + return UINT_MAX; +} + QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const { QXcbWindowFunctions::WmWindowTypes result(0); @@ -2531,6 +2566,11 @@ void QXcbWindow::setAlertState(bool enabled) changeNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); } +uint QXcbWindow::visualId() const +{ + return m_visualId; +} + bool QXcbWindow::needsSync() const { return m_syncState == SyncAndConfigureReceived; diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index fbf3cfe172..512bc54255 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -139,10 +139,13 @@ public: void updateNetWmUserTime(xcb_timestamp_t timestamp); static void setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes); + static uint visualIdStatic(QWindow *window); QXcbWindowFunctions::WmWindowTypes wmWindowTypes() const; void setWmWindowType(QXcbWindowFunctions::WmWindowTypes types); + uint visualId() const; + bool needsSync() const; void postSyncWindowRequest(); -- cgit v1.2.3 From 336648aa1b2f5249749068989959238039f44033 Mon Sep 17 00:00:00 2001 From: Marko Kangas Date: Tue, 14 Apr 2015 09:42:56 +0300 Subject: Fix windows printing "invalid metric command" warning. Added missing PdmDevicePixelRatio return value to printEngine::metric. Change-Id: I40198208ff7c95aa30b0492c410b450a1ae16a30 Reviewed-by: Andy Shaw --- src/printsupport/kernel/qprintengine_win.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index 731e923b2b..b377401ed9 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -384,6 +384,9 @@ int QWin32PrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const case QPaintDevice::PdmDepth: val = GetDeviceCaps(d->hdc, PLANES); break; + case QPaintDevice::PdmDevicePixelRatio: + val = 1; + break; default: qWarning("QPrinter::metric: Invalid metric command"); return 0; -- cgit v1.2.3 From c09ff1dbcb50d77b64e47b333fd1ee2f4c6510e7 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Wed, 15 Apr 2015 12:54:59 +0200 Subject: qdoc: Don't end sentences with a full stop in requisite tables This is a minor visual change that stops QDoc from ending the sentences with a full stop in the tables for class/QML type requisites (Inherits, Inherited by, etc). This ensures a uniform look for the table, as some of the fields were already omitting the full stop. Change-Id: I37b39ed0a5e273b40b24f24602042194d069ed00 Reviewed-by: Martin Smith --- src/tools/qdoc/generator.cpp | 4 ++-- src/tools/qdoc/htmlgenerator.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp index af6cdf7bd1..55050806ec 100644 --- a/src/tools/qdoc/generator.cpp +++ b/src/tools/qdoc/generator.cpp @@ -213,7 +213,7 @@ void Generator::appendSortedNames(Text& text, const ClassNode* cn, const QListbaseClasses().count()); + text << comma(index++, classe->baseClasses().count()); } ++r; } -- cgit v1.2.3 From 4f8171998378f3e0f345b2b417afbfc9ad9738f0 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 14 Apr 2015 12:02:47 +0200 Subject: Pass on the auto repeat information for key events Task-number: QTBUG-45340 Change-Id: Iecc55987fa784e4bf14317d9d4a085a8f0b58451 Reviewed-by: Christian Stromme --- .../src/org/qtproject/qt5/android/QtActivityDelegate.java | 9 ++++----- src/android/jar/src/org/qtproject/qt5/android/QtNative.java | 4 ++-- src/plugins/platforms/android/androidjniinput.cpp | 12 ++++++------ 3 files changed, 12 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index c7355c1530..73140839cc 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -983,7 +983,7 @@ public class QtActivityDelegate if (!m_backKeyPressedSent) return true; } - QtNative.keyDown(keyCode, c, event.getMetaState()); + QtNative.keyDown(keyCode, c, event.getMetaState(), event.getRepeatCount() > 0); return true; } @@ -1007,7 +1007,7 @@ public class QtActivityDelegate } m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode, event); - QtNative.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState()); + QtNative.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState(), event.getRepeatCount() > 0); return true; } @@ -1018,8 +1018,8 @@ public class QtActivityDelegate && event.getCharacters() != null && event.getCharacters().length() == 1 && event.getKeyCode() == 0) { - QtNative.keyDown(0, event.getCharacters().charAt(0), event.getMetaState()); - QtNative.keyUp(0, event.getCharacters().charAt(0), event.getMetaState()); + QtNative.keyDown(0, event.getCharacters().charAt(0), event.getMetaState(), event.getRepeatCount() > 0); + QtNative.keyUp(0, event.getCharacters().charAt(0), event.getMetaState(), event.getRepeatCount() > 0); } try { @@ -1195,7 +1195,6 @@ public class QtActivityDelegate } else { m_activity.getWindow().setBackgroundDrawable(m_activity.getResources().getDrawable(attr.resourceId)); } - if (m_dummyView != null) { m_layout.removeView(m_dummyView); m_dummyView = null; diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index bed9d69782..b2480618f8 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -593,8 +593,8 @@ public class QtNative // pointer methods // keyboard methods - public static native void keyDown(int key, int unicode, int modifier); - public static native void keyUp(int key, int unicode, int modifier); + public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat); + public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat); public static native void keyboardVisibilityChanged(boolean visibility); // keyboard methods diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 14b0c96cb5..8ee3ff88d1 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -663,24 +663,24 @@ namespace QtAndroidInput return unicode ? QString(QChar(unicode)) : QString(); } - static void keyDown(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier) + static void keyDown(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier, jboolean autoRepeat) { QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, mapAndroidKey(key), mapAndroidModifiers(modifier), toString(unicode), - false); + autoRepeat); } - static void keyUp(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier) + static void keyUp(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier, jboolean autoRepeat) { QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, mapAndroidKey(key), mapAndroidModifiers(modifier), toString(unicode), - false); + autoRepeat); } static void keyboardVisibilityChanged(JNIEnv */*env*/, jobject /*thiz*/, jboolean visibility) @@ -702,8 +702,8 @@ namespace QtAndroidInput {"mouseUp", "(III)V", (void *)mouseUp}, {"mouseMove", "(III)V", (void *)mouseMove}, {"longPress", "(III)V", (void *)longPress}, - {"keyDown", "(III)V", (void *)keyDown}, - {"keyUp", "(III)V", (void *)keyUp}, + {"keyDown", "(IIIZ)V", (void *)keyDown}, + {"keyUp", "(IIIZ)V", (void *)keyUp}, {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged} }; -- cgit v1.2.3 From 090002618ff4889f1953642ab9d73bceaa1c962a Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 15 Apr 2015 14:51:04 +0200 Subject: Fix compilation of xcb-qt without system xcb headers Make sure the plugins are actually using the 3rdparty headers we ship, not the system ones. Change-Id: I5c857abee8e62c207843f9d29c369620be0d7da8 Reviewed-by: Laszlo Agocs --- .../platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri b/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri index 8c60268e0d..e859865687 100644 --- a/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri +++ b/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri @@ -29,8 +29,8 @@ CONFIG += qpa/genericunixfontdatabase contains(QT_CONFIG, xcb-qt) { DEFINES += XCB_USE_RENDER - XCB_DIR = ../../../3rdparty/xcb - INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude + XCB_DIR = $$clean_path($$PWD/../../../../3rdparty/xcb) + INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/include/xcb $$XCB_DIR/sysinclude LIBS += -lxcb -L$$OUT_PWD/xcb-static -lxcb-static } else { LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape -lxcb-keysyms -- cgit v1.2.3 From d4bc56cb4218f6f8378f04c23865156b349b037d Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Wed, 15 Apr 2015 14:00:10 +0200 Subject: Fix screen detection on configureNotify If we got two rapid screen changes in a row, we would disregard the second change. This happens because QPlatformScreen::screen() is updated asynchronously, so if we got a screen change A --> B immediately followed by B --> A, before the first screen change event had been processed, we would compare with the old value and conclude nothing had changed. This can happen on creation: if the initial geometry of the window is outside all physical screens, the window manager will immediately move it. The solution is to compare the new screen to the locally cached value. Change-Id: I5440dc035cac4fba4f29ac563e36dfe3e2f82aea Task-number: QTBUG-45076 Reviewed-by: Shawn Rutledge Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 77c431edb2..3188a7f19d 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2005,6 +2005,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * const QRect nativeRect = QRect(pos, QSize(event->width, event->height)); QXcbScreen *newScreen = parent() ? parentScreen() : screenForNativeGeometry(nativeRect); + QXcbScreen *currentScreen = m_xcbScreen; m_xcbScreen = newScreen; if (!newScreen) return; @@ -2012,7 +2013,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); - if (newScreen != screen()) + if (newScreen != currentScreen) QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); m_configureNotifyPending = false; -- cgit v1.2.3 From 528279febe74a5e995589d9c5eeb6c533cc2fe7c Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 13 Apr 2015 11:48:00 +0200 Subject: Optimize non-native bilinear transforms Reading directly from an array instead of calling a function pointer is much faster. Change-Id: I833b33448bad064d6f38d2f9ff44138d90206822 Reviewed-by: Gunnar Sletta --- src/gui/painting/qdrawhelper.cpp | 45 +++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index b75018452a..37f2de98b6 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -1931,10 +1931,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper int x2; fetchTransformedBilinear_pixelBounds(image_width, image_x1, image_x2, x1, x2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; } @@ -1989,10 +1996,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper const uchar *s1 = data->texture.scanLine(y1); const uchar *s2 = data->texture.scanLine(y2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; fy += fdy; @@ -2074,10 +2088,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper const uchar *s1 = data->texture.scanLine(y1); const uchar *s2 = data->texture.scanLine(y2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; fy += fdy; -- cgit v1.2.3 From aea74dcaee2d6930e4d69cbda83088703b45816e Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Tue, 14 Apr 2015 11:27:59 +0200 Subject: qdoc: Properly document "private" signals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a signal declaration is marked with QSignalPrivate, This note is included in its documentation: "Note: This is a private signal. It must not be emitted by the user." For Notifier signals, [see note] is appended to the signature line, and the Note is printed below the list. Change-Id: Ie792894ace56cda47fd9a45af9c732f408ac45f6 Task-number: QTBUG-45535 Reviewed-by: Topi Reiniö --- src/tools/qdoc/cppcodeparser.cpp | 5 +++++ src/tools/qdoc/generator.cpp | 17 +++++++++++++++++ src/tools/qdoc/generator.h | 1 + src/tools/qdoc/htmlgenerator.cpp | 17 +++++++++++++++++ src/tools/qdoc/node.cpp | 2 ++ src/tools/qdoc/node.h | 3 +++ src/tools/qdoc/tokenizer.cpp | 3 ++- src/tools/qdoc/tokenizer.h | 4 ++-- 8 files changed, 49 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp index 4fbe20b09e..f12fb70227 100644 --- a/src/tools/qdoc/cppcodeparser.cpp +++ b/src/tools/qdoc/cppcodeparser.cpp @@ -1329,6 +1329,11 @@ bool CppCodeParser::matchParameter(FunctionNode *func) QString name; CodeChunk defaultValue; + if (match(Tok_QPrivateSignal)) { + func->setPrivateSignal(); + return true; + } + if (!matchDataType(&dataType, &name)) { return false; } diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp index 55050806ec..2ff4df9bd7 100644 --- a/src/tools/qdoc/generator.cpp +++ b/src/tools/qdoc/generator.cpp @@ -1249,6 +1249,23 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) generateText(text, node, marker); } +/*! + Generates a bold line that says: + "The signal is private, not emitted by the user. + The function is public so the user can pass it to connect()." + */ +void Generator::generatePrivateSignalNote(const Node* node, CodeMarker* marker) +{ + Text text; + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Note: " + << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) + << "This is a private signal. It can be used in signal connections but cannot be emitted by the user." + << Atom::ParaRight; + generateText(text, node, marker); +} + /*! Generate the documentation for \a relative. i.e. \a relative is the node that reporesentas the entity where a qdoc comment diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h index 3165e8d449..6d0de8df44 100644 --- a/src/tools/qdoc/generator.h +++ b/src/tools/qdoc/generator.h @@ -156,6 +156,7 @@ protected: const QString& tag); void generateSince(const Node *node, CodeMarker *marker); void generateStatus(const Node *node, CodeMarker *marker); + void generatePrivateSignalNote(const Node* node, CodeMarker* marker); void generateThreadSafeness(const Node *node, CodeMarker *marker); QString getMetadataElement(const InnerNode* inner, const QString& t); QStringList getMetadataElements(const InnerNode* inner, const QString& t); diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index f315099f18..f0a23ac65e 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -3265,6 +3265,7 @@ void HtmlGenerator::generateSectionList(const Section& section, { bool alignNames = true; if (!section.members.isEmpty()) { + bool hasPrivateSignals = false; bool twoColumn = false; if (style == CodeMarker::Subpage) { alignNames = false; @@ -3307,6 +3308,14 @@ void HtmlGenerator::generateSectionList(const Section& section, prefix = prefix.left(section.keys.at(i).indexOf("::")+1); } generateSynopsis(*m, relative, marker, style, alignNames, &prefix); + if ((*m)->isFunction()) { + const FunctionNode* fn = static_cast(*m); + if (fn->isPrivateSignal()) { + hasPrivateSignals = true; + if (alignNames) + out() << "[see note below]"; + } + } if (alignNames) out() << "\n"; else @@ -3321,6 +3330,9 @@ void HtmlGenerator::generateSectionList(const Section& section, if (twoColumn) out() << "\n\n"; } + if (hasPrivateSignals && alignNames) { + generatePrivateSignalNote(relative, marker); + } } if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { @@ -4023,6 +4035,11 @@ void HtmlGenerator::generateDetailedMember(const Node *node, generateSectionList(notifiers, node, marker, CodeMarker::Accessors); } } + else if (node->isFunction()) { + const FunctionNode* fn = static_cast(node); + if (fn->isPrivateSignal()) + generatePrivateSignalNote(node, marker); + } else if (node->type() == Node::Enum) { const EnumNode *enume = static_cast(node); if (enume->flagsType()) { diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp index 24c64538c3..230ce50df8 100644 --- a/src/tools/qdoc/node.cpp +++ b/src/tools/qdoc/node.cpp @@ -1804,6 +1804,7 @@ FunctionNode::FunctionNode(InnerNode *parent, const QString& name) ove(false), reimp(false), attached_(false), + privateSignal_(false), rf(0), ap(0) { @@ -1824,6 +1825,7 @@ FunctionNode::FunctionNode(Type type, InnerNode *parent, const QString& name, bo ove(false), reimp(false), attached_(attached), + privateSignal_(false), rf(0), ap(0) { diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h index fc9d33edc2..85e724b9ca 100644 --- a/src/tools/qdoc/node.h +++ b/src/tools/qdoc/node.h @@ -928,6 +928,8 @@ public: virtual QString logicalModuleIdentifier() const Q_DECL_OVERRIDE { return parent()->logicalModuleIdentifier(); } + bool isPrivateSignal() const { return privateSignal_; } + void setPrivateSignal() { privateSignal_ = true; } void debug() const; @@ -946,6 +948,7 @@ private: bool ove : 1; bool reimp: 1; bool attached_: 1; + bool privateSignal_: 1; QList params; const FunctionNode* rf; const PropertyNode* ap; diff --git a/src/tools/qdoc/tokenizer.cpp b/src/tools/qdoc/tokenizer.cpp index 6bfa678bc6..68c6fb7831 100644 --- a/src/tools/qdoc/tokenizer.cpp +++ b/src/tools/qdoc/tokenizer.cpp @@ -78,7 +78,8 @@ static const char *kwords[] = { "QT3_SUPPORT", "QT3_SUPPORT_CONSTRUCTOR", "QT3_MOC_SUPPORT", - "QDOC_PROPERTY" + "QDOC_PROPERTY", + "QPrivateSignal" }; static const int KwordHashTableSize = 4096; diff --git a/src/tools/qdoc/tokenizer.h b/src/tools/qdoc/tokenizer.h index 5827ce9b7d..2b79320567 100644 --- a/src/tools/qdoc/tokenizer.h +++ b/src/tools/qdoc/tokenizer.h @@ -74,8 +74,8 @@ enum { Tok_Eoi, Tok_Ampersand, Tok_Aster, Tok_Caret, Tok_LeftParen, Tok_Q_DECLARE_FLAGS, Tok_Q_SIGNALS, Tok_Q_SLOTS, Tok_QT_COMPAT, Tok_QT_COMPAT_CONSTRUCTOR, Tok_QT_DEPRECATED, Tok_QT_MOC_COMPAT, Tok_QT_MODULE, Tok_QT3_SUPPORT, Tok_QT3_SUPPORT_CONSTRUCTOR, - Tok_QT3_MOC_SUPPORT, Tok_QDOC_PROPERTY, - Tok_FirstKeyword = Tok_char, Tok_LastKeyword = Tok_QDOC_PROPERTY }; + Tok_QT3_MOC_SUPPORT, Tok_QDOC_PROPERTY, Tok_QPrivateSignal, + Tok_FirstKeyword = Tok_char, Tok_LastKeyword = Tok_QPrivateSignal }; /* The Tokenizer class implements lexical analysis of C++ source -- cgit v1.2.3 From 198190b76baffce9b983d03749e64af6f8428e49 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 15 Apr 2015 11:31:20 +0200 Subject: QList: make QListSpecialMethods dtors protected QList publicly inherits from QListSpecialMethods. Thus, any specialisation of QListSpecialMethods should make their destructor protected, to avoid deletion through a pointer to QListSpecialMethods invoking UB. Change-Id: I7e317606f84826cc0faf1bfc05dee97da6eaf2eb Reviewed-by: Thiago Macieira --- src/corelib/tools/qbytearraylist.h | 4 ++++ src/corelib/tools/qlist.h | 7 ++++++- src/corelib/tools/qstringlist.h | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/tools/qbytearraylist.h b/src/corelib/tools/qbytearraylist.h index 9cd241a87b..f8539ca07a 100644 --- a/src/corelib/tools/qbytearraylist.h +++ b/src/corelib/tools/qbytearraylist.h @@ -55,6 +55,10 @@ class QByteArrayList : public QList template <> struct QListSpecialMethods #endif { +#ifndef Q_QDOC +protected: + ~QListSpecialMethods() {} +#endif public: inline QByteArray join() const { return QtPrivate::QByteArrayList_join(self(), 0, 0); } diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 57e67d52d7..f5ff952f97 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -62,8 +62,13 @@ QT_BEGIN_NAMESPACE template class QVector; template class QSet; -template struct QListSpecialMethods { }; +template struct QListSpecialMethods +{ +protected: + ~QListSpecialMethods() {} +}; template <> struct QListSpecialMethods; +template <> struct QListSpecialMethods; struct Q_CORE_EXPORT QListData { // tags for tag-dispatching of QList implementations, diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h index 89785208c8..8288e430fa 100644 --- a/src/corelib/tools/qstringlist.h +++ b/src/corelib/tools/qstringlist.h @@ -57,6 +57,10 @@ class QStringList : public QList template <> struct QListSpecialMethods #endif { +#ifndef Q_QDOC +protected: + ~QListSpecialMethods() {} +#endif public: inline void sort(Qt::CaseSensitivity cs = Qt::CaseSensitive); inline int removeDuplicates(); -- cgit v1.2.3 From d3dfb8d8f13b8e878778ebf4980a3b192b4b7a08 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 16 Apr 2015 11:18:21 +0200 Subject: QSignalBlocker: mark all functions as noexcept Consequently, mark also QObject::isSignalsBlocked() and QObject::blockSignals() as noexcept. Change-Id: Iaf44674bbf54eeb2bb5f267eb7caa916eccbf7fb Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qobject.cpp | 2 +- src/corelib/kernel/qobject.h | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 774e46ea33..1836405b9c 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1395,7 +1395,7 @@ bool QObject::eventFilter(QObject * /* watched */, QEvent * /* event */) \sa signalsBlocked() */ -bool QObject::blockSignals(bool block) +bool QObject::blockSignals(bool block) Q_DECL_NOTHROW { Q_D(QObject); bool previous = d->blockSig; diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 42d18d6c41..ecea13fc4a 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -137,8 +137,8 @@ public: inline bool isWidgetType() const { return d_ptr->isWidget; } inline bool isWindowType() const { return d_ptr->isWindow; } - inline bool signalsBlocked() const { return d_ptr->blockSig; } - bool blockSignals(bool b); + inline bool signalsBlocked() const Q_DECL_NOTHROW { return d_ptr->blockSig; } + bool blockSignals(bool b) Q_DECL_NOTHROW; QThread *thread() const; void moveToThread(QThread *thread); @@ -552,17 +552,17 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *); class QSignalBlocker { public: - inline explicit QSignalBlocker(QObject *o); - inline explicit QSignalBlocker(QObject &o); + inline explicit QSignalBlocker(QObject *o) Q_DECL_NOTHROW; + inline explicit QSignalBlocker(QObject &o) Q_DECL_NOTHROW; inline ~QSignalBlocker(); #ifdef Q_COMPILER_RVALUE_REFS - inline QSignalBlocker(QSignalBlocker &&other); - inline QSignalBlocker &operator=(QSignalBlocker &&other); + inline QSignalBlocker(QSignalBlocker &&other) Q_DECL_NOTHROW; + inline QSignalBlocker &operator=(QSignalBlocker &&other) Q_DECL_NOTHROW; #endif - inline void reblock(); - inline void unblock(); + inline void reblock() Q_DECL_NOTHROW; + inline void unblock() Q_DECL_NOTHROW; private: Q_DISABLE_COPY(QSignalBlocker) QObject * m_o; @@ -570,20 +570,20 @@ private: bool m_inhibited; }; -QSignalBlocker::QSignalBlocker(QObject *o) +QSignalBlocker::QSignalBlocker(QObject *o) Q_DECL_NOTHROW : m_o(o), m_blocked(o && o->blockSignals(true)), m_inhibited(false) {} -QSignalBlocker::QSignalBlocker(QObject &o) +QSignalBlocker::QSignalBlocker(QObject &o) Q_DECL_NOTHROW : m_o(&o), m_blocked(o.blockSignals(true)), m_inhibited(false) {} #ifdef Q_COMPILER_RVALUE_REFS -QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) +QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) Q_DECL_NOTHROW : m_o(other.m_o), m_blocked(other.m_blocked), m_inhibited(other.m_inhibited) @@ -591,7 +591,7 @@ QSignalBlocker::QSignalBlocker(QSignalBlocker &&other) other.m_o = 0; } -QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) +QSignalBlocker &QSignalBlocker::operator=(QSignalBlocker &&other) Q_DECL_NOTHROW { if (this != &other) { // if both *this and other block the same object's signals: @@ -614,13 +614,13 @@ QSignalBlocker::~QSignalBlocker() m_o->blockSignals(m_blocked); } -void QSignalBlocker::reblock() +void QSignalBlocker::reblock() Q_DECL_NOTHROW { if (m_o) m_o->blockSignals(true); m_inhibited = false; } -void QSignalBlocker::unblock() +void QSignalBlocker::unblock() Q_DECL_NOTHROW { if (m_o) m_o->blockSignals(m_blocked); m_inhibited = true; -- cgit v1.2.3 From fb144aabbf29c583986e8e4147bd0084efb26ef2 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 16 Apr 2015 11:19:59 +0200 Subject: QScopedValueRollback: use ctor-init-list Avoids calls to the default ctor for member 'oldValue'. Change-Id: Ieb9570b74e4a46b28c04625fac3ce267074c4a76 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/tools/qscopedvaluerollback.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/corelib/tools/qscopedvaluerollback.h b/src/corelib/tools/qscopedvaluerollback.h index 66110b88f6..0265665d94 100644 --- a/src/corelib/tools/qscopedvaluerollback.h +++ b/src/corelib/tools/qscopedvaluerollback.h @@ -43,15 +43,13 @@ class QScopedValueRollback { public: explicit QScopedValueRollback(T &var) : - varRef(var) + varRef(var), oldValue(var) { - oldValue = varRef; } explicit QScopedValueRollback(T &var, T value) : - varRef(var) + varRef(var), oldValue(var) { - oldValue = varRef; varRef = value; } -- cgit v1.2.3 From 1ae657344c5e8e7f19eaff0f300e870d0cd1afa1 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 16 Apr 2015 11:20:42 +0200 Subject: QScopedValueRollback: add two strategic qMove()s Use moves instead of copies when the rhs is no longer needed afterwards. Change-Id: If053bfce03b886099688452ada74f6a6f36db5c2 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/tools/qscopedvaluerollback.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/corelib/tools/qscopedvaluerollback.h b/src/corelib/tools/qscopedvaluerollback.h index 0265665d94..2db2ad869c 100644 --- a/src/corelib/tools/qscopedvaluerollback.h +++ b/src/corelib/tools/qscopedvaluerollback.h @@ -50,12 +50,12 @@ public: explicit QScopedValueRollback(T &var, T value) : varRef(var), oldValue(var) { - varRef = value; + varRef = qMove(value); } ~QScopedValueRollback() { - varRef = oldValue; + varRef = qMove(oldValue); } void commit() -- cgit v1.2.3 From 5e8e04a29ff15e8b329c758f2ea62b8e6feb70f9 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 27 Mar 2015 12:28:40 +0100 Subject: OS X: Do not re-create tracking areas over and over again NSTrackingInVisibleRect already makes sure that the tracking area updates itself, so we only need to add our tracking area if it is missing. For some reason this also fixes that Qt mouse tracking was broken after showing e.g. an embedded native WebView. Task-number: QTBUG-21944 Change-Id: I8013517f474f18e44b1ddd411defe1b6e60f05bf Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qnsview.h | 1 + src/plugins/platforms/cocoa/qnsview.mm | 30 ++++++++++++------------------ 2 files changed, 13 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index c3815ee60a..32bc15d092 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -59,6 +59,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); bool m_shouldInvalidateWindowShadow; QWindow *m_window; QCocoaWindow *m_platformWindow; + NSTrackingArea *m_trackingArea; Qt::MouseButtons m_buttons; Qt::MouseButtons m_frameStrutButtons; QString m_composingText; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 7896fffaad..04f7119730 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -167,6 +167,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; - (void)dealloc { CGImageRelease(m_maskImage); + [m_trackingArea release]; m_maskImage = 0; m_window = 0; m_subscribesForGlobalFrameNotifications = false; @@ -188,6 +189,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_window = window; m_platformWindow = platformWindow; m_sendKeyEvent = false; + m_trackingArea = nil; #ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR // prevent rift in space-time continuum, disable @@ -841,19 +843,11 @@ QT_WARNING_POP { [super updateTrackingAreas]; - // [NSView addTrackingArea] is slow, so bail out early if we can: - if (NSIsEmptyRect([self visibleRect])) - return; - - // Remove current trakcing areas: QCocoaAutoReleasePool pool; - if (NSArray *trackingArray = [self trackingAreas]) { - NSUInteger size = [trackingArray count]; - for (NSUInteger i = 0; i < size; ++i) { - NSTrackingArea *t = [trackingArray objectAtIndex:i]; - [self removeTrackingArea:t]; - } - } + + // NSTrackingInVisibleRect keeps care of updating once the tracking is set up, so bail out early + if (m_trackingArea && [[self trackingAreas] containsObject:m_trackingArea]) + return; // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should // only be turned on if mouseTracking, hover is on or a tool tip is set. @@ -863,12 +857,12 @@ QT_WARNING_POP // is a performance hit). So it goes. NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp | NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate; - NSTrackingArea *ta = [[[NSTrackingArea alloc] initWithRect:[self frame] - options:trackingOptions - owner:m_mouseMoveHelper - userInfo:nil] - autorelease]; - [self addTrackingArea:ta]; + [m_trackingArea release]; + m_trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame] + options:trackingOptions + owner:m_mouseMoveHelper + userInfo:nil]; + [self addTrackingArea:m_trackingArea]; } -(void)cursorUpdateImpl:(NSEvent *)theEvent -- cgit v1.2.3 From c52c8e5e1e3482e144279d8f85df06f6c3597041 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 14 Apr 2015 10:22:25 +0200 Subject: Fix compilation error (OS X 10.8, warnings as errors) Failed to compile on my OS X 10.8 (unused variable warning treated as error) Change-Id: I7ee881d4b905539361a10e93cff76b44ec08afbf Reviewed-by: Timur Pocheptsov --- src/widgets/graphicsview/qgraphicsitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index eaa5cb99e4..cd30410097 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -11290,7 +11290,7 @@ static void formatGraphicsItemHelper(QDebug debug, const QGraphicsItem *item) debug << ", pos="; QtDebugUtils::formatQPoint(debug, item->pos()); if (const qreal z = item->zValue()) - debug << ", z=" << item->zValue(); + debug << ", z=" << z; if (item->flags()) debug << ", flags=" << item->flags(); } -- cgit v1.2.3 From cbb918753c493959a53e7e62db62007d3e4ffb4b Mon Sep 17 00:00:00 2001 From: Michal Klocek Date: Wed, 18 Feb 2015 16:15:32 +0100 Subject: Fix crash when qt compiled with dbus support and no dbus interface. Add check if interface exists before calling it. Change-Id: I86762fd9b82131d12aac0281c86eca549752fdbd Reviewed-by: Alex Blasche --- src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 843387e679..e662d5f2d3 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -79,10 +79,14 @@ QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent) connect(ofonoWatcher, SIGNAL(serviceUnregistered(QString)), this, SLOT(ofonoUnRegistered(QString))); - if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.ofono")) + QDBusConnectionInterface *interface = QDBusConnection::systemBus().interface(); + + if (!interface) return; + + if (interface->isServiceRegistered("org.ofono")) QMetaObject::invokeMethod(this, "ofonoRegistered", Qt::QueuedConnection); - if (QDBusConnection::systemBus().interface()->isServiceRegistered(NM_DBUS_SERVICE)) + if (interface->isServiceRegistered(NM_DBUS_SERVICE)) QMetaObject::invokeMethod(this, "nmRegistered", Qt::QueuedConnection); } -- cgit v1.2.3 From 700eb7a2a58dd64c03c5855f2b038e7cbce1fc12 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 13 Apr 2015 08:52:25 +0200 Subject: windows: Add a version test to the Intel HD blacklist The original rule was way too broad: it disabled desktop GL many HD 4400 machines that have no problems with it at all. While the rule with the version check is somewhat dubious, it is the only thing we can do. Task-number: QTBUG-45505 Task-number: QTBUG-43263 Change-Id: I217a96a2a9c7cc2d000a8f06493d0857626f2aaa Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/openglblacklists/default.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index 0217b79ecf..23607523bd 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -4,12 +4,16 @@ "entries": [ { "id": 1, - "description": "Desktop OpenGL is unreliable on Intel HD3000/GMA (QTBUG-43263, QTBUG-42240)", + "description": "Desktop OpenGL is unreliable on some Intel HD laptops (QTBUG-43263, QTBUG-42240)", "vendor_id": "0x8086", "device_id": [ "0x0A16" ], "os": { "type": "win" }, + "driver_version": { + "op": "<=", + "value": "10.18.10.3277" + }, "features": [ "disable_desktopgl" ] -- cgit v1.2.3 From b7d75277208cdbd63c4483fb89fc04798939c651 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 16 Apr 2015 15:44:27 +0200 Subject: Map X11 AudioPause button Add a missing mapping for the X11 media key AudioPause. Change-Id: I2888854a021192942c7e8d47d581d834e1f39736 Reviewed-by: Shawn Rutledge Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbkeyboard.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 376599578f..6a9ef5869e 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -437,6 +437,7 @@ static const unsigned int KeyTbl[] = { XF86XK_AudioPrev, Qt::Key_MediaPrevious, XF86XK_AudioNext, Qt::Key_MediaNext, XF86XK_AudioRecord, Qt::Key_MediaRecord, + XF86XK_AudioPause, Qt::Key_MediaPause, XF86XK_Mail, Qt::Key_LaunchMail, XF86XK_MyComputer, Qt::Key_Launch0, // ### Qt 6: remap properly XF86XK_Calculator, Qt::Key_Launch1, -- cgit v1.2.3 From 71e3ce7f0b671ac8bb6607d18d4fa16c6c81f737 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 26 Mar 2015 16:39:13 +0100 Subject: The default wrap mode is REPEAT As per spec, both for OpenGL and OpenGL ES. No wrap mode is applied unless setWrapMode() is called so the default values should be initialized to match OpenGL's default. Correct the copy-paste mistake in the warning messages. Change-Id: I094cc511dc7de4a214da61faadb1fc362270b2d4 Reviewed-by: Giuseppe D'Angelo --- src/gui/opengl/qopengltexture.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index 9bc9926b70..baa702a982 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -120,7 +120,8 @@ QOpenGLTexturePrivate::QOpenGLTexturePrivate(QOpenGLTexture::Target textureTarge swizzleMask[2] = QOpenGLTexture::BlueValue; swizzleMask[3] = QOpenGLTexture::AlphaValue; - wrapModes[0] = wrapModes[1] = wrapModes[2] = QOpenGLTexture::ClampToEdge; + wrapModes[0] = wrapModes[1] = wrapModes[2] = target == QOpenGLTexture::TargetRectangle + ? QOpenGLTexture::ClampToEdge : QOpenGLTexture::Repeat; } QOpenGLTexturePrivate::~QOpenGLTexturePrivate() @@ -215,7 +216,8 @@ void QOpenGLTexturePrivate::destroy() swizzleMask[2] = QOpenGLTexture::BlueValue; swizzleMask[3] = QOpenGLTexture::AlphaValue; - wrapModes[0] = wrapModes[1] = wrapModes[2] = QOpenGLTexture::ClampToEdge; + wrapModes[0] = wrapModes[1] = wrapModes[2] = target == QOpenGLTexture::TargetRectangle + ? QOpenGLTexture::ClampToEdge : QOpenGLTexture::Repeat; } void QOpenGLTexturePrivate::bind() @@ -1393,7 +1395,7 @@ QOpenGLTexture::WrapMode QOpenGLTexturePrivate::wrapMode(QOpenGLTexture::Coordin case QOpenGLTexture::DirectionT: case QOpenGLTexture::DirectionR: - qWarning("QOpenGLTexture::setWrapMode() direction not valid for this texture target"); + qWarning("QOpenGLTexture::wrapMode() direction not valid for this texture target"); return QOpenGLTexture::Repeat; } break; @@ -1413,7 +1415,7 @@ QOpenGLTexture::WrapMode QOpenGLTexturePrivate::wrapMode(QOpenGLTexture::Coordin return wrapModes[1]; case QOpenGLTexture::DirectionR: - qWarning("QOpenGLTexture::setWrapMode() direction not valid for this texture target"); + qWarning("QOpenGLTexture::wrapMode() direction not valid for this texture target"); return QOpenGLTexture::Repeat; } break; -- cgit v1.2.3 From f3fad26bc9e0fde3bcf1625da731aeb02b04a7a5 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 9 Apr 2015 16:49:34 +0200 Subject: Add matching by GL_VENDOR to QOpenGLConfig This will be essential on Linux, especially Embedded where PCI IDs are not that useful. Change-Id: I2fa8ca07236e8aae203e21fe629d12aab092c7fd Reviewed-by: Friedemann Kleint --- src/gui/opengl/qopengl.cpp | 42 +++++++++++++++++----- src/gui/opengl/qopengl_p.h | 24 +++++++++++-- .../platforms/windows/qwindowsopengltester.cpp | 5 +-- 3 files changed, 56 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp index 61d0614724..c8d33df4ba 100644 --- a/src/gui/opengl/qopengl.cpp +++ b/src/gui/opengl/qopengl.cpp @@ -36,6 +36,7 @@ #include "qopenglcontext.h" #include "qopenglfunctions.h" +#include "qoffscreensurface.h" #include #include @@ -89,8 +90,8 @@ QOpenGLExtensionMatcher::QOpenGLExtensionMatcher() } /* Helpers to read out the list of features matching a device from - * a Chromium driver bug list of the format using a subset of keys - * (namely, matching by gl_vendor RegExp is not implemented): + * a Chromium driver bug list. Note that not all keys are supported and + * some may behave differently: gl_vendor is a substring match instead of regex. { "entries": [ { @@ -291,14 +292,14 @@ static bool matches(const QJsonObject &object, const QJsonValue vendorV = object.value(vendorIdKey()); if (vendorV.isString()) { - if (gpu.vendorId != vendorV.toString().toUInt(Q_NULLPTR, /* base */ 0)) - return false; + if (gpu.vendorId != vendorV.toString().toUInt(Q_NULLPTR, /* base */ 0)) + return false; } else { if (object.contains(glVendorKey())) { - qWarning().nospace() << "Id " << object.value(idKey()).toInt() - << ": Matching by " << glVendorKey() << " is not implemented."; - return false; - } + const QByteArray glVendorV = object.value(glVendorKey()).toString().toUtf8(); + if (!gpu.glVendor.contains(glVendorV)) + return false; + } } if (gpu.deviceId) { @@ -447,5 +448,30 @@ QSet QOpenGLConfig::gpuFeatures(const Gpu &gpu, const QString &fileName return gpuFeatures(gpu, OsTypeTerm::hostOs(), OsTypeTerm::hostKernelVersion(), fileName); } +QOpenGLConfig::Gpu QOpenGLConfig::Gpu::fromContext() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QScopedPointer tmpContext; + QScopedPointer tmpSurface; + if (!ctx) { + tmpContext.reset(new QOpenGLContext); + if (!tmpContext->create()) { + qWarning("QOpenGLConfig::Gpu::fromContext: Failed to create temporary context"); + return QOpenGLConfig::Gpu(); + } + tmpSurface.reset(new QOffscreenSurface); + tmpSurface->setFormat(tmpContext->format()); + tmpSurface->create(); + tmpContext->makeCurrent(tmpSurface.data()); + } + + QOpenGLConfig::Gpu gpu; + ctx = QOpenGLContext::currentContext(); + const GLubyte *p = ctx->functions()->glGetString(GL_VENDOR); + if (p) + gpu.glVendor = QByteArray(reinterpret_cast(p)); + + return gpu; +} QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengl_p.h b/src/gui/opengl/qopengl_p.h index e04ae05120..980e02aea6 100644 --- a/src/gui/opengl/qopengl_p.h +++ b/src/gui/opengl/qopengl_p.h @@ -74,16 +74,34 @@ private: class Q_GUI_EXPORT QOpenGLConfig { public: - struct Gpu { + struct Q_GUI_EXPORT Gpu { Gpu() : vendorId(0), deviceId(0) {} - bool isValid() const { return deviceId; } + bool isValid() const { return deviceId || !glVendor.isEmpty(); } bool equals(const Gpu &other) const { - return vendorId == other.vendorId && deviceId == other.deviceId && driverVersion == other.driverVersion; + return vendorId == other.vendorId && deviceId == other.deviceId && driverVersion == other.driverVersion + && glVendor == other.glVendor; } uint vendorId; uint deviceId; QVersionNumber driverVersion; + QByteArray glVendor; + + static Gpu fromDevice(uint vendorId, uint deviceId, QVersionNumber driverVersion) { + Gpu gpu; + gpu.vendorId = vendorId; + gpu.deviceId = deviceId; + gpu.driverVersion = driverVersion; + return gpu; + } + + static Gpu fromGLVendor(const QByteArray &glVendor) { + Gpu gpu; + gpu.glVendor = glVendor; + return gpu; + } + + static Gpu fromContext(); }; static QSet gpuFeatures(const Gpu &gpu, diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index f5065a22b8..2e6a43f596 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -224,10 +224,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c #elif defined(Q_OS_WINCE) return QWindowsOpenGLTester::Gles; #else - QOpenGLConfig::Gpu qgpu; - qgpu.deviceId = gpu.deviceId; - qgpu.vendorId = gpu.vendorId; - qgpu.driverVersion = gpu.driverVersion; + QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.deviceId, gpu.vendorId, gpu.driverVersion); SupportedRenderersCache *srCache = supportedRenderersCache(); SupportedRenderersCache::const_iterator it = srCache->find(qgpu); if (it != srCache->cend()) -- cgit v1.2.3 From b596acbefb2ddb71d6bac6be1b8aa1d436c63649 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 15 Apr 2015 12:16:54 +0200 Subject: Avoid warnings with clang 6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit warning: 'this' pointer cannot be null in well-defined C++ code The code tries to be smart but compilers warn about this unfortunately. Change-Id: Ifb8deafe8834d580beef829a3079ae9222acfa8f Reviewed-by: Morten Johan Sørvig --- src/widgets/graphicsview/qgraphicsanchorlayout_p.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h index a4609c41cf..c0bb8ef63a 100644 --- a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h @@ -251,9 +251,7 @@ struct AnchorVertexPair : public AnchorVertex { #ifdef QT_DEBUG inline QString AnchorVertex::toString() const { - if (!this) { - return QLatin1String("NULL"); - } else if (m_type == Pair) { + if (m_type == Pair) { const AnchorVertexPair *vp = static_cast(this); return QString::fromLatin1("(%1, %2)").arg(vp->m_first->toString()).arg(vp->m_second->toString()); } else if (!m_item) { -- cgit v1.2.3 From fd2e245edf0535d25011186de6397e56bc02c692 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 15 Apr 2015 12:18:59 +0200 Subject: Avoid signed-unsigned warning on OS X MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I61db35a367b1a96b13af08a5102d6b2a55c68517 Reviewed-by: Morten Johan Sørvig --- src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 99f54237bc..be70092010 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -276,7 +276,7 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) uint length = 128; QVarLengthArray os2Table(length); if (QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length) && length >= 86) { - if (length > os2Table.length()) { + if (length > uint(os2Table.length())) { os2Table.resize(length); if (!QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length)) Q_UNREACHABLE(); -- cgit v1.2.3 From be6b27aaa1ce2d9cdd93e005dafb62fa81c5cdc0 Mon Sep 17 00:00:00 2001 From: Christoph Schleifenbaum Date: Sun, 12 Apr 2015 17:59:19 +0200 Subject: Cocoa: Remove NSMenuItem setEnabled used in wrong way. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Whether menu items are enabled or not is not set via NSMenuItem's enabled property but depends on the return value of CocoaMenu's validateMenuItem. Change-Id: I5673da18ab9eb3510b773e0ab520e5382a160844 Task-number: QTBUG-42511 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoamenuitem.mm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index bf12c0f2ce..f288ab85c0 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -308,7 +308,6 @@ NSMenuItem *QCocoaMenuItem::sync() } [m_native setHidden: !m_isVisible]; - [m_native setEnabled: m_enabled]; [m_native setView:m_itemView]; QString text = mergeText(); @@ -410,7 +409,7 @@ void QCocoaMenuItem::syncModalState(bool modal) if (modal) [m_native setEnabled:NO]; else - [m_native setEnabled:m_enabled]; + [m_native setEnabled:YES]; } QPlatformMenuItem::MenuRole QCocoaMenuItem::effectiveRole() const -- cgit v1.2.3 From 28dcb7101e0038007bf9c2e1e17f9588b5264943 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 16 Apr 2015 19:54:52 +0200 Subject: QFileSystemEngine: optimize from...(qgetenv()) Use the QByteArray overload, which no longer calls strlen(), but uses the QByteArray length. No danger of embedded NULs, because environment variables cannot contain NULs. Change-Id: I33fe479adfce2624c7042608e8e0a5c5b54a85db Reviewed-by: Thiago Macieira --- src/corelib/io/qfilesystemengine_win.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 221cea3bea..5cca3c323e 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -1218,7 +1218,7 @@ QString QFileSystemEngine::rootPath() ret = QDir::fromNativeSeparators(QString::fromWCharArray(finalWinPath.GetRawBuffer(nullptr))); #else - QString ret = QString::fromLatin1(qgetenv("SystemDrive").constData()); + QString ret = QString::fromLatin1(qgetenv("SystemDrive")); if (ret.isEmpty()) ret = QLatin1String("c:"); ret.append(QLatin1Char('/')); @@ -1253,12 +1253,12 @@ QString QFileSystemEngine::homePath() } #endif if (ret.isEmpty() || !QFile::exists(ret)) { - ret = QString::fromLocal8Bit(qgetenv("USERPROFILE").constData()); + ret = QString::fromLocal8Bit(qgetenv("USERPROFILE")); if (ret.isEmpty() || !QFile::exists(ret)) { - ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE").constData()) - + QString::fromLocal8Bit(qgetenv("HOMEPATH").constData()); + ret = QString::fromLocal8Bit(qgetenv("HOMEDRIVE")) + + QString::fromLocal8Bit(qgetenv("HOMEPATH")); if (ret.isEmpty() || !QFile::exists(ret)) { - ret = QString::fromLocal8Bit(qgetenv("HOME").constData()); + ret = QString::fromLocal8Bit(qgetenv("HOME")); if (ret.isEmpty() || !QFile::exists(ret)) { #if defined(Q_OS_WINCE) ret = QLatin1String("\\My Documents"); -- cgit v1.2.3 From 365c63e7b177701c0bf80a7cb138b7559b92f350 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 14 Apr 2015 14:00:05 +0200 Subject: Fix regression in compose table parsing Performance optimization from 1aab68648 revealed that "composeValueEnd" needs adjustment for compose sequences that result in a quotation mark, for example: : "\"" quotedbl # REVERSE SOLIDUS Change-Id: I66bf83fbe62727f1ee245aae90f8d0eb53dea6d4 Task-number: QTBUG-45538 Reviewed-by: Simon Hausmann --- .../platforminputcontexts/compose/generator/qtablegenerator.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index 120b228f79..65020eb848 100644 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -385,6 +385,10 @@ void TableGenerator::parseKeySequence(char *line) if (!composeValueEnd) return; + // if composed value is a quotation mark adjust the end pointer + if (composeValueEnd[1] == '"') + ++composeValueEnd; + if (*composeValue == '\\' && composeValue[1] >= '0' && composeValue[1] <= '9') { // handle octal and hex code values char detectBase = composeValue[2]; -- cgit v1.2.3 From 964ccc58534aac436529007000d1c38d76c88834 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 13 Apr 2015 16:06:57 +0200 Subject: Remove separate SSE4 unpremultiply function Merges the SSE4 specific unpremultiply with the normal version, and adds a SSE2 fallback. There was no reason to split the two since compile time options will ensure the right version is inlined. Also adds short-cut for 0 and 255 values. Change-Id: Ie5aa262f6964219fd3062d4a498f697cf79a4595 Reviewed-by: Thiago Macieira --- src/gui/image/qimage_conversions.cpp | 6 ++--- src/gui/image/qimage_sse4.cpp | 3 +-- src/gui/painting/qdrawhelper.cpp | 10 ++++---- src/gui/painting/qdrawhelper_sse4.cpp | 7 +++--- src/gui/painting/qdrawingprimitive_sse2_p.h | 21 ---------------- src/gui/painting/qrgb.h | 37 ++++++++++++++++++++++++++--- 6 files changed, 45 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 28e3a48689..8cb886e09b 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -117,7 +117,7 @@ static const uint *QT_FASTCALL convertRGB32ToARGB32PM(uint *buffer, const uint * return buffer; } -#ifdef QT_COMPILER_SUPPORTS_SSE4_1 +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) && !defined(__SSE4_1__) extern const uint *QT_FASTCALL convertRGB32FromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); #endif @@ -144,7 +144,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio if (src->format == QImage::Format_RGB32) convertToARGB32PM = convertRGB32ToARGB32PM; if (dest->format == QImage::Format_RGB32) { -#ifdef QT_COMPILER_SUPPORTS_SSE4_1 +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) && !defined(__SSE4_1__) if (qCpuHasFeature(SSE4_1)) convertFromARGB32PM = convertRGB32FromARGB32PM_sse4; else @@ -193,7 +193,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im if (data->format == QImage::Format_RGB32) convertToARGB32PM = convertRGB32ToARGB32PM; if (dst_format == QImage::Format_RGB32) { -#ifdef QT_COMPILER_SUPPORTS_SSE4_1 +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) && !defined(__SSE4_1__) if (qCpuHasFeature(SSE4_1)) convertFromARGB32PM = convertRGB32FromARGB32PM_sse4; else diff --git a/src/gui/image/qimage_sse4.cpp b/src/gui/image/qimage_sse4.cpp index 5fad4f572a..fb63f5bff9 100644 --- a/src/gui/image/qimage_sse4.cpp +++ b/src/gui/image/qimage_sse4.cpp @@ -33,7 +33,6 @@ #include #include -#include #include #include @@ -45,7 +44,7 @@ const uint *QT_FASTCALL convertRGB32FromARGB32PM_sse4(uint *buffer, const uint * const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = 0xff000000 | qUnpremultiply_sse4(src[i]); + buffer[i] = 0xff000000 | qUnpremultiply(src[i]); return buffer; } diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 37f2de98b6..2817a4a145 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6704,24 +6704,22 @@ void qInitDrawhelperAsm() } #endif // SSSE3 -#if QT_COMPILER_SUPPORTS_SSE4_1 +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) && !defined(__SSE4_1__) if (qCpuHasFeature(SSE4_1)) { -#if !defined(__SSE4_1__) extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); - qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4; - qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4; -#endif extern const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888FromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBXFromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); + qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4; + qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4; qPixelLayouts[QImage::Format_ARGB32].convertFromARGB32PM = convertARGB32FromARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBA8888].convertFromARGB32PM = convertRGBA8888FromARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBX8888].convertFromARGB32PM = convertRGBXFromARGB32PM_sse4; } #endif -#if QT_COMPILER_SUPPORTS_AVX2 && !defined(__AVX2__) +#if defined(QT_COMPILER_SUPPORTS_AVX2) && !defined(__AVX2__) if (qCpuHasFeature(AVX2)) { extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp index 43a3958997..8e0b2cbb18 100644 --- a/src/gui/painting/qdrawhelper_sse4.cpp +++ b/src/gui/painting/qdrawhelper_sse4.cpp @@ -32,7 +32,6 @@ ****************************************************************************/ #include -#include #if defined(QT_COMPILER_SUPPORTS_SSE4_1) @@ -54,7 +53,7 @@ const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = qUnpremultiply_sse4(src[i]); + buffer[i] = qUnpremultiply(src[i]); return buffer; } @@ -62,7 +61,7 @@ const uint *QT_FASTCALL convertRGBA8888FromARGB32PM_sse4(uint *buffer, const uin const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(qUnpremultiply_sse4(src[i])); + buffer[i] = ARGB2RGBA(qUnpremultiply(src[i])); return buffer; } @@ -70,7 +69,7 @@ const uint *QT_FASTCALL convertRGBXFromARGB32PM_sse4(uint *buffer, const uint *s const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply_sse4(src[i])); + buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply(src[i])); return buffer; } diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h index 4d0790a502..fbee06e157 100644 --- a/src/gui/painting/qdrawingprimitive_sse2_p.h +++ b/src/gui/painting/qdrawingprimitive_sse2_p.h @@ -236,25 +236,4 @@ QT_END_NAMESPACE #endif // __SSE2__ -QT_BEGIN_NAMESPACE -#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) -QT_FUNCTION_TARGET(SSE4_1) -inline QRgb qUnpremultiply_sse4(QRgb p) -{ - const uint alpha = qAlpha(p); - const uint invAlpha = qt_inv_premul_factor[alpha]; - const __m128i via = _mm_set1_epi32(invAlpha); - const __m128i vr = _mm_set1_epi32(0x8000); - __m128i vl = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(p)); - vl = _mm_mullo_epi32(vl, via); - vl = _mm_add_epi32(vl, vr); - vl = _mm_srai_epi32(vl, 16); - vl = _mm_insert_epi32(vl, alpha, 3); - vl = _mm_packus_epi32(vl, _mm_setzero_si128()); - vl = _mm_packus_epi16(vl, _mm_setzero_si128()); - return _mm_cvtsi128_si32(vl); -} -#endif -QT_END_NAMESPACE - #endif // QDRAWINGPRIMITIVE_SSE2_P_H diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h index f7f2185bef..05b3a76bce 100644 --- a/src/gui/painting/qrgb.h +++ b/src/gui/painting/qrgb.h @@ -36,6 +36,11 @@ #include #include +#if defined(__SSE4_1__) +#include +#elif defined(__SSE2__) +#include +#endif QT_BEGIN_NAMESPACE @@ -87,19 +92,45 @@ inline Q_DECL_RELAXED_CONSTEXPR QRgb qPremultiply(QRgb x) Q_GUI_EXPORT extern const uint qt_inv_premul_factor[]; +#if defined(__SSE2__) +inline QRgb qUnpremultiply(QRgb p) +{ + const uint alpha = qAlpha(p); + if (alpha == 255 || alpha == 0) + return p; + const uint invAlpha = qt_inv_premul_factor[alpha]; + const __m128i via = _mm_set1_epi32(invAlpha); + const __m128i vr = _mm_set1_epi32(0x8000); +#ifdef __SSE4_1__ + __m128i vl = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(p)); + vl = _mm_mullo_epi32(vl, via); +#else + __m128i vl = _mm_unpacklo_epi8(_mm_cvtsi32_si128(p), _mm_setzero_si128()); + vl = _mm_unpacklo_epi16(vl, vl); + __m128i vll = _mm_mullo_epi16(vl, via); + __m128i vlh = _mm_mulhi_epu16(vl, via); + vl = _mm_add_epi32(vll, _mm_slli_epi32(vlh, 16)); +#endif + vl = _mm_add_epi32(vl, vr); + vl = _mm_srli_epi32(vl, 16); + vl = _mm_packs_epi32(vl, _mm_setzero_si128()); + vl = _mm_insert_epi16(vl, alpha, 3); + vl = _mm_packus_epi16(vl, _mm_setzero_si128()); + return _mm_cvtsi128_si32(vl); +} +#else inline QRgb qUnpremultiply(QRgb p) { const uint alpha = qAlpha(p); // Alpha 255 and 0 are the two most common values, which makes them beneficial to short-cut. - if (alpha == 255) + if (alpha == 255 || alpha == 0) return p; - if (alpha == 0) - return 0; // (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256. const uint invAlpha = qt_inv_premul_factor[alpha]; // We add 0x8000 to get even rounding. The rounding also ensures that qPremultiply(qUnpremultiply(p)) == p for all p. return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha); } +#endif QT_END_NAMESPACE -- cgit v1.2.3 From 6668f5becfb8fcb6d10e42495c6ea5cdba2d15c5 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 22 Dec 2012 13:12:02 -0800 Subject: Implement a more direct headersclean check Test each include file directly, instead of doing a large #include. This verifies that each header is compilable on its own. One big advantage of doing it via a special compiler in qmake is that we skip pre-compiled headers, which has hidden build errors in the past. This solution is implemented by making syncqt produce a second list of headers. This list is the same as the list of headers in the source code to be installed, minus the headers that declare themselves to be unclean, via the pragma: #pragma qt_sync_skip_header_check This mechanism is applied only for public libraries (skipping QtPlatformSupport, an internal_module). This test is enabled only for -developer-builds of Qt because it increases the compilation time. On QtTest: the library only links to QtCore, but it has two headers that provide inline-only functionality by including QtGui and QtWidgets headers (namely, qtest_gui.h and qtest_widget.h). If those two modules aren't getting compiled due to -no-gui or -no-widgets to configure, we need to remove the respective headers from the list of headers to be checked. If they are being built, then we need to make QtTest's build wait for the headers to be generated and that happens when qmake is first run inside the src/gui and src/widgets directories. Change-Id: I57d64bd697a92367c8464c073a42e4d142a9a15f Reviewed-by: Oswald Buddenhagen --- src/src.pro | 4 +++- src/testlib/testlib.pro | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/src.pro b/src/src.pro index fcdc6c32e0..b4d62aa8b0 100644 --- a/src/src.pro +++ b/src/src.pro @@ -81,7 +81,7 @@ src_network.depends = src_corelib src_testlib.subdir = $$PWD/testlib src_testlib.target = sub-testlib -src_testlib.depends = src_corelib # src_gui & src_widgets are not build-depends +src_testlib.depends = src_corelib # testlib links only to corelib, but see below for the headers src_3rdparty_pcre.subdir = $$PWD/3rdparty/pcre src_3rdparty_pcre.target = sub-3rdparty-pcre @@ -166,10 +166,12 @@ contains(QT_CONFIG, concurrent):SUBDIRS += src_concurrent SUBDIRS += src_gui src_platformsupport src_platformheaders contains(QT_CONFIG, opengl(es2)?):SUBDIRS += src_openglextensions src_plugins.depends += src_gui src_platformsupport src_platformheaders + src_testlib.depends += src_gui # if QtGui is enabled, QtTest requires QtGui's headers !contains(QT_CONFIG, no-widgets) { SUBDIRS += src_tools_uic src_widgets TOOLS += src_tools_uic src_plugins.depends += src_widgets + src_testlib.depends += src_widgets # if QtWidgets is enabled, QtTest requires QtWidgets's headers contains(QT_CONFIG, opengl(es2)?) { SUBDIRS += src_opengl src_plugins.depends += src_opengl diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index 841d913105..83f217dde9 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -97,4 +97,9 @@ mac { } } +# Exclude these headers from the clean check if their dependencies aren't +# being built +contains(QT_CONFIG, no-widgets): HEADERSCLEAN_EXCLUDE += qtest_widgets.h +contains(QT_CONFIG, no-gui): HEADERSCLEAN_EXCLUDE += qtest_gui.h + load(qt_module) -- cgit v1.2.3 From 92ea91836eedcf34e09df6b2bd3c34f0468acc49 Mon Sep 17 00:00:00 2001 From: John Layt Date: Wed, 4 Jun 2014 16:40:05 +0100 Subject: QPrintDialog - Let OSX handle PDF printing If the user selects to Save as PDF in the native print dialog, then let OSX generate the PDF. Primarily this is to fix QTBUG-38820 where by setting the output mode to PdfFormat we prevent the native print dialog from being called again. This was a regression in 5.1. It also allows for smaller, better quality PDFs with the ability to select text until QTBUG-13826 / QTBUG-10094 fixes the font rendering. Once QTBUG-36112 is also fixed we can consider changing back to Qt's internal PDF support. See also QTBUG-36687 and QTBUG-26054 which are related. Task-number: QTBUG-38820 Change-Id: I74bd885902860ac70068ab25e95765c7f0ee911c Reviewed-by: Andy Shaw Reviewed-by: Shawn Rutledge --- src/printsupport/dialogs/qprintdialog_mac.mm | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/printsupport/dialogs/qprintdialog_mac.mm b/src/printsupport/dialogs/qprintdialog_mac.mm index bc28350f6b..aec1e3babb 100644 --- a/src/printsupport/dialogs/qprintdialog_mac.mm +++ b/src/printsupport/dialogs/qprintdialog_mac.mm @@ -121,19 +121,22 @@ QT_USE_NAMESPACE if (dialog->maxPage() < dialog->toPage()) dialog->setFromTo(dialog->fromPage(), dialog->maxPage()); } - // Keep us in sync with file output - PMDestinationType dest; - // If the user selected print to file, the session has been - // changed behind our back and our d->ep->session object is a - // dangling pointer. Update it based on the "current" session + // Keep us in sync with chosen destination + PMDestinationType dest; PMSessionGetDestinationType(session, settings, &dest); if (dest == kPMDestinationFile) { + // QTBUG-38820 + // If user selected Print to File, leave OSX to generate the PDF, + // otherwise setting PdfFormat would prevent us showing dialog again. + // TODO Restore this when QTBUG-36112 is fixed. + /* QCFType file; PMSessionCopyDestinationLocation(session, settings, &file); UInt8 localFile[2048]; // Assuming there's a POSIX file system here. CFURLGetFileSystemRepresentation(file, true, localFile, sizeof(localFile)); printer->setOutputFileName(QString::fromUtf8(reinterpret_cast(localFile))); + */ } else { PMPrinter macPrinter; PMSessionGetCurrentPrinter(session, &macPrinter); -- cgit v1.2.3 From d0c96c65ec5e25b1b43885a8c32a886a9b6aa834 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Fri, 17 Apr 2015 09:06:04 +0200 Subject: Rework WinRT timer handling The former way of timer handling caused heap corruptions as the timer callbacks tried to access the event dispatcher after it was freed. So instead of accessing the timers inside the callbacks we use native events to signal their expiration and also to cancel them. Task-number: QTBUG-44973 Change-Id: Ib9348651c0545cc4393f0396601f9a5bb183c996 Reviewed-by: Andrew Knight --- src/corelib/kernel/qcoreapplication_win.cpp | 46 ++-- src/corelib/kernel/qeventdispatcher_winrt.cpp | 327 +++++++++++++++----------- 2 files changed, 208 insertions(+), 165 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index 4649c151f7..396d2f740a 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -184,28 +184,6 @@ Q_CORE_EXPORT void __cdecl qWinMain(HINSTANCE instance, HINSTANCE prevInstance, #ifndef QT_NO_QOBJECT -void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId) -{ - QThreadData *data = object->d_func()->threadData; - - QMutexLocker locker(&data->postEventList.mutex); - if (data->postEventList.size() == 0) - return; - for (int i = 0; i < data->postEventList.size(); ++i) { - const QPostEvent & pe = data->postEventList.at(i); - if (pe.receiver == object - && pe.event - && (pe.event->type() == QEvent::Timer || pe.event->type() == QEvent::ZeroTimerEvent) - && static_cast(pe.event)->timerId() == timerId) { - --pe.receiver->d_func()->postedEvents; - pe.event->posted = false; - delete pe.event; - const_cast(pe).event = 0; - return; - } - } -} - #if defined(Q_OS_WIN) && !defined(QT_NO_DEBUG_STREAM) /***************************************************************************** Convenience functions for convert WM_* messages into human readable strings, @@ -1050,4 +1028,28 @@ QDebug operator<<(QDebug dbg, const MSG &msg) #endif // !defined(Q_OS_WINRT) +#ifndef QT_NO_QOBJECT +void QCoreApplicationPrivate::removePostedTimerEvent(QObject *object, int timerId) +{ + QThreadData *data = object->d_func()->threadData; + + QMutexLocker locker(&data->postEventList.mutex); + if (data->postEventList.size() == 0) + return; + for (int i = 0; i < data->postEventList.size(); ++i) { + const QPostEvent &pe = data->postEventList.at(i); + if (pe.receiver == object + && pe.event + && (pe.event->type() == QEvent::Timer || pe.event->type() == QEvent::ZeroTimerEvent) + && static_cast(pe.event)->timerId() == timerId) { + --pe.receiver->d_func()->postedEvents; + pe.event->posted = false; + delete pe.event; + const_cast(pe).event = 0; + return; + } + } +} +#endif // QT_NO_QOBJECT + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index 5e4ef937b9..cc8e961be1 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -54,62 +54,20 @@ using namespace ABI::Windows::ApplicationModel::Core; QT_BEGIN_NAMESPACE -class QZeroTimerEvent : public QTimerEvent -{ -public: - explicit inline QZeroTimerEvent(int timerId) - : QTimerEvent(timerId) - { t = QEvent::ZeroTimerEvent; } -}; - -struct WinRTTimerInfo // internal timer info -{ - WinRTTimerInfo(int timerId, int timerInterval, Qt::TimerType timerType, QObject *object, QEventDispatcherWinRT *dispatcher) - : isFinished(false), id(timerId), interval(timerInterval), timerType(timerType), obj(object), inTimerEvent(false), dispatcher(dispatcher) - { - } - - void cancel() +#define INTERRUPT_HANDLE 0 +#define INVALID_TIMER_ID -1 + +struct WinRTTimerInfo : public QAbstractEventDispatcher::TimerInfo { + WinRTTimerInfo(int timerId = INVALID_TIMER_ID, int interval = 0, Qt::TimerType timerType = Qt::CoarseTimer, + QObject *obj = 0, quint64 tt = 0) : + QAbstractEventDispatcher::TimerInfo(timerId, interval, timerType), + inEvent(false), object(obj), targetTime(tt) { - if (isFinished) { - delete this; - return; - } - isFinished = true; - if (!timer) - return; - - HRESULT hr = timer->Cancel(); - RETURN_VOID_IF_FAILED("Failed to cancel timer"); } - HRESULT timerExpired(IThreadPoolTimer *) - { - if (isFinished) - return S_OK; - if (dispatcher) - QCoreApplication::postEvent(dispatcher, new QTimerEvent(id)); - return S_OK; - } - - HRESULT timerDestroyed(IThreadPoolTimer *) - { - if (isFinished) - delete this; - else - isFinished = true; - return S_OK; - } - - bool isFinished; - int id; - int interval; - Qt::TimerType timerType; - quint64 timeout; // - when to actually fire - QObject *obj; // - object to receive events - bool inTimerEvent; - ComPtr timer; - QPointer dispatcher; + bool inEvent; + QObject *object; + quint64 targetTime; }; class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate @@ -121,13 +79,63 @@ public: ~QEventDispatcherWinRTPrivate(); private: - QHash timerDict; - ComPtr timerFactory; ComPtr coreDispatcher; QPointer thread; - bool interrupt; + QHash timerIdToObject; + QVector timerInfos; + QHash timerHandleToId; + QHash timerIdToHandle; + QHash timerIdToCancelHandle; + + void addTimer(int id, int interval, Qt::TimerType type, QObject *obj, + HANDLE handle, HANDLE cancelHandle) + { + // Zero timer events do not need these handles. + if (interval > 0) { + timerHandleToId.insert(handle, id); + timerIdToHandle.insert(id, handle); + timerIdToCancelHandle.insert(id, cancelHandle); + } + timerIdToObject.insert(id, obj); + const quint64 targetTime = qt_msectime() + interval; + const WinRTTimerInfo info(id, interval, type, obj, targetTime); + if (id >= timerInfos.size()) + timerInfos.resize(id + 1); + timerInfos[id] = info; + timerIdToObject.insert(id, obj); + } + + bool removeTimer(int id) + { + if (id >= timerInfos.size()) + return false; + + WinRTTimerInfo &info = timerInfos[id]; + if (info.timerId == INVALID_TIMER_ID) + return false; + + if (info.interval > 0 && (!timerIdToHandle.contains(id) || !timerIdToCancelHandle.contains(id))) + return false; + + info.timerId = INVALID_TIMER_ID; + + // Remove invalid timerinfos from the vector's end, if the timer with the highest id was removed + int lastTimer = timerInfos.size() - 1; + while (lastTimer >= 0 && timerInfos.at(lastTimer).timerId == INVALID_TIMER_ID) + --lastTimer; + if (lastTimer >= 0 && lastTimer != timerInfos.size() - 1) + timerInfos.resize(lastTimer + 1); + timerIdToObject.remove(id); + // ... remove handle from all lists + if (info.interval > 0) { + HANDLE handle = timerIdToHandle.take(id); + timerHandleToId.remove(handle); + SetEvent(timerIdToCancelHandle.take(id)); + } + return true; + } void fetchCoreDispatcher() { @@ -183,8 +191,7 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) if (d->thread && d->thread != QThread::currentThread()) d->fetchCoreDispatcher(); - bool didProcess = false; - forever { + do { // Process native events if (d->coreDispatcher) { boolean hasThreadAccess; @@ -197,23 +204,32 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) } // Dispatch accumulated user events - didProcess = sendPostedEvents(flags); - if (didProcess) - break; + if (sendPostedEvents(flags)) + return true; - if (d->interrupt) - break; + emit aboutToBlock(); + const QVector timerHandles = d->timerIdToHandle.values().toVector(); + DWORD waitResult = WaitForMultipleObjectsEx(timerHandles.count(), timerHandles.constData(), FALSE, 1, TRUE); + if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0 + timerHandles.count()) { + const HANDLE handle = timerHandles.value(waitResult - WAIT_OBJECT_0); + const int timerId = d->timerHandleToId.value(handle); + if (timerId == INTERRUPT_HANDLE) + break; - // Short sleep if there is nothing to do - if (!(flags & QEventLoop::WaitForMoreEvents)) - break; + WinRTTimerInfo &info = d->timerInfos[timerId]; + Q_ASSERT(info.timerId != INVALID_TIMER_ID); - emit aboutToBlock(); - WaitForSingleObjectEx(GetCurrentThread(), 1, FALSE); + QCoreApplication::postEvent(this, new QTimerEvent(timerId)); + + // Update timer's targetTime + const quint64 targetTime = qt_msectime() + info.interval; + info.targetTime = targetTime; + emit awake(); + return true; + } emit awake(); - } - d->interrupt = false; - return didProcess; + } while (flags & QEventLoop::WaitForMoreEvents); + return false; } bool QEventDispatcherWinRT::sendPostedEvents(QEventLoop::ProcessEventsFlags flags) @@ -246,104 +262,121 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy { Q_UNUSED(timerType); -#ifndef QT_NO_DEBUG if (timerId < 1 || interval < 0 || !object) { +#ifndef QT_NO_DEBUG qWarning("QEventDispatcherWinRT::registerTimer: invalid arguments"); +#endif return; } else if (object->thread() != thread() || thread() != QThread::currentThread()) { +#ifndef QT_NO_DEBUG qWarning("QEventDispatcherWinRT::registerTimer: timers cannot be started from another thread"); +#endif return; } -#endif Q_D(QEventDispatcherWinRT); - - WinRTTimerInfo *t = new WinRTTimerInfo(timerId, interval, timerType, object, this); - t->timeout = qt_msectime() + interval; - d->timerDict.insert(t->id, t); - // Don't use timer factory for zero-delay timers if (interval == 0u) { - QCoreApplication::postEvent(this, new QZeroTimerEvent(timerId)); + d->addTimer(timerId, interval, timerType, object, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE); + QCoreApplication::postEvent(this, new QTimerEvent(timerId)); return; } TimeSpan period; period.Duration = interval ? (interval * 10000) : 1; // TimeSpan is based on 100-nanosecond units + IThreadPoolTimer *timer; + const HANDLE handle = CreateEventEx(NULL, NULL, NULL, SYNCHRONIZE|EVENT_MODIFY_STATE); + const HANDLE cancelHandle = CreateEventEx(NULL, NULL, NULL, SYNCHRONIZE|EVENT_MODIFY_STATE); HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion( - Callback(t, &WinRTTimerInfo::timerExpired).Get(), period, - Callback(t, &WinRTTimerInfo::timerDestroyed).Get(), &t->timer); + Callback([handle, cancelHandle](IThreadPoolTimer *timer) { + DWORD cancelResult = WaitForSingleObjectEx(cancelHandle, 0, TRUE); + if (cancelResult == WAIT_OBJECT_0) { + timer->Cancel(); + return S_OK; + } + if (!SetEvent(handle)) { + Q_ASSERT_X(false, "QEventDispatcherWinRT::registerTimer", + "SetEvent should never fail here"); + return S_OK; + } + return S_OK; + }).Get(), period, + Callback([handle, cancelHandle](IThreadPoolTimer *) { + CloseHandle(handle); + CloseHandle(cancelHandle); + return S_OK; + }).Get(), &timer); if (FAILED(hr)) { qErrnoWarning(hr, "Failed to create periodic timer"); - delete t; - d->timerDict.remove(t->id); + CloseHandle(handle); + CloseHandle(cancelHandle); return; } + d->addTimer(timerId, interval, timerType, object, handle, cancelHandle); } bool QEventDispatcherWinRT::unregisterTimer(int timerId) { -#ifndef QT_NO_DEBUG if (timerId < 1) { +#ifndef QT_NO_DEBUG qWarning("QEventDispatcherWinRT::unregisterTimer: invalid argument"); +#endif return false; } if (thread() != QThread::currentThread()) { +#ifndef QT_NO_DEBUG qWarning("QEventDispatcherWinRT::unregisterTimer: timers cannot be stopped from another thread"); +#endif return false; } -#endif + // As we post all timer events internally, they have to pe removed to prevent stray events + QCoreApplicationPrivate::removePostedTimerEvent(this, timerId); Q_D(QEventDispatcherWinRT); - - WinRTTimerInfo *t = d->timerDict.take(timerId); - if (!t) - return false; - - t->cancel(); - return true; + return d->removeTimer(timerId); } bool QEventDispatcherWinRT::unregisterTimers(QObject *object) { -#ifndef QT_NO_DEBUG if (!object) { +#ifndef QT_NO_DEBUG qWarning("QEventDispatcherWinRT::unregisterTimers: invalid argument"); +#endif return false; } QThread *currentThread = QThread::currentThread(); if (object->thread() != thread() || thread() != currentThread) { +#ifndef QT_NO_DEBUG qWarning("QEventDispatcherWinRT::unregisterTimers: timers cannot be stopped from another thread"); +#endif return false; } -#endif Q_D(QEventDispatcherWinRT); - for (QHash::iterator it = d->timerDict.begin(); it != d->timerDict.end();) { - if (it.value()->obj == object) { - it.value()->cancel(); - it = d->timerDict.erase(it); - continue; - } - ++it; + foreach (int id, d->timerIdToObject.keys()) { + if (d->timerIdToObject.value(id) == object) + unregisterTimer(id); } + return true; } QList QEventDispatcherWinRT::registeredTimers(QObject *object) const { if (!object) { +#ifndef QT_NO_DEBUG qWarning("QEventDispatcherWinRT:registeredTimers: invalid argument"); +#endif return QList(); } Q_D(const QEventDispatcherWinRT); - QList list; - foreach (const WinRTTimerInfo *t, d->timerDict) { - if (t->obj == object) - list.append(TimerInfo(t->id, t->interval, t->timerType)); + QList timerInfos; + foreach (const WinRTTimerInfo &info, d->timerInfos) { + if (info.object == object) + timerInfos.append(info); } - return list; + return timerInfos; } bool QEventDispatcherWinRT::registerEventNotifier(QWinEventNotifier *notifier) @@ -361,27 +394,30 @@ void QEventDispatcherWinRT::unregisterEventNotifier(QWinEventNotifier *notifier) int QEventDispatcherWinRT::remainingTime(int timerId) { -#ifndef QT_NO_DEBUG if (timerId < 1) { +#ifndef QT_NO_DEBUG qWarning("QEventDispatcherWinRT::remainingTime: invalid argument"); +#endif return -1; } -#endif Q_D(QEventDispatcherWinRT); - if (WinRTTimerInfo *t = d->timerDict.value(timerId)) { - const quint64 currentTime = qt_msectime(); - if (currentTime < t->timeout) { - // time to wait - return t->timeout - currentTime; - } else { - return 0; - } - } - + const WinRTTimerInfo timerInfo = d->timerInfos.at(timerId); + if (timerInfo.timerId == INVALID_TIMER_ID) { #ifndef QT_NO_DEBUG - qWarning("QEventDispatcherWinRT::remainingTime: timer id %d not found", timerId); + qWarning("QEventDispatcherWinRT::remainingTime: timer id %d not found", timerId); #endif + return -1; + } + + const quint64 currentTime = qt_msectime(); + if (currentTime < timerInfo.targetTime) { + // time to wait + return timerInfo.targetTime - currentTime; + } else { + return 0; + } + return -1; } @@ -392,7 +428,7 @@ void QEventDispatcherWinRT::wakeUp() void QEventDispatcherWinRT::interrupt() { Q_D(QEventDispatcherWinRT); - d->interrupt = true; + SetEvent(d->timerIdToHandle.value(INTERRUPT_HANDLE)); } void QEventDispatcherWinRT::flush() @@ -405,55 +441,60 @@ void QEventDispatcherWinRT::startingUp() void QEventDispatcherWinRT::closingDown() { - Q_D(QEventDispatcherWinRT); - d->timerDict.clear(); } bool QEventDispatcherWinRT::event(QEvent *e) { Q_D(QEventDispatcherWinRT); - bool ret = false; switch (e->type()) { - case QEvent::ZeroTimerEvent: - ret = true; - // fall through case QEvent::Timer: { QTimerEvent *timerEvent = static_cast(e); const int id = timerEvent->timerId(); - if (WinRTTimerInfo *t = d->timerDict.value(id)) { - if (t->inTimerEvent) // but don't allow event to recurse - break; - t->inTimerEvent = true; + Q_ASSERT(id < d->timerInfos.size()); + WinRTTimerInfo &info = d->timerInfos[id]; + Q_ASSERT(info.timerId != INVALID_TIMER_ID); - QTimerEvent te(id); - QCoreApplication::sendEvent(t->obj, &te); + if (info.inEvent) // but don't allow event to recurse + break; + info.inEvent = true; - if (t = d->timerDict.value(id)) { - if (t->interval == 0 && t->inTimerEvent) { - // post the next zero timer event as long as the timer was not restarted - QCoreApplication::postEvent(this, new QZeroTimerEvent(id)); - } - t->inTimerEvent = false; - } + QTimerEvent te(id); + QCoreApplication::sendEvent(d->timerIdToObject.value(id), &te); + + // The timer might have been removed in the meanwhile + if (id >= d->timerInfos.size()) + break; + + info = d->timerInfos[id]; + if (info.timerId == INVALID_TIMER_ID) + break; + + if (info.interval == 0 && info.inEvent) { + // post the next zero timer event as long as the timer was not restarted + QCoreApplication::postEvent(this, new QTimerEvent(id)); } + info.inEvent = false; } default: break; } - return ret ? true : QAbstractEventDispatcher::event(e); + return QAbstractEventDispatcher::event(e); } QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate() - : interrupt(false) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory); - if (FAILED(hr)) - qWarning("QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate: Could not obtain timer factory: %lx", hr); + Q_ASSERT_SUCCEEDED(hr); + HANDLE interruptHandle = CreateEventEx(NULL, NULL, NULL, SYNCHRONIZE|EVENT_MODIFY_STATE); + timerIdToHandle.insert(INTERRUPT_HANDLE, interruptHandle); + timerHandleToId.insert(interruptHandle, INTERRUPT_HANDLE); + timerInfos.reserve(256); } QEventDispatcherWinRTPrivate::~QEventDispatcherWinRTPrivate() { + CloseHandle(timerIdToHandle.value(INTERRUPT_HANDLE)); CoUninitialize(); } -- cgit v1.2.3 From 6526a4e1367fa134ff29952fcbdd0d7cc937003f Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Fri, 17 Apr 2015 10:29:04 +0200 Subject: qdoc: Remove #ifdef Q_QDOC for uses of QPrivateSignal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signals marked with QPrivateSignal had the QPrivateSignal marker ifdefed out for qdoc. This is no longer necessary, so the #ifdefs are removed. Change-Id: Idb334ed311c6ed6883d7b7b5a3fcdede60c4a1f8 Task-number: QTBUG-45535 Reviewed-by: Oswald Buddenhagen Reviewed-by: Giuseppe D'Angelo Reviewed-by: Topi Reiniö --- src/corelib/io/qfilesystemwatcher.h | 12 +--- src/corelib/io/qprocess.h | 24 ++------ src/corelib/itemmodels/qabstractitemmodel.h | 84 +++++--------------------- src/corelib/itemmodels/qabstractproxymodel.h | 6 +- src/corelib/kernel/qcoreapplication.h | 6 +- src/corelib/kernel/qobject.h | 6 +- src/corelib/kernel/qsocketnotifier.h | 6 +- src/corelib/kernel/qtimer.h | 6 +- src/corelib/kernel/qwineventnotifier.h | 6 +- src/corelib/statemachine/qabstractstate.h | 12 +--- src/corelib/statemachine/qabstracttransition.h | 18 +----- src/corelib/statemachine/qhistorystate.h | 12 +--- src/corelib/statemachine/qsignaltransition.h | 12 +--- src/corelib/statemachine/qstate.h | 30 ++------- src/corelib/statemachine/qstatemachine.h | 12 +--- src/corelib/thread/qthread.h | 12 +--- src/corelib/tools/qtimeline.h | 24 ++------ 17 files changed, 48 insertions(+), 240 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qfilesystemwatcher.h b/src/corelib/io/qfilesystemwatcher.h index 57dac802e8..13d1782913 100644 --- a/src/corelib/io/qfilesystemwatcher.h +++ b/src/corelib/io/qfilesystemwatcher.h @@ -62,16 +62,8 @@ public: QStringList directories() const; Q_SIGNALS: - void fileChanged(const QString &path -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void directoryChanged(const QString &path -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void fileChanged(const QString &path, QPrivateSignal); + void directoryChanged(const QString &path, QPrivateSignal); private: Q_PRIVATE_SLOT(d_func(), void _q_fileChanged(const QString &path, bool removed)) diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 54cf37b717..078217ea0b 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -223,30 +223,14 @@ public Q_SLOTS: void kill(); Q_SIGNALS: - void started( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void started(QPrivateSignal); void finished(int exitCode); // ### Qt 6: merge the two signals with a default value void finished(int exitCode, QProcess::ExitStatus exitStatus); void error(QProcess::ProcessError error); - void stateChanged(QProcess::ProcessState state -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void stateChanged(QProcess::ProcessState state, QPrivateSignal); - void readyReadStandardOutput( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void readyReadStandardError( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void readyReadStandardOutput(QPrivateSignal); + void readyReadStandardError(QPrivateSignal); protected: void setProcessState(ProcessState state); diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h index c4f705e858..5ca7bd0123 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.h +++ b/src/corelib/itemmodels/qabstractitemmodel.h @@ -246,82 +246,26 @@ Q_SIGNALS: void layoutChanged(const QList &parents = QList(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint); void layoutAboutToBeChanged(const QList &parents = QList(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint); - void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void rowsInserted(const QModelIndex &parent, int first, int last -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last, QPrivateSignal); + void rowsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal); - void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void rowsRemoved(const QModelIndex &parent, int first, int last -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal); + void rowsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal); - void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void columnsInserted(const QModelIndex &parent, int first, int last -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last, QPrivateSignal); + void columnsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal); - void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void columnsRemoved(const QModelIndex &parent, int first, int last -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal); + void columnsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal); - void modelAboutToBeReset( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void modelReset( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void modelAboutToBeReset(QPrivateSignal); + void modelReset(QPrivateSignal); - void rowsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void rowsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal); + void rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row, QPrivateSignal); - void columnsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void columnsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void columnsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn, QPrivateSignal); + void columnsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column, QPrivateSignal); public Q_SLOTS: virtual bool submit(); diff --git a/src/corelib/itemmodels/qabstractproxymodel.h b/src/corelib/itemmodels/qabstractproxymodel.h index afd5a1f616..dc8d2d4dc8 100644 --- a/src/corelib/itemmodels/qabstractproxymodel.h +++ b/src/corelib/itemmodels/qabstractproxymodel.h @@ -92,11 +92,7 @@ public: Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE; Q_SIGNALS: - void sourceModelChanged( -#if !defined(qdoc) - QPrivateSignal -#endif - ); + void sourceModelChanged(QPrivateSignal); protected Q_SLOTS: void resetInternalData(); diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index e1fc364cd1..1cd835daae 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -171,11 +171,7 @@ public Q_SLOTS: static void quit(); Q_SIGNALS: - void aboutToQuit( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void aboutToQuit(QPrivateSignal); void organizationNameChanged(); void organizationDomainChanged(); diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index ecea13fc4a..5f61dd984f 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -413,11 +413,7 @@ public: Q_SIGNALS: void destroyed(QObject * = 0); - void objectNameChanged(const QString &objectName -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void objectNameChanged(const QString &objectName, QPrivateSignal); public: inline QObject *parent() const { return d_ptr->parent; } diff --git a/src/corelib/kernel/qsocketnotifier.h b/src/corelib/kernel/qsocketnotifier.h index c6e9d1e13f..4bafbfa69f 100644 --- a/src/corelib/kernel/qsocketnotifier.h +++ b/src/corelib/kernel/qsocketnotifier.h @@ -59,11 +59,7 @@ public Q_SLOTS: void setEnabled(bool); Q_SIGNALS: - void activated(int socket -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void activated(int socket, QPrivateSignal); protected: bool event(QEvent *) Q_DECL_OVERRIDE; diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index dc948228b4..163ef75291 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -141,11 +141,7 @@ public Q_SLOTS: void stop(); Q_SIGNALS: - void timeout( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void timeout(QPrivateSignal); protected: void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE; diff --git a/src/corelib/kernel/qwineventnotifier.h b/src/corelib/kernel/qwineventnotifier.h index 07a0b29d97..95fdff07ce 100644 --- a/src/corelib/kernel/qwineventnotifier.h +++ b/src/corelib/kernel/qwineventnotifier.h @@ -61,11 +61,7 @@ public Q_SLOTS: void setEnabled(bool enable); Q_SIGNALS: - void activated(HANDLE hEvent -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); + void activated(HANDLE hEvent, QPrivateSignal); protected: bool event(QEvent * e); diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h index b6eb742acb..592c841c18 100644 --- a/src/corelib/statemachine/qabstractstate.h +++ b/src/corelib/statemachine/qabstractstate.h @@ -58,16 +58,8 @@ public: bool active() const; Q_SIGNALS: - void entered( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void exited( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void entered(QPrivateSignal); + void exited(QPrivateSignal); void activeChanged(bool active); protected: diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h index 0f1bbdad71..768a364a4b 100644 --- a/src/corelib/statemachine/qabstracttransition.h +++ b/src/corelib/statemachine/qabstracttransition.h @@ -78,21 +78,9 @@ public: #endif Q_SIGNALS: - void triggered( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void targetStateChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void targetStatesChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void triggered(QPrivateSignal); + void targetStateChanged(QPrivateSignal); + void targetStatesChanged(QPrivateSignal); protected: virtual bool eventTest(QEvent *event) = 0; diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h index 31f0d3121b..549be15ab0 100644 --- a/src/corelib/statemachine/qhistorystate.h +++ b/src/corelib/statemachine/qhistorystate.h @@ -65,16 +65,8 @@ public: void setHistoryType(HistoryType type); Q_SIGNALS: - void defaultStateChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void historyTypeChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void defaultStateChanged(QPrivateSignal); + void historyTypeChanged(QPrivateSignal); protected: void onEntry(QEvent *event) Q_DECL_OVERRIDE; diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h index 8b9e63404a..bc56f4e9b7 100644 --- a/src/corelib/statemachine/qsignaltransition.h +++ b/src/corelib/statemachine/qsignaltransition.h @@ -67,16 +67,8 @@ protected: bool event(QEvent *e) Q_DECL_OVERRIDE; Q_SIGNALS: - void senderObjectChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void signalChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void senderObjectChanged(QPrivateSignal); + void signalChanged(QPrivateSignal); private: Q_DISABLE_COPY(QSignalTransition) diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h index b1f2ad05bc..a74c782027 100644 --- a/src/corelib/statemachine/qstate.h +++ b/src/corelib/statemachine/qstate.h @@ -103,31 +103,11 @@ public: #endif Q_SIGNALS: - void finished( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void propertiesAssigned( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void childModeChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void initialStateChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void errorStateChanged( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void finished(QPrivateSignal); + void propertiesAssigned(QPrivateSignal); + void childModeChanged(QPrivateSignal); + void initialStateChanged(QPrivateSignal); + void errorStateChanged(QPrivateSignal); protected: void onEntry(QEvent *event) Q_DECL_OVERRIDE; diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index 7837e6ec5f..d6c3b7bfa7 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -145,16 +145,8 @@ public Q_SLOTS: void setRunning(bool running); Q_SIGNALS: - void started( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void stopped( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void started(QPrivateSignal); + void stopped(QPrivateSignal); void runningChanged(bool running); diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index 58755b9625..bfc469583d 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -106,16 +106,8 @@ public: static void usleep(unsigned long); Q_SIGNALS: - void started( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); - void finished( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void started(QPrivateSignal); + void finished(QPrivateSignal); protected: virtual void run(); diff --git a/src/corelib/tools/qtimeline.h b/src/corelib/tools/qtimeline.h index 388e88d641..21139b37a8 100644 --- a/src/corelib/tools/qtimeline.h +++ b/src/corelib/tools/qtimeline.h @@ -115,26 +115,10 @@ public Q_SLOTS: void toggleDirection(); Q_SIGNALS: - void valueChanged(qreal x -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void frameChanged(int -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void stateChanged(QTimeLine::State newState -#if !defined(Q_QDOC) - , QPrivateSignal -#endif - ); - void finished( -#if !defined(Q_QDOC) - QPrivateSignal -#endif - ); + void valueChanged(qreal x, QPrivateSignal); + void frameChanged(int, QPrivateSignal); + void stateChanged(QTimeLine::State newState, QPrivateSignal); + void finished(QPrivateSignal); protected: void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; -- cgit v1.2.3 From 8fb881900c7bb7895e7a2109a7dc880954bcf3a9 Mon Sep 17 00:00:00 2001 From: Harald Hvaal Date: Sat, 28 Mar 2015 21:03:29 +0100 Subject: Enable checking for whether the system palette was explicitly set In order to obey a palette set globally on QApplication, an application attribute for checking if it's set at all is added. Task-number: QTBUG-39800 Change-Id: I26b965e6e18e0e1ca4df03cf343b3527df3636b2 Reviewed-by: J-P Nurmi Reviewed-by: Friedemann Kleint --- src/corelib/global/qnamespace.h | 1 + src/corelib/global/qnamespace.qdoc | 3 +++ src/gui/kernel/qguiapplication.cpp | 1 + src/widgets/kernel/qapplication.cpp | 1 + 4 files changed, 6 insertions(+) (limited to 'src') diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 745fb442f2..79ddf81b38 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -492,6 +492,7 @@ public: AA_UseOpenGLES = 16, AA_UseSoftwareOpenGL = 17, AA_ShareOpenGLContexts = 18, + AA_SetPalette = 19, // Add new attributes before this line AA_AttributeCount diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 8ebe0da11f..f9d968d47b 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -194,6 +194,9 @@ instances that belong to different top-level windows. This value has been added in Qt 5.4. + \value AA_SetPalette Indicates whether a palette was explicitly set on the + QApplication/QGuiApplication. This value has been added in Qt 5.5. + The following values are obsolete: \value AA_ImmediateWidgetCreation This attribute is no longer fully diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 3e2b692cd0..926ec16f19 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2757,6 +2757,7 @@ void QGuiApplication::setPalette(const QPalette &pal) else *QGuiApplicationPrivate::app_pal = pal; applicationResourceFlags |= ApplicationPaletteExplicitlySet; + QCoreApplication::setAttribute(Qt::AA_SetPalette); emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal); } diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 00f590ebc2..ed10beddd4 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -1508,6 +1508,7 @@ void QApplicationPrivate::setPalette_helper(const QPalette &palette, const char* QApplicationPrivate::set_pal = new QPalette(palette); else *QApplicationPrivate::set_pal = palette; + QCoreApplication::setAttribute(Qt::AA_SetPalette); } } -- cgit v1.2.3 From 280084cf96eb1d7fa8dba580866477c572a976c9 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 17 Apr 2015 09:33:54 +0200 Subject: QFileDialog: save settings to FileDialog group instead of serialized The byte array serialization needed versioning, whereas a collection of separate settings is more robust and accessible. Task-number: QTBUG-36888 Change-Id: I790b1d7574707261923a7a33ccd8bcc596a69de5 Reviewed-by: David Faure --- src/widgets/dialogs/qfiledialog.cpp | 149 +++++++++++++++++++++++++++--------- src/widgets/dialogs/qfiledialog_p.h | 6 ++ 2 files changed, 120 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 6a1374e3ee..9e5548ab4c 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -331,6 +331,7 @@ QT_BEGIN_INCLUDE_NAMESPACE #ifdef Q_DEAD_CODE_FROM_QT4_WIN #include #endif +#include #include #ifdef Q_DEAD_CODE_FROM_QT4_MAC #include @@ -385,9 +386,8 @@ QFileDialog::QFileDialog(const QFileDialogArgs &args) QFileDialog::~QFileDialog() { #ifndef QT_NO_SETTINGS - QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - settings.beginGroup(QLatin1String("Qt")); - settings.setValue(QLatin1String("filedialog"), saveState()); + Q_D(QFileDialog); + d->saveSettings(); #endif } @@ -503,34 +503,7 @@ bool QFileDialog::restoreState(const QByteArray &state) if (!d->usingWidgets()) return true; - if (!d->qFileDialogUi->splitter->restoreState(d->splitterState)) - return false; - QList list = d->qFileDialogUi->splitter->sizes(); - if (list.count() >= 2 && (list.at(0) == 0 || list.at(1) == 0)) { - for (int i = 0; i < list.count(); ++i) - list[i] = d->qFileDialogUi->splitter->widget(i)->sizeHint().width(); - d->qFileDialogUi->splitter->setSizes(list); - } - - d->qFileDialogUi->sidebar->setUrls(d->sidebarUrls); - while (history.count() > 5) - history.pop_front(); - setHistory(history); - QHeaderView *headerView = d->qFileDialogUi->treeView->header(); - if (!headerView->restoreState(d->headerData)) - return false; - - QList actions = headerView->actions(); - QAbstractItemModel *abstractModel = d->model; -#ifndef QT_NO_PROXYMODEL - if (d->proxyModel) - abstractModel = d->proxyModel; -#endif - int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1); - for (int i = 1; i < total; ++i) - actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i)); - - return true; + return d->restoreWidgetState(history, -1); } /*! @@ -2670,6 +2643,104 @@ void QFileDialog::accept() } } +#ifndef QT_NO_SETTINGS +void QFileDialogPrivate::saveSettings() +{ + Q_Q(QFileDialog); + QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); + settings.beginGroup(QLatin1String("FileDialog")); + + if (usingWidgets()) { + settings.setValue(QLatin1String("sidebarWidth"), qFileDialogUi->splitter->sizes().first()); + settings.setValue(QLatin1String("shortcuts"), QUrl::toStringList(qFileDialogUi->sidebar->urls())); + settings.setValue(QLatin1String("treeViewHeader"), qFileDialogUi->treeView->header()->saveState()); + } + QStringList historyUrls; + foreach (const QString &path, q->history()) + historyUrls << QUrl::fromLocalFile(path).toString(); + settings.setValue(QLatin1String("history"), historyUrls); + settings.setValue(QLatin1String("lastVisited"), lastVisitedDir()->toString()); + const QMetaEnum &viewModeMeta = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewMode")); + settings.setValue(QLatin1String("viewMode"), QLatin1String(viewModeMeta.key(q->viewMode()))); + settings.setValue(QLatin1String("qtVersion"), QLatin1String(QT_VERSION_STR)); +} + +bool QFileDialogPrivate::restoreFromSettings() +{ + Q_Q(QFileDialog); + QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); + if (!settings.childGroups().contains(QLatin1String("FileDialog"))) + return false; + settings.beginGroup(QLatin1String("FileDialog")); + + q->setDirectoryUrl(lastVisitedDir()->isEmpty() ? settings.value(QLatin1String("lastVisited")).toUrl() : *lastVisitedDir()); + + QByteArray viewModeStr = settings.value(QLatin1String("viewMode")).toString().toLatin1(); + const QMetaEnum &viewModeMeta = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewMode")); + bool ok = false; + int viewMode = viewModeMeta.keyToValue(viewModeStr.constData(), &ok); + if (!ok) + viewMode = QFileDialog::List; + q->setViewMode(static_cast(viewMode)); + + sidebarUrls = QUrl::fromStringList(settings.value(QLatin1String("shortcuts")).toStringList()); + headerData = settings.value(QLatin1String("treeViewHeader")).toByteArray(); + + if (!usingWidgets()) + return true; + + QStringList history; + foreach (const QString &urlStr, settings.value(QLatin1String("history")).toStringList()) { + QUrl url(urlStr); + if (url.isLocalFile()) + history << url.toLocalFile(); + } + + return restoreWidgetState(history, settings.value(QLatin1String("sidebarWidth"), -1).toInt()); +} +#endif // QT_NO_SETTINGS + +bool QFileDialogPrivate::restoreWidgetState(QStringList &history, int splitterPosition) +{ + Q_Q(QFileDialog); + if (splitterPosition >= 0) { + QList splitterSizes; + splitterSizes.append(splitterPosition); + splitterSizes.append(qFileDialogUi->splitter->widget(1)->sizeHint().width()); + qFileDialogUi->splitter->setSizes(splitterSizes); + } else { + if (!qFileDialogUi->splitter->restoreState(splitterState)) + return false; + QList list = qFileDialogUi->splitter->sizes(); + if (list.count() >= 2 && (list.at(0) == 0 || list.at(1) == 0)) { + for (int i = 0; i < list.count(); ++i) + list[i] = qFileDialogUi->splitter->widget(i)->sizeHint().width(); + qFileDialogUi->splitter->setSizes(list); + } + } + + qFileDialogUi->sidebar->setUrls(sidebarUrls); + while (history.count() > 5) + history.pop_front(); + q->setHistory(history); + + QHeaderView *headerView = qFileDialogUi->treeView->header(); + if (!headerView->restoreState(headerData)) + return false; + + QList actions = headerView->actions(); + QAbstractItemModel *abstractModel = model; +#ifndef QT_NO_PROXYMODEL + if (proxyModel) + abstractModel = proxyModel; +#endif + int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1); + for (int i = 1; i < total; ++i) + actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i)); + + return true; +} + /*! \internal @@ -2696,8 +2767,12 @@ void QFileDialogPrivate::init(const QUrl &directory, const QString &nameFilter, q->selectFile(initialSelection(directory)); #ifndef QT_NO_SETTINGS - const QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - q->restoreState(settings.value(QLatin1String("Qt/filedialog")).toByteArray()); + // Try to restore from the FileDialog settings group; if it fails, fall back + // to the pre-5.5 QByteArray serialized settings. + if (!restoreFromSettings()) { + const QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); + q->restoreState(settings.value(QLatin1String("Qt/filedialog")).toByteArray()); + } #endif #if defined(Q_EMBEDDED_SMALLSCREEN) @@ -2845,8 +2920,12 @@ void QFileDialogPrivate::createWidgets() createMenuActions(); #ifndef QT_NO_SETTINGS - const QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); - q->restoreState(settings.value(QLatin1String("Qt/filedialog")).toByteArray()); + // Try to restore from the FileDialog settings group; if it fails, fall back + // to the pre-5.5 QByteArray serialized settings. + if (!restoreFromSettings()) { + const QSettings settings(QSettings::UserScope, QLatin1String("QtProject")); + q->restoreState(settings.value(QLatin1String("Qt/filedialog")).toByteArray()); + } #endif // Initial widget states from options diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h index 9eb08f7a3a..8a10896966 100644 --- a/src/widgets/dialogs/qfiledialog_p.h +++ b/src/widgets/dialogs/qfiledialog_p.h @@ -181,6 +181,12 @@ public: #endif } +#ifndef QT_NO_SETTINGS + void saveSettings(); + bool restoreFromSettings(); +#endif + + bool restoreWidgetState(QStringList &history, int splitterPosition); void setLastVisitedDirectory(const QUrl &dir); void retranslateWindowTitle(); void retranslateStrings(); -- cgit v1.2.3 From ad03511256a8279a8f55069e5a3a3465a9e122ec Mon Sep 17 00:00:00 2001 From: Nikita Baryshnikov Date: Thu, 9 Apr 2015 13:41:19 +0300 Subject: QDir: fix int overflow This caused reverse order of session items in qt creator. Introduced in ba287c55ef179b073482453298f513992b54c11e. Change-Id: I5c37ca6a1ef4753b6449eb9e87b4def5ea858677 Reviewed-by: Marc Mutz --- src/corelib/io/qdir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 8380404219..3a9ae2ee6d 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -219,7 +219,7 @@ bool QDirSortItemComparator::operator()(const QDirSortItem &n1, const QDirSortIt if ((qt_cmp_si_sort_flags & QDir::DirsLast) && (f1->item.isDir() != f2->item.isDir())) return !f1->item.isDir(); - int r = 0; + qint64 r = 0; int sortBy = (qt_cmp_si_sort_flags & QDir::SortByMask) | (qt_cmp_si_sort_flags & QDir::Type); -- cgit v1.2.3 From 84ad1294401bbbeddee33427c76df41715cc9f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Thu, 19 Mar 2015 20:23:31 +0000 Subject: Fix inconsistent overrides. [-Winconsistent-missing-override] Change-Id: I7c27632cdda13ebc8ee5d2bc18d9ba64c1f4ec70 Reviewed-by: Marc Mutz --- src/tools/qdoc/node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h index 85e724b9ca..2ccd97dbd1 100644 --- a/src/tools/qdoc/node.h +++ b/src/tools/qdoc/node.h @@ -410,7 +410,7 @@ public: void printChildren(const QString& title); void addChild(Node* child); void removeChild(Node* child); - virtual void setOutputSubdirectory(const QString& t); + void setOutputSubdirectory(const QString& t) Q_DECL_OVERRIDE; protected: InnerNode(Type type, InnerNode* parent, const QString& name); -- cgit v1.2.3 From 9286a8e5dd97c5d4d7e0ed07a73d4ce7240fdc1d Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Mon, 20 Apr 2015 02:54:01 +0200 Subject: Understand file:/ url's as local When making a QNetworkAccessManager query, don't require a network session in case of file:/ queries, like we do when "localhost" is the hostname or a loopback device. Change-Id: I4faab7cf356ee53e6e13ab55b152365680af9446 Reviewed-by: Albert Astals Cid Reviewed-by: Richard J. Moore --- src/network/access/qnetworkaccessbackend.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index 183afadf17..692af1b2fc 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -383,7 +383,8 @@ bool QNetworkAccessBackend::start() const QString host = reply->url.host(); if (host == QLatin1String("localhost") || - QHostAddress(host).isLoopback()) { + QHostAddress(host).isLoopback() || + reply->url.isLocalFile()) { // Don't need an open session for localhost access. } else { // need to wait for session to be opened -- cgit v1.2.3 From bf23091e6b29a5ca0875ca281ed346c8493b9396 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 26 Mar 2015 11:24:07 +0100 Subject: Cocoa integration - invalid window state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QCocoaWindow::syncWindowState incorrectly sets m_effectivelyMaximized as !m_effectivelyMaximized after calling zoom. But zoom can trigger windowDidEndLiveResize, which also can set m_effectivelyMaximized, so double negation results in ... the previous value. Fixed. Change-Id: Iea974132a1854a258e27635e8779d7d8c02bfc0c Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index ec289aba99..8ee21b121b 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1510,10 +1510,11 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) } } + const bool effMax = m_effectivelyMaximized; if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) { if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) { [m_nsWindow zoom : m_nsWindow]; // toggles - m_effectivelyMaximized = !m_effectivelyMaximized; + m_effectivelyMaximized = !effMax; } else if (!(newState & Qt::WindowMaximized)) { // it would be nice to change the target geometry that toggleFullScreen will animate toward // but there is no known way, so the maximized state is not possible at this time -- cgit v1.2.3 From 4d2b7e5f2e1e2c3dfe69eb600d330c398a999df9 Mon Sep 17 00:00:00 2001 From: Bjoern Breitmeyer Date: Thu, 19 Mar 2015 11:08:52 +0100 Subject: Remove libs that are already set by the mkspec. Change-Id: I79c47e5a49ce048c634e4bc708b632e51133c027 Reviewed-by: Oswald Buddenhagen Reviewed-by: Friedemann Kleint --- src/testlib/testlib.pro | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index 83f217dde9..52bcdd097b 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -64,8 +64,7 @@ DEFINES *= QT_NO_CAST_TO_ASCII \ QT_NO_CAST_FROM_ASCII \ QT_NO_DATASTREAM embedded:QMAKE_CXXFLAGS += -fno-rtti -wince*::LIBS += libcmt.lib \ - corelibc.lib \ +wince: LIBS += \ ole32.lib \ oleaut32.lib \ uuid.lib \ -- cgit v1.2.3 From a989e5c54fd2f97bd3fd9b9da9d2b677c64c7ea8 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 16 Apr 2015 15:47:15 +0200 Subject: Enhance QWindow::devicePixelRatio() docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document that fact that for non-create()'ed windows this is the same as QGuiApplication::devicePixelRatio() which is the highest dpr in the system. This has consequences when running with multiple displays so application developer's have to be aware of this. Change-Id: Ic05a18732ff021659da04428cb49421ac3453870 Reviewed-by: Morten Johan Sørvig --- src/gui/kernel/qwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index c0f953bcef..a1057691f2 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1075,6 +1075,10 @@ Qt::ScreenOrientation QWindow::contentOrientation() const Common values are 1.0 on normal displays and 2.0 on Apple "retina" displays. + \note For windows not backed by a platform window, meaning that create() was not + called, the function will fall back to QGuiApplication::devicePixelRatio() which in + turn returns the highest screen device pixel ratio found on the system. + \sa QScreen::devicePixelRatio(), QGuiApplication::devicePixelRatio() */ qreal QWindow::devicePixelRatio() const -- cgit v1.2.3 From 8e380c2021aa40796e7924c70d9906cfbd6ab677 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 16 Apr 2015 20:00:11 +0200 Subject: remove redundant definition of ANGLE_ENABLE_D3D11 config.pri already defines it (as needed). Change-Id: If0e87d23a560c6de37457b2d8d3a84b6dc16396f Reviewed-by: Andrew Knight --- src/angle/src/libGLESv2/libGLESv2.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/angle/src/libGLESv2/libGLESv2.pro b/src/angle/src/libGLESv2/libGLESv2.pro index a783318bb1..1bf9af0436 100644 --- a/src/angle/src/libGLESv2/libGLESv2.pro +++ b/src/angle/src/libGLESv2/libGLESv2.pro @@ -20,7 +20,7 @@ for(libname, STATICLIBS) { PRE_TARGETDEPS += $$staticlib } -DEFINES += LIBANGLE_IMPLEMENTATION LIBGLESV2_IMPLEMENTATION GL_APICALL= GL_GLEXT_PROTOTYPES= EGLAPI= ANGLE_ENABLE_D3D11 +DEFINES += LIBANGLE_IMPLEMENTATION LIBGLESV2_IMPLEMENTATION GL_APICALL= GL_GLEXT_PROTOTYPES= EGLAPI= !winrt: DEFINES += ANGLE_ENABLE_D3D9 ANGLE_SKIP_DXGI_1_2_CHECK HEADERS += \ -- cgit v1.2.3 From 628fa13ea4d6ff0e2e2ee76c9adfc78676de3c59 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 21 Apr 2015 16:11:20 +0200 Subject: Fix "Unsupported extension used" error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This error message was a result of calling *_randr_* functions in QXcbWindow::updateGeometry without checking if the X server provides the XRandR extension. Change-Id: I165f201c32ca0f4976f9ff9b9f17323098940511 Task-number: QTBUG-45624 Task-number: QTBUG-45388 Task-number: QTBUG-45312 Reviewed-by: Laszlo Agocs Reviewed-by: Shawn Rutledge Reviewed-by: Jan Kundrát --- src/plugins/platforms/xcb/qxcbscreen.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index bcaa13eb1e..a0d6d88d11 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -468,6 +468,9 @@ void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *chan void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp) { + if (!connection()->hasXRandr()) + return; + xcb_randr_get_crtc_info_cookie_t crtcCookie = xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, timestamp); xcb_randr_get_crtc_info_reply_t *crtc = -- cgit v1.2.3