230 lines
8.1 KiB
C++
230 lines
8.1 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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)
|
|
{
|
|
const _com_error comError(hr);
|
|
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;
|
|
}
|
|
|
|
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, &m_context);
|
|
if (FAILED(hr)) {
|
|
qWarning("Failed to create D3D11 device and context: %s", qPrintable(comErrorMessage(hr)));
|
|
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();
|
|
}
|