diff options
-rw-r--r-- | src/angle/angle.pro | 1 | ||||
-rw-r--r-- | src/angle/d3dcompiler/d3dcompiler.pro | 11 | ||||
-rw-r--r-- | src/angle/d3dcompiler/d3dcompiler_qt.def | 3 | ||||
-rw-r--r-- | src/angle/d3dcompiler/d3dcompiler_qtd.def | 3 | ||||
-rw-r--r-- | src/angle/d3dcompiler/main.cpp | 295 | ||||
-rw-r--r-- | src/src.pro | 1 | ||||
-rw-r--r-- | tests/auto/other/d3dcompiler/d3dcompiler.pro | 5 | ||||
-rw-r--r-- | tests/auto/other/d3dcompiler/tst_d3dcompiler.cpp | 358 | ||||
-rw-r--r-- | tests/auto/other/other.pro | 3 |
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 -= \ |