diff options
Diffstat (limited to 'src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h')
-rw-r--r-- | src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h | 394 |
1 files changed, 394 insertions, 0 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h new file mode 100644 index 0000000000..b30994fe0d --- /dev/null +++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGD3D12ENGINE_P_H +#define QSGD3D12ENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QWindow> +#include <QImage> +#include <QVector4D> +#include <qsggeometry.h> +#include <qsgrendererinterface.h> +#include <qt_windows.h> + +QT_BEGIN_NAMESPACE + +// No D3D or COM headers must be pulled in here. All that has to be isolated +// to engine_p_p.h and engine.cpp. + +class QSGD3D12EnginePrivate; + +// Shader bytecode and other strings are expected to be static so that a +// different pointer means a different shader. + +enum QSGD3D12Format { + FmtUnknown = 0, + + FmtFloat4 = 2, // DXGI_FORMAT_R32G32B32A32_FLOAT + FmtFloat3 = 6, // DXGI_FORMAT_R32G32B32_FLOAT + FmtFloat2 = 16, // DXGI_FORMAT_R32G32_FLOAT + FmtFloat = 41, // DXGI_FORMAT_R32_FLOAT + + // glVertexAttribPointer with GL_UNSIGNED_BYTE and normalized == true maps to the UNORM formats below + FmtUNormByte4 = 28, // DXGI_FORMAT_R8G8B8A8_UNORM + FmtUNormByte2 = 49, // DXGI_FORMAT_R8G8_UNORM + FmtUNormByte = 61, // DXGI_FORMAT_R8_UNORM + + // Index data types + FmtUnsignedShort = 57, // DXGI_FORMAT_R16_UINT + FmtUnsignedInt = 42 // DXGI_FORMAT_R32_UINT +}; + +struct QSGD3D12InputElement +{ + const char *semanticName = nullptr; + int semanticIndex = 0; + QSGD3D12Format format = FmtFloat4; + quint32 slot = 0; + quint32 offset = 0; + + bool operator==(const QSGD3D12InputElement &other) const { + return semanticName == other.semanticName && semanticIndex == other.semanticIndex + && format == other.format && slot == other.slot && offset == other.offset; + } +}; + +inline uint qHash(const QSGD3D12InputElement &key, uint seed = 0) +{ + return qHash(key.semanticName, seed) + key.semanticIndex + key.format + key.offset; +} + +struct QSGD3D12TextureView +{ + enum Filter { + FilterNearest = 0, + FilterLinear = 0x15, + FilterMinMagNearestMipLinear = 0x1, + FilterMinMagLinearMipNearest = 0x14 + }; + + enum AddressMode { + AddressWrap = 1, + AddressClamp = 3 + }; + + Filter filter = FilterLinear; + AddressMode addressModeHoriz = AddressClamp; + AddressMode addressModeVert = AddressClamp; + + bool operator==(const QSGD3D12TextureView &other) const { + return filter == other.filter + && addressModeHoriz == other.addressModeHoriz + && addressModeVert == other.addressModeVert; + } +}; + +inline uint qHash(const QSGD3D12TextureView &key, uint seed = 0) +{ + Q_UNUSED(seed); + return key.filter + key.addressModeHoriz + key.addressModeVert; +} + +const int QSGD3D12_MAX_TEXTURE_VIEWS = 8; + +struct QSGD3D12RootSignature +{ + int textureViewCount = 0; + QSGD3D12TextureView textureViews[QSGD3D12_MAX_TEXTURE_VIEWS]; + + bool operator==(const QSGD3D12RootSignature &other) const { + if (textureViewCount != other.textureViewCount) + return false; + for (int i = 0; i < textureViewCount; ++i) + if (!(textureViews[i] == other.textureViews[i])) + return false; + return true; + } +}; + +inline uint qHash(const QSGD3D12RootSignature &key, uint seed = 0) +{ + return key.textureViewCount + (key.textureViewCount > 0 ? qHash(key.textureViews[0], seed) : 0); +} + +// Shader bytecode blobs and root signature-related data. +struct QSGD3D12ShaderState +{ + const quint8 *vs = nullptr; + quint32 vsSize = 0; + const quint8 *ps = nullptr; + quint32 psSize = 0; + + QSGD3D12RootSignature rootSig; + + bool operator==(const QSGD3D12ShaderState &other) const { + return vs == other.vs && vsSize == other.vsSize + && ps == other.ps && psSize == other.psSize + && rootSig == other.rootSig; + } +}; + +inline uint qHash(const QSGD3D12ShaderState &key, uint seed = 0) +{ + return qHash(key.vs, seed) + key.vsSize + qHash(key.ps, seed) + key.psSize + qHash(key.rootSig, seed); +} + +const int QSGD3D12_MAX_INPUT_ELEMENTS = 8; + +struct QSGD3D12PipelineState +{ + enum CullMode { + CullNone = 1, + CullFront, + CullBack + }; + + enum CompareFunc { + CompareNever = 1, + CompareLess, + CompareEqual, + CompareLessEqual, + CompareGreater, + CompareNotEqual, + CompareGreaterEqual, + CompareAlways + }; + + enum StencilOp { + StencilKeep = 1, + StencilZero, + StencilReplace, + StencilIncrSat, + StencilDecrSat, + StencilInvert, + StencilIncr, + StencilDescr + }; + + enum TopologyType { + TopologyTypePoint = 1, + TopologyTypeLine, + TopologyTypeTriangle + }; + + enum BlendType { + BlendNone, + BlendPremul, // == GL_ONE, GL_ONE_MINUS_SRC_ALPHA + BlendColor // == GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR + }; + + QSGD3D12ShaderState shaders; + + int inputElementCount = 0; + QSGD3D12InputElement inputElements[QSGD3D12_MAX_INPUT_ELEMENTS]; + + CullMode cullMode = CullNone; + bool frontCCW = true; + bool colorWrite = true; + BlendType blend = BlendNone; + bool depthEnable = true; + CompareFunc depthFunc = CompareLess; + bool depthWrite = true; + bool stencilEnable = false; + CompareFunc stencilFunc = CompareEqual; + StencilOp stencilFailOp = StencilKeep; + StencilOp stencilDepthFailOp = StencilKeep; + StencilOp stencilPassOp = StencilKeep; + TopologyType topologyType = TopologyTypeTriangle; + + bool operator==(const QSGD3D12PipelineState &other) const { + bool eq = shaders == other.shaders + && inputElementCount == other.inputElementCount + && cullMode == other.cullMode + && frontCCW == other.frontCCW + && colorWrite == other.colorWrite + && blend == other.blend + && depthEnable == other.depthEnable + && (!depthEnable || depthFunc == other.depthFunc) + && depthWrite == other.depthWrite + && stencilEnable == other.stencilEnable + && (!stencilEnable || stencilFunc == other.stencilFunc) + && (!stencilEnable || stencilFailOp == other.stencilFailOp) + && (!stencilEnable || stencilDepthFailOp == other.stencilDepthFailOp) + && (!stencilEnable || stencilPassOp == other.stencilPassOp) + && topologyType == other.topologyType; + if (eq) { + for (int i = 0; i < inputElementCount; ++i) { + if (!(inputElements[i] == other.inputElements[i])) { + eq = false; + break; + } + } + } + return eq; + } +}; + +inline uint qHash(const QSGD3D12PipelineState &key, uint seed = 0) +{ + return qHash(key.shaders, seed) + key.inputElementCount + + key.cullMode + key.frontCCW + + key.colorWrite + key.blend + + key.depthEnable + key.depthWrite + + key.stencilEnable + + key.topologyType; +} + +class QSGD3D12Engine +{ +public: + QSGD3D12Engine(); + ~QSGD3D12Engine(); + + bool attachToWindow(WId window, const QSize &size, float dpr, int surfaceFormatSamples, bool alpha); + void releaseResources(); + bool hasResources() const; + void setWindowSize(const QSize &size, float dpr); + WId window() const; + QSize windowSize() const; + float windowDevicePixelRatio() const; + uint windowSamples() const; + + void beginFrame(); + void endFrame(); + void beginLayer(); + void endLayer(); + void invalidateCachedFrameState(); + void restoreFrameState(bool minimal = false); + + uint genBuffer(); + void releaseBuffer(uint id); + void resetBuffer(uint id, const quint8 *data, int size); + void markBufferDirty(uint id, int offset, int size); + + enum ClearFlag { + ClearDepth = 0x1, + ClearStencil = 0x2 + }; + Q_DECLARE_FLAGS(ClearFlags, ClearFlag) + + void queueViewport(const QRect &rect); + void queueScissor(const QRect &rect); + void queueSetRenderTarget(uint id = 0); + void queueClearRenderTarget(const QColor &color); + void queueClearDepthStencil(float depthValue, quint8 stencilValue, ClearFlags which); + void queueSetBlendFactor(const QVector4D &factor); + void queueSetStencilRef(quint32 ref); + + void finalizePipeline(const QSGD3D12PipelineState &pipelineState); + + struct DrawParams { + QSGGeometry::DrawingMode mode = QSGGeometry::DrawTriangles; + int count = 0; + uint vertexBuf = 0; + uint indexBuf = 0; + uint constantBuf = 0; + int vboOffset = 0; + int vboSize = 0; + int vboStride = 0; + int cboOffset = 0; + int startIndexIndex = -1; + QSGD3D12Format indexFormat = FmtUnsignedShort; + }; + + void queueDraw(const DrawParams ¶ms); + + void present(); + void waitGPU(); + + static quint32 alignedConstantBufferSize(quint32 size); + static QSGD3D12Format toDXGIFormat(QSGGeometry::Type sgtype, int tupleSize = 1, int *size = nullptr); + static int mipMapLevels(const QSize &size); + static QSize mipMapAdjustedSourceSize(const QSize &size); + + enum TextureCreateFlag { + TextureWithAlpha = 0x01, + TextureWithMipMaps = 0x02, + TextureAlways32Bit = 0x04 + }; + Q_DECLARE_FLAGS(TextureCreateFlags, TextureCreateFlag) + + enum TextureUploadFlag { + TextureUploadAlways32Bit = 0x01 + }; + Q_DECLARE_FLAGS(TextureUploadFlags, TextureUploadFlag) + + uint genTexture(); + void createTexture(uint id, const QSize &size, QImage::Format format, TextureCreateFlags flags); + void queueTextureResize(uint id, const QSize &size); + void queueTextureUpload(uint id, const QImage &image, const QPoint &dstPos = QPoint(), TextureUploadFlags flags = 0); + void queueTextureUpload(uint id, const QVector<QImage> &images, const QVector<QPoint> &dstPos, TextureUploadFlags flags = 0); + void releaseTexture(uint id); + void useTexture(uint id); + + uint genRenderTarget(); + void createRenderTarget(uint id, const QSize &size, const QVector4D &clearColor, uint samples); + void releaseRenderTarget(uint id); + void useRenderTargetAsTexture(uint id); + uint activeRenderTarget() const; + + QImage executeAndWaitReadbackRenderTarget(uint id = 0); + + void simulateDeviceLoss(); + + void *getResource(QQuickWindow *window, QSGRendererInterface::Resource resource) const; + +private: + QSGD3D12EnginePrivate *d; + Q_DISABLE_COPY(QSGD3D12Engine) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::ClearFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::TextureCreateFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QSGD3D12Engine::TextureUploadFlags) + +QT_END_NAMESPACE + +#endif // QSGD3D12ENGINE_P_H |