aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-01-22 12:04:11 +0100
committerAndy Nichols <andy.nichols@theqtcompany.com>2016-01-22 11:19:49 +0000
commit9a95c33279cba9be6e34983c9a2bb1e6f300c2a3 (patch)
treeae849401a6c0d50df8bece7337e98b3675cbdfa7 /examples
parent41358da2d9806c4069263e01d8ecf7df3d7e1192 (diff)
Add QD3D12Window, a HLSL qmake rule and 8 examples
Change-Id: Ida7852af10e0236a5d80e95a0876fff6276b410c Reviewed-by: Andy Nichols <andy.nichols@theqtcompany.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/examples.pro10
-rw-r--r--examples/hellocompressedtexture/hellocompressedtexture.pro23
-rw-r--r--examples/hellocompressedtexture/hellocompressedtexture.qrc5
-rw-r--r--examples/hellocompressedtexture/main.cpp67
-rw-r--r--examples/hellocompressedtexture/qt.ddsbin0 -> 174888 bytes
-rw-r--r--examples/hellocompressedtexture/shader.hlsl36
-rw-r--r--examples/hellocompressedtexture/window.cpp513
-rw-r--r--examples/hellocompressedtexture/window.h72
-rw-r--r--examples/hellodevicereset/hellodevicereset.pro17
-rw-r--r--examples/hellodevicereset/main.cpp69
-rw-r--r--examples/hellodevicereset/tdr.hlsl11
-rw-r--r--examples/hellodevicereset/window.cpp155
-rw-r--r--examples/hellodevicereset/window.h68
-rw-r--r--examples/hellogpumipmap/hellogpumipmap.pro29
-rw-r--r--examples/hellogpumipmap/hellogpumipmap.qrc5
-rw-r--r--examples/hellogpumipmap/main.cpp67
-rw-r--r--examples/hellogpumipmap/mipmapgen.hlsl60
-rw-r--r--examples/hellogpumipmap/qt.pngbin0 -> 11917 bytes
-rw-r--r--examples/hellogpumipmap/shader.hlsl36
-rw-r--r--examples/hellogpumipmap/window.cpp525
-rw-r--r--examples/hellogpumipmap/window.h78
-rw-r--r--examples/hellomultisample/hellomultisample.pro22
-rw-r--r--examples/hellomultisample/main.cpp73
-rw-r--r--examples/hellomultisample/shader.hlsl27
-rw-r--r--examples/hellomultisample/window.cpp274
-rw-r--r--examples/hellomultisample/window.h72
-rw-r--r--examples/hellooffscreen/hellooffscreen.pro32
-rw-r--r--examples/hellooffscreen/main.cpp74
-rw-r--r--examples/hellooffscreen/shader.hlsl52
-rw-r--r--examples/hellooffscreen/window.cpp541
-rw-r--r--examples/hellooffscreen/window.h95
-rw-r--r--examples/hellooffscreen_opengl/hellooffscreen_opengl.pro6
-rw-r--r--examples/hellooffscreen_opengl/hellooffscreen_opengl.qrc8
-rw-r--r--examples/hellooffscreen_opengl/main.cpp74
-rw-r--r--examples/hellooffscreen_opengl/shader_offscreen.frag6
-rw-r--r--examples/hellooffscreen_opengl/shader_offscreen.vert13
-rw-r--r--examples/hellooffscreen_opengl/shader_onscreen.frag8
-rw-r--r--examples/hellooffscreen_opengl/shader_onscreen.vert13
-rw-r--r--examples/hellooffscreen_opengl/window.cpp286
-rw-r--r--examples/hellooffscreen_opengl/window.h94
-rw-r--r--examples/hellotexture/hellotexture.pro23
-rw-r--r--examples/hellotexture/hellotexture.qrc5
-rw-r--r--examples/hellotexture/main.cpp71
-rw-r--r--examples/hellotexture/qt.pngbin0 -> 11917 bytes
-rw-r--r--examples/hellotexture/shader.hlsl36
-rw-r--r--examples/hellotexture/window.cpp406
-rw-r--r--examples/hellotexture/window.h72
-rw-r--r--examples/hellotriangle/hellotriangle.pro22
-rw-r--r--examples/hellotriangle/main.cpp65
-rw-r--r--examples/hellotriangle/shader.hlsl27
-rw-r--r--examples/hellotriangle/window.cpp263
-rw-r--r--examples/hellotriangle/window.h70
-rw-r--r--examples/hellowindow/hellowindow.pro5
-rw-r--r--examples/hellowindow/main.cpp51
-rw-r--r--examples/hellowindow/window.cpp95
-rw-r--r--examples/hellowindow/window.h58
56 files changed, 4885 insertions, 0 deletions
diff --git a/examples/examples.pro b/examples/examples.pro
new file mode 100644
index 0000000..9f8ae64
--- /dev/null
+++ b/examples/examples.pro
@@ -0,0 +1,10 @@
+TEMPLATE = subdirs
+SUBDIRS += hellowindow \
+ hellotriangle \
+ hellotexture \
+ hellooffscreen \
+ hellooffscreen_opengl \
+ hellomultisample \
+ hellogpumipmap \
+ hellocompressedtexture \
+ hellodevicereset
diff --git a/examples/hellocompressedtexture/hellocompressedtexture.pro b/examples/hellocompressedtexture/hellocompressedtexture.pro
new file mode 100644
index 0000000..6db7ae5
--- /dev/null
+++ b/examples/hellocompressedtexture/hellocompressedtexture.pro
@@ -0,0 +1,23 @@
+TEMPLATE = app
+QT += d3d12window widgets
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
+RESOURCES = hellocompressedtexture.qrc
+
+LIBS = -ld3d12
+
+VSPS = shader.hlsl
+
+vshader.input = VSPS
+vshader.header = shader_vs.h
+vshader.entry = VS_Texture
+vshader.type = vs_5_0
+
+pshader.input = VSPS
+pshader.header = shader_ps.h
+pshader.entry = PS_Texture
+pshader.type = ps_5_0
+
+HLSL_SHADERS = vshader pshader
+load(hlsl)
diff --git a/examples/hellocompressedtexture/hellocompressedtexture.qrc b/examples/hellocompressedtexture/hellocompressedtexture.qrc
new file mode 100644
index 0000000..2f44da8
--- /dev/null
+++ b/examples/hellocompressedtexture/hellocompressedtexture.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>qt.dds</file>
+</qresource>
+</RCC>
diff --git a/examples/hellocompressedtexture/main.cpp b/examples/hellocompressedtexture/main.cpp
new file mode 100644
index 0000000..c00dd81
--- /dev/null
+++ b/examples/hellocompressedtexture/main.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QWidget>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QScrollArea>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ Window *d3dw = new Window;
+ QWidget w;
+ QVBoxLayout *vl = new QVBoxLayout;
+ vl->addWidget(new QPushButton("Widgets + a native child window with D3D12, this time in a scroll area"));
+ vl->addWidget(new QLabel("Unlike hellotexture, the image is now loaded from a DDS file (BC1) instead of a PNG"));
+ QWidget *ww = QWidget::createWindowContainer(d3dw);
+ ww->setMinimumSize(100, 100);
+ vl->addWidget(ww);
+ vl->setStretchFactor(ww, 1.0f);
+ w.resize(300, 300);
+ w.setLayout(vl);
+ w.show();
+
+ return app.exec();
+}
diff --git a/examples/hellocompressedtexture/qt.dds b/examples/hellocompressedtexture/qt.dds
new file mode 100644
index 0000000..1581cfb
--- /dev/null
+++ b/examples/hellocompressedtexture/qt.dds
Binary files differ
diff --git a/examples/hellocompressedtexture/shader.hlsl b/examples/hellocompressedtexture/shader.hlsl
new file mode 100644
index 0000000..be69b39
--- /dev/null
+++ b/examples/hellocompressedtexture/shader.hlsl
@@ -0,0 +1,36 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 modelview;
+ float4x4 projection;
+};
+
+struct VSInput
+{
+ float4 position : POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+Texture2D tex : register(t0);
+SamplerState samp : register(s0);
+
+PSInput VS_Texture(VSInput input)
+{
+ PSInput result;
+
+ float4x4 mvp = mul(projection, modelview);
+ result.position = mul(mvp, input.position);
+ result.coord = input.coord;
+
+ return result;
+}
+
+float4 PS_Texture(PSInput input) : SV_TARGET
+{
+ return tex.Sample(samp, input.coord);
+}
diff --git a/examples/hellocompressedtexture/window.cpp b/examples/hellocompressedtexture/window.cpp
new file mode 100644
index 0000000..74c7e6a
--- /dev/null
+++ b/examples/hellocompressedtexture/window.cpp
@@ -0,0 +1,513 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include "shader_vs.h"
+#include "shader_ps.h"
+#include <QFile>
+
+Window::Window()
+ : f(Q_NULLPTR),
+ cbPtr(Q_NULLPTR),
+ rotationAngle(0)
+{
+}
+
+Window::~Window()
+{
+ if (cbPtr)
+ constantBuffer->Unmap(0, Q_NULLPTR);
+
+ delete f;
+}
+
+static const quint32 DDS_MAGIC = 0x20534444; // 'DDS '
+static const quint32 DDS_FOURCC = 4;
+
+#define FOURCC(c0, c1, c2, c3) ((c0) | ((c1) << 8) | ((c2) << 16) | ((c3 << 24)))
+
+struct DDS_PIXELFORMAT {
+ quint32 size;
+ quint32 flags;
+ quint32 fourCC;
+ quint32 rgbBitCount;
+ quint32 rBitMask;
+ quint32 gBitMask;
+ quint32 bBitMask;
+ quint32 aBitMask;
+};
+
+struct DDS_HEADER {
+ quint32 size;
+ quint32 flags;
+ quint32 height;
+ quint32 width;
+ quint32 pitch;
+ quint32 depth;
+ quint32 mipMapCount;
+ quint32 reserved1[11];
+ DDS_PIXELFORMAT pixelFormat;
+ quint32 caps;
+ quint32 caps2;
+ quint32 caps3;
+ quint32 caps4;
+ quint32 reserved2;
+};
+
+static quint32 unalignedDxt1Size(const QSize &size, quint32 *bpl = Q_NULLPTR, quint32 *vertBlocks = Q_NULLPTR)
+{
+ static const quint32 blockSize = 8; // 8 bytes for BC1
+ const quint32 bytesPerLine = qMax<quint32>(1, (size.width() + 3) / 4) * blockSize;
+ const quint32 ySize = qMax<quint32>(1, (size.height() + 3) / 4);
+ if (bpl)
+ *bpl = bytesPerLine;
+ if (vertBlocks)
+ *vertBlocks = ySize;
+ return bytesPerLine * ySize;
+}
+
+// We only support DXT1 (BC1) for the demo's purposes.
+static QByteArrayList loadDXT1(const QString &filename, DXGI_FORMAT *format, QSize *size, int *mipLevelCount)
+{
+ QFile f(filename);
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning("Failed to open %s", qPrintable(filename));
+ return QByteArrayList();
+ }
+
+ quint32 magic = 0;
+ f.read(reinterpret_cast<char *>(&magic), sizeof(magic));
+ if (magic != DDS_MAGIC) {
+ qWarning("%s is not a DDS file", qPrintable(filename));
+ return QByteArrayList();
+ }
+ DDS_HEADER header;
+ f.read(reinterpret_cast<char *>(&header), sizeof(header));
+ if (header.size != sizeof(DDS_HEADER)) {
+ qWarning("Invalid DDS header size");
+ return QByteArrayList();
+ }
+ if (header.pixelFormat.size != sizeof(DDS_PIXELFORMAT)) {
+ qWarning("Invalid DDS pixel format size");
+ return QByteArrayList();
+ }
+ if (!(header.pixelFormat.flags & DDS_FOURCC)) {
+ qWarning("Invalid DDS pixel format");
+ return QByteArrayList();
+ }
+ if (header.pixelFormat.fourCC != FOURCC('D', 'X', 'T', '1')) {
+ qWarning("Only DXT1 (BC1) is supported");
+ return QByteArrayList();
+ }
+
+ QByteArrayList data;
+ QSize sz(header.width, header.height);
+ for (quint32 level = 0; level < header.mipMapCount; ++level) {
+ data.append(f.read(unalignedDxt1Size(sz)));
+ sz.setWidth(qMax(1, sz.width() / 2));
+ sz.setHeight(qMax(1, sz.height() / 2));
+ }
+
+ *format = DXGI_FORMAT_BC1_UNORM;
+ *size = QSize(header.width, header.height);
+ *mipLevelCount = header.mipMapCount;
+
+ return data;
+}
+
+void Window::initializeD3D()
+{
+ DXGI_FORMAT textureFormat;
+ QSize textureSize;
+ int mipLevels;
+ QByteArrayList texData = loadDXT1(QStringLiteral(":/qt.dds"), &textureFormat, &textureSize, &mipLevels);
+ if (texData.isEmpty())
+ return;
+
+ f = createFence();
+ ID3D12Device *dev = device();
+
+ // One static sampler (no sampler heap is needed).
+ D3D12_STATIC_SAMPLER_DESC sampler = {};
+ sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
+ sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.MinLOD = 0.0f;
+ sampler.MaxLOD = D3D12_FLOAT32_MAX;
+ sampler.ShaderRegister = 0;
+ sampler.RegisterSpace = 0;
+ sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ // In addition to the constant buffer view we will now also have a shader
+ // resource view in order to expose the texture to the pixel shader.
+ D3D12_DESCRIPTOR_RANGE descRange[2];
+ descRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+ descRange[0].NumDescriptors = 1;
+ descRange[0].BaseShaderRegister = 0; // b0
+ descRange[0].RegisterSpace = 0;
+ descRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ descRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ descRange[1].NumDescriptors = 1;
+ descRange[1].BaseShaderRegister = 0; // t0
+ descRange[1].RegisterSpace = 0;
+ descRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+
+ D3D12_ROOT_PARAMETER rootParameter;
+ rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ rootParameter.DescriptorTable.NumDescriptorRanges = 2;
+ rootParameter.DescriptorTable.pDescriptorRanges = descRange;
+
+ D3D12_ROOT_SIGNATURE_DESC desc;
+ desc.NumParameters = 1;
+ desc.pParameters = &rootParameter;
+ desc.NumStaticSamplers = 1;
+ desc.pStaticSamplers = &sampler;
+ desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ qWarning("Failed to serialize root signature");
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&rootSignature)))) {
+ qWarning("Failed to create root signature");
+ return;
+ }
+
+ D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
+ };
+
+ D3D12_SHADER_BYTECODE vshader;
+ vshader.pShaderBytecode = g_VS_Texture;
+ vshader.BytecodeLength = sizeof(g_VS_Texture);
+ D3D12_SHADER_BYTECODE pshader;
+ pshader.pShaderBytecode = g_PS_Texture;
+ pshader.BytecodeLength = sizeof(g_PS_Texture);
+
+ D3D12_RASTERIZER_DESC rastDesc = {};
+ rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
+ rastDesc.CullMode = D3D12_CULL_MODE_BACK;
+ rastDesc.FrontCounterClockwise = TRUE; // Vertices are given CCW
+ rastDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ rastDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ rastDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ rastDesc.DepthClipEnable = TRUE;
+
+ // Our material is transparent (the image has alpha < 255). Enable blending.
+ const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
+ TRUE, FALSE,
+ D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
+ D3D12_BLEND_ZERO, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
+ D3D12_LOGIC_OP_NOOP,
+ D3D12_COLOR_WRITE_ENABLE_ALL
+ };
+ D3D12_BLEND_DESC blendDesc = {};
+ blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc;
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
+ psoDesc.pRootSignature = rootSignature.Get();
+ psoDesc.VS = vshader;
+ psoDesc.PS = pshader;
+ psoDesc.RasterizerState = rastDesc;
+ psoDesc.BlendState = blendDesc;
+ psoDesc.DepthStencilState.DepthEnable = TRUE;
+ psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+ psoDesc.DepthStencilState.StencilEnable = FALSE;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
+ psoDesc.SampleDesc.Count = 1;
+ if (FAILED(dev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)))) {
+ qWarning("Failed to create graphics pipeline state");
+ return;
+ }
+
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR, IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+
+ // Vertex buffer
+ const float vertices[] = {
+ -0.5f, -0.5f, 0, /* coords */ 0, 1, // the image was not flipped so accommodate for it here
+ 0.5f, -0.5f, 0, 1, 1,
+ -0.5f, 0.5f, 0, 0, 0,
+
+ -0.5f, 0.5f, 0, 0, 0,
+ 0.5f, -0.5f, 0, 1, 1,
+ 0.5f, 0.5f, 0, 1, 0
+ };
+ const UINT vertexBufferSize = sizeof(vertices);
+
+ D3D12_HEAP_PROPERTIES defaultHeapProp = {};
+ defaultHeapProp.Type = D3D12_HEAP_TYPE_DEFAULT;
+ D3D12_HEAP_PROPERTIES uploadHeapProp = defaultHeapProp;
+ uploadHeapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
+
+ D3D12_RESOURCE_DESC bufDesc = {};
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ bufDesc.Width = vertexBufferSize;
+ bufDesc.Height = 1;
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_UNKNOWN;
+ bufDesc.SampleDesc.Count = 1;
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&vertexBuffer)))) {
+ qWarning("Failed to create committed resource (vertex buffer)");
+ return;
+ }
+
+ quint8 *p = Q_NULLPTR;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (vertex buffer)");
+ return;
+ }
+ memcpy(p, vertices, vertexBufferSize);
+ vertexBuffer->Unmap(0, Q_NULLPTR);
+
+ vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
+ vertexBufferView.StrideInBytes = (3 + 2) * sizeof(float);
+ vertexBufferView.SizeInBytes = vertexBufferSize;
+
+ // Constant buffer
+ const UINT CB_SIZE = alignedCBSize(128); // 2 * float4x4
+ bufDesc.Width = CB_SIZE;
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&constantBuffer)))) {
+ qWarning("Failed to create committed resource (constant buffer)");
+ return;
+ }
+
+ if (FAILED(constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (constant buffer)");
+ return;
+ }
+ cbPtr = p; // won't Unmap() this here
+
+ // Texture (with mipmaps, if the DDS file provided them)
+ D3D12_RESOURCE_DESC textureDesc = {};
+ textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+ textureDesc.Width = textureSize.width();
+ textureDesc.Height = textureSize.height();
+ textureDesc.DepthOrArraySize = 1;
+ textureDesc.MipLevels = mipLevels;
+ textureDesc.Format = textureFormat;
+ textureDesc.SampleDesc.Count = 1;
+ textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+
+ // Ignore UMA for now and do the discrete-friendly upload via an upload buffer (no CPU access to the texture).
+ if (FAILED(dev->CreateCommittedResource(&defaultHeapProp, D3D12_HEAP_FLAG_NONE, &textureDesc,
+ D3D12_RESOURCE_STATE_COPY_DEST, Q_NULLPTR, IID_PPV_ARGS(&texture)))) {
+ qWarning("Failed to create texture resource");
+ return;
+ }
+
+ ComPtr<ID3D12Resource> textureUploadBuffer;
+ const int MAX_MIP_LEVELS = 16;
+ Q_ASSERT(mipLevels <= MAX_MIP_LEVELS);
+ D3D12_PLACED_SUBRESOURCE_FOOTPRINT textureLayout[MAX_MIP_LEVELS];
+ quint32 unalignedPitch[MAX_MIP_LEVELS], pitch[MAX_MIP_LEVELS], vertBlocks[MAX_MIP_LEVELS];
+ int mipOffset = 0;
+ QSize mipSize = textureSize;
+ // Fill out the offset and footprint info ourselves as GetCopyableFootprints does not seem to work with compressed formats.
+ // Offset and pitch must be aligned as required.
+ for (int level = 0; level < mipLevels; ++level) {
+ unalignedDxt1Size(mipSize, &unalignedPitch[level], &vertBlocks[level]);
+ pitch[level] = alignedTexturePitch(unalignedPitch[level]);
+ textureLayout[level].Offset = mipOffset;
+ textureLayout[level].Footprint.Format = DXGI_FORMAT_BC1_UNORM;
+ textureLayout[level].Footprint.Width = mipSize.width();
+ textureLayout[level].Footprint.Height = mipSize.height();
+ textureLayout[level].Footprint.Depth = 1;
+ textureLayout[level].Footprint.RowPitch = pitch[level];
+ mipOffset += alignedTextureOffset(pitch[level] * vertBlocks[level]);
+ mipSize.setWidth(qMax(1, mipSize.width() / 2));
+ mipSize.setHeight(qMax(1, mipSize.height() / 2));
+ }
+ bufDesc.Width = mipOffset;
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&textureUploadBuffer)))) {
+ qWarning("Failed to create texture upload buffer resource");
+ return;
+ }
+
+ if (FAILED(textureUploadBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (texture upload buffer)");
+ return;
+ }
+ // Have to copy line-by-line to account for the potentially bigger row pitch in the upload buffer.
+ for (int level = 0; level < mipLevels; ++level) {
+ quint8 *dst = p + textureLayout[level].Offset;
+ const quint8 *src = (const quint8 *) texData[level].constData();
+ for (quint32 y = 0; y < vertBlocks[level]; ++y) {
+ memcpy(dst, src, unalignedPitch[level]);
+ src += unalignedPitch[level];
+ dst += pitch[level];
+ }
+ }
+ textureUploadBuffer->Unmap(0, Q_NULLPTR);
+
+ for (int level = 0; level < mipLevels; ++level) {
+ D3D12_TEXTURE_COPY_LOCATION dstLoc;
+ dstLoc.pResource = texture.Get();
+ dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ dstLoc.SubresourceIndex = level;
+ D3D12_TEXTURE_COPY_LOCATION srcLoc;
+ srcLoc.pResource = textureUploadBuffer.Get();
+ srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ srcLoc.PlacedFootprint = textureLayout[level];
+ commandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, Q_NULLPTR);
+ }
+
+ // once the copy is done the texture is ready to be used from the pixel shader
+ transitionResource(texture.Get(), commandList.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+
+ // Constant buffer view and shader resource view descriptors are stored in the same heap.
+ const UINT cbvSrvStride = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ D3D12_DESCRIPTOR_HEAP_DESC cbvSrvHeapDesc = {};
+ cbvSrvHeapDesc.NumDescriptors = 2;
+ cbvSrvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+ cbvSrvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ if (FAILED(dev->CreateDescriptorHeap(&cbvSrvHeapDesc, IID_PPV_ARGS(&cbvSrvHeap)))) {
+ qWarning("Failed to create CBV/SRV/UAV descriptor heap");
+ return;
+ }
+
+ D3D12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle = cbvSrvHeap->GetCPUDescriptorHandleForHeapStart();
+ D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
+ cbvDesc.BufferLocation = constantBuffer->GetGPUVirtualAddress();
+ cbvDesc.SizeInBytes = CB_SIZE;
+ dev->CreateConstantBufferView(&cbvDesc, cbvSrvHandle);
+ cbvSrvHandle.ptr += cbvSrvStride;
+
+ D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+ srvDesc.Format = textureDesc.Format;
+ srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = mipLevels;
+ dev->CreateShaderResourceView(texture.Get(), &srvDesc, cbvSrvHandle);
+
+ // Execute the texture upload.
+ commandList->Close();
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ // Block until all the above has finished.
+ waitForGPU(f);
+
+ setupProjection();
+}
+
+void Window::resizeD3D(const QSize &)
+{
+ setupProjection();
+}
+
+void Window::setupProjection()
+{
+ projection.setToIdentity();
+ projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::paintD3D()
+{
+ modelview.setToIdentity();
+ modelview.translate(0, 0, -2);
+ // our highly sophisticated animation
+ modelview.rotate(rotationAngle, 0, 0, 1);
+ rotationAngle += 1;
+
+ memcpy(cbPtr, modelview.constData(), 16 * sizeof(float));
+ memcpy(cbPtr + 16 * sizeof(float), projection.constData(), 16 * sizeof(float));
+
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), pipelineState.Get());
+
+ commandList->SetGraphicsRootSignature(rootSignature.Get());
+
+ ID3D12DescriptorHeap *heaps[] = { cbvSrvHeap.Get() };
+ commandList->SetDescriptorHeaps(_countof(heaps), heaps);
+ commandList->SetGraphicsRootDescriptorTable(0, cbvSrvHeap->GetGPUDescriptorHandleForHeapStart());
+
+ D3D12_VIEWPORT viewport = { 0, 0, float(width()), float(height()), 0, 1 };
+ commandList->RSSetViewports(1, &viewport);
+ D3D12_RECT scissorRect = { 0, 0, width() - 1, height() - 1 };
+ commandList->RSSetScissorRects(1, &scissorRect);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = backBufferRenderTargetCPUHandle();
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = depthStencilCPUHandle();
+ commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
+
+ const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
+ commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, Q_NULLPTR);
+ commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, Q_NULLPTR);
+
+ commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ commandList->IASetVertexBuffers(0, 1, &vertexBufferView);
+ commandList->DrawInstanced(6, 1, 0, 0);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+ commandList->Close();
+
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ update();
+}
+
+void Window::afterPresent()
+{
+ waitForGPU(f);
+}
diff --git a/examples/hellocompressedtexture/window.h b/examples/hellocompressedtexture/window.h
new file mode 100644
index 0000000..a0fef7b
--- /dev/null
+++ b/examples/hellocompressedtexture/window.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QD3D12Window>
+#include <QMatrix4x4>
+
+class Window : public QD3D12Window
+{
+public:
+ Window();
+ ~Window();
+
+ void initializeD3D() Q_DECL_OVERRIDE;
+ void resizeD3D(const QSize &size) Q_DECL_OVERRIDE;
+ void paintD3D() Q_DECL_OVERRIDE;
+ void afterPresent() Q_DECL_OVERRIDE;
+
+private:
+ void setupProjection();
+
+ Fence *f;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ ComPtr<ID3D12PipelineState> pipelineState;
+ ComPtr<ID3D12RootSignature> rootSignature;
+ ComPtr<ID3D12Resource> vertexBuffer;
+ ComPtr<ID3D12Resource> constantBuffer;
+ ComPtr<ID3D12Resource> texture;
+ ComPtr<ID3D12DescriptorHeap> cbvSrvHeap;
+ D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
+
+ QMatrix4x4 projection;
+ QMatrix4x4 modelview;
+ quint8 *cbPtr;
+ float rotationAngle;
+};
diff --git a/examples/hellodevicereset/hellodevicereset.pro b/examples/hellodevicereset/hellodevicereset.pro
new file mode 100644
index 0000000..bf95b25
--- /dev/null
+++ b/examples/hellodevicereset/hellodevicereset.pro
@@ -0,0 +1,17 @@
+TEMPLATE = app
+QT += d3d12window widgets
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
+
+LIBS = -ld3d12
+
+CS = tdr.hlsl
+
+shader.input = CS
+shader.header = tdr.h
+shader.entry = timeout
+shader.type = cs_5_0
+
+HLSL_SHADERS = shader
+load(hlsl)
diff --git a/examples/hellodevicereset/main.cpp b/examples/hellodevicereset/main.cpp
new file mode 100644
index 0000000..fb301b2
--- /dev/null
+++ b/examples/hellodevicereset/main.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QWidget>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QLabel>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ Window *d3dw = new Window;
+ QWidget w;
+ QVBoxLayout *vl = new QVBoxLayout;
+ QPushButton *btn = new QPushButton("Generate a timeout and reset the GPU");
+ QObject::connect(btn, &QPushButton::clicked, d3dw, &Window::timeout);
+ vl->addWidget(btn);
+ vl->addWidget(new QLabel("Due to handling device removed errors and correctly releasing and reinitializing,\n"
+ "the application should be able to survive. Watch the debug output."));
+ QWidget *ww = QWidget::createWindowContainer(d3dw);
+ ww->setMinimumHeight(300);
+ vl->addWidget(ww);
+ vl->setStretchFactor(ww, 1.0f);
+ w.resize(400, 400);
+ w.setLayout(vl);
+ w.show();
+
+ return app.exec();
+}
diff --git a/examples/hellodevicereset/tdr.hlsl b/examples/hellodevicereset/tdr.hlsl
new file mode 100644
index 0000000..f32d4fb
--- /dev/null
+++ b/examples/hellodevicereset/tdr.hlsl
@@ -0,0 +1,11 @@
+// http://gamedev.stackexchange.com/questions/108141/how-can-i-test-dxgi-error-device-removed-error-handling
+
+RWBuffer<uint> uav;
+cbuffer ConstantBuffer { uint zero; }
+
+[numthreads(256, 1, 1)]
+void timeout(uint3 id: SV_DispatchThreadID)
+{
+ while (zero == 0)
+ uav[id.x] = zero;
+}
diff --git a/examples/hellodevicereset/window.cpp b/examples/hellodevicereset/window.cpp
new file mode 100644
index 0000000..ff7f313
--- /dev/null
+++ b/examples/hellodevicereset/window.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include "tdr.h"
+
+void Window::initializeD3D()
+{
+ f.reset(createFence());
+ ID3D12Device *dev = device();
+
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR,
+ IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+ commandList->Close();
+
+ D3D12_DESCRIPTOR_RANGE descRange[2];
+ descRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+ descRange[0].NumDescriptors = 1;
+ descRange[0].BaseShaderRegister = 0;
+ descRange[0].RegisterSpace = 0;
+ descRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ descRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
+ descRange[1].NumDescriptors = 1;
+ descRange[1].BaseShaderRegister = 0;
+ descRange[1].RegisterSpace = 0;
+ descRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+
+ D3D12_ROOT_PARAMETER param;
+ param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ param.DescriptorTable.NumDescriptorRanges = 2;
+ param.DescriptorTable.pDescriptorRanges = descRange;
+
+ D3D12_ROOT_SIGNATURE_DESC desc = {};
+ desc.NumParameters = 1;
+ desc.pParameters = &param;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ QByteArray msg(static_cast<const char *>(error->GetBufferPointer()), error->GetBufferSize());
+ qWarning("Failed to serialize compute root signature: %s", qPrintable(msg));
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),
+ IID_PPV_ARGS(&computeRootSignature)))) {
+ qWarning("Failed to create compute root signature");
+ return;
+ }
+
+ D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.pRootSignature = computeRootSignature.Get();
+ psoDesc.CS.pShaderBytecode = g_timeout;
+ psoDesc.CS.BytecodeLength = sizeof(g_timeout);
+
+ if (FAILED(dev->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&computeState)))) {
+ qWarning("Failed to create compute pipeline state");
+ return;
+ }
+}
+
+void Window::releaseD3D()
+{
+ // Release all resources. initializeD3D() will get invoked later on.
+ commandList = Q_NULLPTR;
+ computeState = Q_NULLPTR;
+ computeRootSignature = Q_NULLPTR;
+ f.reset();
+}
+
+void Window::resizeD3D(const QSize &)
+{
+}
+
+void Window::paintD3D()
+{
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), Q_NULLPTR);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ green += 0.01f;
+ if (green > 1.0f)
+ green = 0.0f;
+ const float clearColor[] = { 0.0f, green, 0.0f, 1.0f };
+ commandList->ClearRenderTargetView(backBufferRenderTargetCPUHandle(), clearColor, 0, Q_NULLPTR);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+
+ commandList->Close();
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ update();
+}
+
+void Window::afterPresent()
+{
+ waitForGPU(f.data());
+}
+
+void Window::timeout()
+{
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), computeState.Get());
+
+ commandList->SetComputeRootSignature(computeRootSignature.Get());
+ commandList->Dispatch(256, 1, 1);
+
+ commandList->Close();
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ waitForGPU(f.data());
+}
diff --git a/examples/hellodevicereset/window.h b/examples/hellodevicereset/window.h
new file mode 100644
index 0000000..2de75bc
--- /dev/null
+++ b/examples/hellodevicereset/window.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QD3D12Window>
+
+class Window : public QD3D12Window
+{
+ Q_OBJECT
+
+public:
+ Window() : green(0) { }
+
+ void initializeD3D() Q_DECL_OVERRIDE;
+ void releaseD3D() Q_DECL_OVERRIDE;
+ void resizeD3D(const QSize &size) Q_DECL_OVERRIDE;
+ void paintD3D() Q_DECL_OVERRIDE;
+ void afterPresent() Q_DECL_OVERRIDE;
+
+public slots:
+ void timeout();
+
+private:
+ void setupProjection();
+
+ QScopedPointer<Fence> f;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ ComPtr<ID3D12PipelineState> computeState;
+ ComPtr<ID3D12RootSignature> computeRootSignature;
+
+ float green;
+};
diff --git a/examples/hellogpumipmap/hellogpumipmap.pro b/examples/hellogpumipmap/hellogpumipmap.pro
new file mode 100644
index 0000000..286784e
--- /dev/null
+++ b/examples/hellogpumipmap/hellogpumipmap.pro
@@ -0,0 +1,29 @@
+TEMPLATE = app
+QT += d3d12window widgets
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
+RESOURCES = hellogpumipmap.qrc
+
+LIBS = -ld3d12
+
+VSPS = shader.hlsl
+CS = mipmapgen.hlsl
+
+vshader.input = VSPS
+vshader.header = shader_vs.h
+vshader.entry = VS_Texture
+vshader.type = vs_5_0
+
+pshader.input = VSPS
+pshader.header = shader_ps.h
+pshader.entry = PS_Texture
+pshader.type = ps_5_0
+
+cshader.input = CS
+cshader.header = shader_cs.h
+cshader.entry = CS_Generate4MipMaps
+cshader.type = cs_5_0
+
+HLSL_SHADERS = vshader pshader cshader
+load(hlsl)
diff --git a/examples/hellogpumipmap/hellogpumipmap.qrc b/examples/hellogpumipmap/hellogpumipmap.qrc
new file mode 100644
index 0000000..ff1d0e5
--- /dev/null
+++ b/examples/hellogpumipmap/hellogpumipmap.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>qt.png</file>
+</qresource>
+</RCC>
diff --git a/examples/hellogpumipmap/main.cpp b/examples/hellogpumipmap/main.cpp
new file mode 100644
index 0000000..57830fa
--- /dev/null
+++ b/examples/hellogpumipmap/main.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QWidget>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QLabel>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ Window *d3dw = new Window;
+ QWidget w;
+ QVBoxLayout *vl = new QVBoxLayout;
+ vl->addWidget(new QPushButton("Widgets + a native child window with D3D12"));
+ vl->addWidget(new QLabel("Like hellotexture but this time the mipmaps are generated via a compute shader"));
+ QWidget *ww = QWidget::createWindowContainer(d3dw);
+ ww->setMinimumWidth(200);
+ ww->setMinimumHeight(200);
+ vl->addWidget(ww);
+ vl->setStretchFactor(ww, 1.0f);
+ w.resize(800, 800);
+ w.setLayout(vl);
+ w.show();
+
+ return app.exec();
+}
diff --git a/examples/hellogpumipmap/mipmapgen.hlsl b/examples/hellogpumipmap/mipmapgen.hlsl
new file mode 100644
index 0000000..6793b53
--- /dev/null
+++ b/examples/hellogpumipmap/mipmapgen.hlsl
@@ -0,0 +1,60 @@
+static const uint GROUP_DIM = 8; // 2 ^ (out_mip_count - 1)
+
+Texture2D tex : register(t0);
+SamplerState samp : register(s0);
+
+cbuffer ConstantBuffer : register(b0)
+{
+ uint2 mip1Size;
+ uint sampleLevel;
+ uint totalMips;
+}
+
+RWTexture2D<float4> mip1 : register(u0);
+RWTexture2D<float4> mip2 : register(u1);
+RWTexture2D<float4> mip3 : register(u2);
+RWTexture2D<float4> mip4 : register(u3);
+
+groupshared float4 groupColor[GROUP_DIM][GROUP_DIM];
+
+[numthreads(GROUP_DIM, GROUP_DIM, 1)]
+void CS_Generate4MipMaps(uint3 localId: SV_GroupThreadId, uint3 globalId: SV_DispatchThreadID)
+{
+ const float2 coord = float2(1.0f / float(mip1Size.x), 1.0f / float(mip1Size.y)) * (globalId.xy + 0.5);
+ float4 c = tex.SampleLevel(samp, coord, sampleLevel);
+
+ mip1[globalId.xy] = c;
+ groupColor[localId.y][localId.x] = c;
+
+ if (sampleLevel + 1 >= totalMips)
+ return;
+
+ GroupMemoryBarrierWithGroupSync();
+
+ if ((localId.x & 1) == 0 && (localId.y & 1) == 0) {
+ c = (c + groupColor[localId.y][localId.x + 1] + groupColor[localId.y + 1][localId.x] + groupColor[localId.y + 1][localId.x + 1]) / 4.0;
+ mip2[globalId.xy / 2] = c;
+ groupColor[localId.y][localId.x] = c;
+ }
+
+ if (sampleLevel + 2 >= totalMips)
+ return;
+
+ GroupMemoryBarrierWithGroupSync();
+
+ if ((localId.x & 3) == 0 && (localId.y & 3) == 0) {
+ c = (c + groupColor[localId.y][localId.x + 2] + groupColor[localId.y + 2][localId.x] + groupColor[localId.y + 2][localId.x + 2]) / 4.0;
+ mip3[globalId.xy / 4] = c;
+ groupColor[localId.y][localId.x] = c;
+ }
+
+ if (sampleLevel + 3 >= totalMips)
+ return;
+
+ GroupMemoryBarrierWithGroupSync();
+
+ if ((localId.x & 7) == 0 && (localId.y & 7) == 0) {
+ c = (c + groupColor[localId.y][localId.x + 3] + groupColor[localId.y + 3][localId.x] + groupColor[localId.y + 3][localId.x + 3]) / 4.0;
+ mip4[globalId.xy / 8] = c;
+ }
+}
diff --git a/examples/hellogpumipmap/qt.png b/examples/hellogpumipmap/qt.png
new file mode 100644
index 0000000..f30eec0
--- /dev/null
+++ b/examples/hellogpumipmap/qt.png
Binary files differ
diff --git a/examples/hellogpumipmap/shader.hlsl b/examples/hellogpumipmap/shader.hlsl
new file mode 100644
index 0000000..be69b39
--- /dev/null
+++ b/examples/hellogpumipmap/shader.hlsl
@@ -0,0 +1,36 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 modelview;
+ float4x4 projection;
+};
+
+struct VSInput
+{
+ float4 position : POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+Texture2D tex : register(t0);
+SamplerState samp : register(s0);
+
+PSInput VS_Texture(VSInput input)
+{
+ PSInput result;
+
+ float4x4 mvp = mul(projection, modelview);
+ result.position = mul(mvp, input.position);
+ result.coord = input.coord;
+
+ return result;
+}
+
+float4 PS_Texture(PSInput input) : SV_TARGET
+{
+ return tex.Sample(samp, input.coord);
+}
diff --git a/examples/hellogpumipmap/window.cpp b/examples/hellogpumipmap/window.cpp
new file mode 100644
index 0000000..c87de78
--- /dev/null
+++ b/examples/hellogpumipmap/window.cpp
@@ -0,0 +1,525 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include "shader_vs.h"
+#include "shader_ps.h"
+#include "shader_cs.h"
+
+// size must be a power of two due to the way mipmap generation is done
+static const int TEXTURE_WIDTH = 512;
+static const int TEXTURE_HEIGHT = 512;
+
+static const int TEXTURE_MIP_LEVELS = 10; // ceil(log2(max(width, height))) + 1
+
+Window::Window()
+ : f(Q_NULLPTR),
+ cbPtr(Q_NULLPTR),
+ rotationAngle(0)
+{
+}
+
+Window::~Window()
+{
+ if (cbPtr)
+ constantBuffer->Unmap(0, Q_NULLPTR);
+
+ delete f;
+}
+
+void Window::initializeD3D()
+{
+ QImage qtLogo = QImage(QStringLiteral(":/qt.png")).convertToFormat(QImage::Format_RGBA8888).scaled(TEXTURE_WIDTH, TEXTURE_HEIGHT);
+ if (qtLogo.isNull()) {
+ qWarning("Failed to load image data");
+ return;
+ }
+
+ f = createFence();
+ ID3D12Device *dev = device();
+
+ // One static sampler (no sampler heap is needed).
+ D3D12_STATIC_SAMPLER_DESC sampler = {};
+ sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
+ sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.MinLOD = 0.0f;
+ sampler.MaxLOD = D3D12_FLOAT32_MAX;
+ sampler.ShaderRegister = 0;
+ sampler.RegisterSpace = 0;
+ sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ // In addition to the constant buffer view we will now also have a shader
+ // resource view in order to expose the texture to the pixel shader.
+ D3D12_DESCRIPTOR_RANGE descRange[2];
+ descRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+ descRange[0].NumDescriptors = 1;
+ descRange[0].BaseShaderRegister = 0; // b0
+ descRange[0].RegisterSpace = 0;
+ descRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ descRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ descRange[1].NumDescriptors = 1;
+ descRange[1].BaseShaderRegister = 0; // t0
+ descRange[1].RegisterSpace = 0;
+ descRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+
+ D3D12_ROOT_PARAMETER rootParameter;
+ rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ rootParameter.DescriptorTable.NumDescriptorRanges = 2;
+ rootParameter.DescriptorTable.pDescriptorRanges = descRange;
+
+ D3D12_ROOT_SIGNATURE_DESC desc;
+ desc.NumParameters = 1;
+ desc.pParameters = &rootParameter;
+ desc.NumStaticSamplers = 1;
+ desc.pStaticSamplers = &sampler;
+ desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ QByteArray msg(static_cast<const char *>(error->GetBufferPointer()), error->GetBufferSize());
+ qWarning("Failed to serialize root signature: %s", qPrintable(msg));
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&rootSignature)))) {
+ qWarning("Failed to create root signature");
+ return;
+ }
+
+ D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
+ };
+
+ D3D12_SHADER_BYTECODE vshader;
+ vshader.pShaderBytecode = g_VS_Texture;
+ vshader.BytecodeLength = sizeof(g_VS_Texture);
+ D3D12_SHADER_BYTECODE pshader;
+ pshader.pShaderBytecode = g_PS_Texture;
+ pshader.BytecodeLength = sizeof(g_PS_Texture);
+
+ D3D12_RASTERIZER_DESC rastDesc = {};
+ rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
+ rastDesc.CullMode = D3D12_CULL_MODE_BACK;
+ rastDesc.FrontCounterClockwise = TRUE; // Vertices are given CCW
+ rastDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ rastDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ rastDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ rastDesc.DepthClipEnable = TRUE;
+
+ // Our material is transparent (the image has alpha < 255). Enable blending.
+ const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
+ TRUE, FALSE,
+ D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
+ D3D12_BLEND_ZERO, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
+ D3D12_LOGIC_OP_NOOP,
+ D3D12_COLOR_WRITE_ENABLE_ALL
+ };
+ D3D12_BLEND_DESC blendDesc = {};
+ blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc;
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
+ psoDesc.pRootSignature = rootSignature.Get();
+ psoDesc.VS = vshader;
+ psoDesc.PS = pshader;
+ psoDesc.RasterizerState = rastDesc;
+ psoDesc.BlendState = blendDesc;
+ psoDesc.DepthStencilState.DepthEnable = TRUE;
+ psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+ psoDesc.DepthStencilState.StencilEnable = FALSE;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
+ psoDesc.SampleDesc.Count = 1;
+ if (FAILED(dev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)))) {
+ qWarning("Failed to create graphics pipeline state");
+ return;
+ }
+
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR, IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+
+ // Vertex buffer
+ const float vertices[] = {
+ -0.5f, -0.5f, 0, /* coords */ 0, 1, // the image was not flipped so accommodate for it here
+ 0.5f, -0.5f, 0, 1, 1,
+ -0.5f, 0.5f, 0, 0, 0,
+
+ -0.5f, 0.5f, 0, 0, 0,
+ 0.5f, -0.5f, 0, 1, 1,
+ 0.5f, 0.5f, 0, 1, 0
+ };
+ const UINT vertexBufferSize = sizeof(vertices);
+
+ D3D12_HEAP_PROPERTIES defaultHeapProp = {};
+ defaultHeapProp.Type = D3D12_HEAP_TYPE_DEFAULT;
+ D3D12_HEAP_PROPERTIES uploadHeapProp = defaultHeapProp;
+ uploadHeapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
+
+ D3D12_RESOURCE_DESC bufDesc = {};
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ bufDesc.Width = vertexBufferSize;
+ bufDesc.Height = 1;
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_UNKNOWN;
+ bufDesc.SampleDesc.Count = 1;
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&vertexBuffer)))) {
+ qWarning("Failed to create committed resource (vertex buffer)");
+ return;
+ }
+
+ quint8 *p = Q_NULLPTR;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (vertex buffer)");
+ return;
+ }
+ memcpy(p, vertices, vertexBufferSize);
+ vertexBuffer->Unmap(0, Q_NULLPTR);
+
+ vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
+ vertexBufferView.StrideInBytes = (3 + 2) * sizeof(float);
+ vertexBufferView.SizeInBytes = vertexBufferSize;
+
+ // Constant buffer
+ const UINT CB_SIZE = alignedCBSize(128); // 2 * float4x4
+ bufDesc.Width = CB_SIZE;
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&constantBuffer)))) {
+ qWarning("Failed to create committed resource (constant buffer)");
+ return;
+ }
+
+ if (FAILED(constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (constant buffer)");
+ return;
+ }
+ cbPtr = p; // won't Unmap() this here
+
+ // Constant buffer view and shader resource view descriptors are stored in the same heap.
+ cbvSrvUavStride = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ D3D12_DESCRIPTOR_HEAP_DESC cbvSrvUavHeapDesc = {};
+ // CBV + SRV + (TEXTURE_MIP_LEVELS - 1) * UAV
+ cbvSrvUavHeapDesc.NumDescriptors = 1 + 1 + (TEXTURE_MIP_LEVELS - 1);
+ cbvSrvUavHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+ cbvSrvUavHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ if (FAILED(dev->CreateDescriptorHeap(&cbvSrvUavHeapDesc, IID_PPV_ARGS(&cbvSrvUavHeap)))) {
+ qWarning("Failed to create CBV/SRV/UAV descriptor heap");
+ return;
+ }
+
+ // CBV for the pixel shader
+ D3D12_CPU_DESCRIPTOR_HANDLE cbvSrvUavHandle = cbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart();
+ D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
+ cbvDesc.BufferLocation = constantBuffer->GetGPUVirtualAddress();
+ cbvDesc.SizeInBytes = CB_SIZE;
+ dev->CreateConstantBufferView(&cbvDesc, cbvSrvUavHandle);
+ cbvSrvUavHandle.ptr += cbvSrvUavStride;
+
+ // Texture (with mipmaps and allowing read/write via UAVs)
+ D3D12_RESOURCE_DESC textureDesc = {};
+ textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+ textureDesc.Width = TEXTURE_WIDTH;
+ textureDesc.Height = TEXTURE_HEIGHT;
+ textureDesc.DepthOrArraySize = 1;
+ textureDesc.MipLevels = TEXTURE_MIP_LEVELS;
+ textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ textureDesc.SampleDesc.Count = 1;
+ textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+ textureDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+
+ if (FAILED(dev->CreateCommittedResource(&defaultHeapProp, D3D12_HEAP_FLAG_NONE, &textureDesc,
+ D3D12_RESOURCE_STATE_COPY_DEST, Q_NULLPTR, IID_PPV_ARGS(&texture)))) {
+ qWarning("Failed to create texture resource");
+ return;
+ }
+
+ // Shader resource view for exposing the texture to the compute and pixel shaders
+ D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+ srvDesc.Format = textureDesc.Format;
+ srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = TEXTURE_MIP_LEVELS;
+ dev->CreateShaderResourceView(texture.Get(), &srvDesc, cbvSrvUavHandle);
+ cbvSrvUavHandle.ptr += cbvSrvUavStride;
+
+ // Mipmap generation will need an UAV for each level that needs to be generated.
+ for (int level = 1; level < TEXTURE_MIP_LEVELS; ++level) {
+ D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
+ uavDesc.Format = textureDesc.Format;
+ uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
+ uavDesc.Texture2D.MipSlice = level;
+ dev->CreateUnorderedAccessView(texture.Get(), Q_NULLPTR, &uavDesc, cbvSrvUavHandle);
+ cbvSrvUavHandle.ptr += cbvSrvUavStride;
+ }
+
+ ComPtr<ID3D12Resource> textureUploadBuffer;
+ UINT64 textureUploadBufferSize;
+ D3D12_PLACED_SUBRESOURCE_FOOTPRINT textureLayout;
+ dev->GetCopyableFootprints(&textureDesc, 0, 1, 0, &textureLayout, Q_NULLPTR, Q_NULLPTR, &textureUploadBufferSize);
+ bufDesc.Width = textureUploadBufferSize;
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&textureUploadBuffer)))) {
+ qWarning("Failed to create texture upload buffer resource");
+ return;
+ }
+
+ // Unlike hellotexture, upload only level 0. Leave the rest to a compute shader.
+ if (FAILED(textureUploadBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (texture upload buffer)");
+ return;
+ }
+ p += textureLayout.Offset;
+ for (int y = 0; y < TEXTURE_HEIGHT; ++y) {
+ memcpy(p, qtLogo.scanLine(y), TEXTURE_WIDTH * 4);
+ p += textureLayout.Footprint.RowPitch;
+ }
+ textureUploadBuffer->Unmap(0, Q_NULLPTR);
+
+ D3D12_TEXTURE_COPY_LOCATION dstLoc;
+ dstLoc.pResource = texture.Get();
+ dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ dstLoc.SubresourceIndex = 0;
+ D3D12_TEXTURE_COPY_LOCATION srcLoc;
+ srcLoc.pResource = textureUploadBuffer.Get();
+ srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ srcLoc.PlacedFootprint = textureLayout;
+ commandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, Q_NULLPTR);
+
+ // once the copy is done, the texture is ready to be used in the compute shader...
+ transitionResource(texture.Get(), commandList.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
+ uavBarrier(texture.Get(), commandList.Get());
+
+ initMipMaps();
+ generateMipMaps();
+
+ // ...and then in the pixel shader
+ uavBarrier(texture.Get(), commandList.Get());
+ transitionResource(texture.Get(), commandList.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+
+ // Execute the texture upload and mipmap generation.
+ commandList->Close();
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ // Block until all the above has finished.
+ waitForGPU(f);
+
+ setupProjection();
+}
+
+void Window::initMipMaps()
+{
+ ID3D12Device *dev = device();
+
+ D3D12_STATIC_SAMPLER_DESC sampler = {};
+ sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
+ sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.MinLOD = 0.0f;
+ sampler.MaxLOD = D3D12_FLOAT32_MAX;
+
+ D3D12_DESCRIPTOR_RANGE descRange[2];
+ descRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ descRange[0].NumDescriptors = 1;
+ descRange[0].BaseShaderRegister = 0; // t0
+ descRange[0].RegisterSpace = 0;
+ descRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ descRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
+ descRange[1].NumDescriptors = 4;
+ descRange[1].BaseShaderRegister = 0; // u0..u3
+ descRange[1].RegisterSpace = 0;
+ descRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+
+ // Split into two to allow switching between the first and second set of UAVs later.
+ D3D12_ROOT_PARAMETER rootParameters[3];
+ rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ rootParameters[0].DescriptorTable.NumDescriptorRanges = 1;
+ rootParameters[0].DescriptorTable.pDescriptorRanges = &descRange[0];
+
+ rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ rootParameters[1].DescriptorTable.NumDescriptorRanges = 1;
+ rootParameters[1].DescriptorTable.pDescriptorRanges = &descRange[1];
+
+ rootParameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+ rootParameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ rootParameters[2].Constants.Num32BitValues = 4; // uint2 mip1Size, uint sampleLevel, uint totalMips
+ rootParameters[2].Constants.ShaderRegister = 0; // b0
+ rootParameters[2].Constants.RegisterSpace = 0;
+
+ D3D12_ROOT_SIGNATURE_DESC desc = {};
+ desc.NumParameters = 3;
+ desc.pParameters = rootParameters;
+ desc.NumStaticSamplers = 1;
+ desc.pStaticSamplers = &sampler;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ QByteArray msg(static_cast<const char *>(error->GetBufferPointer()), error->GetBufferSize());
+ qWarning("Failed to serialize compute root signature: %s", qPrintable(msg));
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),
+ IID_PPV_ARGS(&computeRootSignature)))) {
+ qWarning("Failed to create compute root signature");
+ return;
+ }
+
+ D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.pRootSignature = computeRootSignature.Get();
+ psoDesc.CS.pShaderBytecode = g_CS_Generate4MipMaps;
+ psoDesc.CS.BytecodeLength = sizeof(g_CS_Generate4MipMaps);
+
+ if (FAILED(dev->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&computeState)))) {
+ qWarning("Failed to create compute pipeline state");
+ return;
+ }
+}
+
+void Window::generateMipMaps()
+{
+ commandList->SetPipelineState(computeState.Get());
+ commandList->SetComputeRootSignature(computeRootSignature.Get());
+
+ ID3D12DescriptorHeap *heaps[] = { cbvSrvUavHeap.Get() };
+ commandList->SetDescriptorHeaps(_countof(heaps), heaps);
+
+ D3D12_GPU_DESCRIPTOR_HANDLE h = cbvSrvUavHeap->GetGPUDescriptorHandleForHeapStart(); // CBV, not needed here
+ h.ptr += cbvSrvUavStride; // SRV
+ commandList->SetComputeRootDescriptorTable(0, h);
+
+ h.ptr += cbvSrvUavStride; // now points to the first of (TEXTURE_MIP_LEVELS - 1) UAV descriptors
+
+ for (quint32 level = 1; level < TEXTURE_MIP_LEVELS; level += 4, h.ptr += cbvSrvUavStride * 4) {
+ commandList->SetComputeRootDescriptorTable(1, h);
+
+ QSize sz(TEXTURE_WIDTH, TEXTURE_HEIGHT);
+ sz.setWidth(qMax(1, sz.width() >> level));
+ sz.setHeight(qMax(1, sz.height() >> level));
+
+ const quint32 constants[4] = { quint32(sz.width()), quint32(sz.height()),
+ level - 1,
+ TEXTURE_MIP_LEVELS - 1 };
+ commandList->SetComputeRoot32BitConstants(2, 4, constants, 0);
+
+ commandList->Dispatch(sz.width(), sz.height(), 1);
+ }
+}
+
+void Window::resizeD3D(const QSize &)
+{
+ setupProjection();
+}
+
+void Window::setupProjection()
+{
+ projection.setToIdentity();
+ projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::paintD3D()
+{
+ modelview.setToIdentity();
+ modelview.translate(0, 0, -2);
+ // our highly sophisticated animation
+ modelview.rotate(rotationAngle, 0, 0, 1);
+ rotationAngle += 1;
+
+ memcpy(cbPtr, modelview.constData(), 16 * sizeof(float));
+ memcpy(cbPtr + 16 * sizeof(float), projection.constData(), 16 * sizeof(float));
+
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), pipelineState.Get());
+
+ commandList->SetGraphicsRootSignature(rootSignature.Get());
+
+ ID3D12DescriptorHeap *heaps[] = { cbvSrvUavHeap.Get() };
+ commandList->SetDescriptorHeaps(_countof(heaps), heaps);
+ commandList->SetGraphicsRootDescriptorTable(0, cbvSrvUavHeap->GetGPUDescriptorHandleForHeapStart());
+
+ D3D12_VIEWPORT viewport = { 0, 0, float(width()), float(height()), 0, 1 };
+ commandList->RSSetViewports(1, &viewport);
+ D3D12_RECT scissorRect = { 0, 0, width() - 1, height() - 1 };
+ commandList->RSSetScissorRects(1, &scissorRect);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = backBufferRenderTargetCPUHandle();
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = depthStencilCPUHandle();
+ commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
+
+ const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
+ commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, Q_NULLPTR);
+ commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, Q_NULLPTR);
+
+ commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ commandList->IASetVertexBuffers(0, 1, &vertexBufferView);
+ commandList->DrawInstanced(6, 1, 0, 0);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+
+ commandList->Close();
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ update();
+}
+
+void Window::afterPresent()
+{
+ waitForGPU(f);
+}
diff --git a/examples/hellogpumipmap/window.h b/examples/hellogpumipmap/window.h
new file mode 100644
index 0000000..db3c4ea
--- /dev/null
+++ b/examples/hellogpumipmap/window.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QD3D12Window>
+#include <QMatrix4x4>
+
+class Window : public QD3D12Window
+{
+public:
+ Window();
+ ~Window();
+
+ void initializeD3D() Q_DECL_OVERRIDE;
+ void resizeD3D(const QSize &size) Q_DECL_OVERRIDE;
+ void paintD3D() Q_DECL_OVERRIDE;
+ void afterPresent() Q_DECL_OVERRIDE;
+
+private:
+ void setupProjection();
+ void initMipMaps();
+ void generateMipMaps();
+
+ Fence *f;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ ComPtr<ID3D12PipelineState> pipelineState;
+ ComPtr<ID3D12RootSignature> rootSignature;
+ ComPtr<ID3D12Resource> vertexBuffer;
+ ComPtr<ID3D12Resource> constantBuffer;
+ ComPtr<ID3D12Resource> texture;
+ ComPtr<ID3D12DescriptorHeap> cbvSrvUavHeap;
+ UINT cbvSrvUavStride;
+ D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
+
+ ComPtr<ID3D12PipelineState> computeState;
+ ComPtr<ID3D12RootSignature> computeRootSignature;
+
+ QMatrix4x4 projection;
+ QMatrix4x4 modelview;
+ quint8 *cbPtr;
+ float rotationAngle;
+};
diff --git a/examples/hellomultisample/hellomultisample.pro b/examples/hellomultisample/hellomultisample.pro
new file mode 100644
index 0000000..0d36378
--- /dev/null
+++ b/examples/hellomultisample/hellomultisample.pro
@@ -0,0 +1,22 @@
+TEMPLATE = app
+QT += d3d12window widgets
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
+
+LIBS = -ld3d12
+
+VSPS = shader.hlsl
+
+vshader.input = VSPS
+vshader.header = shader_vs.h
+vshader.entry = VS_Simple
+vshader.type = vs_5_0
+
+pshader.input = VSPS
+pshader.header = shader_ps.h
+pshader.entry = PS_Simple
+pshader.type = ps_5_0
+
+HLSL_SHADERS = vshader pshader
+load(hlsl)
diff --git a/examples/hellomultisample/main.cpp b/examples/hellomultisample/main.cpp
new file mode 100644
index 0000000..4c9c255
--- /dev/null
+++ b/examples/hellomultisample/main.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QWidget>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QGroupBox>
+#include <QLabel>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ Window *d3dw = new Window;
+ QWidget w;
+
+ QGroupBox *gb = new QGroupBox("A triangle again", &w);
+ QVBoxLayout *vl = new QVBoxLayout;
+ vl->addWidget(new QPushButton("Widgets + a native child window with D3D12"));
+ vl->addWidget(gb);
+ QVBoxLayout *gbl = new QVBoxLayout;
+ gbl->addWidget(new QLabel("but this time rendered into a 4x MSAA buffer first"));
+ QWidget *ww = QWidget::createWindowContainer(d3dw);
+ ww->setMinimumHeight(300);
+ gbl->addWidget(ww);
+ gbl->setStretchFactor(ww, 1.0);
+ gb->setLayout(gbl);
+
+ w.setLayout(vl);
+ w.resize(400, 400);
+ w.show();
+
+ return app.exec();
+}
diff --git a/examples/hellomultisample/shader.hlsl b/examples/hellomultisample/shader.hlsl
new file mode 100644
index 0000000..8b9b9ff
--- /dev/null
+++ b/examples/hellomultisample/shader.hlsl
@@ -0,0 +1,27 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 modelview;
+ float4x4 projection;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float4 color : COLOR;
+};
+
+PSInput VS_Simple(float4 position : POSITION, float4 color : COLOR)
+{
+ PSInput result;
+
+ float4x4 mvp = mul(projection, modelview);
+ result.position = mul(mvp, position);
+ result.color = color;
+
+ return result;
+}
+
+float4 PS_Simple(PSInput input) : SV_TARGET
+{
+ return input.color;
+}
diff --git a/examples/hellomultisample/window.cpp b/examples/hellomultisample/window.cpp
new file mode 100644
index 0000000..d2d6350
--- /dev/null
+++ b/examples/hellomultisample/window.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include "shader_vs.h"
+#include "shader_ps.h"
+
+static const int OFFSCREEN_SAMPLES = 4;
+
+static const float offscreenClearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
+
+Window::Window()
+ : f(Q_NULLPTR),
+ cbPtr(Q_NULLPTR),
+ rotationAngle(0)
+{
+ setExtraRenderTargetCount(1);
+}
+
+Window::~Window()
+{
+ if (cbPtr)
+ constantBuffer->Unmap(0, Q_NULLPTR);
+
+ delete f;
+}
+
+void Window::setupOffscreenWithMatchingSize()
+{
+ msaaRT = Q_NULLPTR;
+ msaaDS = Q_NULLPTR;
+ msaaRT.Attach(createExtraRenderTargetAndView(extraRenderTargetCPUHandle(0), size(), offscreenClearColor, OFFSCREEN_SAMPLES));
+ msaaDS.Attach(createExtraDepthStencilAndView(extraDepthStencilCPUHandle(0), size(), OFFSCREEN_SAMPLES));
+
+ projection.setToIdentity();
+ projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::initializeD3D()
+{
+ f = createFence();
+ ID3D12Device *dev = device();
+
+ setupOffscreenWithMatchingSize();
+
+ D3D12_ROOT_PARAMETER rootParameter;
+ rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+ rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+ rootParameter.Descriptor.ShaderRegister = 0; // b0
+ rootParameter.Descriptor.RegisterSpace = 0;
+
+ D3D12_ROOT_SIGNATURE_DESC desc;
+ desc.NumParameters = 1;
+ desc.pParameters = &rootParameter;
+ desc.NumStaticSamplers = 0;
+ desc.pStaticSamplers = Q_NULLPTR;
+ desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ qWarning("Failed to serialize root signature");
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&rootSignature)))) {
+ qWarning("Failed to create root signature");
+ return;
+ }
+
+ D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
+ };
+
+ D3D12_SHADER_BYTECODE vshader;
+ vshader.pShaderBytecode = g_VS_Simple;
+ vshader.BytecodeLength = sizeof(g_VS_Simple);
+ D3D12_SHADER_BYTECODE pshader;
+ pshader.pShaderBytecode = g_PS_Simple;
+ pshader.BytecodeLength = sizeof(g_PS_Simple);
+
+ D3D12_RASTERIZER_DESC rastDesc = {};
+ rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
+ rastDesc.CullMode = D3D12_CULL_MODE_BACK;
+ rastDesc.FrontCounterClockwise = TRUE; // Vertices are given CCW
+ rastDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ rastDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ rastDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ rastDesc.DepthClipEnable = TRUE;
+
+ // No blending, just enable color write.
+ D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {};
+ defaultRenderTargetBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+ D3D12_BLEND_DESC blendDesc = {};
+ blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc;
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
+ psoDesc.pRootSignature = rootSignature.Get();
+ psoDesc.VS = vshader;
+ psoDesc.PS = pshader;
+ psoDesc.RasterizerState = rastDesc;
+ psoDesc.BlendState = blendDesc;
+ psoDesc.DepthStencilState.DepthEnable = TRUE;
+ psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+ psoDesc.DepthStencilState.StencilEnable = FALSE;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
+ psoDesc.SampleDesc = msaaRT->GetDesc().SampleDesc; // use multisampling
+ if (FAILED(dev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)))) {
+ qWarning("Failed to create graphics pipeline state");
+ return;
+ }
+
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR, IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+ commandList->Close();
+
+ const float vertices[] = {
+ 0.0f, 0.707f, 0.0f, /* color */ 1.0f, 0.0f, 0.0f, 1.0f,
+ -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
+ };
+ const UINT vertexBufferSize = sizeof(vertices);
+
+ D3D12_HEAP_PROPERTIES heapProp = {};
+ heapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
+
+ D3D12_RESOURCE_DESC bufDesc;
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ bufDesc.Alignment = 0;
+ bufDesc.Width = vertexBufferSize;
+ bufDesc.Height = 1;
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_UNKNOWN;
+ bufDesc.SampleDesc.Count = 1;
+ bufDesc.SampleDesc.Quality = 0;
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ bufDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ if (FAILED(dev->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&vertexBuffer)))) {
+ qWarning("Failed to create committed resource (vertex buffer)");
+ return;
+ }
+
+ quint8 *p = Q_NULLPTR;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed");
+ return;
+ }
+ memcpy(p, vertices, vertexBufferSize);
+ vertexBuffer->Unmap(0, Q_NULLPTR);
+
+ vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
+ vertexBufferView.StrideInBytes = (3 + 4) * sizeof(float);
+ vertexBufferView.SizeInBytes = vertexBufferSize;
+
+ const UINT CB_SIZE = alignedCBSize(128); // 2 * float4x4
+ bufDesc.Width = CB_SIZE;
+ if (FAILED(dev->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&constantBuffer)))) {
+ qWarning("Failed to create committed resource (constant buffer)");
+ return;
+ }
+
+ if (FAILED(constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (constant buffer)");
+ return;
+ }
+ cbPtr = p;
+}
+
+void Window::resizeD3D(const QSize &)
+{
+ setupOffscreenWithMatchingSize();
+}
+
+void Window::paintD3D()
+{
+ modelview.setToIdentity();
+ modelview.translate(0, 0, -2);
+ // our highly sophisticated animation
+ modelview.rotate(rotationAngle, 0, 0, 1);
+ rotationAngle += 1;
+
+ memcpy(cbPtr, modelview.constData(), 16 * sizeof(float));
+ memcpy(cbPtr + 16 * sizeof(float), projection.constData(), 16 * sizeof(float));
+
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), pipelineState.Get());
+
+ commandList->SetGraphicsRootSignature(rootSignature.Get());
+
+ commandList->SetGraphicsRootConstantBufferView(0, constantBuffer->GetGPUVirtualAddress());
+
+ D3D12_VIEWPORT viewport = { 0, 0, float(width()), float(height()), 0, 1 };
+ commandList->RSSetViewports(1, &viewport);
+ D3D12_RECT scissorRect = { 0, 0, width() - 1, height() - 1 };
+ commandList->RSSetScissorRects(1, &scissorRect);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = extraRenderTargetCPUHandle(0);
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = extraDepthStencilCPUHandle(0);
+ commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
+
+ commandList->ClearRenderTargetView(rtvHandle, offscreenClearColor, 0, Q_NULLPTR);
+ commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, Q_NULLPTR);
+
+ commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ commandList->IASetVertexBuffers(0, 1, &vertexBufferView);
+ commandList->DrawInstanced(3, 1, 0, 0);
+
+ transitionResource(msaaRT.Get(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RESOLVE_DEST);
+ commandList->ResolveSubresource(backBufferRenderTarget(), 0, msaaRT.Get(), 0, DXGI_FORMAT_R8G8B8A8_UNORM);
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_PRESENT);
+ transitionResource(msaaRT.Get(), commandList.Get(), D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+ commandList->Close();
+
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ update();
+}
+
+void Window::afterPresent()
+{
+ waitForGPU(f);
+}
diff --git a/examples/hellomultisample/window.h b/examples/hellomultisample/window.h
new file mode 100644
index 0000000..4c0c544
--- /dev/null
+++ b/examples/hellomultisample/window.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QD3D12Window>
+#include <QMatrix4x4>
+
+class Window : public QD3D12Window
+{
+public:
+ Window();
+ ~Window();
+
+ void initializeD3D() Q_DECL_OVERRIDE;
+ void resizeD3D(const QSize &size) Q_DECL_OVERRIDE;
+ void paintD3D() Q_DECL_OVERRIDE;
+ void afterPresent() Q_DECL_OVERRIDE;
+
+private:
+ void setupOffscreenWithMatchingSize();
+
+ Fence *f;
+ ComPtr<ID3D12Resource> msaaRT;
+ ComPtr<ID3D12Resource> msaaDS;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ ComPtr<ID3D12PipelineState> pipelineState;
+ ComPtr<ID3D12RootSignature> rootSignature;
+ ComPtr<ID3D12Resource> vertexBuffer;
+ ComPtr<ID3D12Resource> constantBuffer;
+ D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
+
+ QMatrix4x4 projection;
+ QMatrix4x4 modelview;
+ quint8 *cbPtr;
+ float rotationAngle;
+};
diff --git a/examples/hellooffscreen/hellooffscreen.pro b/examples/hellooffscreen/hellooffscreen.pro
new file mode 100644
index 0000000..809e618
--- /dev/null
+++ b/examples/hellooffscreen/hellooffscreen.pro
@@ -0,0 +1,32 @@
+TEMPLATE = app
+QT += d3d12window widgets
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
+
+LIBS = -ld3d12
+
+VSPS = shader.hlsl
+
+vshader1.input = VSPS
+vshader1.header = shader_vs_off.h
+vshader1.entry = VS_Offscreen
+vshader1.type = vs_5_0
+
+pshader1.input = VSPS
+pshader1.header = shader_ps_off.h
+pshader1.entry = PS_Offscreen
+pshader1.type = ps_5_0
+
+vshader2.input = VSPS
+vshader2.header = shader_vs_on.h
+vshader2.entry = VS_Onscreen
+vshader2.type = vs_5_0
+
+pshader2.input = VSPS
+pshader2.header = shader_ps_on.h
+pshader2.entry = PS_Onscreen
+pshader2.type = ps_5_0
+
+HLSL_SHADERS = vshader1 pshader1 vshader2 pshader2
+load(hlsl)
diff --git a/examples/hellooffscreen/main.cpp b/examples/hellooffscreen/main.cpp
new file mode 100644
index 0000000..00827b2
--- /dev/null
+++ b/examples/hellooffscreen/main.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QMainWindow>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QMenuBar>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ Window *d3dw = new Window;
+ QMainWindow mw;
+ QWidget *w = new QWidget;
+ QVBoxLayout *vl = new QVBoxLayout;
+ vl->addWidget(new QPushButton("Widgets + a native child window with D3D12"));
+ vl->addWidget(new QLabel("Offscreen rendering to a render target that is then used as a texture.\nNow with bundles!"));
+ QWidget *ww = QWidget::createWindowContainer(d3dw);
+ ww->setMinimumHeight(300);
+ vl->addWidget(ww);
+ vl->setStretchFactor(ww, 1.0);
+ w->setLayout(vl);
+
+ QMenu *fileMenu = mw.menuBar()->addMenu("&File");
+ fileMenu->addAction("&Save image", d3dw, &Window::readbackAndSave);
+ fileMenu->addAction("E&xit", &app, &QApplication::quit);
+
+ mw.setCentralWidget(w);
+ mw.resize(400, 400);
+ mw.show();
+
+ return app.exec();
+}
diff --git a/examples/hellooffscreen/shader.hlsl b/examples/hellooffscreen/shader.hlsl
new file mode 100644
index 0000000..c626447
--- /dev/null
+++ b/examples/hellooffscreen/shader.hlsl
@@ -0,0 +1,52 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 modelview;
+ float4x4 projection;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float4 color : COLOR;
+};
+
+PSInput VS_Offscreen(float4 position : POSITION, float4 color : COLOR)
+{
+ PSInput result;
+
+ float4x4 mvp = mul(projection, modelview);
+ result.position = mul(mvp, position);
+ result.color = color;
+
+ return result;
+}
+
+float4 PS_Offscreen(PSInput input) : SV_TARGET
+{
+ return input.color;
+}
+
+struct PSInput2
+{
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+PSInput2 VS_Onscreen(float4 position : POSITION, float2 coord : TEXCOORD0)
+{
+ PSInput2 result;
+
+ float4x4 mvp = mul(projection, modelview);
+ result.position = mul(mvp, position);
+ result.coord = coord;
+
+ return result;
+}
+
+Texture2D tex : register(t0);
+SamplerState samp : register(s0);
+
+float4 PS_Onscreen(PSInput2 input) : SV_TARGET
+{
+ return tex.Sample(samp, input.coord);
+}
diff --git a/examples/hellooffscreen/window.cpp b/examples/hellooffscreen/window.cpp
new file mode 100644
index 0000000..3dbe583
--- /dev/null
+++ b/examples/hellooffscreen/window.cpp
@@ -0,0 +1,541 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include "shader_vs_off.h"
+#include "shader_ps_off.h"
+#include "shader_vs_on.h"
+#include "shader_ps_on.h"
+#include <QFileDialog>
+#include <QMessageBox>
+
+static const int OFFSCREEN_WIDTH = 512;
+static const int OFFSCREEN_HEIGHT = 512;
+
+static const float offscreenClearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
+static const float onscreenClearColor[] = { 0.4f, 0.5f, 0.5f, 1.0f };
+
+Window::Window()
+ : f(Q_NULLPTR)
+{
+ setExtraRenderTargetCount(1);
+}
+
+Window::~Window()
+{
+ if (offscreen.cbPtr)
+ offscreen.constantBuffer->Unmap(0, Q_NULLPTR);
+ if (onscreen.cbPtr)
+ onscreen.constantBuffer->Unmap(0, Q_NULLPTR);
+
+ delete f;
+}
+
+void Window::initializeD3D()
+{
+ f = createFence();
+ ID3D12Device *dev = device();
+
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR, IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+ commandList->Close(); // created in recording state, close it for now
+
+ D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {};
+ cbvHeapDesc.NumDescriptors = 1;
+ cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+ cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ if (FAILED(dev->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&cbvSrvHeap)))) {
+ qWarning("Failed to create CBV/SRV/UAV descriptor heap");
+ return;
+ }
+
+ initializeOffscreen();
+ initializeOnscreen();
+}
+
+static inline D3D12_GRAPHICS_PIPELINE_STATE_DESC pso()
+{
+ D3D12_RASTERIZER_DESC rastDesc = {};
+ rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
+ rastDesc.CullMode = D3D12_CULL_MODE_BACK;
+ rastDesc.FrontCounterClockwise = TRUE;
+ rastDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ rastDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ rastDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ rastDesc.DepthClipEnable = TRUE;
+
+ // No blending, just enable color write.
+ D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {};
+ defaultRenderTargetBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+ D3D12_BLEND_DESC blendDesc = {};
+ blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc;
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.RasterizerState = rastDesc;
+ psoDesc.BlendState = blendDesc;
+ psoDesc.DepthStencilState.DepthEnable = TRUE;
+ psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+ psoDesc.DepthStencilState.StencilEnable = FALSE;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
+ psoDesc.SampleDesc.Count = 1;
+
+ return psoDesc;
+}
+
+void Window::initializeOffscreen()
+{
+ ID3D12Device *dev = device();
+
+ // Create an offscreen render target of size 512x512. Pass the clear color to avoid performance warnings.
+ // Have a depth-stencil buffer as well with the matching size.
+ QSize sz(OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT);
+ offscreen.rt.Attach(createExtraRenderTargetAndView(extraRenderTargetCPUHandle(0), sz, offscreenClearColor));
+ offscreen.ds.Attach(createExtraDepthStencilAndView(extraDepthStencilCPUHandle(0), sz));
+
+ D3D12_ROOT_PARAMETER rootParameter;
+ rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+ rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+ rootParameter.Descriptor.ShaderRegister = 0; // b0
+ rootParameter.Descriptor.RegisterSpace = 0;
+
+ D3D12_ROOT_SIGNATURE_DESC desc;
+ desc.NumParameters = 1;
+ desc.pParameters = &rootParameter;
+ desc.NumStaticSamplers = 0;
+ desc.pStaticSamplers = Q_NULLPTR;
+ desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ qWarning("Failed to serialize root signature");
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),
+ IID_PPV_ARGS(&offscreen.rootSignature)))) {
+ qWarning("Failed to create root signature");
+ return;
+ }
+
+ const D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
+ };
+
+ D3D12_SHADER_BYTECODE vshader;
+ vshader.pShaderBytecode = g_VS_Offscreen;
+ vshader.BytecodeLength = sizeof(g_VS_Offscreen);
+ D3D12_SHADER_BYTECODE pshader;
+ pshader.pShaderBytecode = g_PS_Offscreen;
+ pshader.BytecodeLength = sizeof(g_PS_Offscreen);
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = pso();
+ psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
+ psoDesc.pRootSignature = offscreen.rootSignature.Get();
+ psoDesc.VS = vshader;
+ psoDesc.PS = pshader;
+
+ if (FAILED(dev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&offscreen.pipelineState)))) {
+ qWarning("Failed to create graphics pipeline state");
+ return;
+ }
+
+ const float vertices[] = {
+ 0.0f, 0.707f, 0.0f, /* color */ 1.0f, 0.0f, 0.0f, 1.0f,
+ -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
+ };
+ const UINT vertexBufferSize = sizeof(vertices);
+
+ D3D12_HEAP_PROPERTIES heapProp = {};
+ heapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
+
+ D3D12_RESOURCE_DESC bufDesc = {};
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ bufDesc.Width = vertexBufferSize;
+ bufDesc.Height = 1;
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_UNKNOWN;
+ bufDesc.SampleDesc.Count = 1;
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+
+ if (FAILED(dev->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR,
+ IID_PPV_ARGS(&offscreen.vertexBuffer)))) {
+ qWarning("Failed to create committed resource (vertex buffer for triangle)");
+ return;
+ }
+
+ quint8 *p = Q_NULLPTR;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(offscreen.vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (vertex buffer for triangle)");
+ return;
+ }
+ memcpy(p, vertices, vertexBufferSize);
+ offscreen.vertexBuffer->Unmap(0, Q_NULLPTR);
+
+ offscreen.vertexBufferView.BufferLocation = offscreen.vertexBuffer->GetGPUVirtualAddress();
+ offscreen.vertexBufferView.StrideInBytes = (3 + 4) * sizeof(float);
+ offscreen.vertexBufferView.SizeInBytes = vertexBufferSize;
+
+ const UINT CB_SIZE = alignedCBSize(128); // 2 * float4x4
+ bufDesc.Width = CB_SIZE;
+ if (FAILED(dev->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR,
+ IID_PPV_ARGS(&offscreen.constantBuffer)))) {
+ qWarning("Failed to create committed resource (constant buffer for triangle)");
+ return;
+ }
+
+ if (FAILED(offscreen.constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (constant buffer for triangle)");
+ return;
+ }
+ offscreen.cbPtr = p;
+
+ offscreen.projection.perspective(60.0f, OFFSCREEN_WIDTH / float(OFFSCREEN_HEIGHT), 0.1f, 100.0f);
+
+ // Create a bundle for drawing a triangle.
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_BUNDLE, bundleAllocator(), Q_NULLPTR, IID_PPV_ARGS(&offscreen.bundle)))) {
+ qWarning("Failed to create offscreen command bundle");
+ return;
+ }
+ offscreen.bundle->SetPipelineState(offscreen.pipelineState.Get());
+ offscreen.bundle->SetGraphicsRootSignature(offscreen.rootSignature.Get());
+ offscreen.bundle->SetGraphicsRootConstantBufferView(0, offscreen.constantBuffer->GetGPUVirtualAddress());
+ offscreen.bundle->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ offscreen.bundle->IASetVertexBuffers(0, 1, &offscreen.vertexBufferView);
+ offscreen.bundle->DrawInstanced(3, 1, 0, 0);
+ offscreen.bundle->Close();
+}
+
+void Window::initializeOnscreen()
+{
+ // Set up a cube that is textured with the render target from the offscreen step.
+
+ ID3D12Device *dev = device();
+
+ D3D12_STATIC_SAMPLER_DESC sampler = {};
+ sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
+ sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.MinLOD = 0.0f;
+ sampler.MaxLOD = D3D12_FLOAT32_MAX;
+ sampler.ShaderRegister = 0; // s0
+ sampler.RegisterSpace = 0;
+ sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ D3D12_ROOT_PARAMETER rootParameters[2];
+ rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+ rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+ rootParameters[0].Descriptor.ShaderRegister = 0; // b0
+ rootParameters[0].Descriptor.RegisterSpace = 0;
+
+ D3D12_DESCRIPTOR_RANGE descRange;
+ descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ descRange.NumDescriptors = 1;
+ descRange.BaseShaderRegister = 0; // t0
+ descRange.RegisterSpace = 0;
+ descRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+
+ rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+ rootParameters[1].DescriptorTable.NumDescriptorRanges = 1;
+ rootParameters[1].DescriptorTable.pDescriptorRanges = &descRange;
+
+ D3D12_ROOT_SIGNATURE_DESC desc;
+ desc.NumParameters = 2;
+ desc.pParameters = rootParameters;
+ desc.NumStaticSamplers = 1;
+ desc.pStaticSamplers = &sampler;
+ desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ qWarning("Failed to serialize root signature");
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(),
+ IID_PPV_ARGS(&onscreen.rootSignature)))) {
+ qWarning("Failed to create root signature");
+ return;
+ }
+
+ // We have a non-interleaved layout.
+ const D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
+ };
+
+ D3D12_SHADER_BYTECODE vshader;
+ vshader.pShaderBytecode = g_VS_Onscreen;
+ vshader.BytecodeLength = sizeof(g_VS_Onscreen);
+ D3D12_SHADER_BYTECODE pshader;
+ pshader.pShaderBytecode = g_PS_Onscreen;
+ pshader.BytecodeLength = sizeof(g_PS_Onscreen);
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = pso();
+ psoDesc.RasterizerState.FrontCounterClockwise = FALSE; // winding order for the cube data below is CW
+ psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
+ psoDesc.pRootSignature = onscreen.rootSignature.Get();
+ psoDesc.VS = vshader;
+ psoDesc.PS = pshader;
+
+ if (FAILED(dev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&onscreen.pipelineState)))) {
+ qWarning("Failed to create graphics pipeline state");
+ return;
+ }
+
+ // borrowed from qtdeclarative/examples/quick/rendercontrol
+ const float v[] = {
+ -0.5, 0.5, 0.5, 0.5,-0.5,0.5,-0.5,-0.5,0.5,
+ 0.5, -0.5, 0.5, -0.5,0.5,0.5,0.5,0.5,0.5,
+ -0.5, -0.5, -0.5, 0.5,-0.5,-0.5,-0.5,0.5,-0.5,
+ 0.5, 0.5, -0.5, -0.5,0.5,-0.5,0.5,-0.5,-0.5,
+
+ 0.5, -0.5, -0.5, 0.5,-0.5,0.5,0.5,0.5,-0.5,
+ 0.5, 0.5, 0.5, 0.5,0.5,-0.5,0.5,-0.5,0.5,
+ -0.5, 0.5, -0.5, -0.5,-0.5,0.5,-0.5,-0.5,-0.5,
+ -0.5, -0.5, 0.5, -0.5,0.5,-0.5,-0.5,0.5,0.5,
+
+ 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,
+ -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5,
+ -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
+ 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5
+ };
+ const float texCoords[] = {
+ 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
+ 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
+ 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
+ 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
+
+ 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
+ 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
+ 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
+ 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
+
+ 0.0f,1.0f, 1.0f,0.0f, 1.0f,1.0f,
+ 1.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f,
+ 1.0f,0.0f, 1.0f,1.0f, 0.0f,0.0f,
+ 0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f
+ };
+
+ const UINT vertexBufferSize = sizeof(v) + sizeof(texCoords);
+
+ D3D12_HEAP_PROPERTIES heapProp = {};
+ heapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
+
+ D3D12_RESOURCE_DESC bufDesc = {};
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ bufDesc.Width = vertexBufferSize;
+ bufDesc.Height = 1;
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_UNKNOWN;
+ bufDesc.SampleDesc.Count = 1;
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+
+ if (FAILED(dev->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR,
+ IID_PPV_ARGS(&onscreen.vertexBuffer)))) {
+ qWarning("Failed to create committed resource (vertex buffer for cube)");
+ return;
+ }
+
+ quint8 *p = Q_NULLPTR;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(onscreen.vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (vertex buffer for cube)");
+ return;
+ }
+ memcpy(p, v, sizeof(v));
+ memcpy(p + sizeof(v), texCoords, sizeof(texCoords));
+ onscreen.vertexBuffer->Unmap(0, Q_NULLPTR);
+
+ onscreen.vertexBufferView[0].BufferLocation = onscreen.vertexBuffer->GetGPUVirtualAddress();
+ onscreen.vertexBufferView[0].StrideInBytes = 3 * sizeof(float);
+ onscreen.vertexBufferView[0].SizeInBytes = sizeof(v);
+ onscreen.vertexBufferView[1].BufferLocation = onscreen.vertexBuffer->GetGPUVirtualAddress() + sizeof(v);
+ onscreen.vertexBufferView[1].StrideInBytes = 2 * sizeof(float);
+ onscreen.vertexBufferView[1].SizeInBytes = sizeof(texCoords);
+
+ const UINT CB_SIZE = alignedCBSize(128); // 2 * float4x4
+ bufDesc.Width = CB_SIZE;
+ if (FAILED(dev->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR,
+ IID_PPV_ARGS(&onscreen.constantBuffer)))) {
+ qWarning("Failed to create committed resource (constant buffer for cube)");
+ return;
+ }
+
+ if (FAILED(onscreen.constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (constant buffer for cube)");
+ return;
+ }
+ onscreen.cbPtr = p;
+
+ dev->CreateShaderResourceView(offscreen.rt.Get(), Q_NULLPTR, cbvSrvHeap->GetCPUDescriptorHandleForHeapStart());
+
+ // Create a bundle for drawing a cube.
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_BUNDLE, bundleAllocator(), Q_NULLPTR, IID_PPV_ARGS(&onscreen.bundle)))) {
+ qWarning("Failed to create onscreen command bundle");
+ return;
+ }
+ onscreen.bundle->SetPipelineState(onscreen.pipelineState.Get());
+ onscreen.bundle->SetGraphicsRootSignature(onscreen.rootSignature.Get());
+ onscreen.bundle->SetGraphicsRootConstantBufferView(0, onscreen.constantBuffer->GetGPUVirtualAddress());
+ // This is only here to be able to add the SetGraphicsRootDescriptorTable call below.
+ // Must match the heap set on the direct command list.
+ ID3D12DescriptorHeap *heaps[] = { cbvSrvHeap.Get() };
+ onscreen.bundle->SetDescriptorHeaps(_countof(heaps), heaps);
+ // cbvSrvHeap has a single SRV descriptor only so the start address is just what we need
+ onscreen.bundle->SetGraphicsRootDescriptorTable(1, cbvSrvHeap->GetGPUDescriptorHandleForHeapStart());
+ onscreen.bundle->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ onscreen.bundle->IASetVertexBuffers(0, 2, onscreen.vertexBufferView);
+ onscreen.bundle->DrawInstanced(36, 1, 0, 0);
+ onscreen.bundle->Close();
+
+ onscreen.projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::resizeD3D(const QSize &)
+{
+ onscreen.projection.setToIdentity();
+ onscreen.projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::paintD3D()
+{
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), Q_NULLPTR);
+
+ paintOffscreen();
+ paintOnscreen();
+
+ commandList->Close();
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ update();
+}
+
+void Window::paintOffscreen()
+{
+ QMatrix4x4 modelview;
+ modelview.translate(0, 0, -2);
+ modelview.rotate(offscreen.rotationAngle, 0, 0, 1);
+ offscreen.rotationAngle += 1;
+ memcpy(offscreen.cbPtr, modelview.constData(), 16 * sizeof(float));
+ memcpy(offscreen.cbPtr + 16 * sizeof(float), offscreen.projection.constData(), 16 * sizeof(float));
+
+ D3D12_VIEWPORT viewport = { 0, 0, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT, 0, 1 };
+ commandList->RSSetViewports(1, &viewport);
+ D3D12_RECT scissorRect = { 0, 0, OFFSCREEN_WIDTH - 1, OFFSCREEN_HEIGHT - 1 };
+ commandList->RSSetScissorRects(1, &scissorRect);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = extraRenderTargetCPUHandle(0);
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = extraDepthStencilCPUHandle(0);
+ commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
+
+ commandList->ClearRenderTargetView(rtvHandle, offscreenClearColor, 0, Q_NULLPTR);
+ commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, Q_NULLPTR);
+
+ commandList->ExecuteBundle(offscreen.bundle.Get());
+}
+
+void Window::paintOnscreen()
+{
+ QMatrix4x4 modelview;
+ modelview.translate(0, 0, -2);
+ modelview.rotate(onscreen.rotationAngle, 1, 0.5, 0);
+ onscreen.rotationAngle += 1;
+ memcpy(onscreen.cbPtr, modelview.constData(), 16 * sizeof(float));
+ memcpy(onscreen.cbPtr + 16 * sizeof(float), onscreen.projection.constData(), 16 * sizeof(float));
+
+ D3D12_VIEWPORT viewport = { 0, 0, float(width()), float(height()), 0, 1 };
+ commandList->RSSetViewports(1, &viewport);
+ D3D12_RECT scissorRect = { 0, 0, width() - 1, height() - 1 };
+ commandList->RSSetScissorRects(1, &scissorRect);
+
+ transitionResource(offscreen.rt.Get(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = backBufferRenderTargetCPUHandle();
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = depthStencilCPUHandle();
+ commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
+
+ commandList->ClearRenderTargetView(rtvHandle, onscreenClearColor, 0, Q_NULLPTR);
+ commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, Q_NULLPTR);
+
+ ID3D12DescriptorHeap *heaps[] = { cbvSrvHeap.Get() };
+ commandList->SetDescriptorHeaps(_countof(heaps), heaps);
+
+ commandList->ExecuteBundle(onscreen.bundle.Get());
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+ transitionResource(offscreen.rt.Get(), commandList.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+}
+
+void Window::afterPresent()
+{
+ waitForGPU(f);
+}
+
+void Window::readbackAndSave()
+{
+ commandList->Reset(commandAllocator(), Q_NULLPTR);
+ QImage img = readbackRGBA8888(offscreen.rt.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, commandList.Get());
+ QString fn = QFileDialog::getSaveFileName(Q_NULLPTR, QStringLiteral("Save PNG"), QString(), QStringLiteral("PNG files (*.png)"));
+ if (!fn.isEmpty()) {
+ img.save(fn);
+ QMessageBox::information(Q_NULLPTR, QStringLiteral("Saved"), QStringLiteral("Offscreen render target read back and saved to ") + fn);
+ }
+}
diff --git a/examples/hellooffscreen/window.h b/examples/hellooffscreen/window.h
new file mode 100644
index 0000000..530d6a3
--- /dev/null
+++ b/examples/hellooffscreen/window.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QD3D12Window>
+#include <QMatrix4x4>
+
+class Window : public QD3D12Window
+{
+public:
+ Window();
+ ~Window();
+
+ void initializeD3D() Q_DECL_OVERRIDE;
+ void resizeD3D(const QSize &size) Q_DECL_OVERRIDE;
+ void paintD3D() Q_DECL_OVERRIDE;
+ void afterPresent() Q_DECL_OVERRIDE;
+
+public slots:
+ void readbackAndSave();
+
+private:
+ void initializeOffscreen();
+ void initializeOnscreen();
+ void paintOffscreen();
+ void paintOnscreen();
+
+ Fence *f;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ ComPtr<ID3D12DescriptorHeap> cbvSrvHeap;
+
+ struct OffscreenData {
+ OffscreenData() : cbPtr(Q_NULLPTR), rotationAngle(0) { }
+ ComPtr<ID3D12Resource> rt;
+ ComPtr<ID3D12Resource> ds;
+ ComPtr<ID3D12GraphicsCommandList> bundle;
+ ComPtr<ID3D12PipelineState> pipelineState;
+ ComPtr<ID3D12RootSignature> rootSignature;
+ ComPtr<ID3D12Resource> vertexBuffer;
+ ComPtr<ID3D12Resource> constantBuffer;
+ quint8 *cbPtr;
+ D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
+ QMatrix4x4 projection;
+ float rotationAngle;
+ } offscreen;
+
+ struct OnscreenData {
+ OnscreenData() : cbPtr(Q_NULLPTR), rotationAngle(0) { }
+ ComPtr<ID3D12GraphicsCommandList> bundle;
+ ComPtr<ID3D12PipelineState> pipelineState;
+ ComPtr<ID3D12RootSignature> rootSignature;
+ ComPtr<ID3D12Resource> vertexBuffer;
+ ComPtr<ID3D12Resource> constantBuffer;
+ quint8 *cbPtr;
+ D3D12_VERTEX_BUFFER_VIEW vertexBufferView[2];
+ QMatrix4x4 projection;
+ float rotationAngle;
+ } onscreen;
+};
diff --git a/examples/hellooffscreen_opengl/hellooffscreen_opengl.pro b/examples/hellooffscreen_opengl/hellooffscreen_opengl.pro
new file mode 100644
index 0000000..f368a99
--- /dev/null
+++ b/examples/hellooffscreen_opengl/hellooffscreen_opengl.pro
@@ -0,0 +1,6 @@
+TEMPLATE = app
+QT += widgets
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
+RESOURCES = hellooffscreen_opengl.qrc
diff --git a/examples/hellooffscreen_opengl/hellooffscreen_opengl.qrc b/examples/hellooffscreen_opengl/hellooffscreen_opengl.qrc
new file mode 100644
index 0000000..bbbcc61
--- /dev/null
+++ b/examples/hellooffscreen_opengl/hellooffscreen_opengl.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>shader_offscreen.vert</file>
+ <file>shader_offscreen.frag</file>
+ <file>shader_onscreen.vert</file>
+ <file>shader_onscreen.frag</file>
+</qresource>
+</RCC>
diff --git a/examples/hellooffscreen_opengl/main.cpp b/examples/hellooffscreen_opengl/main.cpp
new file mode 100644
index 0000000..3cab53f
--- /dev/null
+++ b/examples/hellooffscreen_opengl/main.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QMainWindow>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QMenuBar>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ Window *glw = new Window;
+ QMainWindow mw;
+ QWidget *w = new QWidget;
+ QVBoxLayout *vl = new QVBoxLayout;
+ vl->addWidget(new QPushButton("Widgets + a native child window with OpenGL"));
+ vl->addWidget(new QLabel("Offscreen rendering via an FBO."));
+ QWidget *ww = QWidget::createWindowContainer(glw);
+ ww->setMinimumHeight(300);
+ vl->addWidget(ww);
+ vl->setStretchFactor(ww, 1.0);
+ w->setLayout(vl);
+
+ QMenu *fileMenu = mw.menuBar()->addMenu("&File");
+ fileMenu->addAction("&Save image", glw, &Window::readbackAndSave);
+ fileMenu->addAction("E&xit", &app, &QApplication::quit);
+
+ mw.setCentralWidget(w);
+ mw.resize(400, 400);
+ mw.show();
+
+ return app.exec();
+}
diff --git a/examples/hellooffscreen_opengl/shader_offscreen.frag b/examples/hellooffscreen_opengl/shader_offscreen.frag
new file mode 100644
index 0000000..7bb5db2
--- /dev/null
+++ b/examples/hellooffscreen_opengl/shader_offscreen.frag
@@ -0,0 +1,6 @@
+varying highp vec4 vColor;
+
+void main()
+{
+ gl_FragColor = vColor;
+}
diff --git a/examples/hellooffscreen_opengl/shader_offscreen.vert b/examples/hellooffscreen_opengl/shader_offscreen.vert
new file mode 100644
index 0000000..2dc9fe1
--- /dev/null
+++ b/examples/hellooffscreen_opengl/shader_offscreen.vert
@@ -0,0 +1,13 @@
+attribute vec4 position;
+attribute vec4 color;
+
+varying vec4 vColor;
+
+uniform mat4 projection;
+uniform mat4 modelview;
+
+void main()
+{
+ vColor = color;
+ gl_Position = projection * modelview * position;
+}
diff --git a/examples/hellooffscreen_opengl/shader_onscreen.frag b/examples/hellooffscreen_opengl/shader_onscreen.frag
new file mode 100644
index 0000000..dab1dc4
--- /dev/null
+++ b/examples/hellooffscreen_opengl/shader_onscreen.frag
@@ -0,0 +1,8 @@
+varying highp vec2 vTexCoord;
+
+uniform sampler2D sampler;
+
+void main()
+{
+ gl_FragColor = vec4(texture2D(sampler, vTexCoord).rgb, 1.0);
+}
diff --git a/examples/hellooffscreen_opengl/shader_onscreen.vert b/examples/hellooffscreen_opengl/shader_onscreen.vert
new file mode 100644
index 0000000..094ca59
--- /dev/null
+++ b/examples/hellooffscreen_opengl/shader_onscreen.vert
@@ -0,0 +1,13 @@
+attribute vec4 position;
+attribute vec2 texcoord;
+
+varying vec2 vTexCoord;
+
+uniform mat4 projection;
+uniform mat4 modelview;
+
+void main()
+{
+ vTexCoord = texcoord;
+ gl_Position = projection * modelview * position;
+}
diff --git a/examples/hellooffscreen_opengl/window.cpp b/examples/hellooffscreen_opengl/window.cpp
new file mode 100644
index 0000000..31bc098
--- /dev/null
+++ b/examples/hellooffscreen_opengl/window.cpp
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QOpenGLFramebufferObject>
+#include <QOpenGLShaderProgram>
+#include <QOpenGLFunctions>
+#include <QOpenGLBuffer>
+#include <QOpenGLVertexArrayObject>
+
+static const int OFFSCREEN_WIDTH = 512;
+static const int OFFSCREEN_HEIGHT = 512;
+
+static const float offscreenClearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
+static const float onscreenClearColor[] = { 0.4f, 0.5f, 0.5f, 1.0f };
+
+Window::Window()
+{
+ QSurfaceFormat fmt;
+ fmt.setDepthBufferSize(24);
+ setFormat(fmt);
+}
+
+Window::~Window()
+{
+ makeCurrent();
+
+ delete offscreen.fbo;
+ delete offscreen.prog;
+ delete offscreen.vbo;
+ delete offscreen.vao;
+
+ delete onscreen.prog;
+ delete onscreen.vbo;
+ delete onscreen.vao;
+}
+
+void Window::initializeGL()
+{
+ initializeOffscreen();
+ initializeOnscreen();
+
+ QOpenGLFunctions *f = context()->functions();
+ f->glEnable(GL_DEPTH_TEST);
+ f->glEnable(GL_CULL_FACE);
+}
+
+void Window::initializeOffscreen()
+{
+ offscreen.fbo = new QOpenGLFramebufferObject(OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT, QOpenGLFramebufferObject::CombinedDepthStencil);
+
+ offscreen.prog = new QOpenGLShaderProgram;
+ offscreen.prog->addShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/shader_offscreen.vert"));
+ offscreen.prog->addShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/shader_offscreen.frag"));
+ offscreen.prog->bindAttributeLocation("position", 0);
+ offscreen.prog->bindAttributeLocation("color", 1);
+ offscreen.prog->link();
+
+ offscreen.modelviewLoc = offscreen.prog->uniformLocation("modelview");
+ offscreen.projectionLoc = offscreen.prog->uniformLocation("projection");
+
+ offscreen.vao = new QOpenGLVertexArrayObject;
+ offscreen.vao->create();
+ QOpenGLVertexArrayObject::Binder vaoBinder(offscreen.vao);
+
+ offscreen.vbo = new QOpenGLBuffer;
+ offscreen.vbo->create();
+ offscreen.vbo->bind();
+
+ const float vertices[] = {
+ 0.0f, 0.707f, 0.0f, /* color */ 1.0f, 0.0f, 0.0f, 1.0f,
+ -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
+ };
+
+ const int vertexCount = 3;
+ offscreen.vbo->allocate(sizeof(GLfloat) * vertexCount * 7);
+ offscreen.vbo->write(0, vertices, sizeof(GLfloat) * vertexCount * 7);
+
+ if (offscreen.vao->isCreated())
+ setupOffscreenVertexAttribs();
+
+ offscreen.projection.perspective(60.0f, OFFSCREEN_WIDTH / float(OFFSCREEN_HEIGHT), 0.1f, 100.0f);
+}
+
+void Window::initializeOnscreen()
+{
+ onscreen.prog = new QOpenGLShaderProgram;
+ onscreen.prog->addShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/shader_onscreen.vert"));
+ onscreen.prog->addShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/shader_onscreen.frag"));
+ onscreen.prog->bindAttributeLocation("position", 0);
+ onscreen.prog->bindAttributeLocation("texcoord", 1);
+ onscreen.prog->link();
+
+ onscreen.modelviewLoc = onscreen.prog->uniformLocation("modelview");
+ onscreen.projectionLoc = onscreen.prog->uniformLocation("projection");
+
+ onscreen.vao = new QOpenGLVertexArrayObject;
+ onscreen.vao->create();
+ QOpenGLVertexArrayObject::Binder vaoBinder(onscreen.vao);
+
+ onscreen.vbo = new QOpenGLBuffer;
+ onscreen.vbo->create();
+ onscreen.vbo->bind();
+
+ GLfloat v[] = {
+ -0.5, 0.5, 0.5, 0.5,-0.5,0.5,-0.5,-0.5,0.5,
+ 0.5, -0.5, 0.5, -0.5,0.5,0.5,0.5,0.5,0.5,
+ -0.5, -0.5, -0.5, 0.5,-0.5,-0.5,-0.5,0.5,-0.5,
+ 0.5, 0.5, -0.5, -0.5,0.5,-0.5,0.5,-0.5,-0.5,
+
+ 0.5, -0.5, -0.5, 0.5,-0.5,0.5,0.5,0.5,-0.5,
+ 0.5, 0.5, 0.5, 0.5,0.5,-0.5,0.5,-0.5,0.5,
+ -0.5, 0.5, -0.5, -0.5,-0.5,0.5,-0.5,-0.5,-0.5,
+ -0.5, -0.5, 0.5, -0.5,0.5,-0.5,-0.5,0.5,0.5,
+
+ 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,
+ -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5,
+ -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
+ 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5
+ };
+ GLfloat texCoords[] = {
+ 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
+ 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
+ 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
+ 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
+
+ 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f,
+ 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f,
+ 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f,
+ 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f,
+
+ 0.0f,1.0f, 1.0f,0.0f, 1.0f,1.0f,
+ 1.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f,
+ 1.0f,0.0f, 1.0f,1.0f, 0.0f,0.0f,
+ 0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f
+ };
+
+ const int vertexCount = 36;
+ onscreen.vbo->allocate(sizeof(GLfloat) * vertexCount * 5);
+ onscreen.vbo->write(0, v, sizeof(GLfloat) * vertexCount * 3);
+ onscreen.vbo->write(sizeof(GLfloat) * vertexCount * 3, texCoords, sizeof(GLfloat) * vertexCount * 2);
+
+ if (onscreen.vao->isCreated())
+ setupOnscreenVertexAttribs();
+
+ onscreen.projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::resizeGL(int, int)
+{
+ onscreen.projection.setToIdentity();
+ onscreen.projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::paintGL()
+{
+ paintOffscreen();
+ paintOnscreen();
+
+ update();
+}
+
+void Window::setupOffscreenVertexAttribs()
+{
+ QOpenGLFunctions *f = context()->functions();
+ offscreen.vbo->bind();
+ offscreen.prog->enableAttributeArray(0);
+ offscreen.prog->enableAttributeArray(1);
+ f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), 0);
+ f->glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (const void *)(3 * sizeof(GLfloat)));
+ offscreen.vbo->release();
+}
+
+void Window::paintOffscreen()
+{
+ QOpenGLFunctions *f = context()->functions();
+
+ offscreen.fbo->bind();
+ offscreen.prog->bind();
+ QOpenGLVertexArrayObject::Binder vaoBinder(offscreen.vao);
+ if (!offscreen.vao->isCreated())
+ setupOffscreenVertexAttribs();
+
+ QMatrix4x4 modelview;
+ modelview.translate(0, 0, -2);
+ modelview.rotate(offscreen.rotationAngle, 0, 0, 1);
+ offscreen.rotationAngle += 1;
+ offscreen.prog->setUniformValue(offscreen.modelviewLoc, modelview);
+ offscreen.prog->setUniformValue(offscreen.projectionLoc, offscreen.projection);
+
+ f->glViewport(0, 0, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT);
+ f->glClearColor(offscreenClearColor[0], offscreenClearColor[1], offscreenClearColor[2], offscreenClearColor[3]);
+ f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ f->glFrontFace(GL_CCW);
+ f->glDrawArrays(GL_TRIANGLES, 0, 3);
+
+ offscreen.fbo->release();
+}
+
+void Window::setupOnscreenVertexAttribs()
+{
+ QOpenGLFunctions *f = context()->functions();
+ onscreen.vbo->bind();
+ onscreen.prog->enableAttributeArray(0);
+ onscreen.prog->enableAttributeArray(1);
+ f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+ f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (const void *)(36 * 3 * sizeof(GLfloat)));
+ onscreen.vbo->release();
+}
+
+void Window::paintOnscreen()
+{
+ QOpenGLFunctions *f = context()->functions();
+
+ onscreen.prog->bind();
+ QOpenGLVertexArrayObject::Binder vaoBinder(onscreen.vao);
+ if (!onscreen.vao->isCreated())
+ setupOnscreenVertexAttribs();
+
+ f->glBindTexture(GL_TEXTURE_2D, offscreen.fbo->texture());
+
+ QMatrix4x4 modelview;
+ modelview.translate(0, 0, -2);
+ modelview.rotate(onscreen.rotationAngle, 1, 0.5, 0);
+ onscreen.rotationAngle += 1;
+ onscreen.prog->setUniformValue(onscreen.modelviewLoc, modelview);
+ onscreen.prog->setUniformValue(onscreen.projectionLoc, onscreen.projection);
+
+ f->glViewport(0, 0, width(), height());
+ f->glClearColor(onscreenClearColor[0], onscreenClearColor[1], onscreenClearColor[2], onscreenClearColor[3]);
+ f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ f->glFrontFace(GL_CW);
+ f->glDrawArrays(GL_TRIANGLES, 0, 36);
+}
+
+void Window::readbackAndSave()
+{
+ QImage img = offscreen.fbo->toImage();
+ QString fn = QFileDialog::getSaveFileName(Q_NULLPTR, QStringLiteral("Save PNG"), QString(), QStringLiteral("PNG files (*.png)"));
+ if (!fn.isEmpty()) {
+ img.save(fn);
+ QMessageBox::information(Q_NULLPTR, QStringLiteral("Saved"), QStringLiteral("Offscreen render target read back and saved to ") + fn);
+ }
+}
diff --git a/examples/hellooffscreen_opengl/window.h b/examples/hellooffscreen_opengl/window.h
new file mode 100644
index 0000000..4d7538c
--- /dev/null
+++ b/examples/hellooffscreen_opengl/window.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QOpenGLWindow>
+#include <QMatrix4x4>
+
+QT_BEGIN_NAMESPACE
+class QOpenGLFramebufferObject;
+class QOpenGLShaderProgram;
+class QOpenGLBuffer;
+class QOpenGLVertexArrayObject;
+QT_END_NAMESPACE
+
+class Window : public QOpenGLWindow
+{
+public:
+ Window();
+ ~Window();
+
+ void initializeGL() Q_DECL_OVERRIDE;
+ void resizeGL(int w, int h) Q_DECL_OVERRIDE;
+ void paintGL() Q_DECL_OVERRIDE;
+
+public slots:
+ void readbackAndSave();
+
+private:
+ void initializeOffscreen();
+ void initializeOnscreen();
+ void setupOffscreenVertexAttribs();
+ void paintOffscreen();
+ void setupOnscreenVertexAttribs();
+ void paintOnscreen();
+
+ struct OffscreenData {
+ OffscreenData() : rotationAngle(0), fbo(Q_NULLPTR), prog(Q_NULLPTR), vbo(Q_NULLPTR), vao(Q_NULLPTR) { }
+ QMatrix4x4 projection;
+ float rotationAngle;
+ QOpenGLFramebufferObject *fbo;
+ QOpenGLShaderProgram *prog;
+ QOpenGLBuffer *vbo;
+ QOpenGLVertexArrayObject *vao;
+ int modelviewLoc;
+ int projectionLoc;
+ } offscreen;
+
+ struct OnscreenData {
+ OnscreenData() : rotationAngle(0), prog(Q_NULLPTR), vbo(Q_NULLPTR), vao(Q_NULLPTR) { }
+ QMatrix4x4 projection;
+ float rotationAngle;
+ QOpenGLShaderProgram *prog;
+ QOpenGLBuffer *vbo;
+ QOpenGLVertexArrayObject *vao;
+ int modelviewLoc;
+ int projectionLoc;
+ } onscreen;
+};
diff --git a/examples/hellotexture/hellotexture.pro b/examples/hellotexture/hellotexture.pro
new file mode 100644
index 0000000..b173c9c
--- /dev/null
+++ b/examples/hellotexture/hellotexture.pro
@@ -0,0 +1,23 @@
+TEMPLATE = app
+QT += d3d12window widgets
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
+RESOURCES = hellotexture.qrc
+
+LIBS = -ld3d12
+
+VSPS = shader.hlsl
+
+vshader.input = VSPS
+vshader.header = shader_vs.h
+vshader.entry = VS_Texture
+vshader.type = vs_5_0
+
+pshader.input = VSPS
+pshader.header = shader_ps.h
+pshader.entry = PS_Texture
+pshader.type = ps_5_0
+
+HLSL_SHADERS = vshader pshader
+load(hlsl)
diff --git a/examples/hellotexture/hellotexture.qrc b/examples/hellotexture/hellotexture.qrc
new file mode 100644
index 0000000..ff1d0e5
--- /dev/null
+++ b/examples/hellotexture/hellotexture.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>qt.png</file>
+</qresource>
+</RCC>
diff --git a/examples/hellotexture/main.cpp b/examples/hellotexture/main.cpp
new file mode 100644
index 0000000..be2ebb7
--- /dev/null
+++ b/examples/hellotexture/main.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QWidget>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QScrollArea>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ Window *d3dw = new Window;
+ QWidget w;
+ QVBoxLayout *vl = new QVBoxLayout;
+ vl->addWidget(new QPushButton("Widgets + a native child window with D3D12, this time in a scroll area"));
+ vl->addWidget(new QLabel("Now with a texture and mipmaps!"));
+ QWidget *ww = QWidget::createWindowContainer(d3dw);
+ ww->setMinimumWidth(1000);
+ ww->setMinimumHeight(1000);
+ // NB using a scroll area will result in creating a native window for every
+ // widget in the parent chain in order to ensure proper clipping.
+ QScrollArea *sa = new QScrollArea;
+ sa->setWidget(ww);
+ vl->addWidget(sa);
+ w.resize(400, 400);
+ w.setLayout(vl);
+ w.show();
+
+ return app.exec();
+}
diff --git a/examples/hellotexture/qt.png b/examples/hellotexture/qt.png
new file mode 100644
index 0000000..f30eec0
--- /dev/null
+++ b/examples/hellotexture/qt.png
Binary files differ
diff --git a/examples/hellotexture/shader.hlsl b/examples/hellotexture/shader.hlsl
new file mode 100644
index 0000000..be69b39
--- /dev/null
+++ b/examples/hellotexture/shader.hlsl
@@ -0,0 +1,36 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 modelview;
+ float4x4 projection;
+};
+
+struct VSInput
+{
+ float4 position : POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+};
+
+Texture2D tex : register(t0);
+SamplerState samp : register(s0);
+
+PSInput VS_Texture(VSInput input)
+{
+ PSInput result;
+
+ float4x4 mvp = mul(projection, modelview);
+ result.position = mul(mvp, input.position);
+ result.coord = input.coord;
+
+ return result;
+}
+
+float4 PS_Texture(PSInput input) : SV_TARGET
+{
+ return tex.Sample(samp, input.coord);
+}
diff --git a/examples/hellotexture/window.cpp b/examples/hellotexture/window.cpp
new file mode 100644
index 0000000..0dfb31a
--- /dev/null
+++ b/examples/hellotexture/window.cpp
@@ -0,0 +1,406 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include "shader_vs.h"
+#include "shader_ps.h"
+
+static const int TEXTURE_WIDTH = 512;
+static const int TEXTURE_HEIGHT = 512;
+static const int TEXTURE_MIP_LEVELS = 8;
+
+Window::Window()
+ : f(Q_NULLPTR),
+ cbPtr(Q_NULLPTR),
+ rotationAngle(0)
+{
+}
+
+Window::~Window()
+{
+ if (cbPtr)
+ constantBuffer->Unmap(0, Q_NULLPTR);
+
+ delete f;
+}
+
+void Window::initializeD3D()
+{
+ QImage qtLogo = QImage(QStringLiteral(":/qt.png")).convertToFormat(QImage::Format_RGBA8888).scaled(TEXTURE_WIDTH, TEXTURE_HEIGHT);
+ if (qtLogo.isNull()) {
+ qWarning("Failed to load image data");
+ return;
+ }
+
+ f = createFence();
+ ID3D12Device *dev = device();
+
+ // One static sampler (no sampler heap is needed).
+ D3D12_STATIC_SAMPLER_DESC sampler = {};
+ sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
+ sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ sampler.MinLOD = 0.0f;
+ sampler.MaxLOD = D3D12_FLOAT32_MAX;
+ sampler.ShaderRegister = 0;
+ sampler.RegisterSpace = 0;
+ sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ // In addition to the constant buffer view we will now also have a shader
+ // resource view in order to expose the texture to the pixel shader.
+ D3D12_DESCRIPTOR_RANGE descRange[2];
+ descRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
+ descRange[0].NumDescriptors = 1;
+ descRange[0].BaseShaderRegister = 0; // b0
+ descRange[0].RegisterSpace = 0;
+ descRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+ descRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ descRange[1].NumDescriptors = 1;
+ descRange[1].BaseShaderRegister = 0; // t0
+ descRange[1].RegisterSpace = 0;
+ descRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
+
+ D3D12_ROOT_PARAMETER rootParameter;
+ rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ rootParameter.DescriptorTable.NumDescriptorRanges = 2;
+ rootParameter.DescriptorTable.pDescriptorRanges = descRange;
+
+ D3D12_ROOT_SIGNATURE_DESC desc;
+ desc.NumParameters = 1;
+ desc.pParameters = &rootParameter;
+ desc.NumStaticSamplers = 1;
+ desc.pStaticSamplers = &sampler;
+ desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ qWarning("Failed to serialize root signature");
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&rootSignature)))) {
+ qWarning("Failed to create root signature");
+ return;
+ }
+
+ D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
+ };
+
+ D3D12_SHADER_BYTECODE vshader;
+ vshader.pShaderBytecode = g_VS_Texture;
+ vshader.BytecodeLength = sizeof(g_VS_Texture);
+ D3D12_SHADER_BYTECODE pshader;
+ pshader.pShaderBytecode = g_PS_Texture;
+ pshader.BytecodeLength = sizeof(g_PS_Texture);
+
+ D3D12_RASTERIZER_DESC rastDesc = {};
+ rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
+ rastDesc.CullMode = D3D12_CULL_MODE_BACK;
+ rastDesc.FrontCounterClockwise = TRUE; // Vertices are given CCW
+ rastDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ rastDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ rastDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ rastDesc.DepthClipEnable = TRUE;
+
+ // Our material is transparent (the image has alpha < 255). Enable blending.
+ const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
+ TRUE, FALSE,
+ D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD,
+ D3D12_BLEND_ZERO, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
+ D3D12_LOGIC_OP_NOOP,
+ D3D12_COLOR_WRITE_ENABLE_ALL
+ };
+ D3D12_BLEND_DESC blendDesc = {};
+ blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc;
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
+ psoDesc.pRootSignature = rootSignature.Get();
+ psoDesc.VS = vshader;
+ psoDesc.PS = pshader;
+ psoDesc.RasterizerState = rastDesc;
+ psoDesc.BlendState = blendDesc;
+ psoDesc.DepthStencilState.DepthEnable = TRUE;
+ psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+ psoDesc.DepthStencilState.StencilEnable = FALSE;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
+ psoDesc.SampleDesc.Count = 1;
+ if (FAILED(dev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)))) {
+ qWarning("Failed to create graphics pipeline state");
+ return;
+ }
+
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR, IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+
+ // Vertex buffer
+ const float vertices[] = {
+ -0.5f, -0.5f, 0, /* coords */ 0, 1, // the image was not flipped so accommodate for it here
+ 0.5f, -0.5f, 0, 1, 1,
+ -0.5f, 0.5f, 0, 0, 0,
+
+ -0.5f, 0.5f, 0, 0, 0,
+ 0.5f, -0.5f, 0, 1, 1,
+ 0.5f, 0.5f, 0, 1, 0
+ };
+ const UINT vertexBufferSize = sizeof(vertices);
+
+ D3D12_HEAP_PROPERTIES defaultHeapProp = {};
+ defaultHeapProp.Type = D3D12_HEAP_TYPE_DEFAULT;
+ D3D12_HEAP_PROPERTIES uploadHeapProp = defaultHeapProp;
+ uploadHeapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
+
+ D3D12_RESOURCE_DESC bufDesc = {};
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ bufDesc.Width = vertexBufferSize;
+ bufDesc.Height = 1;
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_UNKNOWN;
+ bufDesc.SampleDesc.Count = 1;
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&vertexBuffer)))) {
+ qWarning("Failed to create committed resource (vertex buffer)");
+ return;
+ }
+
+ quint8 *p = Q_NULLPTR;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (vertex buffer)");
+ return;
+ }
+ memcpy(p, vertices, vertexBufferSize);
+ vertexBuffer->Unmap(0, Q_NULLPTR);
+
+ vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
+ vertexBufferView.StrideInBytes = (3 + 2) * sizeof(float);
+ vertexBufferView.SizeInBytes = vertexBufferSize;
+
+ // Constant buffer
+ const UINT CB_SIZE = alignedCBSize(128); // 2 * float4x4
+ bufDesc.Width = CB_SIZE;
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&constantBuffer)))) {
+ qWarning("Failed to create committed resource (constant buffer)");
+ return;
+ }
+
+ if (FAILED(constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (constant buffer)");
+ return;
+ }
+ cbPtr = p; // won't Unmap() this here
+
+ // Texture (with mipmaps, to make it more exciting)
+ D3D12_RESOURCE_DESC textureDesc = {};
+ textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+ textureDesc.Width = TEXTURE_WIDTH;
+ textureDesc.Height = TEXTURE_HEIGHT;
+ textureDesc.DepthOrArraySize = 1;
+ textureDesc.MipLevels = TEXTURE_MIP_LEVELS;
+ textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ textureDesc.SampleDesc.Count = 1;
+ textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+
+ // Ignore UMA for now and do the discrete-friendly upload via an upload buffer (no CPU access to the texture).
+ if (FAILED(dev->CreateCommittedResource(&defaultHeapProp, D3D12_HEAP_FLAG_NONE, &textureDesc,
+ D3D12_RESOURCE_STATE_COPY_DEST, Q_NULLPTR, IID_PPV_ARGS(&texture)))) {
+ qWarning("Failed to create texture resource");
+ return;
+ }
+
+ ComPtr<ID3D12Resource> textureUploadBuffer;
+ UINT64 textureUploadBufferSize;
+ D3D12_PLACED_SUBRESOURCE_FOOTPRINT textureLayout[TEXTURE_MIP_LEVELS];
+ dev->GetCopyableFootprints(&textureDesc, 0, TEXTURE_MIP_LEVELS, 0, textureLayout,
+ Q_NULLPTR, Q_NULLPTR, &textureUploadBufferSize);
+ bufDesc.Width = textureUploadBufferSize;
+ if (FAILED(dev->CreateCommittedResource(&uploadHeapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&textureUploadBuffer)))) {
+ qWarning("Failed to create texture upload buffer resource");
+ return;
+ }
+
+ if (FAILED(textureUploadBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (texture upload buffer)");
+ return;
+ }
+ int mipW = qtLogo.width(), mipH = qtLogo.height();
+ for (int level = 0; level < TEXTURE_MIP_LEVELS; ++level) {
+ quint8 *mipP = p + textureLayout[level].Offset;
+ // This is not quite how mipmaps are created ideally, but will do for now...
+ QImage img = qtLogo.scaled(mipW, mipH);
+ for (int y = 0; y < mipH; ++y) {
+ memcpy(mipP, img.scanLine(y), mipW * 4);
+ mipP += textureLayout[level].Footprint.RowPitch; // stride is at least 256 here
+ }
+ mipW /= 2;
+ mipH /= 2;
+ }
+ textureUploadBuffer->Unmap(0, Q_NULLPTR);
+
+ for (int level = 0; level < TEXTURE_MIP_LEVELS; ++level) {
+ D3D12_TEXTURE_COPY_LOCATION dstLoc;
+ dstLoc.pResource = texture.Get();
+ dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ dstLoc.SubresourceIndex = level;
+ D3D12_TEXTURE_COPY_LOCATION srcLoc;
+ srcLoc.pResource = textureUploadBuffer.Get();
+ srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ srcLoc.PlacedFootprint = textureLayout[level];
+ commandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, Q_NULLPTR); // upload buffer -> texture
+ }
+
+ // once the copy is done the texture is ready to be used from the pixel shader
+ transitionResource(texture.Get(), commandList.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
+
+ // Constant buffer view and shader resource view descriptors are stored in the same heap.
+ const UINT cbvSrvStride = dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+ D3D12_DESCRIPTOR_HEAP_DESC cbvSrvHeapDesc = {};
+ cbvSrvHeapDesc.NumDescriptors = 2;
+ cbvSrvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+ cbvSrvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ if (FAILED(dev->CreateDescriptorHeap(&cbvSrvHeapDesc, IID_PPV_ARGS(&cbvSrvHeap)))) {
+ qWarning("Failed to create CBV/SRV/UAV descriptor heap");
+ return;
+ }
+
+ D3D12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle = cbvSrvHeap->GetCPUDescriptorHandleForHeapStart();
+ D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
+ cbvDesc.BufferLocation = constantBuffer->GetGPUVirtualAddress();
+ cbvDesc.SizeInBytes = CB_SIZE;
+ dev->CreateConstantBufferView(&cbvDesc, cbvSrvHandle);
+ cbvSrvHandle.ptr += cbvSrvStride;
+
+ D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
+ srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+ srvDesc.Format = textureDesc.Format;
+ srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = TEXTURE_MIP_LEVELS;
+ dev->CreateShaderResourceView(texture.Get(), &srvDesc, cbvSrvHandle);
+
+ // Execute the texture upload.
+ commandList->Close();
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ // Block until all the above has finished.
+ waitForGPU(f);
+
+ setupProjection();
+}
+
+void Window::resizeD3D(const QSize &)
+{
+ setupProjection();
+}
+
+void Window::setupProjection()
+{
+ projection.setToIdentity();
+ projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::paintD3D()
+{
+ modelview.setToIdentity();
+ modelview.translate(0, 0, -2);
+ // our highly sophisticated animation
+ modelview.rotate(rotationAngle, 0, 0, 1);
+ rotationAngle += 1;
+
+ memcpy(cbPtr, modelview.constData(), 16 * sizeof(float));
+ memcpy(cbPtr + 16 * sizeof(float), projection.constData(), 16 * sizeof(float));
+
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), pipelineState.Get());
+
+ commandList->SetGraphicsRootSignature(rootSignature.Get());
+
+ ID3D12DescriptorHeap *heaps[] = { cbvSrvHeap.Get() };
+ commandList->SetDescriptorHeaps(_countof(heaps), heaps);
+ commandList->SetGraphicsRootDescriptorTable(0, cbvSrvHeap->GetGPUDescriptorHandleForHeapStart());
+
+ D3D12_VIEWPORT viewport = { 0, 0, float(width()), float(height()), 0, 1 };
+ commandList->RSSetViewports(1, &viewport);
+ D3D12_RECT scissorRect = { 0, 0, width() - 1, height() - 1 };
+ commandList->RSSetScissorRects(1, &scissorRect);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = backBufferRenderTargetCPUHandle();
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = depthStencilCPUHandle();
+ commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
+
+ const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
+ commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, Q_NULLPTR);
+ commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, Q_NULLPTR);
+
+ commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ commandList->IASetVertexBuffers(0, 1, &vertexBufferView);
+ commandList->DrawInstanced(6, 1, 0, 0);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+ commandList->Close();
+
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ update();
+}
+
+void Window::afterPresent()
+{
+ waitForGPU(f);
+}
diff --git a/examples/hellotexture/window.h b/examples/hellotexture/window.h
new file mode 100644
index 0000000..a0fef7b
--- /dev/null
+++ b/examples/hellotexture/window.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QD3D12Window>
+#include <QMatrix4x4>
+
+class Window : public QD3D12Window
+{
+public:
+ Window();
+ ~Window();
+
+ void initializeD3D() Q_DECL_OVERRIDE;
+ void resizeD3D(const QSize &size) Q_DECL_OVERRIDE;
+ void paintD3D() Q_DECL_OVERRIDE;
+ void afterPresent() Q_DECL_OVERRIDE;
+
+private:
+ void setupProjection();
+
+ Fence *f;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ ComPtr<ID3D12PipelineState> pipelineState;
+ ComPtr<ID3D12RootSignature> rootSignature;
+ ComPtr<ID3D12Resource> vertexBuffer;
+ ComPtr<ID3D12Resource> constantBuffer;
+ ComPtr<ID3D12Resource> texture;
+ ComPtr<ID3D12DescriptorHeap> cbvSrvHeap;
+ D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
+
+ QMatrix4x4 projection;
+ QMatrix4x4 modelview;
+ quint8 *cbPtr;
+ float rotationAngle;
+};
diff --git a/examples/hellotriangle/hellotriangle.pro b/examples/hellotriangle/hellotriangle.pro
new file mode 100644
index 0000000..0d36378
--- /dev/null
+++ b/examples/hellotriangle/hellotriangle.pro
@@ -0,0 +1,22 @@
+TEMPLATE = app
+QT += d3d12window widgets
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
+
+LIBS = -ld3d12
+
+VSPS = shader.hlsl
+
+vshader.input = VSPS
+vshader.header = shader_vs.h
+vshader.entry = VS_Simple
+vshader.type = vs_5_0
+
+pshader.input = VSPS
+pshader.header = shader_ps.h
+pshader.entry = PS_Simple
+pshader.type = ps_5_0
+
+HLSL_SHADERS = vshader pshader
+load(hlsl)
diff --git a/examples/hellotriangle/main.cpp b/examples/hellotriangle/main.cpp
new file mode 100644
index 0000000..94f9ae7
--- /dev/null
+++ b/examples/hellotriangle/main.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QWidget>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QCalendarWidget>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ Window *d3dw = new Window;
+ QWidget w;
+ QVBoxLayout *vl = new QVBoxLayout;
+ vl->addWidget(new QPushButton("Widgets + a native child window with D3D12"));
+ vl->addWidget(new QCalendarWidget);
+ QWidget *ww = QWidget::createWindowContainer(d3dw);
+ ww->setMinimumHeight(300);
+ vl->addWidget(ww);
+ w.resize(400, 400);
+ w.setLayout(vl);
+ w.show();
+
+ return app.exec();
+}
diff --git a/examples/hellotriangle/shader.hlsl b/examples/hellotriangle/shader.hlsl
new file mode 100644
index 0000000..8b9b9ff
--- /dev/null
+++ b/examples/hellotriangle/shader.hlsl
@@ -0,0 +1,27 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 modelview;
+ float4x4 projection;
+};
+
+struct PSInput
+{
+ float4 position : SV_POSITION;
+ float4 color : COLOR;
+};
+
+PSInput VS_Simple(float4 position : POSITION, float4 color : COLOR)
+{
+ PSInput result;
+
+ float4x4 mvp = mul(projection, modelview);
+ result.position = mul(mvp, position);
+ result.color = color;
+
+ return result;
+}
+
+float4 PS_Simple(PSInput input) : SV_TARGET
+{
+ return input.color;
+}
diff --git a/examples/hellotriangle/window.cpp b/examples/hellotriangle/window.cpp
new file mode 100644
index 0000000..049b467
--- /dev/null
+++ b/examples/hellotriangle/window.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include "shader_vs.h"
+#include "shader_ps.h"
+
+Window::Window()
+ : f(Q_NULLPTR),
+ cbPtr(Q_NULLPTR),
+ rotationAngle(0)
+{
+}
+
+Window::~Window()
+{
+ if (cbPtr)
+ constantBuffer->Unmap(0, Q_NULLPTR);
+
+ delete f;
+}
+
+void Window::initializeD3D()
+{
+ f = createFence();
+ ID3D12Device *dev = device();
+
+ D3D12_ROOT_PARAMETER rootParameter;
+ rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+ rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+ rootParameter.Descriptor.ShaderRegister = 0; // b0
+ rootParameter.Descriptor.RegisterSpace = 0;
+
+ D3D12_ROOT_SIGNATURE_DESC desc;
+ desc.NumParameters = 1;
+ desc.pParameters = &rootParameter;
+ desc.NumStaticSamplers = 0;
+ desc.pStaticSamplers = Q_NULLPTR;
+ desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+ ComPtr<ID3DBlob> signature;
+ ComPtr<ID3DBlob> error;
+ if (FAILED(D3D12SerializeRootSignature(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error))) {
+ qWarning("Failed to serialize root signature");
+ return;
+ }
+ if (FAILED(dev->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&rootSignature)))) {
+ qWarning("Failed to create root signature");
+ return;
+ }
+
+ D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
+ };
+
+ D3D12_SHADER_BYTECODE vshader;
+ vshader.pShaderBytecode = g_VS_Simple;
+ vshader.BytecodeLength = sizeof(g_VS_Simple);
+ D3D12_SHADER_BYTECODE pshader;
+ pshader.pShaderBytecode = g_PS_Simple;
+ pshader.BytecodeLength = sizeof(g_PS_Simple);
+
+ D3D12_RASTERIZER_DESC rastDesc = {};
+ rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
+ rastDesc.CullMode = D3D12_CULL_MODE_BACK;
+ rastDesc.FrontCounterClockwise = TRUE; // Vertices are given CCW
+ rastDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ rastDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ rastDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ rastDesc.DepthClipEnable = TRUE;
+
+ // No blending, just enable color write.
+ D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {};
+ defaultRenderTargetBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+ D3D12_BLEND_DESC blendDesc = {};
+ blendDesc.RenderTarget[0] = defaultRenderTargetBlendDesc;
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
+ psoDesc.pRootSignature = rootSignature.Get();
+ psoDesc.VS = vshader;
+ psoDesc.PS = pshader;
+ psoDesc.RasterizerState = rastDesc;
+ psoDesc.BlendState = blendDesc;
+ psoDesc.DepthStencilState.DepthEnable = TRUE;
+ psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
+ psoDesc.DepthStencilState.StencilEnable = FALSE;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
+ psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
+ psoDesc.SampleDesc.Count = 1;
+ if (FAILED(dev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState)))) {
+ qWarning("Failed to create graphics pipeline state");
+ return;
+ }
+
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR, IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+ commandList->Close();
+
+ const float vertices[] = {
+ 0.0f, 0.707f, 0.0f, /* color */ 1.0f, 0.0f, 0.0f, 1.0f,
+ -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
+ };
+ const UINT vertexBufferSize = sizeof(vertices);
+
+ D3D12_HEAP_PROPERTIES heapProp = {};
+ heapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
+
+ D3D12_RESOURCE_DESC bufDesc;
+ bufDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ bufDesc.Alignment = 0;
+ bufDesc.Width = vertexBufferSize;
+ bufDesc.Height = 1;
+ bufDesc.DepthOrArraySize = 1;
+ bufDesc.MipLevels = 1;
+ bufDesc.Format = DXGI_FORMAT_UNKNOWN;
+ bufDesc.SampleDesc.Count = 1;
+ bufDesc.SampleDesc.Quality = 0;
+ bufDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ bufDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ if (FAILED(dev->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&vertexBuffer)))) {
+ qWarning("Failed to create committed resource (vertex buffer)");
+ return;
+ }
+
+ quint8 *p = Q_NULLPTR;
+ D3D12_RANGE readRange = { 0, 0 };
+ if (FAILED(vertexBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed");
+ return;
+ }
+ memcpy(p, vertices, vertexBufferSize);
+ vertexBuffer->Unmap(0, Q_NULLPTR);
+
+ vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
+ vertexBufferView.StrideInBytes = (3 + 4) * sizeof(float);
+ vertexBufferView.SizeInBytes = vertexBufferSize;
+
+ const UINT CB_SIZE = alignedCBSize(128); // 2 * float4x4
+ bufDesc.Width = CB_SIZE;
+ if (FAILED(dev->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &bufDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, Q_NULLPTR, IID_PPV_ARGS(&constantBuffer)))) {
+ qWarning("Failed to create committed resource (constant buffer)");
+ return;
+ }
+
+ if (FAILED(constantBuffer->Map(0, &readRange, reinterpret_cast<void **>(&p)))) {
+ qWarning("Map failed (constant buffer)");
+ return;
+ }
+ cbPtr = p;
+
+ setupProjection();
+}
+
+void Window::resizeD3D(const QSize &)
+{
+ setupProjection();
+}
+
+void Window::setupProjection()
+{
+ projection.setToIdentity();
+ projection.perspective(60.0f, width() / float(height()), 0.1f, 100.0f);
+}
+
+void Window::paintD3D()
+{
+ modelview.setToIdentity();
+ modelview.translate(0, 0, -2);
+ // our highly sophisticated animation
+ modelview.rotate(rotationAngle, 0, 0, 1);
+ rotationAngle += 1;
+
+ memcpy(cbPtr, modelview.constData(), 16 * sizeof(float));
+ memcpy(cbPtr + 16 * sizeof(float), projection.constData(), 16 * sizeof(float));
+
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), pipelineState.Get());
+
+ commandList->SetGraphicsRootSignature(rootSignature.Get()); // invalidates bindings
+
+ commandList->SetGraphicsRootConstantBufferView(0, constantBuffer->GetGPUVirtualAddress());
+
+ D3D12_VIEWPORT viewport = { 0, 0, float(width()), float(height()), 0, 1 };
+ commandList->RSSetViewports(1, &viewport);
+ D3D12_RECT scissorRect = { 0, 0, width() - 1, height() - 1 };
+ commandList->RSSetScissorRects(1, &scissorRect);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = backBufferRenderTargetCPUHandle();
+ D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = depthStencilCPUHandle();
+ commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
+
+ const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
+ commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, Q_NULLPTR);
+ commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, Q_NULLPTR);
+
+ commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ commandList->IASetVertexBuffers(0, 1, &vertexBufferView);
+ commandList->DrawInstanced(3, 1, 0, 0);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+ commandList->Close();
+
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ update();
+}
+
+void Window::afterPresent()
+{
+ waitForGPU(f);
+}
diff --git a/examples/hellotriangle/window.h b/examples/hellotriangle/window.h
new file mode 100644
index 0000000..d50a5a4
--- /dev/null
+++ b/examples/hellotriangle/window.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QD3D12Window>
+#include <QMatrix4x4>
+
+class Window : public QD3D12Window
+{
+public:
+ Window();
+ ~Window();
+
+ void initializeD3D() Q_DECL_OVERRIDE;
+ void resizeD3D(const QSize &size) Q_DECL_OVERRIDE;
+ void paintD3D() Q_DECL_OVERRIDE;
+ void afterPresent() Q_DECL_OVERRIDE;
+
+private:
+ void setupProjection();
+
+ Fence *f;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ ComPtr<ID3D12PipelineState> pipelineState;
+ ComPtr<ID3D12RootSignature> rootSignature;
+ ComPtr<ID3D12Resource> vertexBuffer;
+ ComPtr<ID3D12Resource> constantBuffer;
+ D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
+
+ QMatrix4x4 projection;
+ QMatrix4x4 modelview;
+ quint8 *cbPtr;
+ float rotationAngle;
+};
diff --git a/examples/hellowindow/hellowindow.pro b/examples/hellowindow/hellowindow.pro
new file mode 100644
index 0000000..6922627
--- /dev/null
+++ b/examples/hellowindow/hellowindow.pro
@@ -0,0 +1,5 @@
+TEMPLATE = app
+QT += d3d12window
+
+SOURCES = main.cpp window.cpp
+HEADERS = window.h
diff --git a/examples/hellowindow/main.cpp b/examples/hellowindow/main.cpp
new file mode 100644
index 0000000..08baaff
--- /dev/null
+++ b/examples/hellowindow/main.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include "window.h"
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+ Window window;
+ window.resize(1024, 768);
+ window.show();
+ return app.exec();
+}
diff --git a/examples/hellowindow/window.cpp b/examples/hellowindow/window.cpp
new file mode 100644
index 0000000..9682d56
--- /dev/null
+++ b/examples/hellowindow/window.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+
+Window::Window()
+ : f(Q_NULLPTR),
+ green(0)
+{
+}
+
+Window::~Window()
+{
+ delete f;
+}
+
+void Window::initializeD3D()
+{
+ f = createFence();
+ ID3D12Device *dev = device();
+ if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR, IID_PPV_ARGS(&commandList)))) {
+ qWarning("Failed to create command list");
+ return;
+ }
+ commandList->Close();
+}
+
+void Window::resizeD3D(const QSize &size)
+{
+ qDebug("resize %d %d", size.width(), size.height());
+}
+
+void Window::paintD3D()
+{
+ commandAllocator()->Reset();
+ commandList->Reset(commandAllocator(), Q_NULLPTR);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ green += 0.01f;
+ if (green > 1.0f)
+ green = 0.0f;
+ const float clearColor[] = { 0.0f, green, 0.0f, 1.0f };
+ commandList->ClearRenderTargetView(backBufferRenderTargetCPUHandle(), clearColor, 0, Q_NULLPTR);
+
+ transitionResource(backBufferRenderTarget(), commandList.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
+ commandList->Close();
+
+ ID3D12CommandList *commandLists[] = { commandList.Get() };
+ commandQueue()->ExecuteCommandLists(_countof(commandLists), commandLists);
+
+ update(); // schedule the next frame by posting an UpdateRequest event
+}
+
+void Window::afterPresent()
+{
+ waitForGPU(f);
+}
diff --git a/examples/hellowindow/window.h b/examples/hellowindow/window.h
new file mode 100644
index 0000000..9114e00
--- /dev/null
+++ b/examples/hellowindow/window.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtD3D12Window module
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QD3D12Window>
+
+class Window : public QD3D12Window
+{
+public:
+ Window();
+ ~Window();
+
+ void initializeD3D() Q_DECL_OVERRIDE;
+ void resizeD3D(const QSize &size) Q_DECL_OVERRIDE;
+ void paintD3D() Q_DECL_OVERRIDE;
+ void afterPresent() Q_DECL_OVERRIDE;
+
+private:
+ Fence *f;
+ ComPtr<ID3D12GraphicsCommandList> commandList;
+ float green;
+};