diff options
Diffstat (limited to 'examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp')
-rw-r--r-- | examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp b/examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp new file mode 100644 index 0000000000..be1f6d842c --- /dev/null +++ b/examples/quick/rendercontrol/rendercontrol_d3d11/engine.cpp @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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 "engine.h" +#include <QLibrary> +#include <comdef.h> + +#define ENABLE_DEBUG_LAYER + +Engine::~Engine() +{ + RELEASE(m_context); + RELEASE(m_device); + RELEASE(m_dxgiFactory); +} + +QString comErrorMessage(HRESULT hr) +{ +#ifndef Q_OS_WINRT + const _com_error comError(hr); +#else + const _com_error comError(hr, nullptr); +#endif + QString result = QLatin1String("Error 0x") + QString::number(ulong(hr), 16); + if (const wchar_t *msg = comError.ErrorMessage()) + result += QLatin1String(": ") + QString::fromWCharArray(msg); + return result; +} + +bool Engine::create() +{ + using PtrCreateDXGIFactory2 = HRESULT (WINAPI *)(UINT, REFIID, void **); + QLibrary dxgilib(QStringLiteral("dxgi")); + if (auto createDXGIFactory2 = reinterpret_cast<PtrCreateDXGIFactory2>(dxgilib.resolve("CreateDXGIFactory2"))) { + const HRESULT hr = createDXGIFactory2(0, IID_IDXGIFactory2, reinterpret_cast<void **>(&m_dxgiFactory)); + if (FAILED(hr)) { + qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", qPrintable(comErrorMessage(hr))); + return false; + } + } else { + qWarning("Unable to resolve CreateDXGIFactory2()"); + return false; + } + + ID3D11DeviceContext *ctx = nullptr; + uint flags = 0; +#ifdef ENABLE_DEBUG_LAYER + flags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + // use the default hardware adapter + HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, + nullptr, 0, D3D11_SDK_VERSION, + &m_device, &m_featureLevel, &ctx); + if (FAILED(hr)) { + qWarning("Failed to create D3D11 device and context: %s", qPrintable(comErrorMessage(hr))); + return false; + } + + if (SUCCEEDED(ctx->QueryInterface(IID_ID3D11DeviceContext1, reinterpret_cast<void **>(&m_context)))) { + ctx->Release(); + } else { + qWarning("ID3D11DeviceContext1 not supported"); + return false; + } + + return true; +} + +QSize Engine::swapchainSizeForWindow(QWindow *window) const +{ + const QSize size = window->size() * window->devicePixelRatio(); + return QSize(qMax(8, size.width()), qMax(8, size.height())); +} + +Swapchain Engine::createSwapchain(QWindow *window) +{ + Swapchain sc = {}; + const HWND hwnd = reinterpret_cast<HWND>(window->winId()); + const QSize pixelSize = swapchainSizeForWindow(window); + + // only care about flip discard swapchains here; the old stuff (discard) is + // not supported in this example + + DXGI_SWAP_CHAIN_DESC1 desc = {}; + desc.Width = UINT(pixelSize.width()); + desc.Height = UINT(pixelSize.height()); + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 2; + desc.Scaling = DXGI_SCALING_STRETCH; + desc.SwapEffect = DXGI_SWAP_EFFECT(4); // DXGI_SWAP_EFFECT_FLIP_DISCARD + + IDXGISwapChain1 *swapchain = nullptr; + HRESULT hr = static_cast<IDXGIFactory2 *>(m_dxgiFactory)->CreateSwapChainForHwnd(m_device, hwnd, &desc, + nullptr, nullptr, &swapchain); + if (FAILED(hr)) { + qWarning("Failed to create D3D11 swapchain: %s", qPrintable(comErrorMessage(hr))); + return sc; + } + + sc.swapchain = swapchain; + sc.pixelSize = pixelSize; + createSwapchainBuffers(&sc); + return sc; +} + +void Engine::createSwapchainBuffers(Swapchain *sc) +{ + ID3D11Texture2D *tex = nullptr; + HRESULT hr = sc->swapchain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast<void **>(&tex)); + if (FAILED(hr)) { + qWarning("Failed to query swapchain backbuffer: %s", qPrintable(comErrorMessage(hr))); + return; + } + + ID3D11RenderTargetView *rtv = nullptr; + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {}; + rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + hr = m_device->CreateRenderTargetView(tex, &rtvDesc, &rtv); + if (FAILED(hr)) { + qWarning("Failed to create rtv for swapchain backbuffer: %s", qPrintable(comErrorMessage(hr))); + tex->Release(); + return; + } + + D3D11_TEXTURE2D_DESC texDesc = {}; + texDesc.Width = UINT(sc->pixelSize.width()); + texDesc.Height = UINT(sc->pixelSize.height()); + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.SampleDesc.Count = 1; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + + ID3D11Texture2D *ds = nullptr; + hr = m_device->CreateTexture2D(&texDesc, nullptr, &ds); + if (FAILED(hr)) { + qWarning("Failed to create depth-stencil buffer: %s", qPrintable(comErrorMessage(hr))); + tex->Release(); + rtv->Release(); + return; + } + + ID3D11DepthStencilView *dsv = nullptr; + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; + dsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + hr = m_device->CreateDepthStencilView(ds, &dsvDesc, &dsv); + if (FAILED(hr)) { + qWarning("Failed to create dsv: %s", qPrintable(comErrorMessage(hr))); + tex->Release(); + rtv->Release(); + ds->Release(); + return; + } + + sc->tex = tex; + sc->rtv = rtv; + sc->ds = ds; + sc->dsv = dsv; +} + +void Engine::resizeSwapchain(Swapchain *sc, QWindow *window) +{ + const QSize pixelSize = swapchainSizeForWindow(window); + + RELEASE(sc->dsv); + RELEASE(sc->ds); + RELEASE(sc->rtv); + RELEASE(sc->tex); + + HRESULT hr = sc->swapchain->ResizeBuffers(2, UINT(pixelSize.width()), UINT(pixelSize.height()), + DXGI_FORMAT_R8G8B8A8_UNORM, 0); + if (FAILED(hr)) { + qWarning("Failed to resize D3D11 swapchain: %s", qPrintable(comErrorMessage(hr))); + return; + } + + sc->pixelSize = pixelSize; + createSwapchainBuffers(sc); +} + +void Swapchain::destroy() +{ + RELEASE(dsv); + RELEASE(ds); + RELEASE(rtv); + RELEASE(tex); + RELEASE(swapchain); + pixelSize = QSize(); +} |