summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/angle/angle.pro1
-rw-r--r--src/angle/d3dcompiler/d3dcompiler.pro11
-rw-r--r--src/angle/d3dcompiler/d3dcompiler_qt.def3
-rw-r--r--src/angle/d3dcompiler/d3dcompiler_qtd.def3
-rw-r--r--src/angle/d3dcompiler/main.cpp295
-rw-r--r--src/src.pro1
-rw-r--r--tests/auto/other/d3dcompiler/d3dcompiler.pro5
-rw-r--r--tests/auto/other/d3dcompiler/tst_d3dcompiler.cpp358
-rw-r--r--tests/auto/other/other.pro3
9 files changed, 680 insertions, 0 deletions
diff --git a/src/angle/angle.pro b/src/angle/angle.pro
index 83510698d3..a8040428d1 100644
--- a/src/angle/angle.pro
+++ b/src/angle/angle.pro
@@ -1,5 +1,6 @@
TEMPLATE = subdirs
SUBDIRS += src
+angle_d3d11: SUBDIRS += d3dcompiler
# We do it this way instead of letting load(qt_module) handle it for two reasons:
# 1) qt_module_headers assumes the TARGET is the same as the include directory (eg: libGLESv2 != GLES2)
diff --git a/src/angle/d3dcompiler/d3dcompiler.pro b/src/angle/d3dcompiler/d3dcompiler.pro
new file mode 100644
index 0000000000..35b9be2025
--- /dev/null
+++ b/src/angle/d3dcompiler/d3dcompiler.pro
@@ -0,0 +1,11 @@
+TEMPLATE = lib
+TARGET = $$qtLibraryTarget(d3dcompiler_qt)
+DLLDESTDIR = $$QT_BUILD_TREE/bin
+
+QT = core
+DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
+SOURCES += main.cpp
+win32:!winrt: LIBS += -lole32
+
+# __stdcall exports get mangled, so use a def file
+DEF_FILE += $${TARGET}.def
diff --git a/src/angle/d3dcompiler/d3dcompiler_qt.def b/src/angle/d3dcompiler/d3dcompiler_qt.def
new file mode 100644
index 0000000000..0b8679c8e0
--- /dev/null
+++ b/src/angle/d3dcompiler/d3dcompiler_qt.def
@@ -0,0 +1,3 @@
+LIBRARY d3dcompiler_qt
+EXPORTS
+ D3DCompile @1
diff --git a/src/angle/d3dcompiler/d3dcompiler_qtd.def b/src/angle/d3dcompiler/d3dcompiler_qtd.def
new file mode 100644
index 0000000000..0bdd0a1ffd
--- /dev/null
+++ b/src/angle/d3dcompiler/d3dcompiler_qtd.def
@@ -0,0 +1,3 @@
+LIBRARY d3dcompiler_qtd
+EXPORTS
+ D3DCompile @1
diff --git a/src/angle/d3dcompiler/main.cpp b/src/angle/d3dcompiler/main.cpp
new file mode 100644
index 0000000000..96d71d5e0d
--- /dev/null
+++ b/src/angle/d3dcompiler/main.cpp
@@ -0,0 +1,295 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QByteArray>
+#include <QCryptographicHash>
+#include <QDateTime>
+#include <QDir>
+#include <QElapsedTimer>
+#include <QFile>
+#include <QLoggingCategory>
+#include <QStandardPaths>
+#include <QThread>
+
+#include <qt_windows.h>
+#include <d3dcommon.h>
+
+Q_LOGGING_CATEGORY(QT_D3DCOMPILER, "qt.angle.d3dcompiler")
+
+namespace D3DCompiler {
+
+typedef HRESULT (WINAPI *D3DCompileFunc)(const void *data, SIZE_T data_size, const char *filename,
+ const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint,
+ const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages);
+static D3DCompileFunc compile;
+
+class Blob : public ID3DBlob
+{
+public:
+ Blob(const QByteArray &data) : m_data(data)
+ {
+ IIDFromString(L"00000000-0000-0000-C000-000000000046", &IID_IUnknown);
+ IIDFromString(L"8BA5FB08-5195-40e2-AC58-0D989C3A0102", &IID_ID3DBlob);
+ }
+
+ virtual ~Blob()
+ {
+ }
+
+ // ID3DBlob
+ LPVOID __stdcall GetBufferPointer()
+ {
+ return m_data.data();
+ }
+
+ SIZE_T __stdcall GetBufferSize()
+ {
+ return m_data.size();
+ }
+
+ // IUnknown
+ HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
+ {
+ IUnknown *out = 0;
+ if (riid == IID_IUnknown)
+ out = static_cast<IUnknown*>(this);
+ else if (riid == IID_ID3DBlob)
+ out = this;
+
+ *ppv = out;
+ if (!out)
+ return E_NOINTERFACE;
+
+ out->AddRef();
+ return S_OK;
+ }
+
+ ULONG __stdcall AddRef()
+ {
+ return ++m_ref;
+ }
+
+ ULONG __stdcall Release()
+ {
+ ULONG ref = --m_ref;
+ if (!m_ref)
+ delete this;
+
+ return ref;
+ }
+
+private:
+ QByteArray m_data;
+ ULONG m_ref;
+
+ // These symbols might be missing, so define them here
+ IID IID_IUnknown;
+ IID IID_ID3DBlob;
+};
+
+static bool loadCompiler()
+{
+ static HMODULE d3dcompiler = 0;
+ if (!d3dcompiler) {
+ const wchar_t *dllNames[] = {
+ L"d3dcompiler_47.dll",
+ L"d3dcompiler_46.dll",
+ L"d3dcompiler_45.dll",
+ L"d3dcompiler_44.dll",
+ L"d3dcompiler_43.dll",
+ 0
+ };
+ for (int i = 0; const wchar_t *name = dllNames[i]; ++i) {
+#ifndef Q_OS_WINRT
+ d3dcompiler = LoadLibrary(name);
+#else
+ d3dcompiler = LoadPackagedLibrary(name, NULL);
+#endif
+ if (d3dcompiler) {
+ qCDebug(QT_D3DCOMPILER) << "Found" << QString::fromWCharArray(name);
+ D3DCompiler::compile = reinterpret_cast<D3DCompiler::D3DCompileFunc>(GetProcAddress(d3dcompiler, "D3DCompile"));
+ if (D3DCompiler::compile) {
+ qCDebug(QT_D3DCOMPILER) << "Loaded" << QString::fromWCharArray(name);
+ break;
+ }
+ qCDebug(QT_D3DCOMPILER) << "Failed to load" << QString::fromWCharArray(name);
+ }
+ }
+
+ if (!d3dcompiler)
+ qCDebug(QT_D3DCOMPILER) << "Unable to load D3D shader compiler.";
+ }
+
+ return bool(compile);
+}
+
+static bool serviceAvailable(const QString &path)
+{
+ if (path.isEmpty())
+ return false;
+
+ // Look for a file, "control", and check if it has been touched in the last 60 seconds
+ QFileInfo control(path + QStringLiteral("control"));
+ return control.exists() && control.lastModified().secsTo(QDateTime::currentDateTime()) < 60;
+}
+
+static QString cacheKeyFor(const void *data)
+{
+ return QString::fromUtf8(QCryptographicHash::hash(reinterpret_cast<const char *>(data), QCryptographicHash::Sha1).toHex());
+}
+
+static QString makePath(const QDir &parent, const QString &child)
+{
+ const QString path = parent.absoluteFilePath(child);
+ if (!parent.mkpath(child)) {
+ qCWarning(QT_D3DCOMPILER) << "Path is inaccessible: " << path;
+ return QString();
+ }
+ return path;
+}
+
+} // namespace D3DCompiler
+
+extern "C" __declspec(dllexport) HRESULT WINAPI D3DCompile(
+ const void *, SIZE_T, const char *, const D3D_SHADER_MACRO *, ID3DInclude *,
+ const char *t, const char *, UINT, UINT, ID3DBlob **, ID3DBlob **);
+
+HRESULT WINAPI D3DCompile(
+ const void *data, SIZE_T data_size, const char *filename,
+ const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint,
+ const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **errorMsgs)
+{
+ static QString basePath;
+ static QString binaryPath;
+ static QString sourcePath;
+ if (basePath.isEmpty()) {
+ QDir base;
+ if (qEnvironmentVariableIsSet("QT_D3DCOMPILER_DIR"))
+ base.setPath(QString::fromUtf8(qgetenv("QT_D3DCOMPILER_DIR")));
+ else
+ base.setPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
+
+ if (!base.exists() && !base.mkdir(QStringLiteral("."))) {
+ qCWarning(QT_D3DCOMPILER) << "D3D compiler base directory does not exist: " << QDir::toNativeSeparators(base.path());
+ } else {
+ const QString path = base.absoluteFilePath(QStringLiteral("d3dcompiler/"));
+ if (!QFile::exists(path) && !base.mkdir(QStringLiteral("d3dcompiler")))
+ qCWarning(QT_D3DCOMPILER) << "D3D compiler path could not be created: " << QDir::toNativeSeparators(path);
+ else
+ basePath = path;
+ }
+ }
+
+ if (!basePath.isEmpty()) {
+ binaryPath = D3DCompiler::makePath(basePath, QStringLiteral("binary/"));
+ sourcePath = D3DCompiler::makePath(basePath, QStringLiteral("source/"));
+ }
+
+ // Check if pre-compiled shader blob is available
+ const QByteArray sourceData = QByteArray::fromRawData(reinterpret_cast<const char *>(data), data_size);
+ const QString cacheKey = D3DCompiler::cacheKeyFor(sourceData);
+ QFile blob(binaryPath + cacheKey);
+ if (!binaryPath.isEmpty() && blob.exists()) {
+ if (blob.open(QFile::ReadOnly)) {
+ qCDebug(QT_D3DCOMPILER) << "Opening precompiled shader blob at" << blob.fileName();
+ *shader = new D3DCompiler::Blob(blob.readAll());
+ return S_FALSE;
+ }
+ qCDebug(QT_D3DCOMPILER) << "Found, but unable to open, precompiled shader blob at" << blob.fileName();
+ }
+
+ // Shader blob is not available, compile with compilation service if possible
+ if (D3DCompiler::serviceAvailable(basePath)) {
+
+ if (sourcePath.isEmpty()) {
+ qCWarning(QT_D3DCOMPILER) << "Compiler service is available, but source directory is not writable.";
+ return E_ACCESSDENIED;
+ }
+
+ // Dump source to source path; wait for blob to appear
+ QFile source(sourcePath + cacheKey);
+ if (!source.open(QFile::WriteOnly)) {
+ qCDebug(QT_D3DCOMPILER) << "Unable to write shader source to file:" << source.fileName() << source.errorString();
+ return E_ACCESSDENIED;
+ }
+
+ source.write(sourceData);
+ qCDebug(QT_D3DCOMPILER) << "Wrote shader source, waiting for blob:" << source.fileName();
+ source.close();
+
+ qint64 timeout = qgetenv("QT_D3DCOMPILER_TIMEOUT").toLong();
+ if (!timeout)
+ timeout = 3000;
+
+ QElapsedTimer timer;
+ timer.start();
+ while (!(blob.exists() && blob.open(QFile::ReadOnly)) && timer.elapsed() < timeout)
+ QThread::msleep(100);
+
+ if (blob.isOpen()) {
+ *shader = new D3DCompiler::Blob(blob.readAll());
+ return S_FALSE;
+ }
+
+ qCDebug(QT_D3DCOMPILER) << "Shader blob failed to materialize after" << timeout << "ms.";
+ *errorMsgs = new D3DCompiler::Blob("Shader compilation timeout.");
+ return E_ABORT;
+ }
+
+ // Fall back to compiler DLL
+ if (D3DCompiler::loadCompiler()) {
+ HRESULT hr = D3DCompiler::compile(data, data_size, filename, defines, include, entrypoint,
+ target, sflags, eflags, shader, errorMsgs);
+ // Cache shader
+ if (SUCCEEDED(hr) && !binaryPath.isEmpty()) {
+ const QByteArray blobContents = QByteArray::fromRawData(
+ reinterpret_cast<const char *>((*shader)->GetBufferPointer()), (*shader)->GetBufferSize());
+ if (blob.open(QFile::WriteOnly) && blob.write(blobContents))
+ qCDebug(QT_D3DCOMPILER) << "Cached shader blob at" << blob.fileName();
+ else
+ qCDebug(QT_D3DCOMPILER) << "Unable to write shader blob at" << blob.fileName();
+ }
+ return hr;
+ }
+
+ *errorMsgs = new D3DCompiler::Blob("Unable to load D3D compiler DLL.");
+ return E_FAIL;
+}
diff --git a/src/src.pro b/src/src.pro
index 63cbfacbf4..a782d585d5 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -77,6 +77,7 @@ src_testlib.depends = src_corelib # src_gui & src_widgets are not build-depend
src_angle.subdir = $$PWD/angle
src_angle.target = sub-angle
+angle_d3d11: src_angle.depends = src_corelib
src_gui.subdir = $$PWD/gui
src_gui.target = sub-gui
diff --git a/tests/auto/other/d3dcompiler/d3dcompiler.pro b/tests/auto/other/d3dcompiler/d3dcompiler.pro
new file mode 100644
index 0000000000..6242d0a554
--- /dev/null
+++ b/tests/auto/other/d3dcompiler/d3dcompiler.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_d3dcompiler
+QT = core testlib
+
+SOURCES = tst_d3dcompiler.cpp
diff --git a/tests/auto/other/d3dcompiler/tst_d3dcompiler.cpp b/tests/auto/other/d3dcompiler/tst_d3dcompiler.cpp
new file mode 100644
index 0000000000..1a3f4f4592
--- /dev/null
+++ b/tests/auto/other/d3dcompiler/tst_d3dcompiler.cpp
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This test verifies the behavior of d3dcompiler_qt, which is only built when ANGLE is enabled
+
+#include <QCryptographicHash>
+#include <QDir>
+#include <QFuture>
+#include <QObject>
+#include <QStandardPaths>
+#include <QTemporaryDir>
+#include <QTest>
+#include <QThread>
+
+#if defined(Q_OS_WIN)
+
+#include <d3dcommon.h>
+
+#ifndef Q_OS_WINRT
+#define loadLibrary(library) LoadLibrary(library)
+#else
+#define loadLibrary(library) LoadPackagedLibrary(library, NULL)
+#endif
+
+#ifdef D3DCOMPILER_DLL
+#undef D3DCOMPILER_DLL
+#endif
+
+#ifdef QT_NO_DEBUG
+#define D3DCOMPILER_DLL L"d3dcompiler_qt"
+#else
+#define D3DCOMPILER_DLL L"d3dcompiler_qtd"
+#endif
+
+#define getCompilerFunc(dll) reinterpret_cast<D3DCompileFunc>(GetProcAddress(dll, "D3DCompile"))
+
+typedef HRESULT (WINAPI *D3DCompileFunc)(const void *data, SIZE_T data_size, const char *filename,
+ const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint,
+ const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages);
+
+static const wchar_t *compilerDlls[] = {
+ L"d3dcompiler_47.dll",
+ L"d3dcompiler_46.dll",
+ L"d3dcompiler_45.dll",
+ L"d3dcompiler_44.dll",
+ L"d3dcompiler_43.dll",
+ 0
+};
+
+static const char hlsl[] =
+ "uniform SamplerState Sampler : register(s0);\n"
+ "uniform Texture2D Texture : register(t0);\n"
+ "float4 main(in float4 gl_Position : SV_POSITION, in float2 coord : TEXCOORD0) : SV_TARGET0\n"
+ "{\n"
+ "return Texture.Sample(Sampler, coord);\n"
+ "}\n";
+
+static inline QByteArray blobToByteArray(ID3DBlob *blob)
+{
+ return blob ? QByteArray::fromRawData(reinterpret_cast<const char *>(blob->GetBufferPointer()), blob->GetBufferSize()) : QByteArray();
+}
+
+class CompileRunner : public QThread
+{
+public:
+ CompileRunner(D3DCompileFunc d3dCompile, const QByteArray &data, ID3DBlob **shader, ID3DBlob **error)
+ : m_d3dCompile(d3dCompile), m_data(data), m_shader(shader), m_error(error)
+ {
+ }
+
+ HRESULT result() const
+ {
+ return m_result;
+ }
+
+private:
+ void run()
+ {
+ m_result = m_d3dCompile(m_data.constData(), m_data.size(), 0, 0, 0, "main", "ps_4_0", 0, 0, m_shader, m_error);
+ }
+
+ HRESULT m_result;
+ D3DCompileFunc m_d3dCompile;
+ QByteArray m_data;
+ ID3DBlob **m_shader;
+ ID3DBlob **m_error;
+};
+
+class tst_d3dcompiler : public QObject
+{
+ Q_OBJECT
+private slots:
+ void initTestCase();
+ void init();
+ void cleanup();
+ void service_data();
+ void service();
+ void offlineCompile();
+ void onlineCompile();
+
+private:
+ QString blobPath();
+
+ HMODULE d3dcompiler_qt;
+ HMODULE d3dcompiler_win;
+
+ D3DCompileFunc d3dCompile;
+
+ QTemporaryDir tempDir;
+};
+
+QString tst_d3dcompiler::blobPath()
+{
+ QDir path;
+ if (qEnvironmentVariableIsSet("QT_D3DCOMPILER_DIR"))
+ path.setPath(qgetenv("QT_D3DCOMPILER_DIR"));
+ else
+ path.setPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
+
+ path.mkdir(QStringLiteral("d3dcompiler"));
+
+ return path.absoluteFilePath(QStringLiteral("d3dcompiler/"));
+}
+
+void tst_d3dcompiler::initTestCase()
+{
+ QVERIFY(tempDir.isValid());
+}
+
+void tst_d3dcompiler::init()
+{
+ qunsetenv("QT_D3DCOMPILER_DIR");
+ qunsetenv("QT_D3DCOMPILER_TIMEOUT");
+}
+
+void tst_d3dcompiler::cleanup()
+{
+ FreeLibrary(d3dcompiler_qt);
+ FreeLibrary(d3dcompiler_win);
+
+ QDir path(blobPath());
+ path.removeRecursively();
+}
+
+void tst_d3dcompiler::service_data()
+{
+ QTest::addColumn<QByteArray>("compilerDir");
+ QTest::addColumn<bool>("exists");
+ QTest::addColumn<HRESULT>("result");
+
+ // Don't test the default case, as it would clutter the AppData directory
+ //QTest::newRow("default") << QByteArrayLiteral("") << true << E_ABORT;
+ QTest::newRow("temporary") << tempDir.path().toUtf8() << true << E_ABORT;
+ QTest::newRow("invalid") << QByteArrayLiteral("ZZ:\\") << false << S_OK;
+}
+
+void tst_d3dcompiler::service()
+{
+ QFETCH(QByteArray, compilerDir);
+ QFETCH(bool, exists);
+ QFETCH(HRESULT, result);
+ qputenv("QT_D3DCOMPILER_DIR", compilerDir);
+ const QDir path = blobPath();
+
+ if (exists) {
+ // Activate service
+ QVERIFY(path.exists());
+
+ QFile control(path.absoluteFilePath(QStringLiteral("control")));
+ QVERIFY(control.open(QFile::WriteOnly));
+ control.close();
+ QVERIFY(control.exists());
+ } else {
+ QVERIFY(!path.exists());
+ }
+
+ // Run compiler (fast fail)
+ d3dcompiler_qt = loadLibrary(D3DCOMPILER_DLL);
+ QVERIFY(d3dcompiler_qt);
+ d3dCompile = getCompilerFunc(d3dcompiler_qt);
+ QVERIFY(d3dCompile);
+
+ qputenv("QT_D3DCOMPILER_TIMEOUT", "1");
+ const QByteArray data(hlsl);
+ ID3DBlob *shader = 0, *errorMessage = 0;
+ HRESULT hr = d3dCompile(data.constData(), data.size(), 0, 0, 0, "main", "ps_4_0", 0, 0, &shader, &errorMessage);
+ QVERIFY2(hr == result, blobToByteArray(errorMessage));
+
+ // Check that passthrough works
+ if (hr == S_OK) {
+ for (int i = 0; compilerDlls[i]; ++i) {
+ d3dcompiler_win = loadLibrary(compilerDlls[i]);
+ if (d3dcompiler_win)
+ break;
+ }
+ QVERIFY(d3dcompiler_win);
+ d3dCompile = getCompilerFunc(d3dcompiler_win);
+ QVERIFY(d3dCompile);
+
+ // Compile a shader to compare with
+ ID3DBlob *reference = 0;
+ HRESULT hr = d3dCompile(data.constData(), data.size(), 0, 0, 0, "main", "ps_4_0", 0, 0, &reference, &errorMessage);
+ QVERIFY2(SUCCEEDED(hr), blobToByteArray(errorMessage));
+
+ QByteArray shaderData(reinterpret_cast<const char *>(shader->GetBufferPointer()), shader->GetBufferSize());
+ QByteArray referenceData(reinterpret_cast<const char *>(reference->GetBufferPointer()), reference->GetBufferSize());
+ reference->Release();
+ QCOMPARE(shaderData, referenceData);
+ } else {
+ QVERIFY(FAILED(hr));
+ }
+
+ if (shader)
+ shader->Release();
+}
+
+void tst_d3dcompiler::offlineCompile()
+{
+ for (int i = 0; compilerDlls[i]; ++i) {
+ d3dcompiler_win = loadLibrary(compilerDlls[i]);
+ if (d3dcompiler_win)
+ break;
+ }
+ QVERIFY(d3dcompiler_win);
+ d3dCompile = getCompilerFunc(d3dcompiler_win);
+ QVERIFY(d3dCompile);
+
+ // Compile a shader to place in binary directory
+ const QByteArray data(hlsl);
+ ID3DBlob *shader = 0, *errorMessage = 0;
+ HRESULT hr = d3dCompile(data.constData(), data.size(), 0, 0, 0, "main", "ps_4_0", 0, 0, &shader, &errorMessage);
+ QVERIFY2(SUCCEEDED(hr), blobToByteArray(errorMessage));
+ QVERIFY(shader);
+
+ QDir outputPath(blobPath());
+ QVERIFY(outputPath.mkpath(QStringLiteral("binary")));
+ outputPath.cd(QStringLiteral("binary"));
+ QFile output(outputPath.absoluteFilePath(QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex()));
+ QVERIFY(output.open(QFile::WriteOnly));
+ output.write(reinterpret_cast<const char *>(shader->GetBufferPointer()), shader->GetBufferSize());
+ shader->Release();
+
+ // Run compiler
+ d3dcompiler_qt = loadLibrary(D3DCOMPILER_DLL);
+ QVERIFY(d3dcompiler_qt);
+ d3dCompile = getCompilerFunc(d3dcompiler_qt);
+ QVERIFY(d3dCompile);
+
+ hr = d3dCompile(data.constData(), data.size(), 0, 0, 0, "main", "ps_4_0", 0, 0, &shader, &errorMessage);
+ // Returns S_FALSE if a cached shader was found
+ QVERIFY2(hr == S_FALSE, blobToByteArray(errorMessage));
+}
+
+void tst_d3dcompiler::onlineCompile()
+{
+ QByteArray data(hlsl);
+
+ const QDir path = blobPath();
+
+ // Activate service
+ QVERIFY(path.exists());
+ QFile control(path.absoluteFilePath(QStringLiteral("control")));
+ QVERIFY(control.open(QFile::WriteOnly));
+ control.close();
+ QVERIFY(control.exists());
+
+ d3dcompiler_qt = loadLibrary(D3DCOMPILER_DLL);
+ QVERIFY(d3dcompiler_qt);
+ D3DCompileFunc concurrentCompile = getCompilerFunc(d3dcompiler_qt);
+ QVERIFY(d3dCompile);
+
+ // Run async
+ ID3DBlob *shader = 0, *errorMessage = 0;
+ CompileRunner runner(concurrentCompile, data, &shader, &errorMessage);
+ runner.start();
+
+ // Wait for source to appear
+ QVERIFY(path.mkpath(QStringLiteral("source")));
+ QVERIFY(path.mkpath(QStringLiteral("binary")));
+
+ const QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();
+ QFile input(path.absoluteFilePath(QStringLiteral("source/") + hash));
+ QTRY_VERIFY_WITH_TIMEOUT(input.exists(), 3000);
+ QTRY_VERIFY_WITH_TIMEOUT(input.isOpen() || input.open(QFile::ReadOnly), 1000);
+
+ // Compile passed source
+ const QByteArray inputData = input.readAll();
+ for (int i = 0; compilerDlls[i]; ++i) {
+ d3dcompiler_win = loadLibrary(compilerDlls[i]);
+ if (d3dcompiler_win)
+ break;
+ }
+ QVERIFY(d3dcompiler_win);
+ d3dCompile = getCompilerFunc(d3dcompiler_win);
+ QVERIFY(d3dCompile);
+ ID3DBlob *reference = 0, *errorMessage2 = 0;
+ HRESULT hr = d3dCompile(inputData.constData(), inputData.size(), 0, 0, 0, "main", "ps_4_0", 0, 0, &reference, &errorMessage2);
+ QVERIFY2(SUCCEEDED(hr), blobToByteArray(errorMessage2));
+ const QByteArray referenceData(reinterpret_cast<const char *>(reference->GetBufferPointer()), reference->GetBufferSize());
+ reference->Release();
+
+ // Write to output directory
+ QFile output(path.absoluteFilePath(QStringLiteral("binary/") + hash));
+ QVERIFY(output.open(QFile::WriteOnly));
+ output.write(referenceData);
+ output.close();
+
+ // All done
+ QVERIFY(runner.wait(3000));
+ hr = runner.result();
+ QVERIFY2(hr == S_FALSE, blobToByteArray(errorMessage2));
+ const QByteArray resultData(reinterpret_cast<const char *>(shader->GetBufferPointer()), shader->GetBufferSize());
+ shader->Release();
+ QVERIFY(referenceData == resultData);
+}
+
+QTEST_MAIN(tst_d3dcompiler)
+#include "tst_d3dcompiler.moc"
+
+#endif // Q_OS_WIN
diff --git a/tests/auto/other/other.pro b/tests/auto/other/other.pro
index 63cbca539d..2bddc8d127 100644
--- a/tests/auto/other/other.pro
+++ b/tests/auto/other/other.pro
@@ -4,6 +4,7 @@ SUBDIRS=\
baselineexample \
collections \
compiler \
+ d3dcompiler \
gestures \
headersclean \
lancelot \
@@ -57,6 +58,8 @@ cross_compile: SUBDIRS -= \
wince*|!contains(QT_CONFIG, accessibility): SUBDIRS -= qaccessibility
+!angle_d3d11: SUBDIRS -= d3dcompiler
+
!contains(QT_CONFIG, accessibility-atspi-bridge): SUBDIRS -= qaccessibilitylinux
!mac: SUBDIRS -= \