1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#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();
}
|