Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qrhid3d11.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qrhid3d11_p.h"
5#include "qshader.h"
6#include "vs_test_p.h"
7#include <QWindow>
8#include <qmath.h>
9#include <QtCore/qcryptographichash.h>
10#include <QtCore/private/qsystemerror_p.h>
11#include "qrhid3dhelpers_p.h"
12
14
15using namespace Qt::StringLiterals;
16
17/*
18 Direct3D 11 backend. Provides a double-buffered flip model swapchain.
19 Textures and "static" buffers are USAGE_DEFAULT, leaving it to
20 UpdateSubResource to upload the data in any way it sees fit. "Dynamic"
21 buffers are USAGE_DYNAMIC and updating is done by mapping with WRITE_DISCARD.
22 (so here QRhiBuffer keeps a copy of the buffer contents and all of it is
23 memcpy'd every time, leaving the rest (juggling with the memory area Map
24 returns) to the driver).
25*/
26
114// help mingw with its ancient sdk headers
115#ifndef DXGI_ADAPTER_FLAG_SOFTWARE
116#define DXGI_ADAPTER_FLAG_SOFTWARE 2
117#endif
118
119#ifndef D3D11_1_UAV_SLOT_COUNT
120#define D3D11_1_UAV_SLOT_COUNT 64
121#endif
122
123#ifndef D3D11_VS_INPUT_REGISTER_COUNT
124#define D3D11_VS_INPUT_REGISTER_COUNT 32
125#endif
126
128 : ofr(this)
129{
130 debugLayer = params->enableDebugLayer;
131
132 if (importParams) {
133 if (importParams->dev && importParams->context) {
134 dev = reinterpret_cast<ID3D11Device *>(importParams->dev);
135 ID3D11DeviceContext *ctx = reinterpret_cast<ID3D11DeviceContext *>(importParams->context);
136 if (SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)))) {
137 // get rid of the ref added by QueryInterface
138 ctx->Release();
140 } else {
141 qWarning("ID3D11DeviceContext1 not supported by context, cannot import");
142 }
143 }
144 featureLevel = D3D_FEATURE_LEVEL(importParams->featureLevel);
145 adapterLuid.LowPart = importParams->adapterLuidLow;
146 adapterLuid.HighPart = importParams->adapterLuidHigh;
147 }
148}
149
150template <class Int>
151inline Int aligned(Int v, Int byteAlign)
152{
153 return (v + byteAlign - 1) & ~(byteAlign - 1);
154}
155
156static IDXGIFactory1 *createDXGIFactory2()
157{
158 IDXGIFactory1 *result = nullptr;
159 const HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&result));
160 if (FAILED(hr)) {
161 qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s",
162 qPrintable(QSystemError::windowsComString(hr)));
163 result = nullptr;
164 }
165 return result;
166}
167
168bool QRhiD3D11::create(QRhi::Flags flags)
169{
170 rhiFlags = flags;
171
172 uint devFlags = 0;
173 if (debugLayer)
174 devFlags |= D3D11_CREATE_DEVICE_DEBUG;
175
177 if (!dxgiFactory)
178 return false;
179
180 // For a FLIP_* swapchain Present(0, 0) is not necessarily
181 // sufficient to get non-blocking behavior, try using ALLOW_TEARING
182 // when available.
183 supportsAllowTearing = false;
184 IDXGIFactory5 *factory5 = nullptr;
185 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5), reinterpret_cast<void **>(&factory5)))) {
186 BOOL allowTearing = false;
187 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))))
188 supportsAllowTearing = allowTearing;
189 factory5->Release();
190 }
191
192 if (qEnvironmentVariableIntValue("QT_D3D_FLIP_DISCARD"))
193 qWarning("The default swap effect is FLIP_DISCARD, QT_D3D_FLIP_DISCARD is now ignored");
194
195 if (qEnvironmentVariableIntValue("QT_D3D_NO_FLIP"))
196 qWarning("Non-FLIP swapchains are no longer supported, QT_D3D_NO_FLIP is now ignored");
197
198 qCDebug(QRHI_LOG_INFO, "FLIP_* swapchain supported = true, ALLOW_TEARING supported = %s",
199 supportsAllowTearing ? "true" : "false");
200
201 qCDebug(QRHI_LOG_INFO, "Default swap effect: FLIP_DISCARD");
202
204 IDXGIAdapter1 *adapter;
205 int requestedAdapterIndex = -1;
206 if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX"))
207 requestedAdapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
208
209 // The importParams may specify an adapter by the luid, take that into account.
210 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
211 for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
212 DXGI_ADAPTER_DESC1 desc;
213 adapter->GetDesc1(&desc);
214 adapter->Release();
215 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
216 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
217 {
218 requestedAdapterIndex = adapterIndex;
219 break;
220 }
221 }
222 }
223
224 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
225 for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
226 DXGI_ADAPTER_DESC1 desc;
227 adapter->GetDesc1(&desc);
228 adapter->Release();
229 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
230 requestedAdapterIndex = adapterIndex;
231 break;
232 }
233 }
234 }
235
236 activeAdapter = nullptr;
237 for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
238 DXGI_ADAPTER_DESC1 desc;
239 adapter->GetDesc1(&desc);
240 const QString name = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description));
241 qCDebug(QRHI_LOG_INFO, "Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
242 adapterIndex,
244 desc.VendorId,
245 desc.DeviceId,
246 desc.Flags);
247 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
248 activeAdapter = adapter;
249 adapterLuid = desc.AdapterLuid;
251 driverInfoStruct.deviceId = desc.DeviceId;
252 driverInfoStruct.vendorId = desc.VendorId;
253 qCDebug(QRHI_LOG_INFO, " using this adapter");
254 } else {
255 adapter->Release();
256 }
257 }
258 if (!activeAdapter) {
259 qWarning("No adapter");
260 return false;
261 }
262
263 // Normally we won't specify a requested feature level list,
264 // except when a level was specified in importParams.
265 QVarLengthArray<D3D_FEATURE_LEVEL, 4> requestedFeatureLevels;
266 bool requestFeatureLevels = false;
267 if (featureLevel) {
268 requestFeatureLevels = true;
269 requestedFeatureLevels.append(featureLevel);
270 }
271
272 ID3D11DeviceContext *ctx = nullptr;
273 HRESULT hr = D3D11CreateDevice(activeAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
274 requestFeatureLevels ? requestedFeatureLevels.constData() : nullptr,
275 requestFeatureLevels ? requestedFeatureLevels.count() : 0,
276 D3D11_SDK_VERSION,
277 &dev, &featureLevel, &ctx);
278 // We cannot assume that D3D11_CREATE_DEVICE_DEBUG is always available. Retry without it, if needed.
279 if (hr == DXGI_ERROR_SDK_COMPONENT_MISSING && debugLayer) {
280 qCDebug(QRHI_LOG_INFO, "Debug layer was requested but is not available. "
281 "Attempting to create D3D11 device without it.");
282 devFlags &= ~D3D11_CREATE_DEVICE_DEBUG;
283 hr = D3D11CreateDevice(activeAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
284 requestFeatureLevels ? requestedFeatureLevels.constData() : nullptr,
285 requestFeatureLevels ? requestedFeatureLevels.count() : 0,
286 D3D11_SDK_VERSION,
287 &dev, &featureLevel, &ctx);
288 }
289 if (FAILED(hr)) {
290 qWarning("Failed to create D3D11 device and context: %s",
291 qPrintable(QSystemError::windowsComString(hr)));
292 return false;
293 }
294
295 // Test if creating a Shader Model 5.0 vertex shader works; we want to
296 // fail already in create() if that's not the case.
297 ID3D11VertexShader *testShader = nullptr;
298 if (SUCCEEDED(dev->CreateVertexShader(g_testVertexShader, sizeof(g_testVertexShader), nullptr, &testShader))) {
299 testShader->Release();
300 } else {
301 qWarning("D3D11 smoke test failed (failed to create vertex shader)");
302 ctx->Release();
303 return false;
304 }
305
306 const bool supports11_1 = SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)));
307 ctx->Release();
308 if (!supports11_1) {
309 qWarning("ID3D11DeviceContext1 not supported");
310 return false;
311 }
312
313 D3D11_FEATURE_DATA_D3D11_OPTIONS features = {};
314 if (SUCCEEDED(dev->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &features, sizeof(features)))) {
315 // The D3D _runtime_ may be 11.1, but the underlying _driver_ may
316 // still not support this D3D_FEATURE_LEVEL_11_1 feature. (e.g.
317 // because it only does 11_0)
318 if (!features.ConstantBufferOffsetting) {
319 qWarning("Constant buffer offsetting is not supported by the driver");
320 return false;
321 }
322 } else {
323 qWarning("Failed to query D3D11_FEATURE_D3D11_OPTIONS");
324 return false;
325 }
326 } else {
327 Q_ASSERT(dev && context);
328 featureLevel = dev->GetFeatureLevel();
329 IDXGIDevice *dxgiDev = nullptr;
330 if (SUCCEEDED(dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDev)))) {
331 IDXGIAdapter *adapter = nullptr;
332 if (SUCCEEDED(dxgiDev->GetAdapter(&adapter))) {
333 DXGI_ADAPTER_DESC desc;
334 adapter->GetDesc(&desc);
335 adapterLuid = desc.AdapterLuid;
336 driverInfoStruct.deviceName = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description)).toUtf8();
337 driverInfoStruct.deviceId = desc.DeviceId;
338 driverInfoStruct.vendorId = desc.VendorId;
339 adapter->Release();
340 }
341 dxgiDev->Release();
342 }
343 qCDebug(QRHI_LOG_INFO, "Using imported device %p", dev);
344 }
345
346 if (FAILED(context->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), reinterpret_cast<void **>(&annotations))))
347 annotations = nullptr;
348
349 if (flags.testFlag(QRhi::EnableTimestamps)) {
350 ofr.timestamps.prepare(2, this);
351 // timestamp queries are optional so we can go on even if they failed
352 }
353
354 deviceLost = false;
355
358 nativeHandlesStruct.featureLevel = featureLevel;
359 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
360 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
361
362 return true;
363}
364
366{
367 for (Shader &s : m_shaderCache)
368 s.s->Release();
369
370 m_shaderCache.clear();
371}
372
374{
376
378
380
381 if (annotations) {
382 annotations->Release();
383 annotations = nullptr;
384 }
385
387 if (context) {
388 context->Release();
389 context = nullptr;
390 }
391 if (dev) {
392 dev->Release();
393 dev = nullptr;
394 }
395 }
396
397 if (dcompDevice) {
398 dcompDevice->Release();
399 dcompDevice = nullptr;
400 }
401
402 if (activeAdapter) {
403 activeAdapter->Release();
404 activeAdapter = nullptr;
405 }
406
407 if (dxgiFactory) {
408 dxgiFactory->Release();
409 dxgiFactory = nullptr;
410 }
411}
412
414{
415 // this works only when params.enableDebugLayer was true
416 ID3D11Debug *debug;
417 if (SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void **>(&debug)))) {
418 debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
419 debug->Release();
420 }
421}
422
424{
425 return { 1, 2, 4, 8 };
426}
427
428DXGI_SAMPLE_DESC QRhiD3D11::effectiveSampleCount(int sampleCount) const
429{
430 DXGI_SAMPLE_DESC desc;
431 desc.Count = 1;
432 desc.Quality = 0;
433
434 // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
435 int s = qBound(1, sampleCount, 64);
436
438 qWarning("Attempted to set unsupported sample count %d", sampleCount);
439 return desc;
440 }
441
442 desc.Count = UINT(s);
443 if (s > 1)
444 desc.Quality = UINT(D3D11_STANDARD_MULTISAMPLE_PATTERN);
445 else
446 desc.Quality = 0;
447
448 return desc;
449}
450
452{
453 return new QD3D11SwapChain(this);
454}
455
457{
458 return new QD3D11Buffer(this, type, usage, size);
459}
460
462{
463 return 256;
464}
465
467{
468 return false;
469}
470
472{
473 return true;
474}
475
477{
478 return true;
479}
480
482{
483 // Like with Vulkan, but Y is already good.
484
485 static QMatrix4x4 m;
486 if (m.isIdentity()) {
487 // NB the ctor takes row-major
488 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
489 0.0f, 1.0f, 0.0f, 0.0f,
490 0.0f, 0.0f, 0.5f, 0.5f,
491 0.0f, 0.0f, 0.0f, 1.0f);
492 }
493 return m;
494}
495
497{
499
501 return false;
502
503 return true;
504}
505
507{
508 switch (feature) {
510 return true;
512 return true;
514 return annotations != nullptr;
515 case QRhi::Timestamps:
516 return true;
517 case QRhi::Instancing:
518 return true;
520 return true;
522 return true;
524 return false; // because UpdateSubresource cannot deal with this
526 return true;
528 return true;
530 return true;
532 return true;
533 case QRhi::Compute:
534 return true;
535 case QRhi::WideLines:
536 return false;
538 return false;
539 case QRhi::BaseVertex:
540 return true;
542 return true;
544 return false;
546 return true;
548 return true;
549 case QRhi::TexelFetch:
550 return true;
552 return true;
554 return true;
556 return true;
558 return true;
560 return true;
562 return true;
564 return false;
566 return true;
568 return true;
570 return true;
572 return true;
574 return true;
576 return true;
578 return true;
580 return true;
582 return true;
584 return true;
586 return true;
588 return true;
589 case QRhi::MultiView:
590 return false;
591 default:
592 Q_UNREACHABLE();
593 return false;
594 }
595}
596
598{
599 switch (limit) {
601 return 1;
603 return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
605 return 8;
607 // From our perspective. What D3D does internally is another question
608 // (there could be pipelining, helped f.ex. by our MAP_DISCARD based
609 // uniform buffer update strategy), but that's out of our hands and
610 // does not concern us here.
611 return 1;
613 return 1;
615 return D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
617 return D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP;
619 return D3D11_CS_THREAD_GROUP_MAX_X;
621 return D3D11_CS_THREAD_GROUP_MAX_Y;
623 return D3D11_CS_THREAD_GROUP_MAX_Z;
625 return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
627 return 65536;
631 return D3D11_VS_OUTPUT_REGISTER_COUNT;
632 default:
633 Q_UNREACHABLE();
634 return 0;
635 }
636}
637
639{
640 return &nativeHandlesStruct;
641}
642
644{
645 return driverInfoStruct;
646}
647
649{
651 result.totalPipelineCreationTime = totalPipelineCreationTime();
652 return result;
653}
654
656{
657 // not applicable
658 return false;
659}
660
662{
664 m_bytecodeCache.clear();
665}
666
668{
669 return deviceLost;
670}
671
673{
676 // no need for driver specifics
679};
680
682{
684 if (m_bytecodeCache.isEmpty())
685 return data;
686
688 memset(&header, 0, sizeof(header));
689 header.rhiId = pipelineCacheRhiId();
690 header.arch = quint32(sizeof(void*));
691 header.count = m_bytecodeCache.count();
692
693 const size_t dataOffset = sizeof(header);
694 size_t dataSize = 0;
695 for (auto it = m_bytecodeCache.cbegin(), end = m_bytecodeCache.cend(); it != end; ++it) {
696 BytecodeCacheKey key = it.key();
697 QByteArray bytecode = it.value();
698 dataSize +=
699 sizeof(quint32) + key.sourceHash.size()
700 + sizeof(quint32) + key.target.size()
701 + sizeof(quint32) + key.entryPoint.size()
702 + sizeof(quint32) // compileFlags
703 + sizeof(quint32) + bytecode.size();
704 }
705
707 char *p = buf.data() + dataOffset;
708 for (auto it = m_bytecodeCache.cbegin(), end = m_bytecodeCache.cend(); it != end; ++it) {
709 BytecodeCacheKey key = it.key();
710 QByteArray bytecode = it.value();
711
712 quint32 i = key.sourceHash.size();
713 memcpy(p, &i, 4);
714 p += 4;
715 memcpy(p, key.sourceHash.constData(), key.sourceHash.size());
716 p += key.sourceHash.size();
717
718 i = key.target.size();
719 memcpy(p, &i, 4);
720 p += 4;
721 memcpy(p, key.target.constData(), key.target.size());
722 p += key.target.size();
723
724 i = key.entryPoint.size();
725 memcpy(p, &i, 4);
726 p += 4;
727 memcpy(p, key.entryPoint.constData(), key.entryPoint.size());
728 p += key.entryPoint.size();
729
730 quint32 f = key.compileFlags;
731 memcpy(p, &f, 4);
732 p += 4;
733
734 i = bytecode.size();
735 memcpy(p, &i, 4);
736 p += 4;
737 memcpy(p, bytecode.constData(), bytecode.size());
738 p += bytecode.size();
739 }
740 Q_ASSERT(p == buf.data() + dataOffset + dataSize);
741
742 header.dataSize = quint32(dataSize);
743 memcpy(buf.data(), &header, sizeof(header));
744
745 return buf;
746}
747
749{
750 if (data.isEmpty())
751 return;
752
753 const size_t headerSize = sizeof(QD3D11PipelineCacheDataHeader);
754 if (data.size() < qsizetype(headerSize)) {
755 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Invalid blob size (header incomplete)");
756 return;
757 }
758 const size_t dataOffset = headerSize;
760 memcpy(&header, data.constData(), headerSize);
761
762 const quint32 rhiId = pipelineCacheRhiId();
763 if (header.rhiId != rhiId) {
764 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
765 rhiId, header.rhiId);
766 return;
767 }
768 const quint32 arch = quint32(sizeof(void*));
769 if (header.arch != arch) {
770 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Architecture does not match (%u, %u)",
771 arch, header.arch);
772 return;
773 }
774 if (header.count == 0)
775 return;
776
777 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
778 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Invalid blob size (data incomplete)");
779 return;
780 }
781
782 m_bytecodeCache.clear();
783
784 const char *p = data.constData() + dataOffset;
785 for (quint32 i = 0; i < header.count; ++i) {
786 quint32 len = 0;
787 memcpy(&len, p, 4);
788 p += 4;
790 memcpy(sourceHash.data(), p, len);
791 p += len;
792
793 memcpy(&len, p, 4);
794 p += 4;
796 memcpy(target.data(), p, len);
797 p += len;
798
799 memcpy(&len, p, 4);
800 p += 4;
801 QByteArray entryPoint(len, Qt::Uninitialized);
802 memcpy(entryPoint.data(), p, len);
803 p += len;
804
806 memcpy(&flags, p, 4);
807 p += 4;
808
809 memcpy(&len, p, 4);
810 p += 4;
812 memcpy(bytecode.data(), p, len);
813 p += len;
814
815 BytecodeCacheKey cacheKey;
816 cacheKey.sourceHash = sourceHash;
817 cacheKey.target = target;
818 cacheKey.entryPoint = entryPoint;
819 cacheKey.compileFlags = flags;
820
821 m_bytecodeCache.insert(cacheKey, bytecode);
822 }
823
824 qCDebug(QRHI_LOG_INFO, "Seeded bytecode cache with %d shaders", int(m_bytecodeCache.count()));
825}
826
828 int sampleCount, QRhiRenderBuffer::Flags flags,
829 QRhiTexture::Format backingFormatHint)
830{
831 return new QD3D11RenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint);
832}
833
835 const QSize &pixelSize, int depth, int arraySize,
836 int sampleCount, QRhiTexture::Flags flags)
837{
838 return new QD3D11Texture(this, format, pixelSize, depth, arraySize, sampleCount, flags);
839}
840
842 QRhiSampler::Filter mipmapMode,
844{
845 return new QD3D11Sampler(this, magFilter, minFilter, mipmapMode, u, v, w);
846}
847
849 QRhiTextureRenderTarget::Flags flags)
850{
851 return new QD3D11TextureRenderTarget(this, desc, flags);
852}
853
855{
856 return new QD3D11GraphicsPipeline(this);
857}
858
860{
861 return new QD3D11ComputePipeline(this);
862}
863
865{
866 return new QD3D11ShaderResourceBindings(this);
867}
868
870{
874 const bool pipelineChanged = cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation;
875
876 if (pipelineChanged) {
877 cbD->currentGraphicsPipeline = ps;
878 cbD->currentComputePipeline = nullptr;
880
881 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
883 cmd.args.bindGraphicsPipeline.ps = psD;
884 }
885}
886
887static const int RBM_SUPPORTED_STAGES = 6;
888static const int RBM_VERTEX = 0;
889static const int RBM_HULL = 1;
890static const int RBM_DOMAIN = 2;
891static const int RBM_GEOMETRY = 3;
892static const int RBM_FRAGMENT = 4;
893static const int RBM_COMPUTE = 5;
894
896 int dynamicOffsetCount,
897 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
898{
903
904 if (!srb) {
905 if (gfxPsD)
906 srb = gfxPsD->m_shaderResourceBindings;
907 else
908 srb = compPsD->m_shaderResourceBindings;
909 }
910
912
913 bool srbUpdate = false;
914 for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
917 switch (b->type) {
919 {
920 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
921 // NonDynamicUniformBuffers is not supported by this backend
923
925
926 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
927 srbUpdate = true;
928 bd.ubuf.id = bufD->m_id;
929 bd.ubuf.generation = bufD->generation;
930 }
931 }
932 break;
936 {
938 if (bd.stex.count != data->count) {
939 bd.stex.count = data->count;
940 srbUpdate = true;
941 }
942 for (int elem = 0; elem < data->count; ++elem) {
943 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
944 QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
945 // We use the same code path for both combined and separate
946 // images and samplers, so tex or sampler (but not both) can be
947 // null here.
948 Q_ASSERT(texD || samplerD);
949 const quint64 texId = texD ? texD->m_id : 0;
950 const uint texGen = texD ? texD->generation : 0;
951 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
952 const uint samplerGen = samplerD ? samplerD->generation : 0;
953 if (texGen != bd.stex.d[elem].texGeneration
954 || texId != bd.stex.d[elem].texId
955 || samplerGen != bd.stex.d[elem].samplerGeneration
956 || samplerId != bd.stex.d[elem].samplerId)
957 {
958 srbUpdate = true;
959 bd.stex.d[elem].texId = texId;
960 bd.stex.d[elem].texGeneration = texGen;
961 bd.stex.d[elem].samplerId = samplerId;
962 bd.stex.d[elem].samplerGeneration = samplerGen;
963 }
964 }
965 }
966 break;
970 {
971 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex);
972 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
973 srbUpdate = true;
974 bd.simage.id = texD->m_id;
975 bd.simage.generation = texD->generation;
976 }
977 }
978 break;
982 {
983 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf);
984 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
985 srbUpdate = true;
986 bd.sbuf.id = bufD->m_id;
987 bd.sbuf.generation = bufD->generation;
988 }
989 }
990 break;
991 default:
992 Q_UNREACHABLE();
993 break;
994 }
995 }
996
997 if (srbUpdate) {
999 memset(resBindMaps, 0, sizeof(resBindMaps));
1000 if (gfxPsD) {
1001 resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap;
1002 resBindMaps[RBM_HULL] = &gfxPsD->hs.nativeResourceBindingMap;
1003 resBindMaps[RBM_DOMAIN] = &gfxPsD->ds.nativeResourceBindingMap;
1004 resBindMaps[RBM_GEOMETRY] = &gfxPsD->gs.nativeResourceBindingMap;
1005 resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap;
1006 } else {
1007 resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap;
1008 }
1009 updateShaderResourceBindings(srbD, resBindMaps);
1010 }
1011
1012 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1013 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1014
1015 if (srbChanged || srbRebuilt || srbUpdate || srbD->hasDynamicOffset) {
1016 if (gfxPsD) {
1017 cbD->currentGraphicsSrb = srb;
1018 cbD->currentComputeSrb = nullptr;
1019 } else {
1020 cbD->currentGraphicsSrb = nullptr;
1021 cbD->currentComputeSrb = srb;
1022 }
1023 cbD->currentSrbGeneration = srbD->generation;
1024
1025 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1027 cmd.args.bindShaderResources.srb = srbD;
1028 // dynamic offsets have to be applied at the time of executing the bind
1029 // operations, not here
1030 cmd.args.bindShaderResources.offsetOnlyChange = !srbChanged && !srbRebuilt && !srbUpdate && srbD->hasDynamicOffset;
1032 if (srbD->hasDynamicOffset) {
1033 if (dynamicOffsetCount < QD3D11CommandBuffer::MAX_DYNAMIC_OFFSET_COUNT) {
1034 cmd.args.bindShaderResources.dynamicOffsetCount = dynamicOffsetCount;
1036 for (int i = 0; i < dynamicOffsetCount; ++i) {
1037 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1038 const uint binding = uint(dynOfs.first);
1039 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1040 const quint32 offsetInConstants = dynOfs.second / 16;
1041 *p++ = binding;
1042 *p++ = offsetInConstants;
1043 }
1044 } else {
1045 qWarning("Too many dynamic offsets (%d, max is %d)",
1047 }
1048 }
1049 }
1050}
1051
1053 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
1054 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1055{
1058
1059 bool needsBindVBuf = false;
1060 for (int i = 0; i < bindingCount; ++i) {
1061 const int inputSlot = startBinding + i;
1062 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first);
1063 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1064 if (bufD->m_type == QRhiBuffer::Dynamic)
1066
1067 if (cbD->currentVertexBuffers[inputSlot] != bufD->buffer
1068 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1069 {
1070 needsBindVBuf = true;
1071 cbD->currentVertexBuffers[inputSlot] = bufD->buffer;
1072 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1073 }
1074 }
1075
1076 if (needsBindVBuf) {
1077 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1079 cmd.args.bindVertexBuffers.startSlot = startBinding;
1081 qWarning("Too many vertex buffer bindings (%d, max is %d)",
1084 }
1085 cmd.args.bindVertexBuffers.slotCount = bindingCount;
1087 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1088 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1089 for (int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1090 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first);
1091 cmd.args.bindVertexBuffers.buffers[i] = bufD->buffer;
1092 cmd.args.bindVertexBuffers.offsets[i] = bindings[i].second;
1093 cmd.args.bindVertexBuffers.strides[i] = inputLayout.bindingAt(i)->stride();
1094 }
1095 }
1096
1097 if (indexBuf) {
1098 QD3D11Buffer *ibufD = QRHI_RES(QD3D11Buffer, indexBuf);
1099 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1100 if (ibufD->m_type == QRhiBuffer::Dynamic)
1102
1103 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1104 : DXGI_FORMAT_R32_UINT;
1105 if (cbD->currentIndexBuffer != ibufD->buffer
1106 || cbD->currentIndexOffset != indexOffset
1107 || cbD->currentIndexFormat != dxgiFormat)
1108 {
1109 cbD->currentIndexBuffer = ibufD->buffer;
1110 cbD->currentIndexOffset = indexOffset;
1111 cbD->currentIndexFormat = dxgiFormat;
1112
1113 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1115 cmd.args.bindIndexBuffer.buffer = ibufD->buffer;
1116 cmd.args.bindIndexBuffer.offset = indexOffset;
1117 cmd.args.bindIndexBuffer.format = dxgiFormat;
1118 }
1119 }
1120}
1121
1123{
1126 Q_ASSERT(cbD->currentTarget);
1127 const QSize outputSize = cbD->currentTarget->pixelSize();
1128
1129 // d3d expects top-left, QRhiViewport is bottom-left
1130 float x, y, w, h;
1131 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1132 return;
1133
1134 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1136 cmd.args.viewport.x = x;
1137 cmd.args.viewport.y = y;
1138 cmd.args.viewport.w = w;
1139 cmd.args.viewport.h = h;
1140 cmd.args.viewport.d0 = viewport.minDepth();
1141 cmd.args.viewport.d1 = viewport.maxDepth();
1142}
1143
1145{
1148 Q_ASSERT(cbD->currentTarget);
1149 const QSize outputSize = cbD->currentTarget->pixelSize();
1150
1151 // d3d expects top-left, QRhiScissor is bottom-left
1152 int x, y, w, h;
1153 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1154 return;
1155
1156 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1158 cmd.args.scissor.x = x;
1159 cmd.args.scissor.y = y;
1160 cmd.args.scissor.w = w;
1161 cmd.args.scissor.h = h;
1162}
1163
1165{
1168
1169 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1172 cmd.args.blendConstants.c[0] = float(c.redF());
1173 cmd.args.blendConstants.c[1] = float(c.greenF());
1174 cmd.args.blendConstants.c[2] = float(c.blueF());
1175 cmd.args.blendConstants.c[3] = float(c.alphaF());
1176}
1177
1179{
1182
1183 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1186 cmd.args.stencilRef.ref = refValue;
1187}
1188
1190 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1191{
1194
1195 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1198 cmd.args.draw.vertexCount = vertexCount;
1200 cmd.args.draw.firstVertex = firstVertex;
1201 cmd.args.draw.firstInstance = firstInstance;
1202}
1203
1205 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1206{
1209
1210 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1213 cmd.args.drawIndexed.indexCount = indexCount;
1215 cmd.args.drawIndexed.firstIndex = firstIndex;
1216 cmd.args.drawIndexed.vertexOffset = vertexOffset;
1217 cmd.args.drawIndexed.firstInstance = firstInstance;
1218}
1219
1221{
1222 if (!debugMarkers || !annotations)
1223 return;
1224
1226 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1228 qstrncpy(cmd.args.debugMark.s, name.constData(), sizeof(cmd.args.debugMark.s));
1229}
1230
1232{
1233 if (!debugMarkers || !annotations)
1234 return;
1235
1237 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1239}
1240
1242{
1243 if (!debugMarkers || !annotations)
1244 return;
1245
1247 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1249 qstrncpy(cmd.args.debugMark.s, msg.constData(), sizeof(cmd.args.debugMark.s));
1250}
1251
1253{
1254 Q_UNUSED(cb);
1255 return nullptr;
1256}
1257
1259{
1261 // no timestampSwapChain, in order to avoid timestamp mess
1263 cbD->resetCommands();
1264}
1265
1267{
1269 Q_ASSERT(cbD->commands.isEmpty());
1270 cbD->resetCachedState();
1271 if (cbD->currentTarget) { // could be compute, no rendertarget then
1272 QD3D11CommandBuffer::Command &fbCmd(cbD->commands.get());
1274 fbCmd.args.setRenderTarget.rt = cbD->currentTarget;
1275 }
1276}
1277
1279{
1281 return cbD->lastGpuTime;
1282}
1283
1285{
1286 Q_UNUSED(flags);
1287
1288 QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
1289 contextState.currentSwapChain = swapChainD;
1290 const int currentFrameSlot = swapChainD->currentFrameSlot;
1291
1292 swapChainD->cb.resetState();
1293
1294 swapChainD->rt.d.rtv[0] = swapChainD->sampleDesc.Count > 1 ?
1295 swapChainD->msaaRtv[currentFrameSlot] : swapChainD->backBufferRtv;
1296 swapChainD->rt.d.dsv = swapChainD->ds ? swapChainD->ds->dsv : nullptr;
1297
1299
1300 if (swapChainD->timestamps.active[currentFrameSlot]) {
1301 double elapsedSec = 0;
1302 if (swapChainD->timestamps.tryQueryTimestamps(currentFrameSlot, context, &elapsedSec))
1303 swapChainD->cb.lastGpuTime = elapsedSec;
1304 }
1305
1306 return QRhi::FrameOpSuccess;
1307}
1308
1310{
1311 QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
1312 Q_ASSERT(contextState.currentSwapChain = swapChainD);
1313 const int currentFrameSlot = swapChainD->currentFrameSlot;
1314
1315 ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[currentFrameSlot];
1317 ID3D11Query *tsStart = swapChainD->timestamps.query[tsIdx];
1318 ID3D11Query *tsEnd = swapChainD->timestamps.query[tsIdx + 1];
1319 const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !swapChainD->timestamps.active[currentFrameSlot];
1320
1321 // send all commands to the context
1322 if (recordTimestamps)
1323 executeCommandBuffer(&swapChainD->cb, swapChainD);
1324 else
1325 executeCommandBuffer(&swapChainD->cb);
1326
1327 if (swapChainD->sampleDesc.Count > 1) {
1328 context->ResolveSubresource(swapChainD->backBufferTex, 0,
1329 swapChainD->msaaTex[currentFrameSlot], 0,
1330 swapChainD->colorFormat);
1331 }
1332
1333 // this is here because we want to include the time spent on the resolve as well
1334 if (recordTimestamps) {
1335 context->End(tsEnd);
1336 context->End(tsDisjoint);
1337 swapChainD->timestamps.active[currentFrameSlot] = true;
1338 }
1339
1340 if (!flags.testFlag(QRhi::SkipPresent)) {
1341 UINT presentFlags = 0;
1342 if (swapChainD->swapInterval == 0 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1343 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1344 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
1345 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
1346 qWarning("Device loss detected in Present()");
1347 deviceLost = true;
1349 } else if (FAILED(hr)) {
1350 qWarning("Failed to present: %s",
1351 qPrintable(QSystemError::windowsComString(hr)));
1352 return QRhi::FrameOpError;
1353 }
1354
1355 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
1356 dcompDevice->Commit();
1357
1358 // move on to the next buffer
1359 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D11SwapChain::BUFFER_COUNT;
1360 } else {
1361 context->Flush();
1362 }
1363
1364 swapChainD->frameCount += 1;
1365 contextState.currentSwapChain = nullptr;
1366
1367 return QRhi::FrameOpSuccess;
1368}
1369
1371{
1372 Q_UNUSED(flags);
1373 ofr.active = true;
1374
1376 *cb = &ofr.cbWrapper;
1377
1379 double elapsedSec = 0;
1381 ofr.cbWrapper.lastGpuTime = elapsedSec;
1382 }
1383
1384 return QRhi::FrameOpSuccess;
1385}
1386
1388{
1389 Q_UNUSED(flags);
1390 ofr.active = false;
1391
1392 ID3D11Query *tsDisjoint = ofr.timestamps.disjointQuery[ofr.timestampIdx];
1393 ID3D11Query *tsStart = ofr.timestamps.query[ofr.timestampIdx * 2];
1394 ID3D11Query *tsEnd = ofr.timestamps.query[ofr.timestampIdx * 2 + 1];
1395 const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !ofr.timestamps.active[ofr.timestampIdx];
1396 if (recordTimestamps) {
1397 context->Begin(tsDisjoint);
1398 context->End(tsStart); // record timestamp; no Begin() for D3D11_QUERY_TIMESTAMP
1399 }
1400
1402 context->Flush();
1403
1405
1406 if (recordTimestamps) {
1407 context->End(tsEnd);
1408 context->End(tsDisjoint);
1410 ofr.timestampIdx = (ofr.timestampIdx + 1) % 2;
1411 }
1412
1413 return QRhi::FrameOpSuccess;
1414}
1415
1416static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
1417{
1418 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1419 switch (format) {
1420 case QRhiTexture::RGBA8:
1421 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
1422 case QRhiTexture::BGRA8:
1423 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
1424 case QRhiTexture::R8:
1425 return DXGI_FORMAT_R8_UNORM;
1426 case QRhiTexture::RG8:
1427 return DXGI_FORMAT_R8G8_UNORM;
1428 case QRhiTexture::R16:
1429 return DXGI_FORMAT_R16_UNORM;
1430 case QRhiTexture::RG16:
1431 return DXGI_FORMAT_R16G16_UNORM;
1433 return DXGI_FORMAT_R8_UNORM;
1434
1436 return DXGI_FORMAT_R16G16B16A16_FLOAT;
1438 return DXGI_FORMAT_R32G32B32A32_FLOAT;
1439 case QRhiTexture::R16F:
1440 return DXGI_FORMAT_R16_FLOAT;
1441 case QRhiTexture::R32F:
1442 return DXGI_FORMAT_R32_FLOAT;
1443
1445 return DXGI_FORMAT_R10G10B10A2_UNORM;
1446
1447 case QRhiTexture::D16:
1448 return DXGI_FORMAT_R16_TYPELESS;
1449 case QRhiTexture::D24:
1450 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
1451 case QRhiTexture::D24S8:
1452 return DXGI_FORMAT_D24_UNORM_S8_UINT;
1453 case QRhiTexture::D32F:
1454 return DXGI_FORMAT_R32_TYPELESS;
1455
1456 case QRhiTexture::BC1:
1457 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
1458 case QRhiTexture::BC2:
1459 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
1460 case QRhiTexture::BC3:
1461 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
1462 case QRhiTexture::BC4:
1463 return DXGI_FORMAT_BC4_UNORM;
1464 case QRhiTexture::BC5:
1465 return DXGI_FORMAT_BC5_UNORM;
1466 case QRhiTexture::BC6H:
1467 return DXGI_FORMAT_BC6H_UF16;
1468 case QRhiTexture::BC7:
1469 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
1470
1474 qWarning("QRhiD3D11 does not support ETC2 textures");
1475 return DXGI_FORMAT_R8G8B8A8_UNORM;
1476
1491 qWarning("QRhiD3D11 does not support ASTC textures");
1492 return DXGI_FORMAT_R8G8B8A8_UNORM;
1493
1494 default:
1495 Q_UNREACHABLE();
1496 return DXGI_FORMAT_R8G8B8A8_UNORM;
1497 }
1498}
1499
1500static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
1501{
1502 switch (format) {
1503 case DXGI_FORMAT_R8G8B8A8_UNORM:
1504 return QRhiTexture::RGBA8;
1505 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
1506 if (flags)
1507 (*flags) |= QRhiTexture::sRGB;
1508 return QRhiTexture::RGBA8;
1509 case DXGI_FORMAT_B8G8R8A8_UNORM:
1510 return QRhiTexture::BGRA8;
1511 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
1512 if (flags)
1513 (*flags) |= QRhiTexture::sRGB;
1514 return QRhiTexture::BGRA8;
1515 case DXGI_FORMAT_R16G16B16A16_FLOAT:
1516 return QRhiTexture::RGBA16F;
1517 case DXGI_FORMAT_R32G32B32A32_FLOAT:
1518 return QRhiTexture::RGBA32F;
1519 case DXGI_FORMAT_R10G10B10A2_UNORM:
1520 return QRhiTexture::RGB10A2;
1521 default:
1522 qWarning("DXGI_FORMAT %d cannot be read back", format);
1523 break;
1524 }
1526}
1527
1529{
1530 switch (format) {
1535 return true;
1536
1537 default:
1538 return false;
1539 }
1540}
1541
1543{
1544 if (inFrame) {
1545 if (ofr.active) {
1546 Q_ASSERT(!contextState.currentSwapChain);
1550 } else {
1551 Q_ASSERT(contextState.currentSwapChain);
1552 Q_ASSERT(contextState.currentSwapChain->cb.recordingPass == QD3D11CommandBuffer::NoPass);
1553 executeCommandBuffer(&contextState.currentSwapChain->cb); // no timestampSwapChain, in order to avoid timestamp mess
1554 contextState.currentSwapChain->cb.resetCommands();
1555 }
1556 }
1557
1559
1560 return QRhi::FrameOpSuccess;
1561}
1562
1564 int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc)
1565{
1566 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1567 UINT subres = D3D11CalcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
1568 D3D11_BOX box;
1569 box.front = is3D ? UINT(layer) : 0u;
1570 // back, right, bottom are exclusive
1571 box.back = box.front + 1;
1572 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1574 cmd.args.updateSubRes.dst = texD->textureResource();
1575 cmd.args.updateSubRes.dstSubRes = subres;
1576
1577 const QPoint dp = subresDesc.destinationTopLeft();
1578 if (!subresDesc.image().isNull()) {
1579 QImage img = subresDesc.image();
1580 QSize size = img.size();
1581 int bpl = img.bytesPerLine();
1582 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
1583 const QPoint sp = subresDesc.sourceTopLeft();
1584 if (!subresDesc.sourceSize().isEmpty())
1585 size = subresDesc.sourceSize();
1586 if (img.depth() == 32) {
1587 const int offset = sp.y() * img.bytesPerLine() + sp.x() * 4;
1588 cmd.args.updateSubRes.src = cbD->retainImage(img) + offset;
1589 } else {
1590 img = img.copy(sp.x(), sp.y(), size.width(), size.height());
1591 bpl = img.bytesPerLine();
1592 cmd.args.updateSubRes.src = cbD->retainImage(img);
1593 }
1594 } else {
1595 cmd.args.updateSubRes.src = cbD->retainImage(img);
1596 }
1597 box.left = UINT(dp.x());
1598 box.top = UINT(dp.y());
1599 box.right = UINT(dp.x() + size.width());
1600 box.bottom = UINT(dp.y() + size.height());
1601 cmd.args.updateSubRes.hasDstBox = true;
1603 cmd.args.updateSubRes.srcRowPitch = UINT(bpl);
1604 } else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
1605 const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
1606 : subresDesc.sourceSize();
1607 quint32 bpl = 0;
1608 QSize blockDim;
1609 compressedFormatInfo(texD->m_format, size, &bpl, nullptr, &blockDim);
1610 // Everything must be a multiple of the block width and
1611 // height, so e.g. a mip level of size 2x2 will be 4x4 when it
1612 // comes to the actual data.
1613 box.left = UINT(aligned(dp.x(), blockDim.width()));
1614 box.top = UINT(aligned(dp.y(), blockDim.height()));
1615 box.right = UINT(aligned(dp.x() + size.width(), blockDim.width()));
1616 box.bottom = UINT(aligned(dp.y() + size.height(), blockDim.height()));
1617 cmd.args.updateSubRes.hasDstBox = true;
1619 cmd.args.updateSubRes.src = cbD->retainData(subresDesc.data());
1620 cmd.args.updateSubRes.srcRowPitch = bpl;
1621 } else if (!subresDesc.data().isEmpty()) {
1622 const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
1623 : subresDesc.sourceSize();
1624 quint32 bpl = 0;
1625 if (subresDesc.dataStride())
1626 bpl = subresDesc.dataStride();
1627 else
1628 textureFormatInfo(texD->m_format, size, &bpl, nullptr, nullptr);
1629 box.left = UINT(dp.x());
1630 box.top = UINT(dp.y());
1631 box.right = UINT(dp.x() + size.width());
1632 box.bottom = UINT(dp.y() + size.height());
1633 cmd.args.updateSubRes.hasDstBox = true;
1635 cmd.args.updateSubRes.src = cbD->retainData(subresDesc.data());
1636 cmd.args.updateSubRes.srcRowPitch = bpl;
1637 } else {
1638 qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
1639 cbD->commands.unget();
1640 }
1641}
1642
1644{
1647
1648 for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
1653 memcpy(bufD->dynBuf + u.offset, u.data.constData(), size_t(u.data.size()));
1654 bufD->hasPendingDynamicUpdates = true;
1658 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
1659 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1661 cmd.args.updateSubRes.dst = bufD->buffer;
1662 cmd.args.updateSubRes.dstSubRes = 0;
1665 // Specify the region (even when offset is 0 and all data is provided)
1666 // since the ID3D11Buffer's size is rounded up to be a multiple of 256
1667 // while the data we have has the original size.
1668 D3D11_BOX box;
1669 box.left = u.offset;
1670 box.top = box.front = 0;
1671 box.back = box.bottom = 1;
1672 box.right = u.offset + u.data.size(); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
1673 cmd.args.updateSubRes.hasDstBox = true;
1677 if (bufD->m_type == QRhiBuffer::Dynamic) {
1678 u.result->data.resize(u.readSize);
1679 memcpy(u.result->data.data(), bufD->dynBuf + u.offset, size_t(u.readSize));
1680 if (u.result->completed)
1681 u.result->completed();
1682 } else {
1683 BufferReadback readback;
1684 readback.result = u.result;
1685 readback.byteSize = u.readSize;
1686
1687 D3D11_BUFFER_DESC desc = {};
1688 desc.ByteWidth = readback.byteSize;
1689 desc.Usage = D3D11_USAGE_STAGING;
1690 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1691 HRESULT hr = dev->CreateBuffer(&desc, nullptr, &readback.stagingBuf);
1692 if (FAILED(hr)) {
1693 qWarning("Failed to create buffer: %s",
1694 qPrintable(QSystemError::windowsComString(hr)));
1695 continue;
1696 }
1697
1698 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1700 cmd.args.copySubRes.dst = readback.stagingBuf;
1701 cmd.args.copySubRes.dstSubRes = 0;
1702 cmd.args.copySubRes.dstX = 0;
1703 cmd.args.copySubRes.dstY = 0;
1704 cmd.args.copySubRes.dstZ = 0;
1705 cmd.args.copySubRes.src = bufD->buffer;
1706 cmd.args.copySubRes.srcSubRes = 0;
1707 cmd.args.copySubRes.hasSrcBox = true;
1708 D3D11_BOX box;
1709 box.left = u.offset;
1710 box.top = box.front = 0;
1711 box.back = box.bottom = 1;
1712 box.right = u.offset + u.readSize;
1713 cmd.args.copySubRes.srcBox = box;
1714
1715 activeBufferReadbacks.append(readback);
1716 }
1717 }
1718 }
1719 for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
1723 for (int layer = 0, maxLayer = u.subresDesc.count(); layer < maxLayer; ++layer) {
1724 for (int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
1725 for (const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
1726 enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
1727 }
1728 }
1730 Q_ASSERT(u.src && u.dst);
1733 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1734 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1735 UINT srcSubRes = D3D11CalcSubresource(UINT(u.desc.sourceLevel()), srcIs3D ? 0u : UINT(u.desc.sourceLayer()), srcD->mipLevelCount);
1736 UINT dstSubRes = D3D11CalcSubresource(UINT(u.desc.destinationLevel()), dstIs3D ? 0u : UINT(u.desc.destinationLayer()), dstD->mipLevelCount);
1737 const QPoint dp = u.desc.destinationTopLeft();
1738 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
1739 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
1740 const QPoint sp = u.desc.sourceTopLeft();
1741 D3D11_BOX srcBox;
1742 srcBox.left = UINT(sp.x());
1743 srcBox.top = UINT(sp.y());
1744 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
1745 // back, right, bottom are exclusive
1746 srcBox.right = srcBox.left + UINT(copySize.width());
1747 srcBox.bottom = srcBox.top + UINT(copySize.height());
1748 srcBox.back = srcBox.front + 1;
1749 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1751 cmd.args.copySubRes.dst = dstD->textureResource();
1752 cmd.args.copySubRes.dstSubRes = dstSubRes;
1753 cmd.args.copySubRes.dstX = UINT(dp.x());
1754 cmd.args.copySubRes.dstY = UINT(dp.y());
1755 cmd.args.copySubRes.dstZ = dstIs3D ? UINT(u.desc.destinationLayer()) : 0u;
1756 cmd.args.copySubRes.src = srcD->textureResource();
1757 cmd.args.copySubRes.srcSubRes = srcSubRes;
1758 cmd.args.copySubRes.hasSrcBox = true;
1759 cmd.args.copySubRes.srcBox = srcBox;
1761 TextureReadback readback;
1762 readback.desc = u.rb;
1763 readback.result = u.result;
1764
1765 ID3D11Resource *src;
1766 DXGI_FORMAT dxgiFormat;
1767 QSize pixelSize;
1769 UINT subres = 0;
1771 QD3D11SwapChain *swapChainD = nullptr;
1772 bool is3D = false;
1773
1774 if (texD) {
1775 if (texD->sampleDesc.Count > 1) {
1776 qWarning("Multisample texture cannot be read back");
1777 continue;
1778 }
1779 src = texD->textureResource();
1780 dxgiFormat = texD->dxgiFormat;
1781 pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
1782 format = texD->m_format;
1783 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1784 subres = D3D11CalcSubresource(UINT(u.rb.level()), UINT(is3D ? 0 : u.rb.layer()), texD->mipLevelCount);
1785 } else {
1786 Q_ASSERT(contextState.currentSwapChain);
1787 swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain);
1788 if (swapChainD->sampleDesc.Count > 1) {
1789 // Unlike with textures, reading back a multisample swapchain image
1790 // has to be supported. Insert a resolve.
1791 QD3D11CommandBuffer::Command &rcmd(cbD->commands.get());
1793 rcmd.args.resolveSubRes.dst = swapChainD->backBufferTex;
1794 rcmd.args.resolveSubRes.dstSubRes = 0;
1795 rcmd.args.resolveSubRes.src = swapChainD->msaaTex[swapChainD->currentFrameSlot];
1796 rcmd.args.resolveSubRes.srcSubRes = 0;
1797 rcmd.args.resolveSubRes.format = swapChainD->colorFormat;
1798 }
1799 src = swapChainD->backBufferTex;
1800 dxgiFormat = swapChainD->colorFormat;
1801 pixelSize = swapChainD->pixelSize;
1802 format = swapchainReadbackTextureFormat(dxgiFormat, nullptr);
1804 continue;
1805 }
1806 quint32 byteSize = 0;
1807 quint32 bpl = 0;
1808 textureFormatInfo(format, pixelSize, &bpl, &byteSize, nullptr);
1809
1810 D3D11_TEXTURE2D_DESC desc = {};
1811 desc.Width = UINT(pixelSize.width());
1812 desc.Height = UINT(pixelSize.height());
1813 desc.MipLevels = 1;
1814 desc.ArraySize = 1;
1815 desc.Format = dxgiFormat;
1816 desc.SampleDesc.Count = 1;
1817 desc.Usage = D3D11_USAGE_STAGING;
1818 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1819 ID3D11Texture2D *stagingTex;
1820 HRESULT hr = dev->CreateTexture2D(&desc, nullptr, &stagingTex);
1821 if (FAILED(hr)) {
1822 qWarning("Failed to create readback staging texture: %s",
1823 qPrintable(QSystemError::windowsComString(hr)));
1824 return;
1825 }
1826
1827 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1829 cmd.args.copySubRes.dst = stagingTex;
1830 cmd.args.copySubRes.dstSubRes = 0;
1831 cmd.args.copySubRes.dstX = 0;
1832 cmd.args.copySubRes.dstY = 0;
1833 cmd.args.copySubRes.dstZ = 0;
1834 cmd.args.copySubRes.src = src;
1835 cmd.args.copySubRes.srcSubRes = subres;
1836 if (is3D) {
1837 D3D11_BOX srcBox = {};
1838 srcBox.front = UINT(u.rb.layer());
1839 srcBox.right = desc.Width; // exclusive
1840 srcBox.bottom = desc.Height;
1841 srcBox.back = srcBox.front + 1;
1842 cmd.args.copySubRes.hasSrcBox = true;
1843 cmd.args.copySubRes.srcBox = srcBox;
1844 } else {
1845 cmd.args.copySubRes.hasSrcBox = false;
1846 }
1847
1848 readback.stagingTex = stagingTex;
1849 readback.byteSize = byteSize;
1850 readback.bpl = bpl;
1851 readback.pixelSize = pixelSize;
1852 readback.format = format;
1853
1854 activeTextureReadbacks.append(readback);
1857 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1859 cmd.args.genMip.srv = QRHI_RES(QD3D11Texture, u.dst)->srv;
1860 }
1861 }
1862
1863 ud->free();
1864}
1865
1867{
1868 QVarLengthArray<std::function<void()>, 4> completedCallbacks;
1869
1870 for (int i = activeTextureReadbacks.count() - 1; i >= 0; --i) {
1872 readback.result->format = readback.format;
1873 readback.result->pixelSize = readback.pixelSize;
1874
1875 D3D11_MAPPED_SUBRESOURCE mp;
1876 HRESULT hr = context->Map(readback.stagingTex, 0, D3D11_MAP_READ, 0, &mp);
1877 if (SUCCEEDED(hr)) {
1878 readback.result->data.resize(int(readback.byteSize));
1879 // nothing says the rows are tightly packed in the texture, must take
1880 // the stride into account
1881 char *dst = readback.result->data.data();
1882 char *src = static_cast<char *>(mp.pData);
1883 for (int y = 0, h = readback.pixelSize.height(); y != h; ++y) {
1884 memcpy(dst, src, readback.bpl);
1885 dst += readback.bpl;
1886 src += mp.RowPitch;
1887 }
1888 context->Unmap(readback.stagingTex, 0);
1889 } else {
1890 qWarning("Failed to map readback staging texture: %s",
1891 qPrintable(QSystemError::windowsComString(hr)));
1892 }
1893
1894 readback.stagingTex->Release();
1895
1896 if (readback.result->completed)
1897 completedCallbacks.append(readback.result->completed);
1898
1899 activeTextureReadbacks.removeLast();
1900 }
1901
1902 for (int i = activeBufferReadbacks.count() - 1; i >= 0; --i) {
1904
1905 D3D11_MAPPED_SUBRESOURCE mp;
1906 HRESULT hr = context->Map(readback.stagingBuf, 0, D3D11_MAP_READ, 0, &mp);
1907 if (SUCCEEDED(hr)) {
1908 readback.result->data.resize(int(readback.byteSize));
1909 memcpy(readback.result->data.data(), mp.pData, readback.byteSize);
1910 context->Unmap(readback.stagingBuf, 0);
1911 } else {
1912 qWarning("Failed to map readback staging texture: %s",
1913 qPrintable(QSystemError::windowsComString(hr)));
1914 }
1915
1916 readback.stagingBuf->Release();
1917
1918 if (readback.result->completed)
1919 completedCallbacks.append(readback.result->completed);
1920
1921 activeBufferReadbacks.removeLast();
1922 }
1923
1924 for (auto f : completedCallbacks)
1925 f();
1926}
1927
1929{
1930 switch (rt->resourceType()) {
1932 return &QRHI_RES(QD3D11SwapChainRenderTarget, rt)->d;
1934 return &QRHI_RES(QD3D11TextureRenderTarget, rt)->d;
1935 default:
1936 Q_UNREACHABLE();
1937 return nullptr;
1938 }
1939}
1940
1942{
1944
1945 enqueueResourceUpdates(cb, resourceUpdates);
1946}
1947
1949 QRhiRenderTarget *rt,
1950 const QColor &colorClearValue,
1951 const QRhiDepthStencilClearValue &depthStencilClearValue,
1952 QRhiResourceUpdateBatch *resourceUpdates,
1953 QRhiCommandBuffer::BeginPassFlags)
1954{
1957
1958 if (resourceUpdates)
1959 enqueueResourceUpdates(cb, resourceUpdates);
1960
1961 bool wantsColorClear = true;
1962 bool wantsDsClear = true;
1963 QD3D11RenderTargetData *rtD = rtData(rt);
1966 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
1967 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
1968 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(rtTex->description(), rtD->currentResIdList))
1969 rtTex->create();
1970 }
1971
1973
1974 QD3D11CommandBuffer::Command &fbCmd(cbD->commands.get());
1976 fbCmd.args.setRenderTarget.rt = rt;
1977
1978 QD3D11CommandBuffer::Command &clearCmd(cbD->commands.get());
1980 clearCmd.args.clear.rt = rt;
1981 clearCmd.args.clear.mask = 0;
1982 if (rtD->colorAttCount && wantsColorClear)
1984 if (rtD->dsAttCount && wantsDsClear)
1986
1987 clearCmd.args.clear.c[0] = float(colorClearValue.redF());
1988 clearCmd.args.clear.c[1] = float(colorClearValue.greenF());
1989 clearCmd.args.clear.c[2] = float(colorClearValue.blueF());
1990 clearCmd.args.clear.c[3] = float(colorClearValue.alphaF());
1991 clearCmd.args.clear.d = depthStencilClearValue.depthClearValue();
1992 clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
1993
1995 cbD->currentTarget = rt;
1996
1997 cbD->resetCachedState();
1998}
1999
2001{
2004
2007 for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2008 it != itEnd; ++it)
2009 {
2010 const QRhiColorAttachment &colorAtt(*it);
2011 if (!colorAtt.resolveTexture())
2012 continue;
2013
2014 QD3D11Texture *dstTexD = QRHI_RES(QD3D11Texture, colorAtt.resolveTexture());
2015 QD3D11Texture *srcTexD = QRHI_RES(QD3D11Texture, colorAtt.texture());
2017 Q_ASSERT(srcTexD || srcRbD);
2018 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2020 cmd.args.resolveSubRes.dst = dstTexD->textureResource();
2021 cmd.args.resolveSubRes.dstSubRes = D3D11CalcSubresource(UINT(colorAtt.resolveLevel()),
2022 UINT(colorAtt.resolveLayer()),
2023 dstTexD->mipLevelCount);
2024 if (srcTexD) {
2025 cmd.args.resolveSubRes.src = srcTexD->textureResource();
2026 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2027 qWarning("Resolve source (%d) and destination (%d) formats do not match",
2028 int(srcTexD->dxgiFormat), int(dstTexD->dxgiFormat));
2029 cbD->commands.unget();
2030 continue;
2031 }
2032 if (srcTexD->sampleDesc.Count <= 1) {
2033 qWarning("Cannot resolve a non-multisample texture");
2034 cbD->commands.unget();
2035 continue;
2036 }
2037 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2038 qWarning("Resolve source and destination sizes do not match");
2039 cbD->commands.unget();
2040 continue;
2041 }
2042 } else {
2043 cmd.args.resolveSubRes.src = srcRbD->tex;
2044 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2045 qWarning("Resolve source (%d) and destination (%d) formats do not match",
2046 int(srcRbD->dxgiFormat), int(dstTexD->dxgiFormat));
2047 cbD->commands.unget();
2048 continue;
2049 }
2050 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2051 qWarning("Resolve source and destination sizes do not match");
2052 cbD->commands.unget();
2053 continue;
2054 }
2055 }
2056 cmd.args.resolveSubRes.srcSubRes = D3D11CalcSubresource(0, UINT(colorAtt.layer()), 1);
2057 cmd.args.resolveSubRes.format = dstTexD->dxgiFormat;
2058 }
2059 }
2060
2062 cbD->currentTarget = nullptr;
2063
2064 if (resourceUpdates)
2065 enqueueResourceUpdates(cb, resourceUpdates);
2066}
2067
2069 QRhiResourceUpdateBatch *resourceUpdates,
2070 QRhiCommandBuffer::BeginPassFlags)
2071{
2074
2075 if (resourceUpdates)
2076 enqueueResourceUpdates(cb, resourceUpdates);
2077
2078 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2080
2082
2083 cbD->resetCachedState();
2084}
2085
2087{
2090
2092
2093 if (resourceUpdates)
2094 enqueueResourceUpdates(cb, resourceUpdates);
2095}
2096
2098{
2102 const bool pipelineChanged = cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation;
2103
2104 if (pipelineChanged) {
2105 cbD->currentGraphicsPipeline = nullptr;
2106 cbD->currentComputePipeline = psD;
2108
2109 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2111 cmd.args.bindComputePipeline.ps = psD;
2112 }
2113}
2114
2116{
2119
2120 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2122 cmd.args.dispatch.x = UINT(x);
2123 cmd.args.dispatch.y = UINT(y);
2124 cmd.args.dispatch.z = UINT(z);
2125}
2126
2127static inline QPair<int, int> mapBinding(int binding,
2128 int stageIndex,
2129 const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
2130{
2131 const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
2132 if (!map || map->isEmpty())
2133 return { binding, binding }; // assume 1:1 mapping
2134
2135 auto it = map->constFind(binding);
2136 if (it != map->cend())
2137 return *it;
2138
2139 // Hitting this path is normal too. It is not given that the resource is
2140 // present in the shaders for all the stages specified by the visibility
2141 // mask in the QRhiShaderResourceBinding.
2142 return { -1, -1 };
2143}
2144
2146 const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
2147{
2154
2155 srbD->vsSamplerBatches.clear();
2156 srbD->hsSamplerBatches.clear();
2157 srbD->dsSamplerBatches.clear();
2158 srbD->gsSamplerBatches.clear();
2159 srbD->fsSamplerBatches.clear();
2160 srbD->csSamplerBatches.clear();
2161
2162 srbD->csUavBatches.clear();
2163
2164 struct Stage {
2165 struct Buffer {
2166 int binding; // stored and sent along in XXorigbindings just for applyDynamicOffsets()
2167 int breg; // b0, b1, ...
2168 ID3D11Buffer *buffer;
2169 uint offsetInConstants;
2170 uint sizeInConstants;
2171 };
2172 struct Texture {
2173 int treg; // t0, t1, ...
2174 ID3D11ShaderResourceView *srv;
2175 };
2176 struct Sampler {
2177 int sreg; // s0, s1, ...
2178 ID3D11SamplerState *sampler;
2179 };
2180 struct Uav {
2181 int ureg;
2182 ID3D11UnorderedAccessView *uav;
2183 };
2188 void buildBufferBatches(QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches) const
2189 {
2190 for (const Buffer &buf : buffers) {
2191 batches.ubufs.feed(buf.breg, buf.buffer);
2192 batches.ubuforigbindings.feed(buf.breg, UINT(buf.binding));
2193 batches.ubufoffsets.feed(buf.breg, buf.offsetInConstants);
2194 batches.ubufsizes.feed(buf.breg, buf.sizeInConstants);
2195 }
2196 batches.finish();
2197 }
2198 void buildSamplerBatches(QD3D11ShaderResourceBindings::StageSamplerBatches &batches) const
2199 {
2200 for (const Texture &t : textures)
2201 batches.shaderresources.feed(t.treg, t.srv);
2202 for (const Sampler &s : samplers)
2203 batches.samplers.feed(s.sreg, s.sampler);
2204 batches.finish();
2205 }
2206 void buildUavBatches(QD3D11ShaderResourceBindings::StageUavBatches &batches) const
2207 {
2208 for (const Stage::Uav &u : uavs)
2209 batches.uavs.feed(u.ureg, u.uav);
2210 batches.finish();
2211 }
2213
2214 for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
2217 switch (b->type) {
2219 {
2220 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
2221 Q_ASSERT(aligned(b->u.ubuf.offset, 256u) == b->u.ubuf.offset);
2222 bd.ubuf.id = bufD->m_id;
2223 bd.ubuf.generation = bufD->generation;
2224 // Dynamic ubuf offsets are not considered here, those are baked in
2225 // at a later stage, which is good as vsubufoffsets and friends are
2226 // per-srb, not per-setShaderResources call. Other backends (GL,
2227 // Metal) are different in this respect since those do not store
2228 // per-srb vsubufoffsets etc. data so life's a bit easier for them.
2229 // But here we have to defer baking in the dynamic offset.
2230 const quint32 offsetInConstants = b->u.ubuf.offset / 16;
2231 // size must be 16 mult. (in constants, i.e. multiple of 256 bytes).
2232 // We can round up if needed since the buffers's actual size
2233 // (ByteWidth) is always a multiple of 256.
2234 const quint32 sizeInConstants = aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256u) / 16;
2235 if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
2236 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
2237 if (nativeBinding.first >= 0)
2238 res[RBM_VERTEX].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2239 }
2241 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps);
2242 if (nativeBinding.first >= 0)
2243 res[RBM_HULL].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2244 }
2246 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps);
2247 if (nativeBinding.first >= 0)
2248 res[RBM_DOMAIN].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2249 }
2250 if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) {
2251 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps);
2252 if (nativeBinding.first >= 0)
2253 res[RBM_GEOMETRY].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2254 }
2255 if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
2256 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
2257 if (nativeBinding.first >= 0)
2258 res[RBM_FRAGMENT].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2259 }
2260 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2261 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2262 if (nativeBinding.first >= 0)
2263 res[RBM_COMPUTE].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2264 }
2265 }
2266 break;
2270 {
2272 bd.stex.count = data->count;
2273 const QPair<int, int> nativeBindingVert = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
2274 const QPair<int, int> nativeBindingHull = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps);
2275 const QPair<int, int> nativeBindingDomain = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps);
2276 const QPair<int, int> nativeBindingGeom = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps);
2277 const QPair<int, int> nativeBindingFrag = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
2278 const QPair<int, int> nativeBindingComp = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2279 // if SPIR-V binding b is mapped to tN and sN in HLSL, and it
2280 // is an array, then it will use tN, tN+1, tN+2, ..., and sN,
2281 // sN+1, sN+2, ...
2282 for (int elem = 0; elem < data->count; ++elem) {
2283 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
2284 QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
2285 bd.stex.d[elem].texId = texD ? texD->m_id : 0;
2286 bd.stex.d[elem].texGeneration = texD ? texD->generation : 0;
2287 bd.stex.d[elem].samplerId = samplerD ? samplerD->m_id : 0;
2288 bd.stex.d[elem].samplerGeneration = samplerD ? samplerD->generation : 0;
2289 // Must handle all three cases (combined, separate, separate):
2290 // first = texture binding, second = sampler binding
2291 // first = texture binding
2292 // first = sampler binding
2293 if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
2294 const int samplerBinding = texD && samplerD ? nativeBindingVert.second
2295 : (samplerD ? nativeBindingVert.first : -1);
2296 if (nativeBindingVert.first >= 0 && texD)
2297 res[RBM_VERTEX].textures.append({ nativeBindingVert.first + elem, texD->srv });
2298 if (samplerBinding >= 0)
2299 res[RBM_VERTEX].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2300 }
2302 const int samplerBinding = texD && samplerD ? nativeBindingHull.second
2303 : (samplerD ? nativeBindingHull.first : -1);
2304 if (nativeBindingHull.first >= 0 && texD)
2305 res[RBM_HULL].textures.append({ nativeBindingHull.first + elem, texD->srv });
2306 if (samplerBinding >= 0)
2307 res[RBM_HULL].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2308 }
2310 const int samplerBinding = texD && samplerD ? nativeBindingDomain.second
2311 : (samplerD ? nativeBindingDomain.first : -1);
2312 if (nativeBindingDomain.first >= 0 && texD)
2313 res[RBM_DOMAIN].textures.append({ nativeBindingDomain.first + elem, texD->srv });
2314 if (samplerBinding >= 0)
2315 res[RBM_DOMAIN].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2316 }
2317 if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) {
2318 const int samplerBinding = texD && samplerD ? nativeBindingGeom.second
2319 : (samplerD ? nativeBindingGeom.first : -1);
2320 if (nativeBindingGeom.first >= 0 && texD)
2321 res[RBM_GEOMETRY].textures.append({ nativeBindingGeom.first + elem, texD->srv });
2322 if (samplerBinding >= 0)
2323 res[RBM_GEOMETRY].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2324 }
2325 if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
2326 const int samplerBinding = texD && samplerD ? nativeBindingFrag.second
2327 : (samplerD ? nativeBindingFrag.first : -1);
2328 if (nativeBindingFrag.first >= 0 && texD)
2329 res[RBM_FRAGMENT].textures.append({ nativeBindingFrag.first + elem, texD->srv });
2330 if (samplerBinding >= 0)
2331 res[RBM_FRAGMENT].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2332 }
2333 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2334 const int samplerBinding = texD && samplerD ? nativeBindingComp.second
2335 : (samplerD ? nativeBindingComp.first : -1);
2336 if (nativeBindingComp.first >= 0 && texD)
2337 res[RBM_COMPUTE].textures.append({ nativeBindingComp.first + elem, texD->srv });
2338 if (samplerBinding >= 0)
2339 res[RBM_COMPUTE].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2340 }
2341 }
2342 }
2343 break;
2347 {
2348 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex);
2349 bd.simage.id = texD->m_id;
2350 bd.simage.generation = texD->generation;
2351 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2352 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2353 if (nativeBinding.first >= 0) {
2354 ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level);
2355 if (uav)
2356 res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
2357 }
2358 } else {
2359 qWarning("Unordered access only supported at compute stage");
2360 }
2361 }
2362 break;
2366 {
2367 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf);
2368 bd.sbuf.id = bufD->m_id;
2369 bd.sbuf.generation = bufD->generation;
2370 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2371 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2372 if (nativeBinding.first >= 0) {
2373 ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(b->u.sbuf.offset);
2374 if (uav)
2375 res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
2376 }
2377 } else {
2378 qWarning("Unordered access only supported at compute stage");
2379 }
2380 }
2381 break;
2382 default:
2383 Q_UNREACHABLE();
2384 break;
2385 }
2386 }
2387
2388 // QRhiBatchedBindings works with the native bindings and expects
2389 // sorted input. The pre-sorted QRhiShaderResourceBinding list (based
2390 // on the QRhi (SPIR-V) binding) is not helpful in this regard, so we
2391 // have to sort here every time.
2392 for (int stage = 0; stage < RBM_SUPPORTED_STAGES; ++stage) {
2393 std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) {
2394 return a.breg < b.breg;
2395 });
2396 std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) {
2397 return a.treg < b.treg;
2398 });
2399 std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) {
2400 return a.sreg < b.sreg;
2401 });
2402 std::sort(res[stage].uavs.begin(), res[stage].uavs.end(), [](const Stage::Uav &a, const Stage::Uav &b) {
2403 return a.ureg < b.ureg;
2404 });
2405 }
2406
2407 res[RBM_VERTEX].buildBufferBatches(srbD->vsUniformBufferBatches);
2408 res[RBM_HULL].buildBufferBatches(srbD->hsUniformBufferBatches);
2409 res[RBM_DOMAIN].buildBufferBatches(srbD->dsUniformBufferBatches);
2410 res[RBM_GEOMETRY].buildBufferBatches(srbD->gsUniformBufferBatches);
2411 res[RBM_FRAGMENT].buildBufferBatches(srbD->fsUniformBufferBatches);
2412 res[RBM_COMPUTE].buildBufferBatches(srbD->csUniformBufferBatches);
2413
2414 res[RBM_VERTEX].buildSamplerBatches(srbD->vsSamplerBatches);
2415 res[RBM_HULL].buildSamplerBatches(srbD->hsSamplerBatches);
2416 res[RBM_DOMAIN].buildSamplerBatches(srbD->dsSamplerBatches);
2417 res[RBM_GEOMETRY].buildSamplerBatches(srbD->gsSamplerBatches);
2418 res[RBM_FRAGMENT].buildSamplerBatches(srbD->fsSamplerBatches);
2419 res[RBM_COMPUTE].buildSamplerBatches(srbD->csSamplerBatches);
2420
2421 res[RBM_COMPUTE].buildUavBatches(srbD->csUavBatches);
2422}
2423
2425{
2426 if (!bufD->hasPendingDynamicUpdates || bufD->m_size < 1)
2427 return;
2428
2430 bufD->hasPendingDynamicUpdates = false;
2431 D3D11_MAPPED_SUBRESOURCE mp;
2432 HRESULT hr = context->Map(bufD->buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
2433 if (SUCCEEDED(hr)) {
2434 memcpy(mp.pData, bufD->dynBuf, bufD->m_size);
2435 context->Unmap(bufD->buffer, 0);
2436 } else {
2437 qWarning("Failed to map buffer: %s",
2438 qPrintable(QSystemError::windowsComString(hr)));
2439 }
2440}
2441
2443 int batchIndex,
2444 const QRhiBatchedBindings<UINT> *originalBindings,
2445 const QRhiBatchedBindings<UINT> *staticOffsets,
2446 const uint *dynOfsPairs, int dynOfsPairCount)
2447{
2448 const int count = staticOffsets->batches[batchIndex].resources.count();
2449 // Make a copy of the offset list, the entries that have no corresponding
2450 // dynamic offset will continue to use the existing offset value.
2451 for (int b = 0; b < count; ++b) {
2452 offsets[b] = staticOffsets->batches[batchIndex].resources[b];
2453 for (int di = 0; di < dynOfsPairCount; ++di) {
2454 const uint binding = dynOfsPairs[2 * di];
2455 // binding is the SPIR-V style binding point here, nothing to do
2456 // with the native one.
2457 if (binding == originalBindings->batches[batchIndex].resources[b]) {
2458 const uint offsetInConstants = dynOfsPairs[2 * di + 1];
2459 offsets[b] = offsetInConstants;
2460 break;
2461 }
2462 }
2463 }
2464}
2465
2466static inline uint clampedResourceCount(uint startSlot, int countSlots, uint maxSlots, const char *resType)
2467{
2468 if (startSlot + countSlots > maxSlots) {
2469 qWarning("Not enough D3D11 %s slots to bind %d resources starting at slot %d, max slots is %d",
2470 resType, countSlots, startSlot, maxSlots);
2471 countSlots = maxSlots > startSlot ? maxSlots - startSlot : 0;
2472 }
2473 return countSlots;
2474}
2475
2476#define SETUBUFBATCH(stagePrefixL, stagePrefixU) \
2477 if (srbD->stagePrefixL##UniformBufferBatches.present) { \
2478 const QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches(srbD->stagePrefixL##UniformBufferBatches); \
2479 for (int i = 0, ie = batches.ubufs.batches.count(); i != ie; ++i) { \
2480 const uint count = clampedResourceCount(batches.ubufs.batches[i].startBinding, \
2481 batches.ubufs.batches[i].resources.count(), \
2482 D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, \
2483 #stagePrefixU " cbuf"); \
2484 if (count) { \
2485 if (!dynOfsPairCount) { \
2486 context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \
2487 count, \
2488 batches.ubufs.batches[i].resources.constData(), \
2489 batches.ubufoffsets.batches[i].resources.constData(), \
2490 batches.ubufsizes.batches[i].resources.constData()); \
2491 } else { \
2492 applyDynamicOffsets(offsets, i, \
2493 &batches.ubuforigbindings, &batches.ubufoffsets, \
2494 dynOfsPairs, dynOfsPairCount); \
2495 context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \
2496 count, \
2497 batches.ubufs.batches[i].resources.constData(), \
2498 offsets, \
2499 batches.ubufsizes.batches[i].resources.constData()); \
2500 } \
2501 } \
2502 } \
2503 }
2504
2505#define SETSAMPLERBATCH(stagePrefixL, stagePrefixU) \
2506 if (srbD->stagePrefixL##SamplerBatches.present) { \
2507 for (const auto &batch : srbD->stagePrefixL##SamplerBatches.samplers.batches) { \
2508 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2509 D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, #stagePrefixU " sampler"); \
2510 if (count) \
2511 context->stagePrefixU##SetSamplers(batch.startBinding, count, batch.resources.constData()); \
2512 } \
2513 for (const auto &batch : srbD->stagePrefixL##SamplerBatches.shaderresources.batches) { \
2514 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2515 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, #stagePrefixU " SRV"); \
2516 if (count) { \
2517 context->stagePrefixU##SetShaderResources(batch.startBinding, count, batch.resources.constData()); \
2518 contextState.stagePrefixL##HighestActiveSrvBinding = qMax(contextState.stagePrefixL##HighestActiveSrvBinding, \
2519 int(batch.startBinding + count) - 1); \
2520 } \
2521 } \
2522 }
2523
2524#define SETUAVBATCH(stagePrefixL, stagePrefixU) \
2525 if (srbD->stagePrefixL##UavBatches.present) { \
2526 for (const auto &batch : srbD->stagePrefixL##UavBatches.uavs.batches) { \
2527 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2528 D3D11_1_UAV_SLOT_COUNT, #stagePrefixU " UAV"); \
2529 if (count) { \
2530 context->stagePrefixU##SetUnorderedAccessViews(batch.startBinding, \
2531 count, \
2532 batch.resources.constData(), \
2533 nullptr); \
2534 contextState.stagePrefixL##HighestActiveUavBinding = qMax(contextState.stagePrefixL##HighestActiveUavBinding, \
2535 int(batch.startBinding + count) - 1); \
2536 } \
2537 } \
2538 }
2539
2541 const uint *dynOfsPairs, int dynOfsPairCount,
2542 bool offsetOnlyChange)
2543{
2545
2546 SETUBUFBATCH(vs, VS)
2547 SETUBUFBATCH(hs, HS)
2548 SETUBUFBATCH(ds, DS)
2549 SETUBUFBATCH(gs, GS)
2550 SETUBUFBATCH(fs, PS)
2551 SETUBUFBATCH(cs, CS)
2552
2553 if (!offsetOnlyChange) {
2554 SETSAMPLERBATCH(vs, VS)
2555 SETSAMPLERBATCH(hs, HS)
2556 SETSAMPLERBATCH(ds, DS)
2557 SETSAMPLERBATCH(gs, GS)
2558 SETSAMPLERBATCH(fs, PS)
2559 SETSAMPLERBATCH(cs, CS)
2560
2561 SETUAVBATCH(cs, CS)
2562 }
2563}
2564
2566{
2567 // Output cannot be bound on input etc.
2568
2569 if (contextState.vsHasIndexBufferBound) {
2570 context->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
2571 contextState.vsHasIndexBufferBound = false;
2572 }
2573
2574 if (contextState.vsHighestActiveVertexBufferBinding >= 0) {
2575 const int count = contextState.vsHighestActiveVertexBufferBinding + 1;
2577 for (int i = 0; i < count; ++i)
2578 nullbufs[i] = nullptr;
2580 for (int i = 0; i < count; ++i)
2581 nullstrides[i] = 0;
2583 for (int i = 0; i < count; ++i)
2584 nulloffsets[i] = 0;
2585 context->IASetVertexBuffers(0, UINT(count), nullbufs.constData(), nullstrides.constData(), nulloffsets.constData());
2586 contextState.vsHighestActiveVertexBufferBinding = -1;
2587 }
2588
2589 int nullsrvCount = qMax(contextState.vsHighestActiveSrvBinding, contextState.fsHighestActiveSrvBinding);
2590 nullsrvCount = qMax(nullsrvCount, contextState.hsHighestActiveSrvBinding);
2591 nullsrvCount = qMax(nullsrvCount, contextState.dsHighestActiveSrvBinding);
2592 nullsrvCount = qMax(nullsrvCount, contextState.gsHighestActiveSrvBinding);
2593 nullsrvCount = qMax(nullsrvCount, contextState.csHighestActiveSrvBinding);
2594 nullsrvCount += 1;
2595 if (nullsrvCount > 0) {
2596 QVarLengthArray<ID3D11ShaderResourceView *,
2597 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nullsrvs(nullsrvCount);
2598 for (int i = 0; i < nullsrvs.count(); ++i)
2599 nullsrvs[i] = nullptr;
2600 if (contextState.vsHighestActiveSrvBinding >= 0) {
2601 context->VSSetShaderResources(0, UINT(contextState.vsHighestActiveSrvBinding + 1), nullsrvs.constData());
2602 contextState.vsHighestActiveSrvBinding = -1;
2603 }
2604 if (contextState.hsHighestActiveSrvBinding >= 0) {
2605 context->HSSetShaderResources(0, UINT(contextState.hsHighestActiveSrvBinding + 1), nullsrvs.constData());
2606 contextState.hsHighestActiveSrvBinding = -1;
2607 }
2608 if (contextState.dsHighestActiveSrvBinding >= 0) {
2609 context->DSSetShaderResources(0, UINT(contextState.dsHighestActiveSrvBinding + 1), nullsrvs.constData());
2610 contextState.dsHighestActiveSrvBinding = -1;
2611 }
2612 if (contextState.gsHighestActiveSrvBinding >= 0) {
2613 context->GSSetShaderResources(0, UINT(contextState.gsHighestActiveSrvBinding + 1), nullsrvs.constData());
2614 contextState.gsHighestActiveSrvBinding = -1;
2615 }
2616 if (contextState.fsHighestActiveSrvBinding >= 0) {
2617 context->PSSetShaderResources(0, UINT(contextState.fsHighestActiveSrvBinding + 1), nullsrvs.constData());
2618 contextState.fsHighestActiveSrvBinding = -1;
2619 }
2620 if (contextState.csHighestActiveSrvBinding >= 0) {
2621 context->CSSetShaderResources(0, UINT(contextState.csHighestActiveSrvBinding + 1), nullsrvs.constData());
2622 contextState.csHighestActiveSrvBinding = -1;
2623 }
2624 }
2625
2626 if (contextState.csHighestActiveUavBinding >= 0) {
2627 const int nulluavCount = contextState.csHighestActiveUavBinding + 1;
2628 QVarLengthArray<ID3D11UnorderedAccessView *,
2629 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nulluavs(nulluavCount);
2630 for (int i = 0; i < nulluavCount; ++i)
2631 nulluavs[i] = nullptr;
2632 context->CSSetUnorderedAccessViews(0, UINT(nulluavCount), nulluavs.constData(), nullptr);
2633 contextState.csHighestActiveUavBinding = -1;
2634 }
2635}
2636
2637#define SETSHADER(StageL, StageU) \
2638 if (psD->StageL.shader) { \
2639 context->StageU##SetShader(psD->StageL.shader, nullptr, 0); \
2640 currentShaderMask |= StageU##MaskBit; \
2641 } else if (currentShaderMask & StageU##MaskBit) { \
2642 context->StageU##SetShader(nullptr, nullptr, 0); \
2643 currentShaderMask &= ~StageU##MaskBit; \
2644 }
2645
2647{
2648 quint32 stencilRef = 0;
2649 float blendConstants[] = { 1, 1, 1, 1 };
2650 enum ActiveShaderMask {
2651 VSMaskBit = 0x01,
2652 HSMaskBit = 0x02,
2653 DSMaskBit = 0x04,
2654 GSMaskBit = 0x08,
2655 PSMaskBit = 0x10
2656 };
2657 int currentShaderMask = 0xFF;
2658
2659 if (timestampSwapChain) {
2660 const int currentFrameSlot = timestampSwapChain->currentFrameSlot;
2661 ID3D11Query *tsDisjoint = timestampSwapChain->timestamps.disjointQuery[currentFrameSlot];
2663 ID3D11Query *tsStart = timestampSwapChain->timestamps.query[tsIdx];
2664 if (tsDisjoint && tsStart && !timestampSwapChain->timestamps.active[currentFrameSlot]) {
2665 // The timestamps seem to include vsync time with Present(1), except
2666 // when running on a non-primary gpu. This is not ideal. So try working
2667 // it around by issuing a semi-fake OMSetRenderTargets early and
2668 // writing the first timestamp only afterwards.
2669 context->Begin(tsDisjoint);
2670 QD3D11RenderTargetData *rtD = rtData(&timestampSwapChain->rt);
2671 context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
2672 context->End(tsStart); // just record a timestamp, no Begin needed
2673 }
2674 }
2675
2676 for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) {
2677 const QD3D11CommandBuffer::Command &cmd(*it);
2678 switch (cmd.cmd) {
2681 break;
2683 {
2685 context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
2686 }
2687 break;
2689 {
2692 for (int i = 0; i < rtD->colorAttCount; ++i)
2693 context->ClearRenderTargetView(rtD->rtv[i], cmd.args.clear.c);
2694 }
2695 uint ds = 0;
2697 ds |= D3D11_CLEAR_DEPTH;
2699 ds |= D3D11_CLEAR_STENCIL;
2700 if (ds)
2701 context->ClearDepthStencilView(rtD->dsv, ds, cmd.args.clear.d, UINT8(cmd.args.clear.s));
2702 }
2703 break;
2705 {
2706 D3D11_VIEWPORT v;
2707 v.TopLeftX = cmd.args.viewport.x;
2708 v.TopLeftY = cmd.args.viewport.y;
2709 v.Width = cmd.args.viewport.w;
2710 v.Height = cmd.args.viewport.h;
2711 v.MinDepth = cmd.args.viewport.d0;
2712 v.MaxDepth = cmd.args.viewport.d1;
2713 context->RSSetViewports(1, &v);
2714 }
2715 break;
2717 {
2718 D3D11_RECT r;
2719 r.left = cmd.args.scissor.x;
2720 r.top = cmd.args.scissor.y;
2721 // right and bottom are exclusive
2722 r.right = cmd.args.scissor.x + cmd.args.scissor.w;
2723 r.bottom = cmd.args.scissor.y + cmd.args.scissor.h;
2724 context->RSSetScissorRects(1, &r);
2725 }
2726 break;
2728 contextState.vsHighestActiveVertexBufferBinding = qMax<int>(
2729 contextState.vsHighestActiveVertexBufferBinding,
2731 context->IASetVertexBuffers(UINT(cmd.args.bindVertexBuffers.startSlot),
2736 break;
2738 contextState.vsHasIndexBufferBound = true;
2739 context->IASetIndexBuffer(cmd.args.bindIndexBuffer.buffer,
2742 break;
2744 {
2746 SETSHADER(vs, VS)
2747 SETSHADER(hs, HS)
2748 SETSHADER(ds, DS)
2749 SETSHADER(gs, GS)
2750 SETSHADER(fs, PS)
2751 context->IASetPrimitiveTopology(psD->d3dTopology);
2752 context->IASetInputLayout(psD->inputLayout); // may be null, that's ok
2753 context->OMSetDepthStencilState(psD->dsState, stencilRef);
2754 context->OMSetBlendState(psD->blendState, blendConstants, 0xffffffff);
2755 context->RSSetState(psD->rastState);
2756 }
2757 break;
2763 break;
2765 stencilRef = cmd.args.stencilRef.ref;
2766 context->OMSetDepthStencilState(cmd.args.stencilRef.ps->dsState, stencilRef);
2767 break;
2769 memcpy(blendConstants, cmd.args.blendConstants.c, 4 * sizeof(float));
2770 context->OMSetBlendState(cmd.args.blendConstants.ps->blendState, blendConstants, 0xffffffff);
2771 break;
2773 if (cmd.args.draw.ps) {
2774 if (cmd.args.draw.instanceCount == 1)
2776 else
2777 context->DrawInstanced(cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
2779 } else {
2780 qWarning("No graphics pipeline active for draw; ignored");
2781 }
2782 break;
2784 if (cmd.args.drawIndexed.ps) {
2785 if (cmd.args.drawIndexed.instanceCount == 1)
2788 else
2789 context->DrawIndexedInstanced(cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
2792 } else {
2793 qWarning("No graphics pipeline active for drawIndexed; ignored");
2794 }
2795 break;
2797 context->UpdateSubresource(cmd.args.updateSubRes.dst, cmd.args.updateSubRes.dstSubRes,
2798 cmd.args.updateSubRes.hasDstBox ? &cmd.args.updateSubRes.dstBox : nullptr,
2800 break;
2802 context->CopySubresourceRegion(cmd.args.copySubRes.dst, cmd.args.copySubRes.dstSubRes,
2805 cmd.args.copySubRes.hasSrcBox ? &cmd.args.copySubRes.srcBox : nullptr);
2806 break;
2808 context->ResolveSubresource(cmd.args.resolveSubRes.dst, cmd.args.resolveSubRes.dstSubRes,
2811 break;
2813 context->GenerateMips(cmd.args.genMip.srv);
2814 break;
2816 annotations->BeginEvent(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16()));
2817 break;
2819 annotations->EndEvent();
2820 break;
2822 annotations->SetMarker(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16()));
2823 break;
2825 context->CSSetShader(cmd.args.bindComputePipeline.ps->cs.shader, nullptr, 0);
2826 break;
2828 context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z);
2829 break;
2830 default:
2831 break;
2832 }
2833 }
2834}
2835
2837 : QRhiBuffer(rhi, type, usage, size)
2838{
2839}
2840
2842{
2843 destroy();
2844}
2845
2847{
2848 if (!buffer)
2849 return;
2850
2851 buffer->Release();
2852 buffer = nullptr;
2853
2854 delete[] dynBuf;
2855 dynBuf = nullptr;
2856
2857 for (auto it = uavs.begin(), end = uavs.end(); it != end; ++it)
2858 it.value()->Release();
2859 uavs.clear();
2860
2862 if (rhiD)
2863 rhiD->unregisterResource(this);
2864}
2865
2866static inline uint toD3DBufferUsage(QRhiBuffer::UsageFlags usage)
2867{
2868 int u = 0;
2869 if (usage.testFlag(QRhiBuffer::VertexBuffer))
2870 u |= D3D11_BIND_VERTEX_BUFFER;
2871 if (usage.testFlag(QRhiBuffer::IndexBuffer))
2872 u |= D3D11_BIND_INDEX_BUFFER;
2873 if (usage.testFlag(QRhiBuffer::UniformBuffer))
2874 u |= D3D11_BIND_CONSTANT_BUFFER;
2875 if (usage.testFlag(QRhiBuffer::StorageBuffer))
2876 u |= D3D11_BIND_UNORDERED_ACCESS;
2877 return uint(u);
2878}
2879
2881{
2882 if (buffer)
2883 destroy();
2884
2885 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
2886 qWarning("UniformBuffer must always be combined with Dynamic on D3D11");
2887 return false;
2888 }
2889
2890 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
2891 qWarning("StorageBuffer cannot be combined with Dynamic");
2892 return false;
2893 }
2894
2895 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
2896 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
2897
2898 D3D11_BUFFER_DESC desc = {};
2899 desc.ByteWidth = roundedSize;
2900 desc.Usage = m_type == Dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
2901 desc.BindFlags = toD3DBufferUsage(m_usage);
2902 desc.CPUAccessFlags = m_type == Dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
2903 desc.MiscFlags = m_usage.testFlag(QRhiBuffer::StorageBuffer) ? D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS : 0;
2904
2906 HRESULT hr = rhiD->dev->CreateBuffer(&desc, nullptr, &buffer);
2907 if (FAILED(hr)) {
2908 qWarning("Failed to create buffer: %s",
2909 qPrintable(QSystemError::windowsComString(hr)));
2910 return false;
2911 }
2912
2913 if (m_type == Dynamic) {
2914 dynBuf = new char[nonZeroSize];
2916 }
2917
2918 if (!m_objectName.isEmpty())
2919 buffer->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
2920
2921 generation += 1;
2922 rhiD->registerResource(this);
2923 return true;
2924}
2925
2927{
2928 if (m_type == Dynamic) {
2930 rhiD->executeBufferHostWrites(this);
2931 }
2932 return { { &buffer }, 1 };
2933}
2934
2936{
2937 // Shortcut the entire buffer update mechanism and allow the client to do
2938 // the host writes directly to the buffer. This will lead to unexpected
2939 // results when combined with QRhiResourceUpdateBatch-based updates for the
2940 // buffer, since dynBuf is left untouched and out of sync, but provides a
2941 // fast path for dynamic buffers that have all their content changed in
2942 // every frame.
2944 D3D11_MAPPED_SUBRESOURCE mp;
2946 HRESULT hr = rhiD->context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
2947 if (FAILED(hr)) {
2948 qWarning("Failed to map buffer: %s",
2949 qPrintable(QSystemError::windowsComString(hr)));
2950 return nullptr;
2951 }
2952 return static_cast<char *>(mp.pData);
2953}
2954
2956{
2958 rhiD->context->Unmap(buffer, 0);
2959}
2960
2962{
2963 auto it = uavs.find(offset);
2964 if (it != uavs.end())
2965 return it.value();
2966
2967 // SPIRV-Cross generated HLSL uses RWByteAddressBuffer
2968 D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
2969 desc.Format = DXGI_FORMAT_R32_TYPELESS;
2970 desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
2971 desc.Buffer.FirstElement = offset / 4u;
2972 desc.Buffer.NumElements = aligned(m_size - offset, 4u) / 4u;
2973 desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
2974
2976 ID3D11UnorderedAccessView *uav = nullptr;
2977 HRESULT hr = rhiD->dev->CreateUnorderedAccessView(buffer, &desc, &uav);
2978 if (FAILED(hr)) {
2979 qWarning("Failed to create UAV: %s",
2980 qPrintable(QSystemError::windowsComString(hr)));
2981 return nullptr;
2982 }
2983
2984 uavs[offset] = uav;
2985 return uav;
2986}
2987
2989 int sampleCount, QRhiRenderBuffer::Flags flags,
2990 QRhiTexture::Format backingFormatHint)
2991 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
2992{
2993}
2994
2996{
2997 destroy();
2998}
2999
3001{
3002 if (!tex)
3003 return;
3004
3005 if (dsv) {
3006 dsv->Release();
3007 dsv = nullptr;
3008 }
3009
3010 if (rtv) {
3011 rtv->Release();
3012 rtv = nullptr;
3013 }
3014
3015 tex->Release();
3016 tex = nullptr;
3017
3019 if (rhiD)
3020 rhiD->unregisterResource(this);
3021}
3022
3024{
3025 if (tex)
3026 destroy();
3027
3028 if (m_pixelSize.isEmpty())
3029 return false;
3030
3032 sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
3033
3034 D3D11_TEXTURE2D_DESC desc = {};
3035 desc.Width = UINT(m_pixelSize.width());
3036 desc.Height = UINT(m_pixelSize.height());
3037 desc.MipLevels = 1;
3038 desc.ArraySize = 1;
3039 desc.SampleDesc = sampleDesc;
3040 desc.Usage = D3D11_USAGE_DEFAULT;
3041
3042 if (m_type == Color) {
3043 dxgiFormat = m_backingFormatHint == QRhiTexture::UnknownFormat ? DXGI_FORMAT_R8G8B8A8_UNORM
3045 desc.Format = dxgiFormat;
3046 desc.BindFlags = D3D11_BIND_RENDER_TARGET;
3047 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3048 if (FAILED(hr)) {
3049 qWarning("Failed to create color renderbuffer: %s",
3050 qPrintable(QSystemError::windowsComString(hr)));
3051 return false;
3052 }
3053 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
3054 rtvDesc.Format = dxgiFormat;
3055 rtvDesc.ViewDimension = desc.SampleDesc.Count > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS
3056 : D3D11_RTV_DIMENSION_TEXTURE2D;
3057 hr = rhiD->dev->CreateRenderTargetView(tex, &rtvDesc, &rtv);
3058 if (FAILED(hr)) {
3059 qWarning("Failed to create rtv: %s",
3060 qPrintable(QSystemError::windowsComString(hr)));
3061 return false;
3062 }
3063 } else if (m_type == DepthStencil) {
3064 dxgiFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
3065 desc.Format = dxgiFormat;
3066 desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
3067 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3068 if (FAILED(hr)) {
3069 qWarning("Failed to create depth-stencil buffer: %s",
3070 qPrintable(QSystemError::windowsComString(hr)));
3071 return false;
3072 }
3073 D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
3074 dsvDesc.Format = dxgiFormat;
3075 dsvDesc.ViewDimension = desc.SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
3076 : D3D11_DSV_DIMENSION_TEXTURE2D;
3077 hr = rhiD->dev->CreateDepthStencilView(tex, &dsvDesc, &dsv);
3078 if (FAILED(hr)) {
3079 qWarning("Failed to create dsv: %s",
3080 qPrintable(QSystemError::windowsComString(hr)));
3081 return false;
3082 }
3083 } else {
3084 return false;
3085 }
3086
3087 if (!m_objectName.isEmpty())
3088 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3089
3090 generation += 1;
3091 rhiD->registerResource(this);
3092 return true;
3093}
3094
3096{
3098 return m_backingFormatHint;
3099 else
3101}
3102
3104 int arraySize, int sampleCount, Flags flags)
3105 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
3106{
3107 for (int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
3108 perLevelViews[i] = nullptr;
3109}
3110
3112{
3113 destroy();
3114}
3115
3117{
3118 if (!tex && !tex3D && !tex1D)
3119 return;
3120
3121 if (srv) {
3122 srv->Release();
3123 srv = nullptr;
3124 }
3125
3126 for (int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
3127 if (perLevelViews[i]) {
3128 perLevelViews[i]->Release();
3129 perLevelViews[i] = nullptr;
3130 }
3131 }
3132
3133 if (owns) {
3134 if (tex)
3135 tex->Release();
3136 if (tex3D)
3137 tex3D->Release();
3138 if (tex1D)
3139 tex1D->Release();
3140 }
3141
3142 tex = nullptr;
3143 tex3D = nullptr;
3144 tex1D = nullptr;
3145
3147 if (rhiD)
3148 rhiD->unregisterResource(this);
3149}
3150
3152{
3153 switch (format) {
3155 return DXGI_FORMAT_R16_FLOAT;
3157 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3159 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3161 return DXGI_FORMAT_R32_FLOAT;
3162 default:
3163 Q_UNREACHABLE();
3164 return DXGI_FORMAT_R32_FLOAT;
3165 }
3166}
3167
3169{
3170 switch (format) {
3172 return DXGI_FORMAT_D16_UNORM;
3174 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3176 return DXGI_FORMAT_D24_UNORM_S8_UINT;
3178 return DXGI_FORMAT_D32_FLOAT;
3179 default:
3180 Q_UNREACHABLE();
3181 return DXGI_FORMAT_D32_FLOAT;
3182 }
3183}
3184
3186{
3187 if (tex || tex3D || tex1D)
3188 destroy();
3189
3190 const bool isDepth = isDepthTextureFormat(m_format);
3191 const bool isCube = m_flags.testFlag(CubeMap);
3192 const bool is3D = m_flags.testFlag(ThreeDimensional);
3193 const bool isArray = m_flags.testFlag(TextureArray);
3194 const bool hasMipMaps = m_flags.testFlag(MipMapped);
3195 const bool is1D = m_flags.testFlag(OneDimensional);
3196
3197 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
3198 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
3199
3202 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
3203 sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
3204 if (sampleDesc.Count > 1) {
3205 if (isCube) {
3206 qWarning("Cubemap texture cannot be multisample");
3207 return false;
3208 }
3209 if (is3D) {
3210 qWarning("3D texture cannot be multisample");
3211 return false;
3212 }
3213 if (hasMipMaps) {
3214 qWarning("Multisample texture cannot have mipmaps");
3215 return false;
3216 }
3217 }
3218 if (isDepth && hasMipMaps) {
3219 qWarning("Depth texture cannot have mipmaps");
3220 return false;
3221 }
3222 if (isCube && is3D) {
3223 qWarning("Texture cannot be both cube and 3D");
3224 return false;
3225 }
3226 if (isArray && is3D) {
3227 qWarning("Texture cannot be both array and 3D");
3228 return false;
3229 }
3230 if (isCube && is1D) {
3231 qWarning("Texture cannot be both cube and 1D");
3232 return false;
3233 }
3234 if (is1D && is3D) {
3235 qWarning("Texture cannot be both 1D and 3D");
3236 return false;
3237 }
3238 if (m_depth > 1 && !is3D) {
3239 qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
3240 return false;
3241 }
3242 if (m_arraySize > 0 && !isArray) {
3243 qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
3244 return false;
3245 }
3246 if (m_arraySize < 1 && isArray) {
3247 qWarning("Texture is an array but array size is %d", m_arraySize);
3248 return false;
3249 }
3250
3251 if (adjustedSize)
3252 *adjustedSize = size;
3253
3254 return true;
3255}
3256
3258{
3260 const bool isDepth = isDepthTextureFormat(m_format);
3261 const bool isCube = m_flags.testFlag(CubeMap);
3262 const bool is3D = m_flags.testFlag(ThreeDimensional);
3263 const bool isArray = m_flags.testFlag(TextureArray);
3264 const bool is1D = m_flags.testFlag(OneDimensional);
3265
3266 D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3267 srvDesc.Format = isDepth ? toD3DDepthTextureSRVFormat(m_format) : dxgiFormat;
3268 if (isCube) {
3269 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
3270 srvDesc.TextureCube.MipLevels = mipLevelCount;
3271 } else {
3272 if (is1D) {
3273 if (isArray) {
3274 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
3275 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
3276 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3277 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
3278 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
3279 } else {
3280 srvDesc.Texture1DArray.FirstArraySlice = 0;
3281 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
3282 }
3283 } else {
3284 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
3285 srvDesc.Texture1D.MipLevels = mipLevelCount;
3286 }
3287 } else if (isArray) {
3288 if (sampleDesc.Count > 1) {
3289 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
3290 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3291 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
3292 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
3293 } else {
3294 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
3295 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
3296 }
3297 } else {
3298 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
3299 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
3300 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3301 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
3302 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
3303 } else {
3304 srvDesc.Texture2DArray.FirstArraySlice = 0;
3305 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
3306 }
3307 }
3308 } else {
3309 if (sampleDesc.Count > 1) {
3310 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
3311 } else if (is3D) {
3312 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
3313 srvDesc.Texture3D.MipLevels = mipLevelCount;
3314 } else {
3315 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
3316 srvDesc.Texture2D.MipLevels = mipLevelCount;
3317 }
3318 }
3319 }
3320
3321 HRESULT hr = rhiD->dev->CreateShaderResourceView(textureResource(), &srvDesc, &srv);
3322 if (FAILED(hr)) {
3323 qWarning("Failed to create srv: %s",
3324 qPrintable(QSystemError::windowsComString(hr)));
3325 return false;
3326 }
3327
3328 generation += 1;
3329 return true;
3330}
3331
3333{
3334 QSize size;
3335 if (!prepareCreate(&size))
3336 return false;
3337
3338 const bool isDepth = isDepthTextureFormat(m_format);
3339 const bool isCube = m_flags.testFlag(CubeMap);
3340 const bool is3D = m_flags.testFlag(ThreeDimensional);
3341 const bool isArray = m_flags.testFlag(TextureArray);
3342 const bool is1D = m_flags.testFlag(OneDimensional);
3343
3344 uint bindFlags = D3D11_BIND_SHADER_RESOURCE;
3345 uint miscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
3346 if (m_flags.testFlag(RenderTarget)) {
3347 if (isDepth)
3348 bindFlags |= D3D11_BIND_DEPTH_STENCIL;
3349 else
3350 bindFlags |= D3D11_BIND_RENDER_TARGET;
3351 }
3352 if (m_flags.testFlag(UsedWithGenerateMips)) {
3353 if (isDepth) {
3354 qWarning("Depth texture cannot have mipmaps generated");
3355 return false;
3356 }
3357 bindFlags |= D3D11_BIND_RENDER_TARGET;
3358 miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS;
3359 }
3360 if (m_flags.testFlag(UsedWithLoadStore))
3361 bindFlags |= D3D11_BIND_UNORDERED_ACCESS;
3362
3364 if (is1D) {
3365 D3D11_TEXTURE1D_DESC desc = {};
3366 desc.Width = UINT(size.width());
3367 desc.MipLevels = mipLevelCount;
3368 desc.ArraySize = isArray ? UINT(qMax(0, m_arraySize)) : 1;
3369 desc.Format = dxgiFormat;
3370 desc.Usage = D3D11_USAGE_DEFAULT;
3371 desc.BindFlags = bindFlags;
3372 desc.MiscFlags = miscFlags;
3373
3374 HRESULT hr = rhiD->dev->CreateTexture1D(&desc, nullptr, &tex1D);
3375 if (FAILED(hr)) {
3376 qWarning("Failed to create 1D texture: %s",
3377 qPrintable(QSystemError::windowsComString(hr)));
3378 return false;
3379 }
3380 if (!m_objectName.isEmpty())
3381 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()),
3383 } else if (!is3D) {
3384 D3D11_TEXTURE2D_DESC desc = {};
3385 desc.Width = UINT(size.width());
3386 desc.Height = UINT(size.height());
3387 desc.MipLevels = mipLevelCount;
3388 desc.ArraySize = isCube ? 6 : (isArray ? UINT(qMax(0, m_arraySize)) : 1);
3389 desc.Format = dxgiFormat;
3390 desc.SampleDesc = sampleDesc;
3391 desc.Usage = D3D11_USAGE_DEFAULT;
3392 desc.BindFlags = bindFlags;
3393 desc.MiscFlags = miscFlags;
3394
3395 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3396 if (FAILED(hr)) {
3397 qWarning("Failed to create 2D texture: %s",
3398 qPrintable(QSystemError::windowsComString(hr)));
3399 return false;
3400 }
3401 if (!m_objectName.isEmpty())
3402 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3403 } else {
3404 D3D11_TEXTURE3D_DESC desc = {};
3405 desc.Width = UINT(size.width());
3406 desc.Height = UINT(size.height());
3407 desc.Depth = UINT(qMax(1, m_depth));
3408 desc.MipLevels = mipLevelCount;
3409 desc.Format = dxgiFormat;
3410 desc.Usage = D3D11_USAGE_DEFAULT;
3411 desc.BindFlags = bindFlags;
3412 desc.MiscFlags = miscFlags;
3413
3414 HRESULT hr = rhiD->dev->CreateTexture3D(&desc, nullptr, &tex3D);
3415 if (FAILED(hr)) {
3416 qWarning("Failed to create 3D texture: %s",
3417 qPrintable(QSystemError::windowsComString(hr)));
3418 return false;
3419 }
3420 if (!m_objectName.isEmpty())
3421 tex3D->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3422 }
3423
3424 if (!finishCreate())
3425 return false;
3426
3427 owns = true;
3428 rhiD->registerResource(this);
3429 return true;
3430}
3431
3433{
3434 if (!src.object)
3435 return false;
3436
3437 if (!prepareCreate())
3438 return false;
3439
3440 if (m_flags.testFlag(ThreeDimensional))
3441 tex3D = reinterpret_cast<ID3D11Texture3D *>(src.object);
3442 else if (m_flags.testFlags(OneDimensional))
3443 tex1D = reinterpret_cast<ID3D11Texture1D *>(src.object);
3444 else
3445 tex = reinterpret_cast<ID3D11Texture2D *>(src.object);
3446
3447 if (!finishCreate())
3448 return false;
3449
3450 owns = false;
3452 rhiD->registerResource(this);
3453 return true;
3454}
3455
3457{
3458 return { quint64(textureResource()), 0 };
3459}
3460
3462{
3463 if (perLevelViews[level])
3464 return perLevelViews[level];
3465
3466 const bool isCube = m_flags.testFlag(CubeMap);
3467 const bool isArray = m_flags.testFlag(TextureArray);
3468 const bool is3D = m_flags.testFlag(ThreeDimensional);
3469 D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
3470 desc.Format = dxgiFormat;
3471 if (isCube) {
3472 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
3473 desc.Texture2DArray.MipSlice = UINT(level);
3474 desc.Texture2DArray.FirstArraySlice = 0;
3475 desc.Texture2DArray.ArraySize = 6;
3476 } else if (isArray) {
3477 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
3478 desc.Texture2DArray.MipSlice = UINT(level);
3479 desc.Texture2DArray.FirstArraySlice = 0;
3480 desc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
3481 } else if (is3D) {
3482 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
3483 desc.Texture3D.MipSlice = UINT(level);
3484 } else {
3485 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
3486 desc.Texture2D.MipSlice = UINT(level);
3487 }
3488
3490 ID3D11UnorderedAccessView *uav = nullptr;
3491 HRESULT hr = rhiD->dev->CreateUnorderedAccessView(textureResource(), &desc, &uav);
3492 if (FAILED(hr)) {
3493 qWarning("Failed to create UAV: %s",
3494 qPrintable(QSystemError::windowsComString(hr)));
3495 return nullptr;
3496 }
3497
3498 perLevelViews[level] = uav;
3499 return uav;
3500}
3501
3504 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
3505{
3506}
3507
3509{
3510 destroy();
3511}
3512
3514{
3515 if (!samplerState)
3516 return;
3517
3518 samplerState->Release();
3519 samplerState = nullptr;
3520
3522 if (rhiD)
3523 rhiD->unregisterResource(this);
3524}
3525
3526static inline D3D11_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
3527{
3528 if (minFilter == QRhiSampler::Nearest) {
3529 if (magFilter == QRhiSampler::Nearest) {
3530 if (mipFilter == QRhiSampler::Linear)
3531 return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
3532 else
3533 return D3D11_FILTER_MIN_MAG_MIP_POINT;
3534 } else {
3535 if (mipFilter == QRhiSampler::Linear)
3536 return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
3537 else
3538 return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
3539 }
3540 } else {
3541 if (magFilter == QRhiSampler::Nearest) {
3542 if (mipFilter == QRhiSampler::Linear)
3543 return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
3544 else
3545 return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
3546 } else {
3547 if (mipFilter == QRhiSampler::Linear)
3548 return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
3549 else
3550 return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3551 }
3552 }
3553
3554 Q_UNREACHABLE();
3555 return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
3556}
3557
3558static inline D3D11_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
3559{
3560 switch (m) {
3562 return D3D11_TEXTURE_ADDRESS_WRAP;
3564 return D3D11_TEXTURE_ADDRESS_CLAMP;
3566 return D3D11_TEXTURE_ADDRESS_MIRROR;
3567 default:
3568 Q_UNREACHABLE();
3569 return D3D11_TEXTURE_ADDRESS_CLAMP;
3570 }
3571}
3572
3573static inline D3D11_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
3574{
3575 switch (op) {
3576 case QRhiSampler::Never:
3577 return D3D11_COMPARISON_NEVER;
3578 case QRhiSampler::Less:
3579 return D3D11_COMPARISON_LESS;
3580 case QRhiSampler::Equal:
3581 return D3D11_COMPARISON_EQUAL;
3583 return D3D11_COMPARISON_LESS_EQUAL;
3585 return D3D11_COMPARISON_GREATER;
3587 return D3D11_COMPARISON_NOT_EQUAL;
3589 return D3D11_COMPARISON_GREATER_EQUAL;
3591 return D3D11_COMPARISON_ALWAYS;
3592 default:
3593 Q_UNREACHABLE();
3594 return D3D11_COMPARISON_NEVER;
3595 }
3596}
3597
3599{
3600 if (samplerState)
3601 destroy();
3602
3603 D3D11_SAMPLER_DESC desc = {};
3605 if (m_compareOp != Never)
3606 desc.Filter = D3D11_FILTER(desc.Filter | 0x80);
3607 desc.AddressU = toD3DAddressMode(m_addressU);
3608 desc.AddressV = toD3DAddressMode(m_addressV);
3609 desc.AddressW = toD3DAddressMode(m_addressW);
3610 desc.MaxAnisotropy = 1.0f;
3612 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 1000.0f;
3613
3615 HRESULT hr = rhiD->dev->CreateSamplerState(&desc, &samplerState);
3616 if (FAILED(hr)) {
3617 qWarning("Failed to create sampler state: %s",
3618 qPrintable(QSystemError::windowsComString(hr)));
3619 return false;
3620 }
3621
3622 generation += 1;
3623 rhiD->registerResource(this);
3624 return true;
3625}
3626
3627// dummy, no Vulkan-style RenderPass+Framebuffer concept here
3630{
3631}
3632
3634{
3635 destroy();
3636}
3637
3639{
3641 if (rhiD)
3642 rhiD->unregisterResource(this);
3643}
3644
3646{
3647 Q_UNUSED(other);
3648 return true;
3649}
3650
3652{
3655 rhiD->registerResource(rpD, false);
3656 return rpD;
3657}
3658
3660{
3661 return {};
3662}
3663
3665 : QRhiSwapChainRenderTarget(rhi, swapchain),
3666 d(rhi)
3667{
3668}
3669
3671{
3672 destroy();
3673}
3674
3676{
3677 // nothing to do here
3678}
3679
3681{
3682 return d.pixelSize;
3683}
3684
3686{
3687 return d.dpr;
3688}
3689
3691{
3692 return d.sampleCount;
3693}
3694
3697 Flags flags)
3699 d(rhi)
3700{
3702 ownsRtv[i] = false;
3703 rtv[i] = nullptr;
3704 }
3705}
3706
3708{
3709 destroy();
3710}
3711
3713{
3714 if (!rtv[0] && !dsv)
3715 return;
3716
3717 if (dsv) {
3718 if (ownsDsv)
3719 dsv->Release();
3720 dsv = nullptr;
3721 }
3722
3724 if (rtv[i]) {
3725 if (ownsRtv[i])
3726 rtv[i]->Release();
3727 rtv[i] = nullptr;
3728 }
3729 }
3730
3732 if (rhiD)
3733 rhiD->unregisterResource(this);
3734}
3735
3737{
3740 rhiD->registerResource(rpD, false);
3741 return rpD;
3742}
3743
3745{
3746 if (rtv[0] || dsv)
3747 destroy();
3748
3751 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
3752
3754
3755 d.colorAttCount = 0;
3756 int attIndex = 0;
3757 for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
3758 d.colorAttCount += 1;
3759 const QRhiColorAttachment &colorAtt(*it);
3760 QRhiTexture *texture = colorAtt.texture();
3761 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
3762 Q_ASSERT(texture || rb);
3763 if (texture) {
3765 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
3766 rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
3767 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
3768 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
3769 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
3770 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
3771 rtvDesc.Texture2DArray.ArraySize = 1;
3772 } else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
3773 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
3774 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY;
3775 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
3776 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
3777 rtvDesc.Texture1DArray.ArraySize = 1;
3778 } else {
3779 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D;
3780 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
3781 }
3782 } else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
3783 if (texD->sampleDesc.Count > 1) {
3784 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
3785 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
3786 rtvDesc.Texture2DMSArray.ArraySize = 1;
3787 } else {
3788 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
3789 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
3790 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
3791 rtvDesc.Texture2DArray.ArraySize = 1;
3792 }
3793 } else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
3794 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
3795 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
3796 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
3797 rtvDesc.Texture3D.WSize = 1;
3798 } else {
3799 if (texD->sampleDesc.Count > 1) {
3800 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
3801 } else {
3802 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
3803 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
3804 }
3805 }
3806 HRESULT hr = rhiD->dev->CreateRenderTargetView(texD->textureResource(), &rtvDesc, &rtv[attIndex]);
3807 if (FAILED(hr)) {
3808 qWarning("Failed to create rtv: %s",
3809 qPrintable(QSystemError::windowsComString(hr)));
3810 return false;
3811 }
3812 ownsRtv[attIndex] = true;
3813 if (attIndex == 0) {
3814 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
3815 d.sampleCount = int(texD->sampleDesc.Count);
3816 }
3817 } else if (rb) {
3819 ownsRtv[attIndex] = false;
3820 rtv[attIndex] = rbD->rtv;
3821 if (attIndex == 0) {
3822 d.pixelSize = rbD->pixelSize();
3823 d.sampleCount = int(rbD->sampleDesc.Count);
3824 }
3825 }
3826 }
3827 d.dpr = 1;
3828
3829 if (hasDepthStencil) {
3830 if (m_desc.depthTexture()) {
3831 ownsDsv = true;
3833 D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
3834 dsvDesc.Format = toD3DDepthTextureDSVFormat(depthTexD->format());
3835 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
3836 : D3D11_DSV_DIMENSION_TEXTURE2D;
3837 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
3838 if (depthTexD->sampleDesc.Count > 1) {
3839 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
3840 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
3841 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
3842 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
3843 } else {
3844 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
3845 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
3846 }
3847 } else {
3848 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
3849 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
3850 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
3851 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
3852 } else {
3853 dsvDesc.Texture2DArray.FirstArraySlice = 0;
3854 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
3855 }
3856 }
3857 }
3858 HRESULT hr = rhiD->dev->CreateDepthStencilView(depthTexD->tex, &dsvDesc, &dsv);
3859 if (FAILED(hr)) {
3860 qWarning("Failed to create dsv: %s",
3861 qPrintable(QSystemError::windowsComString(hr)));
3862 return false;
3863 }
3864 if (d.colorAttCount == 0) {
3865 d.pixelSize = depthTexD->pixelSize();
3866 d.sampleCount = int(depthTexD->sampleDesc.Count);
3867 }
3868 } else {
3869 ownsDsv = false;
3871 dsv = depthRbD->dsv;
3872 if (d.colorAttCount == 0) {
3874 d.sampleCount = int(depthRbD->sampleDesc.Count);
3875 }
3876 }
3877 d.dsAttCount = 1;
3878 } else {
3879 d.dsAttCount = 0;
3880 }
3881
3883 d.rtv[i] = i < d.colorAttCount ? rtv[i] : nullptr;
3884
3885 d.dsv = dsv;
3887
3888 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D11Texture, QD3D11RenderBuffer>(m_desc, &d.currentResIdList);
3889
3890 rhiD->registerResource(this);
3891 return true;
3892}
3893
3895{
3896 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(m_desc, d.currentResIdList))
3897 const_cast<QD3D11TextureRenderTarget *>(this)->create();
3898
3899 return d.pixelSize;
3900}
3901
3903{
3904 return d.dpr;
3905}
3906
3908{
3909 return d.sampleCount;
3910}
3911
3914{
3915}
3916
3918{
3919 destroy();
3920}
3921
3923{
3925 boundResourceData.clear();
3926
3928 if (rhiD)
3929 rhiD->unregisterResource(this);
3930}
3931
3933{
3934 if (!sortedBindings.isEmpty())
3935 destroy();
3936
3938 if (!rhiD->sanityCheckShaderResourceBindings(this))
3939 return false;
3940
3941 rhiD->updateLayoutDesc(this);
3942
3943 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
3945
3947
3949 memset(&bd, 0, sizeof(BoundResourceData));
3950
3951 hasDynamicOffset = false;
3955 hasDynamicOffset = true;
3956 break;
3957 }
3958 }
3959
3960 generation += 1;
3961 rhiD->registerResource(this, false);
3962 return true;
3963}
3964
3966{
3968 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
3969 if (!flags.testFlag(BindingsAreSorted))
3971
3974 memset(&bd, 0, sizeof(BoundResourceData));
3975
3976 generation += 1;
3977}
3978
3981{
3982}
3983
3985{
3986 destroy();
3987}
3988
3989template<typename T>
3991{
3992 if (s.shader) {
3993 s.shader->Release();
3994 s.shader = nullptr;
3995 }
3996 s.nativeResourceBindingMap.clear();
3997}
3998
4000{
4001 if (!dsState)
4002 return;
4003
4004 dsState->Release();
4005 dsState = nullptr;
4006
4007 if (blendState) {
4008 blendState->Release();
4009 blendState = nullptr;
4010 }
4011
4012 if (inputLayout) {
4013 inputLayout->Release();
4014 inputLayout = nullptr;
4015 }
4016
4017 if (rastState) {
4018 rastState->Release();
4019 rastState = nullptr;
4020 }
4021
4027
4029 if (rhiD)
4030 rhiD->unregisterResource(this);
4031}
4032
4033static inline D3D11_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
4034{
4035 switch (c) {
4037 return D3D11_CULL_NONE;
4039 return D3D11_CULL_FRONT;
4041 return D3D11_CULL_BACK;
4042 default:
4043 Q_UNREACHABLE();
4044 return D3D11_CULL_NONE;
4045 }
4046}
4047
4049{
4050 switch (mode) {
4052 return D3D11_FILL_SOLID;
4054 return D3D11_FILL_WIREFRAME;
4055 default:
4056 Q_UNREACHABLE();
4057 return D3D11_FILL_SOLID;
4058 }
4059}
4060
4061static inline D3D11_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
4062{
4063 switch (op) {
4065 return D3D11_COMPARISON_NEVER;
4067 return D3D11_COMPARISON_LESS;
4069 return D3D11_COMPARISON_EQUAL;
4071 return D3D11_COMPARISON_LESS_EQUAL;
4073 return D3D11_COMPARISON_GREATER;
4075 return D3D11_COMPARISON_NOT_EQUAL;
4077 return D3D11_COMPARISON_GREATER_EQUAL;
4079 return D3D11_COMPARISON_ALWAYS;
4080 default:
4081 Q_UNREACHABLE();
4082 return D3D11_COMPARISON_ALWAYS;
4083 }
4084}
4085
4086static inline D3D11_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
4087{
4088 switch (op) {
4090 return D3D11_STENCIL_OP_ZERO;
4092 return D3D11_STENCIL_OP_KEEP;
4094 return D3D11_STENCIL_OP_REPLACE;
4096 return D3D11_STENCIL_OP_INCR_SAT;
4098 return D3D11_STENCIL_OP_DECR_SAT;
4100 return D3D11_STENCIL_OP_INVERT;
4102 return D3D11_STENCIL_OP_INCR;
4104 return D3D11_STENCIL_OP_DECR;
4105 default:
4106 Q_UNREACHABLE();
4107 return D3D11_STENCIL_OP_KEEP;
4108 }
4109}
4110
4112{
4113 switch (format) {
4115 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4117 return DXGI_FORMAT_R32G32B32_FLOAT;
4119 return DXGI_FORMAT_R32G32_FLOAT;
4121 return DXGI_FORMAT_R32_FLOAT;
4123 return DXGI_FORMAT_R8G8B8A8_UNORM;
4125 return DXGI_FORMAT_R8G8_UNORM;
4127 return DXGI_FORMAT_R8_UNORM;
4129 return DXGI_FORMAT_R32G32B32A32_UINT;
4131 return DXGI_FORMAT_R32G32B32_UINT;
4133 return DXGI_FORMAT_R32G32_UINT;
4135 return DXGI_FORMAT_R32_UINT;
4137 return DXGI_FORMAT_R32G32B32A32_SINT;
4139 return DXGI_FORMAT_R32G32B32_SINT;
4141 return DXGI_FORMAT_R32G32_SINT;
4143 return DXGI_FORMAT_R32_SINT;
4145 // Note: D3D does not support half3. Pass through half3 as half4.
4147 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4149 return DXGI_FORMAT_R16G16_FLOAT;
4151 return DXGI_FORMAT_R16_FLOAT;
4152 default:
4153 Q_UNREACHABLE();
4154 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4155 }
4156}
4157
4158static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t, int patchControlPointCount)
4159{
4160 switch (t) {
4162 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
4164 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
4166 return D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
4168 return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP;
4170 return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
4172 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
4173 return D3D11_PRIMITIVE_TOPOLOGY(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
4174 default:
4175 Q_UNREACHABLE();
4176 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
4177 }
4178}
4179
4180static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
4181{
4182 UINT8 f = 0;
4183 if (c.testFlag(QRhiGraphicsPipeline::R))
4184 f |= D3D11_COLOR_WRITE_ENABLE_RED;
4185 if (c.testFlag(QRhiGraphicsPipeline::G))
4186 f |= D3D11_COLOR_WRITE_ENABLE_GREEN;
4187 if (c.testFlag(QRhiGraphicsPipeline::B))
4188 f |= D3D11_COLOR_WRITE_ENABLE_BLUE;
4189 if (c.testFlag(QRhiGraphicsPipeline::A))
4190 f |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
4191 return f;
4192}
4193
4195{
4196 // SrcBlendAlpha and DstBlendAlpha do not accept *_COLOR. With other APIs
4197 // this is handled internally (so that e.g. VK_BLEND_FACTOR_SRC_COLOR is
4198 // accepted and is in effect equivalent to VK_BLEND_FACTOR_SRC_ALPHA when
4199 // set as an alpha src/dest factor), but for D3D we have to take care of it
4200 // ourselves. Hence the rgb argument.
4201
4202 switch (f) {
4204 return D3D11_BLEND_ZERO;
4206 return D3D11_BLEND_ONE;
4208 return rgb ? D3D11_BLEND_SRC_COLOR : D3D11_BLEND_SRC_ALPHA;
4210 return rgb ? D3D11_BLEND_INV_SRC_COLOR : D3D11_BLEND_INV_SRC_ALPHA;
4212 return rgb ? D3D11_BLEND_DEST_COLOR : D3D11_BLEND_DEST_ALPHA;
4214 return rgb ? D3D11_BLEND_INV_DEST_COLOR : D3D11_BLEND_INV_DEST_ALPHA;
4216 return D3D11_BLEND_SRC_ALPHA;
4218 return D3D11_BLEND_INV_SRC_ALPHA;
4220 return D3D11_BLEND_DEST_ALPHA;
4222 return D3D11_BLEND_INV_DEST_ALPHA;
4225 return D3D11_BLEND_BLEND_FACTOR;
4228 return D3D11_BLEND_INV_BLEND_FACTOR;
4230 return D3D11_BLEND_SRC_ALPHA_SAT;
4232 return rgb ? D3D11_BLEND_SRC1_COLOR : D3D11_BLEND_SRC1_ALPHA;
4234 return rgb ? D3D11_BLEND_INV_SRC1_COLOR : D3D11_BLEND_INV_SRC1_ALPHA;
4236 return D3D11_BLEND_SRC1_ALPHA;
4238 return D3D11_BLEND_INV_SRC1_ALPHA;
4239 default:
4240 Q_UNREACHABLE();
4241 return D3D11_BLEND_ZERO;
4242 }
4243}
4244
4245static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
4246{
4247 switch (op) {
4249 return D3D11_BLEND_OP_ADD;
4251 return D3D11_BLEND_OP_SUBTRACT;
4253 return D3D11_BLEND_OP_REV_SUBTRACT;
4255 return D3D11_BLEND_OP_MIN;
4257 return D3D11_BLEND_OP_MAX;
4258 default:
4259 Q_UNREACHABLE();
4260 return D3D11_BLEND_OP_ADD;
4261 }
4262}
4263
4265{
4266 // taken from the GL backend, use the same mechanism to get a key
4268 keyBuilder.addData(source);
4269 return keyBuilder.result().toHex();
4270}
4271
4273 QString *error, QShaderKey *usedShaderKey)
4274{
4275 QShaderKey key = { QShader::DxbcShader, 50, shaderVariant };
4276 QShaderCode dxbc = shader.shader(key);
4277 if (!dxbc.shader().isEmpty()) {
4278 if (usedShaderKey)
4279 *usedShaderKey = key;
4280 return dxbc.shader();
4281 }
4282
4283 key = { QShader::HlslShader, 50, shaderVariant };
4284 QShaderCode hlslSource = shader.shader(key);
4285 if (hlslSource.shader().isEmpty()) {
4286 qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader;
4287 return QByteArray();
4288 }
4289
4290 if (usedShaderKey)
4291 *usedShaderKey = key;
4292
4293 const char *target;
4294 switch (shader.stage()) {
4296 target = "vs_5_0";
4297 break;
4299 target = "hs_5_0";
4300 break;
4302 target = "ds_5_0";
4303 break;
4305 target = "gs_5_0";
4306 break;
4308 target = "ps_5_0";
4309 break;
4311 target = "cs_5_0";
4312 break;
4313 default:
4314 Q_UNREACHABLE();
4315 return QByteArray();
4316 }
4317
4318 BytecodeCacheKey cacheKey;
4320 cacheKey.sourceHash = sourceHash(hlslSource.shader());
4321 cacheKey.target = target;
4322 cacheKey.entryPoint = hlslSource.entryPoint();
4323 cacheKey.compileFlags = flags;
4324 auto cacheIt = m_bytecodeCache.constFind(cacheKey);
4325 if (cacheIt != m_bytecodeCache.constEnd())
4326 return cacheIt.value();
4327 }
4328
4329 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
4330 if (d3dCompile == nullptr) {
4331 qWarning("Unable to resolve function D3DCompile()");
4332 return QByteArray();
4333 }
4334
4335 ID3DBlob *bytecode = nullptr;
4336 ID3DBlob *errors = nullptr;
4337 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
4338 nullptr, nullptr, nullptr,
4339 hlslSource.entryPoint().constData(), target, flags, 0, &bytecode, &errors);
4340 if (FAILED(hr) || !bytecode) {
4341 qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
4342 if (errors) {
4343 *error = QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()),
4344 int(errors->GetBufferSize()));
4345 errors->Release();
4346 }
4347 return QByteArray();
4348 }
4349
4351 result.resize(int(bytecode->GetBufferSize()));
4352 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
4353 bytecode->Release();
4354
4356 m_bytecodeCache.insert(cacheKey, result);
4357
4358 return result;
4359}
4360
4362{
4363 if (dsState)
4364 destroy();
4365
4367 rhiD->pipelineCreationStart();
4368 if (!rhiD->sanityCheckGraphicsPipeline(this))
4369 return false;
4370
4371 D3D11_RASTERIZER_DESC rastDesc = {};
4372 rastDesc.FillMode = toD3DFillMode(m_polygonMode);
4373 rastDesc.CullMode = toD3DCullMode(m_cullMode);
4374 rastDesc.FrontCounterClockwise = m_frontFace == CCW;
4375 rastDesc.DepthBias = m_depthBias;
4376 rastDesc.SlopeScaledDepthBias = m_slopeScaledDepthBias;
4377 rastDesc.DepthClipEnable = true;
4378 rastDesc.ScissorEnable = m_flags.testFlag(UsesScissor);
4379 rastDesc.MultisampleEnable = rhiD->effectiveSampleCount(m_sampleCount).Count > 1;
4380 HRESULT hr = rhiD->dev->CreateRasterizerState(&rastDesc, &rastState);
4381 if (FAILED(hr)) {
4382 qWarning("Failed to create rasterizer state: %s",
4383 qPrintable(QSystemError::windowsComString(hr)));
4384 return false;
4385 }
4386
4387 D3D11_DEPTH_STENCIL_DESC dsDesc = {};
4388 dsDesc.DepthEnable = m_depthTest;
4389 dsDesc.DepthWriteMask = m_depthWrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
4390 dsDesc.DepthFunc = toD3DCompareOp(m_depthOp);
4391 dsDesc.StencilEnable = m_stencilTest;
4392 if (m_stencilTest) {
4393 dsDesc.StencilReadMask = UINT8(m_stencilReadMask);
4394 dsDesc.StencilWriteMask = UINT8(m_stencilWriteMask);
4395 dsDesc.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
4396 dsDesc.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
4397 dsDesc.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
4398 dsDesc.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
4399 dsDesc.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
4400 dsDesc.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
4401 dsDesc.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
4402 dsDesc.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
4403 }
4404 hr = rhiD->dev->CreateDepthStencilState(&dsDesc, &dsState);
4405 if (FAILED(hr)) {
4406 qWarning("Failed to create depth-stencil state: %s",
4407 qPrintable(QSystemError::windowsComString(hr)));
4408 return false;
4409 }
4410
4411 D3D11_BLEND_DESC blendDesc = {};
4412 blendDesc.IndependentBlendEnable = m_targetBlends.count() > 1;
4413 for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
4415 D3D11_RENDER_TARGET_BLEND_DESC blend = {};
4416 blend.BlendEnable = b.enable;
4417 blend.SrcBlend = toD3DBlendFactor(b.srcColor, true);
4418 blend.DestBlend = toD3DBlendFactor(b.dstColor, true);
4419 blend.BlendOp = toD3DBlendOp(b.opColor);
4420 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha, false);
4421 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha, false);
4422 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
4423 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
4424 blendDesc.RenderTarget[i] = blend;
4425 }
4426 if (m_targetBlends.isEmpty()) {
4427 D3D11_RENDER_TARGET_BLEND_DESC blend = {};
4428 blend.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
4429 blendDesc.RenderTarget[0] = blend;
4430 }
4431 hr = rhiD->dev->CreateBlendState(&blendDesc, &blendState);
4432 if (FAILED(hr)) {
4433 qWarning("Failed to create blend state: %s",
4434 qPrintable(QSystemError::windowsComString(hr)));
4435 return false;
4436 }
4437
4438 QByteArray vsByteCode;
4439 for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
4440 auto cacheIt = rhiD->m_shaderCache.constFind(shaderStage);
4441 if (cacheIt != rhiD->m_shaderCache.constEnd()) {
4442 switch (shaderStage.type()) {
4444 vs.shader = static_cast<ID3D11VertexShader *>(cacheIt->s);
4445 vs.shader->AddRef();
4446 vsByteCode = cacheIt->bytecode;
4447 vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4448 break;
4450 hs.shader = static_cast<ID3D11HullShader *>(cacheIt->s);
4451 hs.shader->AddRef();
4452 hs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4453 break;
4455 ds.shader = static_cast<ID3D11DomainShader *>(cacheIt->s);
4456 ds.shader->AddRef();
4457 ds.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4458 break;
4460 gs.shader = static_cast<ID3D11GeometryShader *>(cacheIt->s);
4461 gs.shader->AddRef();
4462 gs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4463 break;
4465 fs.shader = static_cast<ID3D11PixelShader *>(cacheIt->s);
4466 fs.shader->AddRef();
4467 fs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4468 break;
4469 default:
4470 break;
4471 }
4472 } else {
4473 QString error;
4474 QShaderKey shaderKey;
4475 UINT compileFlags = 0;
4477 compileFlags |= D3DCOMPILE_DEBUG;
4478
4479 const QByteArray bytecode = rhiD->compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), compileFlags,
4480 &error, &shaderKey);
4481 if (bytecode.isEmpty()) {
4482 qWarning("HLSL shader compilation failed: %s", qPrintable(error));
4483 return false;
4484 }
4485
4486 if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) {
4487 // Use the simplest strategy: too many cached shaders -> drop them all.
4488 rhiD->clearShaderCache();
4489 }
4490
4491 switch (shaderStage.type()) {
4493 hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader);
4494 if (FAILED(hr)) {
4495 qWarning("Failed to create vertex shader: %s",
4496 qPrintable(QSystemError::windowsComString(hr)));
4497 return false;
4498 }
4499 vsByteCode = bytecode;
4500 vs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4501 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap));
4502 vs.shader->AddRef();
4503 break;
4505 hr = rhiD->dev->CreateHullShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &hs.shader);
4506 if (FAILED(hr)) {
4507 qWarning("Failed to create hull shader: %s",
4508 qPrintable(QSystemError::windowsComString(hr)));
4509 return false;
4510 }
4511 hs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4512 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(hs.shader, bytecode, hs.nativeResourceBindingMap));
4513 hs.shader->AddRef();
4514 break;
4516 hr = rhiD->dev->CreateDomainShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &ds.shader);
4517 if (FAILED(hr)) {
4518 qWarning("Failed to create domain shader: %s",
4519 qPrintable(QSystemError::windowsComString(hr)));
4520 return false;
4521 }
4522 ds.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4523 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(ds.shader, bytecode, ds.nativeResourceBindingMap));
4524 ds.shader->AddRef();
4525 break;
4527 hr = rhiD->dev->CreateGeometryShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &gs.shader);
4528 if (FAILED(hr)) {
4529 qWarning("Failed to create geometry shader: %s",
4530 qPrintable(QSystemError::windowsComString(hr)));
4531 return false;
4532 }
4533 gs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4534 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(gs.shader, bytecode, gs.nativeResourceBindingMap));
4535 gs.shader->AddRef();
4536 break;
4538 hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader);
4539 if (FAILED(hr)) {
4540 qWarning("Failed to create pixel shader: %s",
4541 qPrintable(QSystemError::windowsComString(hr)));
4542 return false;
4543 }
4544 fs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4545 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap));
4546 fs.shader->AddRef();
4547 break;
4548 default:
4549 break;
4550 }
4551 }
4552 }
4553
4555
4556 if (!vsByteCode.isEmpty()) {
4557 QByteArrayList matrixSliceSemantics;
4560 it != itEnd; ++it)
4561 {
4562 D3D11_INPUT_ELEMENT_DESC desc = {};
4563 // The output from SPIRV-Cross uses TEXCOORD<location> as the
4564 // semantic, except for matrices that are unrolled into consecutive
4565 // vec2/3/4s attributes and need TEXCOORD<location>_ as
4566 // SemanticName and row/column index as SemanticIndex.
4567 const int matrixSlice = it->matrixSlice();
4568 if (matrixSlice < 0) {
4569 desc.SemanticName = "TEXCOORD";
4570 desc.SemanticIndex = UINT(it->location());
4571 } else {
4573 sem.resize(16);
4574 qsnprintf(sem.data(), sem.size(), "TEXCOORD%d_", it->location() - matrixSlice);
4575 matrixSliceSemantics.append(sem);
4576 desc.SemanticName = matrixSliceSemantics.last().constData();
4577 desc.SemanticIndex = UINT(matrixSlice);
4578 }
4579 desc.Format = toD3DAttributeFormat(it->format());
4580 desc.InputSlot = UINT(it->binding());
4581 desc.AlignedByteOffset = it->offset();
4582 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
4583 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
4584 desc.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
4585 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
4586 } else {
4587 desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
4588 }
4589 inputDescs.append(desc);
4590 }
4591 if (!inputDescs.isEmpty()) {
4592 hr = rhiD->dev->CreateInputLayout(inputDescs.constData(), UINT(inputDescs.count()),
4593 vsByteCode, SIZE_T(vsByteCode.size()), &inputLayout);
4594 if (FAILED(hr)) {
4595 qWarning("Failed to create input layout: %s",
4596 qPrintable(QSystemError::windowsComString(hr)));
4597 return false;
4598 }
4599 } // else leave inputLayout set to nullptr; that's valid and it avoids a debug layer warning about an input layout with 0 elements
4600 }
4601
4602 rhiD->pipelineCreationEnd();
4603 generation += 1;
4604 rhiD->registerResource(this);
4605 return true;
4606}
4607
4609 : QRhiComputePipeline(rhi)
4610{
4611}
4612
4614{
4615 destroy();
4616}
4617
4619{
4620 if (!cs.shader)
4621 return;
4622
4623 cs.shader->Release();
4624 cs.shader = nullptr;
4625 cs.nativeResourceBindingMap.clear();
4626
4628 if (rhiD)
4629 rhiD->unregisterResource(this);
4630}
4631
4633{
4634 if (cs.shader)
4635 destroy();
4636
4638 rhiD->pipelineCreationStart();
4639
4640 auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage);
4641 if (cacheIt != rhiD->m_shaderCache.constEnd()) {
4642 cs.shader = static_cast<ID3D11ComputeShader *>(cacheIt->s);
4643 cs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4644 } else {
4645 QString error;
4646 QShaderKey shaderKey;
4647 UINT compileFlags = 0;
4649 compileFlags |= D3DCOMPILE_DEBUG;
4650
4651 const QByteArray bytecode = rhiD->compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), compileFlags,
4652 &error, &shaderKey);
4653 if (bytecode.isEmpty()) {
4654 qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
4655 return false;
4656 }
4657
4658 HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader);
4659 if (FAILED(hr)) {
4660 qWarning("Failed to create compute shader: %s",
4661 qPrintable(QSystemError::windowsComString(hr)));
4662 return false;
4663 }
4664
4665 cs.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
4666
4667 if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES)
4668 rhiD->clearShaderCache();
4669
4670 rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs.shader, bytecode, cs.nativeResourceBindingMap));
4671 }
4672
4673 cs.shader->AddRef();
4674
4675 rhiD->pipelineCreationEnd();
4676 generation += 1;
4677 rhiD->registerResource(this);
4678 return true;
4679}
4680
4682 : QRhiCommandBuffer(rhi)
4683{
4684 resetState();
4685}
4686
4688{
4689 destroy();
4690}
4691
4693{
4694 // nothing to do here
4695}
4696
4697bool QD3D11Timestamps::prepare(int pairCount, QRhiD3D11 *rhiD)
4698{
4699 // Creates the query objects if not yet done, but otherwise calling this
4700 // function is expected to be a no-op.
4701
4703 D3D11_QUERY_DESC queryDesc = {};
4704 for (int i = 0; i < pairCount; ++i) {
4705 if (!disjointQuery[i]) {
4706 queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
4707 HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &disjointQuery[i]);
4708 if (FAILED(hr)) {
4709 qWarning("Failed to create timestamp disjoint query: %s",
4710 qPrintable(QSystemError::windowsComString(hr)));
4711 return false;
4712 }
4713 }
4714 queryDesc.Query = D3D11_QUERY_TIMESTAMP;
4715 for (int j = 0; j < 2; ++j) {
4716 const int idx = pairCount * i + j;
4717 if (!query[idx]) {
4718 HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &query[idx]);
4719 if (FAILED(hr)) {
4720 qWarning("Failed to create timestamp query: %s",
4721 qPrintable(QSystemError::windowsComString(hr)));
4722 return false;
4723 }
4724 }
4725 }
4726 }
4727 this->pairCount = pairCount;
4728 return true;
4729}
4730
4732{
4733 for (int i = 0; i < MAX_TIMESTAMP_PAIRS; ++i) {
4734 active[i] = false;
4735 if (disjointQuery[i]) {
4736 disjointQuery[i]->Release();
4737 disjointQuery[i] = nullptr;
4738 }
4739 for (int j = 0; j < 2; ++j) {
4740 const int idx = MAX_TIMESTAMP_PAIRS * i + j;
4741 if (query[idx]) {
4742 query[idx]->Release();
4743 query[idx] = nullptr;
4744 }
4745 }
4746 }
4747}
4748
4749bool QD3D11Timestamps::tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec)
4750{
4751 bool result = false;
4752 if (!active[idx])
4753 return result;
4754
4755 ID3D11Query *tsDisjoint = disjointQuery[idx];
4756 const int tsIdx = pairCount * idx;
4757 ID3D11Query *tsStart = query[tsIdx];
4758 ID3D11Query *tsEnd = query[tsIdx + 1];
4759 quint64 timestamps[2];
4760 D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
4761
4762 bool ok = true;
4763 ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4764 ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4765 // this above is often not ready, not even in frame_where_recorded+2,
4766 // not clear why. so make the whole thing async and do not touch the
4767 // queries until they are finally all available in frame this+2 or
4768 // this+4 or ...
4769 ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4770
4771 if (ok) {
4772 if (!dj.Disjoint && dj.Frequency) {
4773 const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
4774 *elapsedSec = elapsedMs / 1000.0;
4775 result = true;
4776 }
4777 active[idx] = false;
4778 } // else leave active set, will retry in a subsequent beginFrame or similar
4779
4780 return result;
4781}
4782
4784 : QRhiSwapChain(rhi),
4785 rt(rhi, this),
4786 cb(rhi)
4787{
4788 backBufferTex = nullptr;
4789 backBufferRtv = nullptr;
4790 for (int i = 0; i < BUFFER_COUNT; ++i) {
4791 msaaTex[i] = nullptr;
4792 msaaRtv[i] = nullptr;
4793 }
4794}
4795
4797{
4798 destroy();
4799}
4800
4802{
4803 if (backBufferRtv) {
4804 backBufferRtv->Release();
4805 backBufferRtv = nullptr;
4806 }
4807 if (backBufferTex) {
4808 backBufferTex->Release();
4809 backBufferTex = nullptr;
4810 }
4811 for (int i = 0; i < BUFFER_COUNT; ++i) {
4812 if (msaaRtv[i]) {
4813 msaaRtv[i]->Release();
4814 msaaRtv[i] = nullptr;
4815 }
4816 if (msaaTex[i]) {
4817 msaaTex[i]->Release();
4818 msaaTex[i] = nullptr;
4819 }
4820 }
4821}
4822
4824{
4825 if (!swapChain)
4826 return;
4827
4829
4831
4832 swapChain->Release();
4833 swapChain = nullptr;
4834
4835 if (dcompVisual) {
4836 dcompVisual->Release();
4837 dcompVisual = nullptr;
4838 }
4839
4840 if (dcompTarget) {
4841 dcompTarget->Release();
4842 dcompTarget = nullptr;
4843 }
4844
4846 if (rhiD)
4847 rhiD->unregisterResource(this);
4848}
4849
4851{
4852 return &cb;
4853}
4854
4856{
4857 return &rt;
4858}
4859
4861{
4863 return m_window->size() * m_window->devicePixelRatio();
4864}
4865
4866static bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result)
4867{
4868 bool ok = false;
4869 QRect wr = w->geometry();
4870 wr = QRect(wr.topLeft() * w->devicePixelRatio(), wr.size() * w->devicePixelRatio());
4871 const QPoint center = wr.center();
4872 IDXGIOutput *currentOutput = nullptr;
4873 IDXGIOutput *output = nullptr;
4874 for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; ++i) {
4875 DXGI_OUTPUT_DESC desc;
4876 output->GetDesc(&desc);
4877 const RECT r = desc.DesktopCoordinates;
4878 const QRect dr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
4879 if (dr.contains(center)) {
4880 currentOutput = output;
4881 break;
4882 } else {
4883 output->Release();
4884 }
4885 }
4886 if (currentOutput) {
4887 ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast<void **>(result)));
4888 currentOutput->Release();
4889 }
4890 return ok;
4891}
4892
4893static bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
4894{
4895 bool ok = false;
4896 IDXGIOutput6 *out6 = nullptr;
4897 if (output6ForWindow(w, adapter, &out6)) {
4898 ok = SUCCEEDED(out6->GetDesc1(result));
4899 out6->Release();
4900 }
4901 return ok;
4902}
4903
4905{
4906 if (f == SDR)
4907 return true;
4908
4909 if (!m_window) {
4910 qWarning("Attempted to call isFormatSupported() without a window set");
4911 return false;
4912 }
4913
4915 DXGI_OUTPUT_DESC1 desc1;
4916 if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) {
4917 if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
4919 }
4920
4921 return false;
4922}
4923
4925{
4927 if (m_window) {
4929 DXGI_OUTPUT_DESC1 hdrOutputDesc;
4930 if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
4931 info.isHardCodedDefaults = false;
4933 info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
4934 info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
4935 }
4936 }
4937 return info;
4938}
4939
4941{
4944 rhiD->registerResource(rpD, false);
4945 return rpD;
4946}
4947
4948bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
4949 ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const
4950{
4951 D3D11_TEXTURE2D_DESC desc = {};
4952 desc.Width = UINT(size.width());
4953 desc.Height = UINT(size.height());
4954 desc.MipLevels = 1;
4955 desc.ArraySize = 1;
4956 desc.Format = format;
4957 desc.SampleDesc = sampleDesc;
4958 desc.Usage = D3D11_USAGE_DEFAULT;
4959 desc.BindFlags = D3D11_BIND_RENDER_TARGET;
4960
4962 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, tex);
4963 if (FAILED(hr)) {
4964 qWarning("Failed to create color buffer texture: %s",
4965 qPrintable(QSystemError::windowsComString(hr)));
4966 return false;
4967 }
4968
4969 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
4970 rtvDesc.Format = format;
4971 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
4972 hr = rhiD->dev->CreateRenderTargetView(*tex, &rtvDesc, rtv);
4973 if (FAILED(hr)) {
4974 qWarning("Failed to create color buffer rtv: %s",
4975 qPrintable(QSystemError::windowsComString(hr)));
4976 (*tex)->Release();
4977 *tex = nullptr;
4978 return false;
4979 }
4980
4981 return true;
4982}
4983
4985{
4986 if (dcompDevice)
4987 return true;
4988
4989 qCDebug(QRHI_LOG_INFO, "Creating Direct Composition device (needed for semi-transparent windows)");
4991 return dcompDevice ? true : false;
4992}
4993
4994static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
4995static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
4996
4998{
4999 // Can be called multiple times due to window resizes - that is not the
5000 // same as a simple destroy+create (as with other resources). Just need to
5001 // resize the buffers then.
5002
5003 const bool needsRegistration = !window || window != m_window;
5004
5005 // except if the window actually changes
5006 if (window && window != m_window)
5007 destroy();
5008
5009 window = m_window;
5012
5013 if (pixelSize.isEmpty())
5014 return false;
5015
5016 HWND hwnd = reinterpret_cast<HWND>(window->winId());
5017 HRESULT hr;
5018
5020
5022 if (rhiD->ensureDirectCompositionDevice()) {
5023 if (!dcompTarget) {
5024 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd, true, &dcompTarget);
5025 if (FAILED(hr)) {
5026 qWarning("Failed to create Direct Compsition target for the window: %s",
5027 qPrintable(QSystemError::windowsComString(hr)));
5028 }
5029 }
5030 if (dcompTarget && !dcompVisual) {
5031 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
5032 if (FAILED(hr)) {
5033 qWarning("Failed to create DirectComposition visual: %s",
5034 qPrintable(QSystemError::windowsComString(hr)));
5035 }
5036 }
5037 }
5038 // simple consistency check
5039 if (window->requestedFormat().alphaBufferSize() <= 0)
5040 qWarning("Swapchain says surface has alpha but the window has no alphaBufferSize set. "
5041 "This may lead to problems.");
5042 }
5043
5044 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
5045 swapChainFlags = 0;
5046
5047 // A non-flip swapchain can do Present(0) as expected without
5048 // ALLOW_TEARING, and ALLOW_TEARING is not compatible with it at all so the
5049 // flag must not be set then. Whereas for flip we should use it, if
5050 // supported, to get better results for 'unthrottled' presentation.
5051 if (swapInterval == 0 && rhiD->supportsAllowTearing)
5052 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
5053
5054 if (!swapChain) {
5055 sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
5058
5059 DXGI_COLOR_SPACE_TYPE hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR
5060 DXGI_OUTPUT_DESC1 hdrOutputDesc;
5061 if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
5062 // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
5063 if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
5064 switch (m_format) {
5066 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
5067 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
5069 break;
5070 case HDR10:
5071 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
5072 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
5074 break;
5075 default:
5076 break;
5077 }
5078 } else {
5079 // This happens also when Use HDR is set to Off in the Windows
5080 // Display settings. Show a helpful warning, but continue with the
5081 // default non-HDR format.
5082 qWarning("The output associated with the window is not HDR capable "
5083 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
5084 }
5085 }
5086
5087 // We use a FLIP model swapchain which implies a buffer count of 2
5088 // (as opposed to the old DISCARD with back buffer count == 1).
5089 // This makes no difference for the rest of the stuff except that
5090 // automatic MSAA is unsupported and needs to be implemented via a
5091 // custom multisample render target and an explicit resolve.
5092
5093 DXGI_SWAP_CHAIN_DESC1 desc = {};
5094 desc.Width = UINT(pixelSize.width());
5095 desc.Height = UINT(pixelSize.height());
5096 desc.Format = colorFormat;
5097 desc.SampleDesc.Count = 1;
5098 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5099 desc.BufferCount = BUFFER_COUNT;
5100 desc.Flags = swapChainFlags;
5101 desc.Scaling = DXGI_SCALING_NONE;
5102 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
5103
5104 if (dcompVisual) {
5105 // With DirectComposition setting AlphaMode to STRAIGHT fails the
5106 // swapchain creation, whereas the result seems to be identical
5107 // with any of the other values, including IGNORE. (?)
5108 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
5109
5110 // DirectComposition has its own limitations, cannot use
5111 // SCALING_NONE. So with semi-transparency requested we are forced
5112 // to SCALING_STRETCH.
5113 desc.Scaling = DXGI_SCALING_STRETCH;
5114 }
5115
5116 IDXGIFactory2 *fac = static_cast<IDXGIFactory2 *>(rhiD->dxgiFactory);
5117 IDXGISwapChain1 *sc1;
5118
5119 if (dcompVisual)
5120 hr = fac->CreateSwapChainForComposition(rhiD->dev, &desc, nullptr, &sc1);
5121 else
5122 hr = fac->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc, nullptr, nullptr, &sc1);
5123
5124 // If failed and we tried a HDR format, then try with SDR. This
5125 // matches other backends, such as Vulkan where if the format is
5126 // not supported, the default one is used instead.
5127 if (FAILED(hr) && m_format != SDR) {
5129 desc.Format = DEFAULT_FORMAT;
5130 if (dcompVisual)
5131 hr = fac->CreateSwapChainForComposition(rhiD->dev, &desc, nullptr, &sc1);
5132 else
5133 hr = fac->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc, nullptr, nullptr, &sc1);
5134 }
5135
5136 if (SUCCEEDED(hr)) {
5137 swapChain = sc1;
5138 if (m_format != SDR) {
5139 IDXGISwapChain3 *sc3 = nullptr;
5140 if (SUCCEEDED(sc1->QueryInterface(__uuidof(IDXGISwapChain3), reinterpret_cast<void **>(&sc3)))) {
5141 hr = sc3->SetColorSpace1(hdrColorSpace);
5142 if (FAILED(hr))
5143 qWarning("Failed to set color space on swapchain: %s",
5144 qPrintable(QSystemError::windowsComString(hr)));
5145 sc3->Release();
5146 } else {
5147 qWarning("IDXGISwapChain3 not available, HDR swapchain will not work as expected");
5148 }
5149 }
5150 if (dcompVisual) {
5151 hr = dcompVisual->SetContent(sc1);
5152 if (SUCCEEDED(hr)) {
5153 hr = dcompTarget->SetRoot(dcompVisual);
5154 if (FAILED(hr)) {
5155 qWarning("Failed to associate Direct Composition visual with the target: %s",
5156 qPrintable(QSystemError::windowsComString(hr)));
5157 }
5158 } else {
5159 qWarning("Failed to set content for Direct Composition visual: %s",
5160 qPrintable(QSystemError::windowsComString(hr)));
5161 }
5162 } else {
5163 // disable Alt+Enter; not relevant when using DirectComposition
5164 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
5165 }
5166 }
5167 if (FAILED(hr)) {
5168 qWarning("Failed to create D3D11 swapchain: %s",
5169 qPrintable(QSystemError::windowsComString(hr)));
5170 return false;
5171 }
5172 } else {
5174 // flip model -> buffer count is the real buffer count, not 1 like with the legacy modes
5175 hr = swapChain->ResizeBuffers(UINT(BUFFER_COUNT), UINT(pixelSize.width()), UINT(pixelSize.height()),
5177 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
5178 qWarning("Device loss detected in ResizeBuffers()");
5179 rhiD->deviceLost = true;
5180 return false;
5181 } else if (FAILED(hr)) {
5182 qWarning("Failed to resize D3D11 swapchain: %s",
5183 qPrintable(QSystemError::windowsComString(hr)));
5184 return false;
5185 }
5186 }
5187
5188 // This looks odd (for FLIP_*, esp. compared with backends for Vulkan
5189 // & co.) but the backbuffer is always at index 0, with magic underneath.
5190 // Some explanation from
5191 // https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-1-4-improvements
5192 //
5193 // "In Direct3D 11, applications could call GetBuffer( 0, … ) only once.
5194 // Every call to Present implicitly changed the resource identity of the
5195 // returned interface. Direct3D 12 no longer supports that implicit
5196 // resource identity change, due to the CPU overhead required and the
5197 // flexible resource descriptor design. As a result, the application must
5198 // manually call GetBuffer for every each buffer created with the
5199 // swapchain."
5200
5201 // So just query index 0 once (per resize) and be done with it.
5202 hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&backBufferTex));
5203 if (FAILED(hr)) {
5204 qWarning("Failed to query swapchain backbuffer: %s",
5205 qPrintable(QSystemError::windowsComString(hr)));
5206 return false;
5207 }
5208 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5209 rtvDesc.Format = srgbAdjustedColorFormat;
5210 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
5211 hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtv);
5212 if (FAILED(hr)) {
5213 qWarning("Failed to create rtv for swapchain backbuffer: %s",
5214 qPrintable(QSystemError::windowsComString(hr)));
5215 return false;
5216 }
5217
5218 // Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer.
5219 for (int i = 0; i < BUFFER_COUNT; ++i) {
5220 if (sampleDesc.Count > 1) {
5222 return false;
5223 }
5224 }
5225
5227 qWarning("Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
5229 }
5233 if (!m_depthStencil->create())
5234 qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
5236 } else {
5237 qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
5240 }
5241 }
5242
5243 currentFrameSlot = 0;
5244 frameCount = 0;
5246
5247 rt.setRenderPassDescriptor(m_renderPassDesc); // for the public getter in QRhiRenderTarget
5250 rtD->d.pixelSize = pixelSize;
5251 rtD->d.dpr = float(window->devicePixelRatio());
5252 rtD->d.sampleCount = int(sampleDesc.Count);
5253 rtD->d.colorAttCount = 1;
5254 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
5255
5256 if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps)) {
5258 // timestamp queries are optional so we can go on even if they failed
5259 }
5260
5261 if (needsRegistration)
5262 rhiD->registerResource(this);
5263
5264 return true;
5265}
5266
IOBluetoothDevice * device
\inmodule QtCore
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray toHex(char separator='\0') const
Returns a hex encoded copy of the byte array.
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
float greenF() const noexcept
Returns the green color component of this color.
Definition qcolor.cpp:1643
float redF() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1611
float alphaF() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1497
float blueF() const noexcept
Returns the blue color component of this color.
Definition qcolor.cpp:1675
void addData(QByteArrayView data) noexcept
Adds the characters in bytes to the cryptographic hash.
QByteArray result() const
Returns the final hash value.
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1202
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1258
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:949
\inmodule QtGui
Definition qimage.h:37
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition qimage.cpp:1197
Definition qlist.h:74
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
const_iterator cend() const
Definition qmap.h:604
const_iterator constFind(const Key &key) const
Definition qmap.h:654
bool isEmpty() const
Definition qmap.h:268
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0, otherwise returns false.
Definition qpoint.h:122
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:132
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:851
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:241
constexpr QPoint center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:232
quint32 size() const
Definition qrhi_p.h:344
const char * constData() const
Definition qrhi_p.h:340
\inmodule QtGui
Definition qrhi.h:834
UsageFlags m_usage
Definition qrhi.h:876
Type m_type
Definition qrhi.h:875
Type
Specifies storage type of buffer resource.
Definition qrhi.h:836
@ Dynamic
Definition qrhi.h:839
@ IndexBuffer
Definition qrhi.h:844
@ VertexBuffer
Definition qrhi.h:843
@ UniformBuffer
Definition qrhi.h:845
@ StorageBuffer
Definition qrhi.h:846
quint32 m_size
Definition qrhi.h:877
\inmodule QtGui
Definition qrhi.h:568
QRhiRenderBuffer * renderBuffer() const
Definition qrhi.h:577
int resolveLevel() const
Definition qrhi.h:592
QRhiTexture * texture() const
Definition qrhi.h:574
int resolveLayer() const
Definition qrhi.h:589
QRhiTexture * resolveTexture() const
Definition qrhi.h:586
int level() const
Definition qrhi.h:583
int layer() const
Definition qrhi.h:580
\inmodule QtGui
Definition qrhi.h:1614
QPair< QRhiBuffer *, quint32 > VertexInput
Synonym for QPair<QRhiBuffer *, quint32>.
Definition qrhi.h:1643
QPair< int, quint32 > DynamicOffset
Synonym for QPair<int, quint32>.
Definition qrhi.h:1639
IndexFormat
Specifies the index data type.
Definition qrhi.h:1616
\inmodule QtGui
Definition qrhi.h:1585
QRhiShaderStage m_shaderStage
Definition qrhi.h:1607
QRhiShaderResourceBindings * m_shaderResourceBindings
Definition qrhi.h:1608
@ CompileShadersWithDebugInfo
Definition qrhi.h:1588
\inmodule QtGui
\variable QRhiD3D11InitParams::enableDebugLayer
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override
bool deviceLost
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override
QRhiD3D11NativeHandles nativeHandlesStruct
bool isYUpInNDC() const override
ID3D11Device * dev
QRhiSwapChain * createSwapChain() override
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
bool isFeatureSupported(QRhi::Feature feature) const override
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override
bool isDeviceLost() const override
void executeBufferHostWrites(QD3D11Buffer *bufD)
void resetShaderResources()
void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD, const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
QRhiStats statistics() override
QHash< BytecodeCacheKey, QByteArray > m_bytecodeCache
QRhiComputePipeline * createComputePipeline() override
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override
bool debugLayer
QRhi::FrameOpResult finish() override
void setVertexInput(QRhiCommandBuffer *cb, int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings, QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat) override
IDXGIAdapter1 * activeAdapter
QRhiGraphicsPipeline * createGraphicsPipeline() override
QRhiShaderResourceBindings * createShaderResourceBindings() override
QVarLengthArray< BufferReadback, 2 > activeBufferReadbacks
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override
ID3D11DeviceContext1 * context
QList< int > supportedSampleCounts() const override
QRhiTextureRenderTarget * createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags) override
QRhi::Flags rhiFlags
QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, uint flags, QString *error, QShaderKey *usedShaderKey)
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override
bool isClipDepthZeroToOne() const override
IDCompositionDevice * dcompDevice
QRhiDriverInfo driverInfoStruct
QHash< QRhiShaderStage, Shader > m_shaderCache
bool ensureDirectCompositionDevice()
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
void draw(QRhiCommandBuffer *cb, quint32 vertexCount, quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override
void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD, int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc)
void reportLiveObjects(ID3D11Device *device)
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
void destroy() override
QMatrix4x4 clipSpaceCorrMatrix() const override
void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain=nullptr)
struct QRhiD3D11::OffscreenFrame ofr
bool isYUpInFramebuffer() const override
int resourceLimit(QRhi::ResourceLimit limit) const override
void beginExternal(QRhiCommandBuffer *cb) override
QRhiTexture * createTexture(QRhiTexture::Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, QRhiTexture::Flags flags) override
void setPipelineCacheData(const QByteArray &data) override
void bindShaderResources(QD3D11ShaderResourceBindings *srbD, const uint *dynOfsPairs, int dynOfsPairCount, bool offsetOnlyChange)
LUID adapterLuid
void debugMarkEnd(QRhiCommandBuffer *cb) override
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const
void releaseCachedResources() override
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override
ID3DUserDefinedAnnotation * annotations
bool importedDeviceAndContext
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override
QRhiBuffer * createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size) override
bool supportsAllowTearing
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override
void endExternal(QRhiCommandBuffer *cb) override
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override
QVarLengthArray< TextureReadback, 2 > activeTextureReadbacks
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override
void setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb, int dynamicOffsetCount, const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override
void clearShaderCache()
D3D_FEATURE_LEVEL featureLevel
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
bool makeThreadLocalNativeContextCurrent() override
bool create(QRhi::Flags flags) override
void finishActiveReadbacks()
IDXGIFactory1 * dxgiFactory
QByteArray pipelineCacheData() override
const QRhiNativeHandles * nativeHandles() override
QRhiDriverInfo driverInfo() const override
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override
int ubufAlignment() const override
void beginPass(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates, QRhiCommandBuffer::BeginPassFlags flags) override
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount, quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance) override
QRhiSampler * createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w) override
QRhiRenderBuffer * createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags, QRhiTexture::Format backingFormatHint) override
void setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps) override
QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice=nullptr)
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
struct QRhiD3D11::@352 contextState
\inmodule QtGui
Definition qrhi.h:44
float depthClearValue() const
Definition qrhi.h:49
quint32 stencilClearValue() const
Definition qrhi.h:52
\inmodule QtGui
Definition qrhi.h:1241
quint32 m_stencilReadMask
Definition qrhi.h:1462
@ CompileShadersWithDebugInfo
Definition qrhi.h:1247
BlendOp
Specifies the blend operation.
Definition qrhi.h:1302
PolygonMode
Specifies the polygon rasterization mode.
Definition qrhi.h:1350
BlendFactor
Specifies the blend factor.
Definition qrhi.h:1280
StencilOpState m_stencilFront
Definition qrhi.h:1460
quint32 m_stencilWriteMask
Definition qrhi.h:1463
CompareOp
Specifies the depth or stencil comparison function.
Definition qrhi.h:1321
Topology m_topology
Definition qrhi.h:1452
CullMode
Specifies the culling mode.
Definition qrhi.h:1261
QVarLengthArray< QRhiShaderStage, 4 > m_shaderStages
Definition qrhi.h:1471
QRhiVertexInputLayout m_vertexInputLayout
Definition qrhi.h:1472
QVarLengthArray< TargetBlend, 8 > m_targetBlends
Definition qrhi.h:1455
QRhiShaderResourceBindings * m_shaderResourceBindings
Definition qrhi.h:1473
PolygonMode m_polygonMode
Definition qrhi.h:1469
float m_slopeScaledDepthBias
Definition qrhi.h:1467
Topology
Specifies the primitive topology.
Definition qrhi.h:1251
StencilOpState m_stencilBack
Definition qrhi.h:1461
FrontFace m_frontFace
Definition qrhi.h:1454
StencilOp
Specifies the stencil operation.
Definition qrhi.h:1332
int m_patchControlPointCount
Definition qrhi.h:1468
CullMode m_cullMode
Definition qrhi.h:1453
CompareOp m_depthOp
Definition qrhi.h:1458
bool isCompressedFormat(QRhiTexture::Format format) const
Definition qrhi.cpp:7731
static const QRhiShaderResourceBinding::Data * shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
Definition qrhi_p.h:210
quint32 pipelineCacheRhiId() const
Definition qrhi_p.h:186
void compressedFormatInfo(QRhiTexture::Format format, const QSize &size, quint32 *bpl, quint32 *byteSize, QSize *blockDim) const
Definition qrhi.cpp:7738
static const int MAX_SHADER_CACHE_ENTRIES
Definition qrhi_p.h:227
static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
Definition qrhi_p.h:220
qint64 totalPipelineCreationTime() const
Definition qrhi_p.h:202
void textureFormatInfo(QRhiTexture::Format format, const QSize &size, quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const
Definition qrhi.cpp:7858
int layer() const
Definition qrhi.h:773
QRhiTexture * texture() const
Definition qrhi.h:770
int level() const
Definition qrhi.h:776
\inmodule QtGui
Definition qrhi.h:1071
Flags flags() const
Definition qrhi.h:1098
void setPixelSize(const QSize &sz)
Sets the size (in pixels) to sz.
Definition qrhi.h:1093
QSize pixelSize() const
Definition qrhi.h:1092
int sampleCount() const
Definition qrhi.h:1095
int m_sampleCount
Definition qrhi.h:1111
QRhiTexture::Format m_backingFormatHint
Definition qrhi.h:1113
QSize m_pixelSize
Definition qrhi.h:1110
Type
Specifies the type of the renderbuffer.
Definition qrhi.h:1073
virtual bool create()=0
Creates the corresponding native graphics resources.
@ UsedWithSwapChainOnly
Definition qrhi.h:1079
\inmodule QtGui
Definition qrhi.h:1119
\inmodule QtGui
Definition qrhi.h:1135
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Sets the QRhiRenderPassDescriptor desc for use with this render target.
Definition qrhi.h:1142
virtual QSize pixelSize() const =0
QRhiRenderPassDescriptor * m_renderPassDesc
Definition qrhi.h:1146
QVarLengthArray< BufferOp, BUFFER_OPS_STATIC_ALLOC > bufferOps
Definition qrhi_p.h:508
QVarLengthArray< TextureOp, TEXTURE_OPS_STATIC_ALLOC > textureOps
Definition qrhi_p.h:512
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
Definition qrhi_p.h:523
\inmodule QtGui
Definition qrhi.h:1694
QByteArray m_objectName
Definition qrhi.h:830
@ SwapChainRenderTarget
Definition qrhi.h:800
@ TextureRenderTarget
Definition qrhi.h:801
quint64 m_id
Definition qrhi.h:829
virtual Type resourceType() const =0
QRhiImplementation * m_rhi
Definition qrhi.h:828
\inmodule QtGui
Definition qrhi.h:1007
Filter m_minFilter
Definition qrhi.h:1062
Filter
Specifies the minification, magnification, or mipmap filtering.
Definition qrhi.h:1009
AddressMode m_addressV
Definition qrhi.h:1065
Filter m_mipmapMode
Definition qrhi.h:1063
AddressMode m_addressU
Definition qrhi.h:1064
AddressMode
Specifies the addressing mode.
Definition qrhi.h:1015
@ ClampToEdge
Definition qrhi.h:1017
CompareOp
Specifies the texture comparison function.
Definition qrhi.h:1021
@ LessOrEqual
Definition qrhi.h:1025
@ GreaterOrEqual
Definition qrhi.h:1028
CompareOp m_compareOp
Definition qrhi.h:1067
AddressMode m_addressW
Definition qrhi.h:1066
Filter m_magFilter
Definition qrhi.h:1061
\inmodule QtGui
Definition qrhi.h:138
std::array< int, 4 > scissor() const
Definition qrhi.h:143
\inmodule QtGui
Definition qrhi.h:431
\inmodule QtGui
Definition qrhi.h:1190
QVarLengthArray< QRhiShaderResourceBinding, BINDING_PREALLOC > m_bindings
Definition qrhi.h:1222
\inmodule QtGui
Definition qrhi.h:371
QShader::Variant shaderVariant() const
Definition qrhi.h:392
QShader shader() const
Definition qrhi.h:389
@ TessellationControl
Definition qrhi.h:375
@ TessellationEvaluation
Definition qrhi.h:376
\inmodule QtGui
Definition qrhi.h:1150
\inmodule QtGui
Definition qrhi.h:1513
Format format() const
Definition qrhi.h:1547
QWindow * m_window
Definition qrhi.h:1572
int m_sampleCount
Definition qrhi.h:1576
@ SurfaceHasNonPreMulAlpha
Definition qrhi.h:1517
@ SurfaceHasPreMulAlpha
Definition qrhi.h:1516
QRhiRenderPassDescriptor * m_renderPassDesc
Definition qrhi.h:1577
QSize m_currentPixelSize
Definition qrhi.h:1578
Flags m_flags
Definition qrhi.h:1573
Format
Describes the swapchain format.
Definition qrhi.h:1525
@ HDRExtendedSrgbLinear
Definition qrhi.h:1527
Format m_format
Definition qrhi.h:1574
virtual QRhiSwapChainHdrInfo hdrInfo()
\variable QRhiSwapChainHdrInfo::isHardCodedDefaults
Definition qrhi.cpp:7479
QRhiRenderBuffer * m_depthStencil
Definition qrhi.h:1575
QPoint destinationTopLeft() const
Definition qrhi.h:749
QPoint sourceTopLeft() const
Definition qrhi.h:740
int destinationLevel() const
Definition qrhi.h:746
int sourceLevel() const
Definition qrhi.h:737
QSize pixelSize() const
Definition qrhi.h:731
int sourceLayer() const
Definition qrhi.h:734
int destinationLayer() const
Definition qrhi.h:743
const QRhiColorAttachment * cbeginColorAttachments() const
Definition qrhi.h:626
QRhiTexture * depthTexture() const
Definition qrhi.h:634
const QRhiColorAttachment * cendColorAttachments() const
Definition qrhi.h:627
QRhiRenderBuffer * depthStencilBuffer() const
Definition qrhi.h:631
qsizetype colorAttachmentCount() const
Definition qrhi.h:629
\inmodule QtGui
Definition qrhi.h:1161
QRhiTextureRenderTargetDescription m_desc
Definition qrhi.h:1183
QRhiTextureRenderTargetDescription description() const
Definition qrhi.h:1171
\inmodule QtGui
Definition qrhi.h:883
QSize m_pixelSize
Definition qrhi.h:995
int m_arraySize
Definition qrhi.h:997
int m_depth
Definition qrhi.h:996
Format format() const
Definition qrhi.h:960
int arraySize() const
Definition qrhi.h:969
@ ThreeDimensional
Definition qrhi.h:895
@ UsedWithLoadStore
Definition qrhi.h:892
@ UsedWithGenerateMips
Definition qrhi.h:891
@ MipMapped
Definition qrhi.h:888
@ RenderTarget
Definition qrhi.h:886
@ OneDimensional
Definition qrhi.h:898
@ TextureArray
Definition qrhi.h:897
@ CubeMap
Definition qrhi.h:887
int arrayRangeStart() const
Definition qrhi.h:972
int m_arrayRangeLength
Definition qrhi.h:1001
Format
Specifies the texture format.
Definition qrhi.h:902
@ ASTC_10x8
Definition qrhi.h:947
@ ASTC_12x12
Definition qrhi.h:950
@ ASTC_8x5
Definition qrhi.h:942
@ ASTC_10x5
Definition qrhi.h:945
@ RGBA32F
Definition qrhi.h:914
@ ETC2_RGBA8
Definition qrhi.h:935
@ ASTC_5x5
Definition qrhi.h:939
@ ASTC_4x4
Definition qrhi.h:937
@ ASTC_6x6
Definition qrhi.h:941
@ ASTC_12x10
Definition qrhi.h:949
@ ETC2_RGB8
Definition qrhi.h:933
@ ASTC_5x4
Definition qrhi.h:938
@ RED_OR_ALPHA8
Definition qrhi.h:911
@ ASTC_6x5
Definition qrhi.h:940
@ ASTC_8x8
Definition qrhi.h:944
@ RGBA16F
Definition qrhi.h:913
@ RGB10A2
Definition qrhi.h:918
@ ASTC_10x6
Definition qrhi.h:946
@ ASTC_10x10
Definition qrhi.h:948
@ UnknownFormat
Definition qrhi.h:903
@ ETC2_RGB8A1
Definition qrhi.h:934
@ ASTC_8x6
Definition qrhi.h:943
Flags flags() const
Definition qrhi.h:980
QSize pixelSize() const
Definition qrhi.h:963
Format m_format
Definition qrhi.h:994
Flags m_flags
Definition qrhi.h:999
int m_arrayRangeStart
Definition qrhi.h:1000
int m_sampleCount
Definition qrhi.h:998
int arrayRangeLength() const
Definition qrhi.h:973
Format
Specifies the type of the element data.
Definition qrhi.h:234
\inmodule QtGui
Definition qrhi.h:179
quint32 instanceStepRate() const
Definition qrhi.h:195
Classification classification() const
Definition qrhi.h:192
quint32 stride() const
Definition qrhi.h:189
\inmodule QtGui
Definition qrhi.h:313
const QRhiVertexInputBinding * bindingAt(qsizetype index) const
Definition qrhi.h:326
const QRhiVertexInputAttribute * cendAttributes() const
Definition qrhi.h:337
const QRhiVertexInputBinding * cendBindings() const
Definition qrhi.h:325
const QRhiVertexInputAttribute * cbeginAttributes() const
Definition qrhi.h:336
const QRhiVertexInputBinding * cbeginBindings() const
Definition qrhi.h:324
\inmodule QtGui
Definition qrhi.h:85
ResourceLimit
Describes the resource limit to query.
Definition qrhi.h:1846
@ MaxThreadsPerThreadGroup
Definition qrhi.h:1853
@ MaxThreadGroupZ
Definition qrhi.h:1856
@ FramesInFlight
Definition qrhi.h:1850
@ TextureSizeMin
Definition qrhi.h:1847
@ MaxThreadGroupsPerDimension
Definition qrhi.h:1852
@ MaxAsyncReadbackFrames
Definition qrhi.h:1851
@ TextureArraySizeMax
Definition qrhi.h:1857
@ MaxColorAttachments
Definition qrhi.h:1849
@ MaxThreadGroupY
Definition qrhi.h:1855
@ MaxVertexInputs
Definition qrhi.h:1859
@ MaxThreadGroupX
Definition qrhi.h:1854
@ TextureSizeMax
Definition qrhi.h:1848
@ MaxVertexOutputs
Definition qrhi.h:1860
@ MaxUniformBufferRange
Definition qrhi.h:1858
@ SkipPresent
Definition qrhi.h:1842
Feature
Flag values to indicate what features are supported by the backend currently in use.
Definition qrhi.h:1793
@ HalfAttributes
Definition qrhi.h:1831
@ CustomInstanceStepRate
Definition qrhi.h:1799
@ NonDynamicUniformBuffers
Definition qrhi.h:1801
@ ElementIndexUint
Definition qrhi.h:1805
@ RenderToNonBaseMipLevel
Definition qrhi.h:1815
@ MultisampleRenderBuffer
Definition qrhi.h:1795
@ RenderTo3DTextureSlice
Definition qrhi.h:1823
@ Tessellation
Definition qrhi.h:1825
@ IntAttributes
Definition qrhi.h:1816
@ TextureArrays
Definition qrhi.h:1824
@ PipelineCacheDataLoadSave
Definition qrhi.h:1819
@ ReadBackNonUniformBuffer
Definition qrhi.h:1812
@ MultiView
Definition qrhi.h:1834
@ TexelFetch
Definition qrhi.h:1814
@ TextureArrayRange
Definition qrhi.h:1827
@ RenderToOneDimensionalTexture
Definition qrhi.h:1832
@ BaseVertex
Definition qrhi.h:1809
@ GeometryShader
Definition qrhi.h:1826
@ Compute
Definition qrhi.h:1806
@ OneDimensionalTextureMipmaps
Definition qrhi.h:1830
@ WideLines
Definition qrhi.h:1807
@ TriangleFanTopology
Definition qrhi.h:1811
@ OneDimensionalTextures
Definition qrhi.h:1829
@ ImageDataStride
Definition qrhi.h:1820
@ BaseInstance
Definition qrhi.h:1810
@ DebugMarkers
Definition qrhi.h:1796
@ ReadBackNonBaseMipLevel
Definition qrhi.h:1813
@ MultisampleTexture
Definition qrhi.h:1794
@ ThreeDimensionalTextureMipmaps
Definition qrhi.h:1833
@ NonFourAlignedEffectiveIndexBufferOffset
Definition qrhi.h:1802
@ RedOrAlpha8IsRed
Definition qrhi.h:1804
@ NonFillPolygonMode
Definition qrhi.h:1828
@ Timestamps
Definition qrhi.h:1797
@ ThreeDimensionalTextures
Definition qrhi.h:1822
@ PrimitiveRestart
Definition qrhi.h:1800
@ ReadBackAnyTextureFormat
Definition qrhi.h:1818
@ RenderBufferImport
Definition qrhi.h:1821
@ ScreenSpaceDerivatives
Definition qrhi.h:1817
@ VertexShaderPointSize
Definition qrhi.h:1808
@ NPOTTextureRepeat
Definition qrhi.h:1803
@ Instancing
Definition qrhi.h:1798
static const int MAX_MIP_LEVELS
Definition qrhi.h:1955
FrameOpResult
Describes the result of operations that can have a soft failure.
Definition qrhi.h:1786
@ FrameOpSuccess
Definition qrhi.h:1787
@ FrameOpDeviceLost
Definition qrhi.h:1790
@ FrameOpError
Definition qrhi.h:1788
@ EnablePipelineCacheDataSave
Definition qrhi.h:1781
@ PreferSoftwareRenderer
Definition qrhi.h:1780
@ EnableTimestamps
Definition qrhi.h:1782
qsizetype size() const
Definition qset.h:50
\inmodule QtGui
Definition qshader.h:60
QByteArray shader() const
Definition qshader.h:65
QByteArray entryPoint() const
Definition qshader.h:68
\inmodule QtGui
Definition qshader.h:174
\inmodule QtGui
Definition qshader.h:81
NativeResourceBindingMap nativeResourceBindingMap(const QShaderKey &key) const
Definition qshader.cpp:994
Variant
Describes what kind of shader code an entry contains.
Definition qshader.h:103
@ HlslShader
Definition qshader.h:95
@ DxbcShader
Definition qshader.h:96
@ GeometryStage
Definition qshader.h:87
@ ComputeStage
Definition qshader.h:89
@ TessellationEvaluationStage
Definition qshader.h:86
@ VertexStage
Definition qshader.h:84
@ FragmentStage
Definition qshader.h:88
@ TessellationControlStage
Definition qshader.h:85
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:123
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
Definition qstring.cpp:6737
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition qstring.cpp:5883
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1101
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
qsizetype count(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4732
QByteArray toUtf8() const &
Definition qstring.h:563
int alphaBufferSize() const
Get the size in bits of the alpha channel of the color buffer.
bool isEmpty() const
const T & at(qsizetype idx) const
const_iterator cbegin() const noexcept
qsizetype count() const
const_iterator cend() const noexcept
iterator end() noexcept
void append(const T &t)
const T * constData() const
iterator begin() noexcept
\inmodule QtGui
Definition qwindow.h:63
QSize size() const override
Returns the size of the window excluding any window frame.
Definition qwindow.h:210
EGLContext ctx
#define this
Definition dialogs.cpp:9
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
pD3DCompile resolveD3DCompile()
IDCompositionDevice * createDirectCompositionDevice()
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
static void * context
Q_CORE_EXPORT char * qstrncpy(char *dst, const char *src, size_t len)
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
#define rgb(r, g, b)
Definition qcolor.cpp:124
std::pair< T1, T2 > QPair
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
static int instanceCount
static QString header(const QString &name)
static const qint64 headerSize
EGLOutputLayerEXT layer
Flags
#define qWarning
Definition qlogging.h:162
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLuint const GLuint * buffers
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
const GLfloat * m
GLenum GLuint GLint level
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLuint const GLuint GLuint const GLuint * textures
GLenum GLsizei dataSize
GLuint sampler
GLenum GLenum GLsizei count
GLfloat GLfloat f
GLenum src
GLenum GLuint buffer
GLenum type
GLenum GLenum dst
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum target
GLbitfield flags
GLenum GLuint texture
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLuint name
GLint first
GLint GLsizei GLsizei GLenum format
GLsizei const GLint * box
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
void ** params
GLenum query
GLuint res
const GLubyte * c
GLint void * img
Definition qopenglext.h:233
GLuint GLsizei const GLuint const GLintptr * offsets
GLuint shader
Definition qopenglext.h:665
GLenum GLsizei len
GLint limit
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint * samplers
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLenum GLenum colorFormat
GLsizeiptr const void GLenum usage
Definition qopenglext.h:543
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QRHI_RES_RHI(t)
Definition qrhi_p.h:29
#define QRHI_RES(t, x)
Definition qrhi_p.h:28
static const int RBM_VERTEX
static QPair< int, int > mapBinding(int binding, int stageIndex, const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
static bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result)
static void applyDynamicOffsets(UINT *offsets, int batchIndex, const QRhiBatchedBindings< UINT > *originalBindings, const QRhiBatchedBindings< UINT > *staticOffsets, const uint *dynOfsPairs, int dynOfsPairCount)
static D3D11_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
#define SETUAVBATCH(stagePrefixL, stagePrefixU)
static QByteArray sourceHash(const QByteArray &source)
#define SETSAMPLERBATCH(stagePrefixL, stagePrefixU)
static uint toD3DBufferUsage(QRhiBuffer::UsageFlags usage)
static bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
#define SETUBUFBATCH(stagePrefixL, stagePrefixU)
static const int RBM_DOMAIN
static const DXGI_FORMAT DEFAULT_SRGB_FORMAT
Int aligned(Int v, Int byteAlign)
static DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
static const DXGI_FORMAT DEFAULT_FORMAT
static D3D11_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f, bool rgb)
static D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
static D3D11_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
static QD3D11RenderTargetData * rtData(QRhiRenderTarget *rt)
static UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
static const int RBM_COMPUTE
static D3D11_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
void releasePipelineShader(T &s)
static D3D11_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
static DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format format)
static D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t, int patchControlPointCount)
static const int RBM_HULL
static const int RBM_FRAGMENT
static IDXGIFactory1 * createDXGIFactory2()
static D3D11_FILL_MODE toD3DFillMode(QRhiGraphicsPipeline::PolygonMode mode)
static bool isDepthTextureFormat(QRhiTexture::Format format)
static D3D11_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
#define SETSHADER(StageL, StageU)
static DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
static uint clampedResourceCount(uint startSlot, int countSlots, uint maxSlots, const char *resType)
static const int RBM_SUPPORTED_STAGES
#define D3D11_VS_INPUT_REGISTER_COUNT
#define DXGI_ADAPTER_FLAG_SOFTWARE
\variable QRhiD3D11NativeHandles::dev
static QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
static D3D11_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
static DXGI_FORMAT toD3DDepthTextureSRVFormat(QRhiTexture::Format format)
static const int RBM_GEOMETRY
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define qPrintable(string)
Definition qstring.h:1391
#define sp
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
@ desc
unsigned int quint32
Definition qtypes.h:45
int qint32
Definition qtypes.h:44
unsigned long long quint64
Definition qtypes.h:56
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
QT_BEGIN_NAMESPACE typedef uchar * output
long HRESULT
QFileInfo info(fileName)
[8]
QSemaphore sem(5)
[0]
QSharedPointer< T > other(t)
[5]
view viewport() -> scroll(dx, dy, deviceRect)
bool hasPendingDynamicUpdates
Definition qrhid3d11_p.h:44
void endFullDynamicBufferUpdateForCurrentFrame() override
To be called when the entire contents of the buffer data has been updated in the memory block returne...
char * dynBuf
Definition qrhid3d11_p.h:43
ID3D11Buffer * buffer
Definition qrhid3d11_p.h:42
QD3D11Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size)
char * beginFullDynamicBufferUpdateForCurrentFrame() override
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QHash< quint32, ID3D11UnorderedAccessView * > uavs
Definition qrhid3d11_p.h:45
QRhiBuffer::NativeBuffer nativeBuffer() override
ID3D11UnorderedAccessView * unorderedAccessView(quint32 offset)
union QD3D11CommandBuffer::Command::Args args
QRhiRenderTarget * currentTarget
static const int MAX_DYNAMIC_OFFSET_COUNT
const uchar * retainBufferData(const QRhiBufferData &data)
ID3D11Buffer * currentVertexBuffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]
static const int MAX_VERTEX_BUFFER_BINDING_COUNT
QRhiShaderResourceBindings * currentGraphicsSrb
const uchar * retainImage(const QImage &image)
QD3D11CommandBuffer(QRhiImplementation *rhi)
const uchar * retainData(const QByteArray &data)
QRhiShaderResourceBindings * currentComputeSrb
QRhiBackendCommandList< Command > commands
QRhiComputePipeline * currentComputePipeline
ID3D11Buffer * currentIndexBuffer
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
DXGI_FORMAT currentIndexFormat
quint32 currentVertexOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]
QRhiGraphicsPipeline * currentGraphicsPipeline
QD3D11ComputePipeline(QRhiImplementation *rhi)
bool create() override
QShader::NativeResourceBindingMap nativeResourceBindingMap
struct QD3D11ComputePipeline::@253 cs
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QD3D11GraphicsPipeline(QRhiImplementation *rhi)
ID3D11VertexShader * shader
ID3D11InputLayout * inputLayout
struct QD3D11GraphicsPipeline::@246 vs
ID3D11BlendState * blendState
ID3D11RasterizerState * rastState
D3D11_PRIMITIVE_TOPOLOGY d3dTopology
struct QD3D11GraphicsPipeline::@249 ds
struct QD3D11GraphicsPipeline::@251 fs
bool create() override
Creates the corresponding native graphics resources.
struct QD3D11GraphicsPipeline::@250 gs
ID3D11DepthStencilState * dsState
struct QD3D11GraphicsPipeline::@248 hs
QShader::NativeResourceBindingMap nativeResourceBindingMap
QD3D11RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, int sampleCount, QRhiRenderBuffer::Flags flags, QRhiTexture::Format backingFormatHint)
ID3D11RenderTargetView * rtv
Definition qrhid3d11_p.h:62
DXGI_FORMAT dxgiFormat
Definition qrhid3d11_p.h:63
ID3D11DepthStencilView * dsv
Definition qrhid3d11_p.h:61
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
DXGI_SAMPLE_DESC sampleDesc
Definition qrhid3d11_p.h:64
bool create() override
Creates the corresponding native graphics resources.
QRhiTexture::Format backingFormat() const override
ID3D11Texture2D * tex
Definition qrhid3d11_p.h:60
QD3D11RenderPassDescriptor(QRhiImplementation *rhi)
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool isCompatible(const QRhiRenderPassDescriptor *other) const override
QVector< quint32 > serializedFormat() const override
static const int MAX_COLOR_ATTACHMENTS
ID3D11RenderTargetView * rtv[MAX_COLOR_ATTACHMENTS]
ID3D11DepthStencilView * dsv
QD3D11RenderPassDescriptor * rp
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QD3D11Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v, AddressMode w)
ID3D11SamplerState * samplerState
bool create() override
struct QD3D11ShaderResourceBindings::BoundSampledTextureData::@242 d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE]
QRhiBatchedBindings< ID3D11SamplerState * > samplers
QRhiBatchedBindings< ID3D11ShaderResourceView * > shaderresources
QRhiBatchedBindings< ID3D11UnorderedAccessView * > uavs
QRhiBatchedBindings< ID3D11Buffer * > ubufs
QVarLengthArray< BoundResourceData, 8 > boundResourceData
StageSamplerBatches hsSamplerBatches
QVarLengthArray< QRhiShaderResourceBinding, 8 > sortedBindings
StageSamplerBatches gsSamplerBatches
StageUniformBufferBatches dsUniformBufferBatches
StageUniformBufferBatches gsUniformBufferBatches
void updateResources(UpdateFlags flags) override
StageSamplerBatches vsSamplerBatches
StageSamplerBatches fsSamplerBatches
StageUniformBufferBatches fsUniformBufferBatches
StageSamplerBatches dsSamplerBatches
StageSamplerBatches csSamplerBatches
StageUniformBufferBatches csUniformBufferBatches
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QD3D11ShaderResourceBindings(QRhiImplementation *rhi)
StageUniformBufferBatches hsUniformBufferBatches
StageUniformBufferBatches vsUniformBufferBatches
int sampleCount() const override
QD3D11SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain)
float devicePixelRatio() const override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QD3D11RenderTargetData d
QSize pixelSize() const override
QRhiSwapChainHdrInfo hdrInfo() override
\variable QRhiSwapChainHdrInfo::isHardCodedDefaults
QD3D11Timestamps timestamps
QD3D11CommandBuffer cb
ID3D11RenderTargetView * backBufferRtv
QWindow * window
QD3D11RenderBuffer * ds
QRhiRenderTarget * currentFrameRenderTarget() override
ID3D11Texture2D * msaaTex[BUFFER_COUNT]
DXGI_FORMAT colorFormat
QD3D11SwapChain(QRhiImplementation *rhi)
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
IDCompositionTarget * dcompTarget
ID3D11RenderTargetView * msaaRtv[BUFFER_COUNT]
bool createOrResize() override
Creates the swapchain if not already done and resizes the swapchain buffers to match the current size...
QSize surfacePixelSize() override
bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc, ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const
static const int BUFFER_COUNT
QD3D11SwapChainRenderTarget rt
bool isFormatSupported(Format f) override
DXGI_SAMPLE_DESC sampleDesc
IDCompositionVisual * dcompVisual
QRhiCommandBuffer * currentFrameCommandBuffer() override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
IDXGISwapChain * swapChain
DXGI_FORMAT srgbAdjustedColorFormat
ID3D11Texture2D * backBufferTex
QSize pixelSize() const override
QD3D11TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags)
ID3D11DepthStencilView * dsv
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
float devicePixelRatio() const override
QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() override
int sampleCount() const override
bool ownsRtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS]
ID3D11RenderTargetView * rtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS]
bool create() override
Creates the corresponding native graphics resources.
QD3D11RenderTargetData d
ID3D11Texture1D * tex1D
Definition qrhid3d11_p.h:93
bool create() override
Creates the corresponding native graphics resources.
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
bool createFrom(NativeTexture src) override
Similar to create(), except that no new native textures are created.
NativeTexture nativeTexture() override
ID3D11UnorderedAccessView * perLevelViews[QRhi::MAX_MIP_LEVELS]
Definition qrhid3d11_p.h:99
ID3D11Texture2D * tex
Definition qrhid3d11_p.h:91
bool prepareCreate(QSize *adjustedSize=nullptr)
DXGI_FORMAT dxgiFormat
Definition qrhid3d11_p.h:96
QD3D11Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, int arraySize, int sampleCount, Flags flags)
ID3D11UnorderedAccessView * unorderedAccessViewForLevel(int level)
DXGI_SAMPLE_DESC sampleDesc
Definition qrhid3d11_p.h:98
bool finishCreate()
ID3D11ShaderResourceView * srv
Definition qrhid3d11_p.h:95
ID3D11Texture3D * tex3D
Definition qrhid3d11_p.h:92
ID3D11Resource * textureResource() const
Definition qrhid3d11_p.h:82
ID3D11Query * disjointQuery[MAX_TIMESTAMP_PAIRS]
bool active[MAX_TIMESTAMP_PAIRS]
ID3D11Query * query[MAX_TIMESTAMP_PAIRS *2]
bool tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec)
bool prepare(int pairCount, QRhiD3D11 *rhiD)
static const int MAX_TIMESTAMP_PAIRS
void feed(int binding, T resource)
Definition qrhi_p.h:529
QVarLengthArray< Batch, 4 > batches
Definition qrhi_p.h:569
\inmodule QtGui
Definition qrhi.h:850
ID3D11Buffer * stagingBuf
QRhiReadbackResult * result
QD3D11CommandBuffer cbWrapper
QD3D11Timestamps timestamps
QRhiReadbackResult * result
QRhiTexture::Format format
QRhiReadbackDescription desc
ID3D11Texture2D * stagingTex
\inmodule QtGui
Definition qrhi.h:1722
quint64 deviceId
Definition qrhi.h:1733
QByteArray deviceName
Definition qrhi.h:1732
quint64 vendorId
Definition qrhi.h:1734
\variable QRhiReadbackResult::completed
Definition qrhi.h:788
QByteArray data
Definition qrhi.h:1690
QRhiTexture::Format format
Definition qrhi.h:1688
std::function< void()> completed
Definition qrhi.h:1687
QRhiTextureCopyDescription desc
Definition qrhi_p.h:458
QVarLengthArray< MipLevelUploadList, 6 > subresDesc
Definition qrhi_p.h:456
UniformBufferData ubuf
Definition qrhi.h:513
union QRhiShaderResourceBinding::Data::@328 u
QRhiShaderResourceBinding::Type type
Definition qrhi.h:491
\inmodule QtGui
Definition qrhi.h:1745
\inmodule QtGui
Definition qrhi.h:1482
\inmodule QtGui
Definition qrhi.h:953
Definition moc.h:24
struct QD3D11CommandBuffer::Command::Args::@327 copySubRes
ID3D11Buffer * buffers[MAX_VERTEX_BUFFER_BINDING_COUNT]
struct QD3D11CommandBuffer::Command::Args::@320 bindGraphicsPipeline
QD3D11ShaderResourceBindings * srb
struct QD3D11CommandBuffer::Command::Args::@321 bindShaderResources
struct QD3D11CommandBuffer::Command::Args::@334 bindComputePipeline
struct QD3D11CommandBuffer::Command::Args::@322 stencilRef
struct QD3D11CommandBuffer::Command::Args::@314 clear
ID3D11ShaderResourceView * srv
struct QD3D11CommandBuffer::Command::Args::@333 debugMark
struct QD3D11CommandBuffer::Command::Args::@323 blendConstants
struct QD3D11CommandBuffer::Command::Args::@329 resolveSubRes
struct QD3D11CommandBuffer::Command::Args::@326 updateSubRes
UINT offsets[MAX_VERTEX_BUFFER_BINDING_COUNT]
struct QD3D11CommandBuffer::Command::Args::@325 drawIndexed
uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT *2]
struct QD3D11CommandBuffer::Command::Args::@315 viewport
QD3D11GraphicsPipeline * ps
UINT strides[MAX_VERTEX_BUFFER_BINDING_COUNT]
struct QD3D11CommandBuffer::Command::Args::@332 genMip
struct QD3D11CommandBuffer::Command::Args::@319 bindIndexBuffer
struct QD3D11CommandBuffer::Command::Args::@318 bindVertexBuffers
struct QD3D11CommandBuffer::Command::Args::@324 draw
struct QD3D11CommandBuffer::Command::Args::@312 setRenderTarget
struct QD3D11CommandBuffer::Command::Args::@317 scissor
struct QD3D11CommandBuffer::Command::Args::@335 dispatch