Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
139// help mingw with its ancient sdk headers
140#ifndef DXGI_ADAPTER_FLAG_SOFTWARE
141#define DXGI_ADAPTER_FLAG_SOFTWARE 2
142#endif
143
144#ifndef D3D11_1_UAV_SLOT_COUNT
145#define D3D11_1_UAV_SLOT_COUNT 64
146#endif
147
148#ifndef D3D11_VS_INPUT_REGISTER_COUNT
149#define D3D11_VS_INPUT_REGISTER_COUNT 32
150#endif
151
153 : ofr(this)
154{
155 debugLayer = params->enableDebugLayer;
156
157 if (importParams) {
158 if (importParams->dev && importParams->context) {
159 dev = reinterpret_cast<ID3D11Device *>(importParams->dev);
160 ID3D11DeviceContext *ctx = reinterpret_cast<ID3D11DeviceContext *>(importParams->context);
161 if (SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)))) {
162 // get rid of the ref added by QueryInterface
163 ctx->Release();
165 } else {
166 qWarning("ID3D11DeviceContext1 not supported by context, cannot import");
167 }
168 }
169 featureLevel = D3D_FEATURE_LEVEL(importParams->featureLevel);
170 adapterLuid.LowPart = importParams->adapterLuidLow;
171 adapterLuid.HighPart = importParams->adapterLuidHigh;
172 }
173}
174
175template <class Int>
176inline Int aligned(Int v, Int byteAlign)
177{
178 return (v + byteAlign - 1) & ~(byteAlign - 1);
179}
180
181static IDXGIFactory1 *createDXGIFactory2()
182{
183 IDXGIFactory1 *result = nullptr;
184 const HRESULT hr = CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&result));
185 if (FAILED(hr)) {
186 qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s",
187 qPrintable(QSystemError::windowsComString(hr)));
188 result = nullptr;
189 }
190 return result;
191}
192
193bool QRhiD3D11::create(QRhi::Flags flags)
194{
195 rhiFlags = flags;
196
197 uint devFlags = 0;
198 if (debugLayer)
199 devFlags |= D3D11_CREATE_DEVICE_DEBUG;
200
202 if (!dxgiFactory)
203 return false;
204
205 // For a FLIP_* swapchain Present(0, 0) is not necessarily
206 // sufficient to get non-blocking behavior, try using ALLOW_TEARING
207 // when available.
208 supportsAllowTearing = false;
209 IDXGIFactory5 *factory5 = nullptr;
210 if (SUCCEEDED(dxgiFactory->QueryInterface(__uuidof(IDXGIFactory5), reinterpret_cast<void **>(&factory5)))) {
211 BOOL allowTearing = false;
212 if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))))
213 supportsAllowTearing = allowTearing;
214 factory5->Release();
215 }
216
217 if (qEnvironmentVariableIntValue("QT_D3D_FLIP_DISCARD"))
218 qWarning("The default swap effect is FLIP_DISCARD, QT_D3D_FLIP_DISCARD is now ignored");
219
220 // Support for flip model swapchains is required now (since we are
221 // targeting Windows 10+), but the option for using the old model is still
222 // there. (some features are not supported then, however)
224
225 qCDebug(QRHI_LOG_INFO, "FLIP_* swapchain supported = true, ALLOW_TEARING supported = %s, use legacy (non-FLIP) model = %s",
226 supportsAllowTearing ? "true" : "false",
227 useLegacySwapchainModel ? "true" : "false");
228
230 IDXGIAdapter1 *adapter;
231 int requestedAdapterIndex = -1;
232 if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX"))
233 requestedAdapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
234
235 // The importParams may specify an adapter by the luid, take that into account.
236 if (requestedAdapterIndex < 0 && (adapterLuid.LowPart || adapterLuid.HighPart)) {
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 adapter->Release();
241 if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
242 && desc.AdapterLuid.HighPart == adapterLuid.HighPart)
243 {
244 requestedAdapterIndex = adapterIndex;
245 break;
246 }
247 }
248 }
249
250 if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
251 for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
252 DXGI_ADAPTER_DESC1 desc;
253 adapter->GetDesc1(&desc);
254 adapter->Release();
255 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
256 requestedAdapterIndex = adapterIndex;
257 break;
258 }
259 }
260 }
261
262 activeAdapter = nullptr;
263 for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
264 DXGI_ADAPTER_DESC1 desc;
265 adapter->GetDesc1(&desc);
266 const QString name = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description));
267 qCDebug(QRHI_LOG_INFO, "Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
268 adapterIndex,
270 desc.VendorId,
271 desc.DeviceId,
272 desc.Flags);
273 if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
274 activeAdapter = adapter;
275 adapterLuid = desc.AdapterLuid;
277 qCDebug(QRHI_LOG_INFO, " using this adapter");
278 } else {
279 adapter->Release();
280 }
281 }
282 if (!activeAdapter) {
283 qWarning("No adapter");
284 return false;
285 }
286
287 // Normally we won't specify a requested feature level list,
288 // except when a level was specified in importParams.
289 QVarLengthArray<D3D_FEATURE_LEVEL, 4> requestedFeatureLevels;
290 bool requestFeatureLevels = false;
291 if (featureLevel) {
292 requestFeatureLevels = true;
293 requestedFeatureLevels.append(featureLevel);
294 }
295
296 ID3D11DeviceContext *ctx = nullptr;
297 HRESULT hr = D3D11CreateDevice(activeAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
298 requestFeatureLevels ? requestedFeatureLevels.constData() : nullptr,
299 requestFeatureLevels ? requestedFeatureLevels.count() : 0,
300 D3D11_SDK_VERSION,
301 &dev, &featureLevel, &ctx);
302 // We cannot assume that D3D11_CREATE_DEVICE_DEBUG is always available. Retry without it, if needed.
303 if (hr == DXGI_ERROR_SDK_COMPONENT_MISSING && debugLayer) {
304 qCDebug(QRHI_LOG_INFO, "Debug layer was requested but is not available. "
305 "Attempting to create D3D11 device without it.");
306 devFlags &= ~D3D11_CREATE_DEVICE_DEBUG;
307 hr = D3D11CreateDevice(activeAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, devFlags,
308 requestFeatureLevels ? requestedFeatureLevels.constData() : nullptr,
309 requestFeatureLevels ? requestedFeatureLevels.count() : 0,
310 D3D11_SDK_VERSION,
311 &dev, &featureLevel, &ctx);
312 }
313 if (FAILED(hr)) {
314 qWarning("Failed to create D3D11 device and context: %s",
315 qPrintable(QSystemError::windowsComString(hr)));
316 return false;
317 }
318
319 const bool supports11_1 = SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)));
320 ctx->Release();
321 if (!supports11_1) {
322 qWarning("ID3D11DeviceContext1 not supported");
323 return false;
324 }
325
326 // Test if creating a Shader Model 5.0 vertex shader works; we want to
327 // fail already in create() if that's not the case.
328 ID3D11VertexShader *testShader = nullptr;
329 if (SUCCEEDED(dev->CreateVertexShader(g_testVertexShader, sizeof(g_testVertexShader), nullptr, &testShader))) {
330 testShader->Release();
331 } else {
332 static const char *msg = "D3D11 smoke test: Failed to create vertex shader";
334 qCDebug(QRHI_LOG_INFO, "%s", msg);
335 else
336 qWarning("%s", msg);
337 return false;
338 }
339
340 D3D11_FEATURE_DATA_D3D11_OPTIONS features = {};
341 if (SUCCEEDED(dev->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &features, sizeof(features)))) {
342 // The D3D _runtime_ may be 11.1, but the underlying _driver_ may
343 // still not support this D3D_FEATURE_LEVEL_11_1 feature. (e.g.
344 // because it only does 11_0)
345 if (!features.ConstantBufferOffsetting) {
346 static const char *msg = "D3D11 smoke test: Constant buffer offsetting is not supported by the driver";
348 qCDebug(QRHI_LOG_INFO, "%s", msg);
349 else
350 qWarning("%s", msg);
351 return false;
352 }
353 } else {
354 static const char *msg = "D3D11 smoke test: Failed to query D3D11_FEATURE_D3D11_OPTIONS";
356 qCDebug(QRHI_LOG_INFO, "%s", msg);
357 else
358 qWarning("%s", msg);
359 return false;
360 }
361 } else {
362 Q_ASSERT(dev && context);
363 featureLevel = dev->GetFeatureLevel();
364 IDXGIDevice *dxgiDev = nullptr;
365 if (SUCCEEDED(dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDev)))) {
366 IDXGIAdapter *adapter = nullptr;
367 if (SUCCEEDED(dxgiDev->GetAdapter(&adapter))) {
368 IDXGIAdapter1 *adapter1 = nullptr;
369 if (SUCCEEDED(adapter->QueryInterface(__uuidof(IDXGIAdapter1), reinterpret_cast<void **>(&adapter1)))) {
370 DXGI_ADAPTER_DESC1 desc;
371 adapter1->GetDesc1(&desc);
372 adapterLuid = desc.AdapterLuid;
374 adapter1->Release();
375 }
376 adapter->Release();
377 }
378 dxgiDev->Release();
379 }
380 qCDebug(QRHI_LOG_INFO, "Using imported device %p", dev);
381 }
382
383 if (FAILED(context->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), reinterpret_cast<void **>(&annotations))))
384 annotations = nullptr;
385
386 deviceLost = false;
387
390 nativeHandlesStruct.featureLevel = featureLevel;
391 nativeHandlesStruct.adapterLuidLow = adapterLuid.LowPart;
392 nativeHandlesStruct.adapterLuidHigh = adapterLuid.HighPart;
393
394 return true;
395}
396
398{
399 for (Shader &s : m_shaderCache)
400 s.s->Release();
401
402 m_shaderCache.clear();
403}
404
406{
408
410
411 if (ofr.tsDisjointQuery) {
412 ofr.tsDisjointQuery->Release();
413 ofr.tsDisjointQuery = nullptr;
414 }
415 for (int i = 0; i < 2; ++i) {
416 if (ofr.tsQueries[i]) {
417 ofr.tsQueries[i]->Release();
418 ofr.tsQueries[i] = nullptr;
419 }
420 }
421
422 if (annotations) {
423 annotations->Release();
424 annotations = nullptr;
425 }
426
428 if (context) {
429 context->Release();
430 context = nullptr;
431 }
432 if (dev) {
433 dev->Release();
434 dev = nullptr;
435 }
436 }
437
438 if (dcompDevice) {
439 dcompDevice->Release();
440 dcompDevice = nullptr;
441 }
442
443 if (activeAdapter) {
444 activeAdapter->Release();
445 activeAdapter = nullptr;
446 }
447
448 if (dxgiFactory) {
449 dxgiFactory->Release();
450 dxgiFactory = nullptr;
451 }
452}
453
455{
456 // this works only when params.enableDebugLayer was true
457 ID3D11Debug *debug;
458 if (SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void **>(&debug)))) {
459 debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
460 debug->Release();
461 }
462}
463
465{
466 return { 1, 2, 4, 8 };
467}
468
469DXGI_SAMPLE_DESC QRhiD3D11::effectiveSampleDesc(int sampleCount) const
470{
471 DXGI_SAMPLE_DESC desc;
472 desc.Count = 1;
473 desc.Quality = 0;
474
475 const int s = effectiveSampleCount(sampleCount);
476
477 desc.Count = UINT(s);
478 if (s > 1)
479 desc.Quality = UINT(D3D11_STANDARD_MULTISAMPLE_PATTERN);
480 else
481 desc.Quality = 0;
482
483 return desc;
484}
485
490
492{
493 return new QD3D11Buffer(this, type, usage, size);
494}
495
497{
498 return 256;
499}
500
502{
503 return false;
504}
505
507{
508 return true;
509}
510
512{
513 return true;
514}
515
517{
518 // Like with Vulkan, but Y is already good.
519
520 static QMatrix4x4 m;
521 if (m.isIdentity()) {
522 // NB the ctor takes row-major
523 m = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
524 0.0f, 1.0f, 0.0f, 0.0f,
525 0.0f, 0.0f, 0.5f, 0.5f,
526 0.0f, 0.0f, 0.0f, 1.0f);
527 }
528 return m;
529}
530
532{
534
536 return false;
537
538 return true;
539}
540
542{
543 switch (feature) {
545 return true;
547 return true;
549 return annotations != nullptr;
550 case QRhi::Timestamps:
551 return true;
552 case QRhi::Instancing:
553 return true;
555 return true;
557 return true;
559 return false; // because UpdateSubresource cannot deal with this
561 return true;
563 return true;
565 return true;
567 return true;
568 case QRhi::Compute:
569 return true;
570 case QRhi::WideLines:
571 return false;
573 return false;
574 case QRhi::BaseVertex:
575 return true;
577 return true;
579 return false;
581 return true;
583 return true;
584 case QRhi::TexelFetch:
585 return true;
587 return true;
589 return true;
591 return true;
593 return true;
595 return true;
597 return true;
599 return false;
601 return true;
603 return true;
605 return true;
607 return true;
609 return true;
611 return true;
613 return true;
615 return true;
617 return true;
619 return true;
621 return true;
623 return true;
624 case QRhi::MultiView:
625 return false;
627 return false; // because we use fully typed formats for textures and relaxed casting is a D3D12 thing
629 return false;
630 default:
631 Q_UNREACHABLE();
632 return false;
633 }
634}
635
637{
638 switch (limit) {
640 return 1;
642 return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
644 return 8;
646 // From our perspective. What D3D does internally is another question
647 // (there could be pipelining, helped f.ex. by our MAP_DISCARD based
648 // uniform buffer update strategy), but that's out of our hands and
649 // does not concern us here.
650 return 1;
652 return 1;
654 return D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
656 return D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP;
658 return D3D11_CS_THREAD_GROUP_MAX_X;
660 return D3D11_CS_THREAD_GROUP_MAX_Y;
662 return D3D11_CS_THREAD_GROUP_MAX_Z;
664 return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
666 return 65536;
670 return D3D11_VS_OUTPUT_REGISTER_COUNT;
671 default:
672 Q_UNREACHABLE();
673 return 0;
674 }
675}
676
681
686
688{
690 result.totalPipelineCreationTime = totalPipelineCreationTime();
691 return result;
692}
693
695{
696 // not applicable
697 return false;
698}
699
705
707{
708 return deviceLost;
709}
710
712{
715 // no need for driver specifics
718};
719
721{
723 if (m_bytecodeCache.isEmpty())
724 return data;
725
727 memset(&header, 0, sizeof(header));
728 header.rhiId = pipelineCacheRhiId();
729 header.arch = quint32(sizeof(void*));
730 header.count = m_bytecodeCache.count();
731
732 const size_t dataOffset = sizeof(header);
733 size_t dataSize = 0;
734 for (auto it = m_bytecodeCache.cbegin(), end = m_bytecodeCache.cend(); it != end; ++it) {
735 BytecodeCacheKey key = it.key();
736 QByteArray bytecode = it.value();
737 dataSize +=
738 sizeof(quint32) + key.sourceHash.size()
739 + sizeof(quint32) + key.target.size()
740 + sizeof(quint32) + key.entryPoint.size()
741 + sizeof(quint32) // compileFlags
742 + sizeof(quint32) + bytecode.size();
743 }
744
746 char *p = buf.data() + dataOffset;
747 for (auto it = m_bytecodeCache.cbegin(), end = m_bytecodeCache.cend(); it != end; ++it) {
748 BytecodeCacheKey key = it.key();
749 QByteArray bytecode = it.value();
750
751 quint32 i = key.sourceHash.size();
752 memcpy(p, &i, 4);
753 p += 4;
754 memcpy(p, key.sourceHash.constData(), key.sourceHash.size());
755 p += key.sourceHash.size();
756
757 i = key.target.size();
758 memcpy(p, &i, 4);
759 p += 4;
760 memcpy(p, key.target.constData(), key.target.size());
761 p += key.target.size();
762
763 i = key.entryPoint.size();
764 memcpy(p, &i, 4);
765 p += 4;
766 memcpy(p, key.entryPoint.constData(), key.entryPoint.size());
767 p += key.entryPoint.size();
768
769 quint32 f = key.compileFlags;
770 memcpy(p, &f, 4);
771 p += 4;
772
773 i = bytecode.size();
774 memcpy(p, &i, 4);
775 p += 4;
776 memcpy(p, bytecode.constData(), bytecode.size());
777 p += bytecode.size();
778 }
779 Q_ASSERT(p == buf.data() + dataOffset + dataSize);
780
781 header.dataSize = quint32(dataSize);
782 memcpy(buf.data(), &header, sizeof(header));
783
784 return buf;
785}
786
788{
789 if (data.isEmpty())
790 return;
791
792 const size_t headerSize = sizeof(QD3D11PipelineCacheDataHeader);
793 if (data.size() < qsizetype(headerSize)) {
794 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Invalid blob size (header incomplete)");
795 return;
796 }
797 const size_t dataOffset = headerSize;
799 memcpy(&header, data.constData(), headerSize);
800
801 const quint32 rhiId = pipelineCacheRhiId();
802 if (header.rhiId != rhiId) {
803 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: The data is for a different QRhi version or backend (%u, %u)",
804 rhiId, header.rhiId);
805 return;
806 }
807 const quint32 arch = quint32(sizeof(void*));
808 if (header.arch != arch) {
809 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Architecture does not match (%u, %u)",
810 arch, header.arch);
811 return;
812 }
813 if (header.count == 0)
814 return;
815
816 if (data.size() < qsizetype(dataOffset + header.dataSize)) {
817 qCDebug(QRHI_LOG_INFO, "setPipelineCacheData: Invalid blob size (data incomplete)");
818 return;
819 }
820
821 m_bytecodeCache.clear();
822
823 const char *p = data.constData() + dataOffset;
824 for (quint32 i = 0; i < header.count; ++i) {
825 quint32 len = 0;
826 memcpy(&len, p, 4);
827 p += 4;
829 memcpy(sourceHash.data(), p, len);
830 p += len;
831
832 memcpy(&len, p, 4);
833 p += 4;
835 memcpy(target.data(), p, len);
836 p += len;
837
838 memcpy(&len, p, 4);
839 p += 4;
840 QByteArray entryPoint(len, Qt::Uninitialized);
841 memcpy(entryPoint.data(), p, len);
842 p += len;
843
845 memcpy(&flags, p, 4);
846 p += 4;
847
848 memcpy(&len, p, 4);
849 p += 4;
851 memcpy(bytecode.data(), p, len);
852 p += len;
853
855 cacheKey.sourceHash = sourceHash;
856 cacheKey.target = target;
857 cacheKey.entryPoint = entryPoint;
858 cacheKey.compileFlags = flags;
859
860 m_bytecodeCache.insert(cacheKey, bytecode);
861 }
862
863 qCDebug(QRHI_LOG_INFO, "Seeded bytecode cache with %d shaders", int(m_bytecodeCache.count()));
864}
865
867 int sampleCount, QRhiRenderBuffer::Flags flags,
868 QRhiTexture::Format backingFormatHint)
869{
870 return new QD3D11RenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint);
871}
872
874 const QSize &pixelSize, int depth, int arraySize,
875 int sampleCount, QRhiTexture::Flags flags)
876{
877 return new QD3D11Texture(this, format, pixelSize, depth, arraySize, sampleCount, flags);
878}
879
881 QRhiSampler::Filter mipmapMode,
883{
884 return new QD3D11Sampler(this, magFilter, minFilter, mipmapMode, u, v, w);
885}
886
888 QRhiTextureRenderTarget::Flags flags)
889{
890 return new QD3D11TextureRenderTarget(this, desc, flags);
891}
892
897
902
907
909{
913 const bool pipelineChanged = cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation;
914
915 if (pipelineChanged) {
916 cbD->currentGraphicsPipeline = ps;
917 cbD->currentComputePipeline = nullptr;
918 cbD->currentPipelineGeneration = psD->generation;
919
920 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
922 cmd.args.bindGraphicsPipeline.ps = psD;
923 }
924}
925
926static const int RBM_SUPPORTED_STAGES = 6;
927static const int RBM_VERTEX = 0;
928static const int RBM_HULL = 1;
929static const int RBM_DOMAIN = 2;
930static const int RBM_GEOMETRY = 3;
931static const int RBM_FRAGMENT = 4;
932static const int RBM_COMPUTE = 5;
933
935 int dynamicOffsetCount,
936 const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
937{
942
943 if (!srb) {
944 if (gfxPsD)
945 srb = gfxPsD->m_shaderResourceBindings;
946 else
947 srb = compPsD->m_shaderResourceBindings;
948 }
949
951
952 bool srbUpdate = false;
953 for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
954 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
955 QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
956 switch (b->type) {
958 {
959 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
960 // NonDynamicUniformBuffers is not supported by this backend
961 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic && bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
962
964
965 if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
966 srbUpdate = true;
967 bd.ubuf.id = bufD->m_id;
968 bd.ubuf.generation = bufD->generation;
969 }
970 }
971 break;
975 {
977 if (bd.stex.count != data->count) {
978 bd.stex.count = data->count;
979 srbUpdate = true;
980 }
981 for (int elem = 0; elem < data->count; ++elem) {
982 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
983 QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
984 // We use the same code path for both combined and separate
985 // images and samplers, so tex or sampler (but not both) can be
986 // null here.
987 Q_ASSERT(texD || samplerD);
988 const quint64 texId = texD ? texD->m_id : 0;
989 const uint texGen = texD ? texD->generation : 0;
990 const quint64 samplerId = samplerD ? samplerD->m_id : 0;
991 const uint samplerGen = samplerD ? samplerD->generation : 0;
992 if (texGen != bd.stex.d[elem].texGeneration
993 || texId != bd.stex.d[elem].texId
994 || samplerGen != bd.stex.d[elem].samplerGeneration
995 || samplerId != bd.stex.d[elem].samplerId)
996 {
997 srbUpdate = true;
998 bd.stex.d[elem].texId = texId;
999 bd.stex.d[elem].texGeneration = texGen;
1000 bd.stex.d[elem].samplerId = samplerId;
1001 bd.stex.d[elem].samplerGeneration = samplerGen;
1002 }
1003 }
1004 }
1005 break;
1009 {
1010 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex);
1011 if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
1012 srbUpdate = true;
1013 bd.simage.id = texD->m_id;
1014 bd.simage.generation = texD->generation;
1015 }
1016 }
1017 break;
1021 {
1022 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf);
1023 if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
1024 srbUpdate = true;
1025 bd.sbuf.id = bufD->m_id;
1026 bd.sbuf.generation = bufD->generation;
1027 }
1028 }
1029 break;
1030 default:
1031 Q_UNREACHABLE();
1032 break;
1033 }
1034 }
1035
1036 if (srbUpdate) {
1038 memset(resBindMaps, 0, sizeof(resBindMaps));
1039 if (gfxPsD) {
1040 resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap;
1041 resBindMaps[RBM_HULL] = &gfxPsD->hs.nativeResourceBindingMap;
1042 resBindMaps[RBM_DOMAIN] = &gfxPsD->ds.nativeResourceBindingMap;
1043 resBindMaps[RBM_GEOMETRY] = &gfxPsD->gs.nativeResourceBindingMap;
1044 resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap;
1045 } else {
1046 resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap;
1047 }
1048 updateShaderResourceBindings(srbD, resBindMaps);
1049 }
1050
1051 const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
1052 const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
1053
1054 if (srbChanged || srbRebuilt || srbUpdate || srbD->hasDynamicOffset) {
1055 if (gfxPsD) {
1056 cbD->currentGraphicsSrb = srb;
1057 cbD->currentComputeSrb = nullptr;
1058 } else {
1059 cbD->currentGraphicsSrb = nullptr;
1060 cbD->currentComputeSrb = srb;
1061 }
1062 cbD->currentSrbGeneration = srbD->generation;
1063
1064 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1066 cmd.args.bindShaderResources.srb = srbD;
1067 // dynamic offsets have to be applied at the time of executing the bind
1068 // operations, not here
1069 cmd.args.bindShaderResources.offsetOnlyChange = !srbChanged && !srbRebuilt && !srbUpdate && srbD->hasDynamicOffset;
1070 cmd.args.bindShaderResources.dynamicOffsetCount = 0;
1071 if (srbD->hasDynamicOffset) {
1072 if (dynamicOffsetCount < QD3D11CommandBuffer::MAX_DYNAMIC_OFFSET_COUNT) {
1073 cmd.args.bindShaderResources.dynamicOffsetCount = dynamicOffsetCount;
1074 uint *p = cmd.args.bindShaderResources.dynamicOffsetPairs;
1075 for (int i = 0; i < dynamicOffsetCount; ++i) {
1076 const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
1077 const uint binding = uint(dynOfs.first);
1078 Q_ASSERT(aligned(dynOfs.second, 256u) == dynOfs.second);
1079 const quint32 offsetInConstants = dynOfs.second / 16;
1080 *p++ = binding;
1081 *p++ = offsetInConstants;
1082 }
1083 } else {
1084 qWarning("Too many dynamic offsets (%d, max is %d)",
1086 }
1087 }
1088 }
1089}
1090
1092 int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
1093 QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
1094{
1097
1098 bool needsBindVBuf = false;
1099 for (int i = 0; i < bindingCount; ++i) {
1100 const int inputSlot = startBinding + i;
1101 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first);
1102 Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
1103 if (bufD->m_type == QRhiBuffer::Dynamic)
1105
1106 if (cbD->currentVertexBuffers[inputSlot] != bufD->buffer
1107 || cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
1108 {
1109 needsBindVBuf = true;
1110 cbD->currentVertexBuffers[inputSlot] = bufD->buffer;
1111 cbD->currentVertexOffsets[inputSlot] = bindings[i].second;
1112 }
1113 }
1114
1115 if (needsBindVBuf) {
1116 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1118 cmd.args.bindVertexBuffers.startSlot = startBinding;
1120 qWarning("Too many vertex buffer bindings (%d, max is %d)",
1123 }
1124 cmd.args.bindVertexBuffers.slotCount = bindingCount;
1126 const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
1127 const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
1128 for (int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
1129 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first);
1130 cmd.args.bindVertexBuffers.buffers[i] = bufD->buffer;
1131 cmd.args.bindVertexBuffers.offsets[i] = bindings[i].second;
1132 cmd.args.bindVertexBuffers.strides[i] = inputLayout.bindingAt(i)->stride();
1133 }
1134 }
1135
1136 if (indexBuf) {
1137 QD3D11Buffer *ibufD = QRHI_RES(QD3D11Buffer, indexBuf);
1138 Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
1139 if (ibufD->m_type == QRhiBuffer::Dynamic)
1141
1142 const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
1143 : DXGI_FORMAT_R32_UINT;
1144 if (cbD->currentIndexBuffer != ibufD->buffer
1145 || cbD->currentIndexOffset != indexOffset
1146 || cbD->currentIndexFormat != dxgiFormat)
1147 {
1148 cbD->currentIndexBuffer = ibufD->buffer;
1149 cbD->currentIndexOffset = indexOffset;
1150 cbD->currentIndexFormat = dxgiFormat;
1151
1152 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1154 cmd.args.bindIndexBuffer.buffer = ibufD->buffer;
1155 cmd.args.bindIndexBuffer.offset = indexOffset;
1156 cmd.args.bindIndexBuffer.format = dxgiFormat;
1157 }
1158 }
1159}
1160
1162{
1165 Q_ASSERT(cbD->currentTarget);
1166 const QSize outputSize = cbD->currentTarget->pixelSize();
1167
1168 // d3d expects top-left, QRhiViewport is bottom-left
1169 float x, y, w, h;
1170 if (!qrhi_toTopLeftRenderTargetRect<UnBounded>(outputSize, viewport.viewport(), &x, &y, &w, &h))
1171 return;
1172
1173 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1175 cmd.args.viewport.x = x;
1176 cmd.args.viewport.y = y;
1177 cmd.args.viewport.w = w;
1178 cmd.args.viewport.h = h;
1179 cmd.args.viewport.d0 = viewport.minDepth();
1180 cmd.args.viewport.d1 = viewport.maxDepth();
1181}
1182
1184{
1187 Q_ASSERT(cbD->currentTarget);
1188 const QSize outputSize = cbD->currentTarget->pixelSize();
1189
1190 // d3d expects top-left, QRhiScissor is bottom-left
1191 int x, y, w, h;
1192 if (!qrhi_toTopLeftRenderTargetRect<Bounded>(outputSize, scissor.scissor(), &x, &y, &w, &h))
1193 return;
1194
1195 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1197 cmd.args.scissor.x = x;
1198 cmd.args.scissor.y = y;
1199 cmd.args.scissor.w = w;
1200 cmd.args.scissor.h = h;
1201}
1202
1204{
1207
1208 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1210 cmd.args.blendConstants.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline);
1211 cmd.args.blendConstants.c[0] = float(c.redF());
1212 cmd.args.blendConstants.c[1] = float(c.greenF());
1213 cmd.args.blendConstants.c[2] = float(c.blueF());
1214 cmd.args.blendConstants.c[3] = float(c.alphaF());
1215}
1216
1227
1229 quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
1230{
1233
1234 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1237 cmd.args.draw.vertexCount = vertexCount;
1238 cmd.args.draw.instanceCount = instanceCount;
1239 cmd.args.draw.firstVertex = firstVertex;
1240 cmd.args.draw.firstInstance = firstInstance;
1241}
1242
1244 quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
1245{
1248
1249 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1251 cmd.args.drawIndexed.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline);
1252 cmd.args.drawIndexed.indexCount = indexCount;
1253 cmd.args.drawIndexed.instanceCount = instanceCount;
1254 cmd.args.drawIndexed.firstIndex = firstIndex;
1255 cmd.args.drawIndexed.vertexOffset = vertexOffset;
1256 cmd.args.drawIndexed.firstInstance = firstInstance;
1257}
1258
1260{
1261 if (!debugMarkers || !annotations)
1262 return;
1263
1265 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1267 qstrncpy(cmd.args.debugMark.s, name.constData(), sizeof(cmd.args.debugMark.s));
1268}
1269
1279
1281{
1282 if (!debugMarkers || !annotations)
1283 return;
1284
1286 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1288 qstrncpy(cmd.args.debugMark.s, msg.constData(), sizeof(cmd.args.debugMark.s));
1289}
1290
1292{
1293 Q_UNUSED(cb);
1294 return nullptr;
1295}
1296
1303
1305{
1307 Q_ASSERT(cbD->commands.isEmpty());
1308 cbD->resetCachedState();
1309 if (cbD->currentTarget) { // could be compute, no rendertarget then
1310 QD3D11CommandBuffer::Command &fbCmd(cbD->commands.get());
1312 fbCmd.args.setRenderTarget.rt = cbD->currentTarget;
1313 }
1314}
1315
1321
1323{
1324 switch (rt->resourceType()) {
1326 return &QRHI_RES(QD3D11SwapChainRenderTarget, rt)->d;
1328 return &QRHI_RES(QD3D11TextureRenderTarget, rt)->d;
1329 default:
1330 Q_UNREACHABLE();
1331 return nullptr;
1332 }
1333}
1334
1336{
1337 Q_UNUSED(flags);
1338
1339 QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
1340 contextState.currentSwapChain = swapChainD;
1341 const int currentFrameSlot = swapChainD->currentFrameSlot;
1342
1343 swapChainD->cb.resetState();
1344
1345 swapChainD->rt.d.rtv[0] = swapChainD->sampleDesc.Count > 1 ?
1346 swapChainD->msaaRtv[currentFrameSlot] : swapChainD->backBufferRtv;
1347 swapChainD->rt.d.dsv = swapChainD->ds ? swapChainD->ds->dsv : nullptr;
1348
1350
1351 if (swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex]) {
1352 double elapsedSec = 0;
1353 if (swapChainD->timestamps.tryQueryTimestamps(swapChainD->currentTimestampPairIndex, context, &elapsedSec))
1354 swapChainD->cb.lastGpuTime = elapsedSec;
1355 }
1356
1357 ID3D11Query *tsStart = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2];
1358 ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[swapChainD->currentTimestampPairIndex];
1359 const bool recordTimestamps = tsStart && tsDisjoint && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
1360
1361 QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
1363 cmd.args.beginFrame.tsQuery = recordTimestamps ? tsStart : nullptr;
1364 cmd.args.beginFrame.tsDisjointQuery = recordTimestamps ? tsDisjoint : nullptr;
1365 cmd.args.beginFrame.swapchainData = rtData(&swapChainD->rt);
1366
1367 return QRhi::FrameOpSuccess;
1368}
1369
1371{
1372 QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
1373 Q_ASSERT(contextState.currentSwapChain = swapChainD);
1374 const int currentFrameSlot = swapChainD->currentFrameSlot;
1375
1376 QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
1378 cmd.args.endFrame.tsQuery = nullptr; // done later manually, see below
1379 cmd.args.endFrame.tsDisjointQuery = nullptr;
1380
1381 // send all commands to the context
1382 executeCommandBuffer(&swapChainD->cb);
1383
1384 if (swapChainD->sampleDesc.Count > 1) {
1385 context->ResolveSubresource(swapChainD->backBufferTex, 0,
1386 swapChainD->msaaTex[currentFrameSlot], 0,
1387 swapChainD->colorFormat);
1388 }
1389
1390 // this is here because we want to include the time spent on the ResolveSubresource as well
1391 ID3D11Query *tsEnd = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2 + 1];
1392 ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[swapChainD->currentTimestampPairIndex];
1393 const bool recordTimestamps = tsEnd && tsDisjoint && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
1394 if (recordTimestamps) {
1395 context->End(tsEnd);
1396 context->End(tsDisjoint);
1397 swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex] = true;
1398 swapChainD->currentTimestampPairIndex = (swapChainD->currentTimestampPairIndex + 1) % QD3D11SwapChainTimestamps::TIMESTAMP_PAIRS;
1399 }
1400
1401 if (!flags.testFlag(QRhi::SkipPresent)) {
1402 UINT presentFlags = 0;
1403 if (swapChainD->swapInterval == 0 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
1404 presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
1405 if (!swapChainD->swapChain) {
1406 qWarning("Failed to present: IDXGISwapChain is unavailable");
1407 return QRhi::FrameOpError;
1408 }
1409 HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
1410 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
1411 qWarning("Device loss detected in Present()");
1412 deviceLost = true;
1414 } else if (FAILED(hr)) {
1415 qWarning("Failed to present: %s",
1416 qPrintable(QSystemError::windowsComString(hr)));
1417 return QRhi::FrameOpError;
1418 }
1419
1420 if (dcompDevice && swapChainD->dcompTarget && swapChainD->dcompVisual)
1421 dcompDevice->Commit();
1422
1423 // move on to the next buffer
1424 swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D11SwapChain::BUFFER_COUNT;
1425 } else {
1426 context->Flush();
1427 }
1428
1429 swapChainD->frameCount += 1;
1430 contextState.currentSwapChain = nullptr;
1431
1432 return QRhi::FrameOpSuccess;
1433}
1434
1436{
1437 Q_UNUSED(flags);
1438 ofr.active = true;
1439
1440 ofr.cbWrapper.resetState();
1441 *cb = &ofr.cbWrapper;
1442
1443 if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
1444 D3D11_QUERY_DESC queryDesc = {};
1445 if (!ofr.tsDisjointQuery) {
1446 queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
1447 HRESULT hr = dev->CreateQuery(&queryDesc, &ofr.tsDisjointQuery);
1448 if (FAILED(hr)) {
1449 qWarning("Failed to create timestamp disjoint query: %s",
1450 qPrintable(QSystemError::windowsComString(hr)));
1451 return QRhi::FrameOpError;
1452 }
1453 }
1454 queryDesc.Query = D3D11_QUERY_TIMESTAMP;
1455 for (int i = 0; i < 2; ++i) {
1456 if (!ofr.tsQueries[i]) {
1457 HRESULT hr = dev->CreateQuery(&queryDesc, &ofr.tsQueries[i]);
1458 if (FAILED(hr)) {
1459 qWarning("Failed to create timestamp query: %s",
1460 qPrintable(QSystemError::windowsComString(hr)));
1461 return QRhi::FrameOpError;
1462 }
1463 }
1464 }
1465 }
1466
1467 QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
1469 cmd.args.beginFrame.tsQuery = ofr.tsQueries[0] ? ofr.tsQueries[0] : nullptr;
1470 cmd.args.beginFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
1471 cmd.args.beginFrame.swapchainData = nullptr;
1472
1473 return QRhi::FrameOpSuccess;
1474}
1475
1477{
1478 Q_UNUSED(flags);
1479 ofr.active = false;
1480
1481 QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
1483 cmd.args.endFrame.tsQuery = ofr.tsQueries[1] ? ofr.tsQueries[1] : nullptr;
1484 cmd.args.endFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
1485
1486 executeCommandBuffer(&ofr.cbWrapper);
1487 context->Flush();
1488
1490
1491 if (ofr.tsQueries[0]) {
1492 quint64 timestamps[2];
1493 D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
1494 HRESULT hr;
1495 bool ok = true;
1496 do {
1497 hr = context->GetData(ofr.tsDisjointQuery, &dj, sizeof(dj), 0);
1498 } while (hr == S_FALSE);
1499 ok &= hr == S_OK;
1500 do {
1501 hr = context->GetData(ofr.tsQueries[1], &timestamps[1], sizeof(quint64), 0);
1502 } while (hr == S_FALSE);
1503 ok &= hr == S_OK;
1504 do {
1505 hr = context->GetData(ofr.tsQueries[0], &timestamps[0], sizeof(quint64), 0);
1506 } while (hr == S_FALSE);
1507 ok &= hr == S_OK;
1508 if (ok) {
1509 if (!dj.Disjoint && dj.Frequency) {
1510 const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
1511 ofr.cbWrapper.lastGpuTime = elapsedMs / 1000.0;
1512 }
1513 }
1514 }
1515
1516 return QRhi::FrameOpSuccess;
1517}
1518
1519static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags)
1520{
1521 const bool srgb = flags.testFlag(QRhiTexture::sRGB);
1522 switch (format) {
1523 case QRhiTexture::RGBA8:
1524 return srgb ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
1525 case QRhiTexture::BGRA8:
1526 return srgb ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM;
1527 case QRhiTexture::R8:
1528 return DXGI_FORMAT_R8_UNORM;
1529 case QRhiTexture::RG8:
1530 return DXGI_FORMAT_R8G8_UNORM;
1531 case QRhiTexture::R16:
1532 return DXGI_FORMAT_R16_UNORM;
1533 case QRhiTexture::RG16:
1534 return DXGI_FORMAT_R16G16_UNORM;
1536 return DXGI_FORMAT_R8_UNORM;
1537
1539 return DXGI_FORMAT_R16G16B16A16_FLOAT;
1541 return DXGI_FORMAT_R32G32B32A32_FLOAT;
1542 case QRhiTexture::R16F:
1543 return DXGI_FORMAT_R16_FLOAT;
1544 case QRhiTexture::R32F:
1545 return DXGI_FORMAT_R32_FLOAT;
1546
1548 return DXGI_FORMAT_R10G10B10A2_UNORM;
1549
1550 case QRhiTexture::D16:
1551 return DXGI_FORMAT_R16_TYPELESS;
1552 case QRhiTexture::D24:
1553 return DXGI_FORMAT_R24G8_TYPELESS;
1554 case QRhiTexture::D24S8:
1555 return DXGI_FORMAT_R24G8_TYPELESS;
1556 case QRhiTexture::D32F:
1557 return DXGI_FORMAT_R32_TYPELESS;
1558
1559 case QRhiTexture::BC1:
1560 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
1561 case QRhiTexture::BC2:
1562 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
1563 case QRhiTexture::BC3:
1564 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
1565 case QRhiTexture::BC4:
1566 return DXGI_FORMAT_BC4_UNORM;
1567 case QRhiTexture::BC5:
1568 return DXGI_FORMAT_BC5_UNORM;
1569 case QRhiTexture::BC6H:
1570 return DXGI_FORMAT_BC6H_UF16;
1571 case QRhiTexture::BC7:
1572 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
1573
1577 qWarning("QRhiD3D11 does not support ETC2 textures");
1578 return DXGI_FORMAT_R8G8B8A8_UNORM;
1579
1594 qWarning("QRhiD3D11 does not support ASTC textures");
1595 return DXGI_FORMAT_R8G8B8A8_UNORM;
1596
1597 default:
1598 Q_UNREACHABLE();
1599 return DXGI_FORMAT_R8G8B8A8_UNORM;
1600 }
1601}
1602
1603static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
1604{
1605 switch (format) {
1606 case DXGI_FORMAT_R8G8B8A8_UNORM:
1607 return QRhiTexture::RGBA8;
1608 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
1609 if (flags)
1610 (*flags) |= QRhiTexture::sRGB;
1611 return QRhiTexture::RGBA8;
1612 case DXGI_FORMAT_B8G8R8A8_UNORM:
1613 return QRhiTexture::BGRA8;
1614 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
1615 if (flags)
1616 (*flags) |= QRhiTexture::sRGB;
1617 return QRhiTexture::BGRA8;
1618 case DXGI_FORMAT_R16G16B16A16_FLOAT:
1619 return QRhiTexture::RGBA16F;
1620 case DXGI_FORMAT_R32G32B32A32_FLOAT:
1621 return QRhiTexture::RGBA32F;
1622 case DXGI_FORMAT_R10G10B10A2_UNORM:
1623 return QRhiTexture::RGB10A2;
1624 default:
1625 qWarning("DXGI_FORMAT %d cannot be read back", format);
1626 break;
1627 }
1629}
1630
1632{
1633 switch (format) {
1638 return true;
1639
1640 default:
1641 return false;
1642 }
1643}
1644
1646{
1647 if (inFrame) {
1648 if (ofr.active) {
1649 Q_ASSERT(!contextState.currentSwapChain);
1650 Q_ASSERT(ofr.cbWrapper.recordingPass == QD3D11CommandBuffer::NoPass);
1651 executeCommandBuffer(&ofr.cbWrapper);
1652 ofr.cbWrapper.resetCommands();
1653 } else {
1654 Q_ASSERT(contextState.currentSwapChain);
1655 Q_ASSERT(contextState.currentSwapChain->cb.recordingPass == QD3D11CommandBuffer::NoPass);
1656 executeCommandBuffer(&contextState.currentSwapChain->cb);
1657 contextState.currentSwapChain->cb.resetCommands();
1658 }
1659 }
1660
1662
1663 return QRhi::FrameOpSuccess;
1664}
1665
1667 int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc)
1668{
1669 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1670 UINT subres = D3D11CalcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
1671 D3D11_BOX box;
1672 box.front = is3D ? UINT(layer) : 0u;
1673 // back, right, bottom are exclusive
1674 box.back = box.front + 1;
1675 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1677 cmd.args.updateSubRes.dst = texD->textureResource();
1678 cmd.args.updateSubRes.dstSubRes = subres;
1679
1680 const QPoint dp = subresDesc.destinationTopLeft();
1681 if (!subresDesc.image().isNull()) {
1682 QImage img = subresDesc.image();
1683 QSize size = img.size();
1684 int bpl = img.bytesPerLine();
1685 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
1686 const QPoint sp = subresDesc.sourceTopLeft();
1687 if (!subresDesc.sourceSize().isEmpty())
1688 size = subresDesc.sourceSize();
1689 if (img.depth() == 32) {
1690 const int offset = sp.y() * img.bytesPerLine() + sp.x() * 4;
1691 cmd.args.updateSubRes.src = cbD->retainImage(img) + offset;
1692 } else {
1693 img = img.copy(sp.x(), sp.y(), size.width(), size.height());
1694 bpl = img.bytesPerLine();
1695 cmd.args.updateSubRes.src = cbD->retainImage(img);
1696 }
1697 } else {
1698 cmd.args.updateSubRes.src = cbD->retainImage(img);
1699 }
1700 box.left = UINT(dp.x());
1701 box.top = UINT(dp.y());
1702 box.right = UINT(dp.x() + size.width());
1703 box.bottom = UINT(dp.y() + size.height());
1704 cmd.args.updateSubRes.hasDstBox = true;
1705 cmd.args.updateSubRes.dstBox = box;
1706 cmd.args.updateSubRes.srcRowPitch = UINT(bpl);
1707 } else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
1708 const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
1709 : subresDesc.sourceSize();
1710 quint32 bpl = 0;
1711 QSize blockDim;
1712 compressedFormatInfo(texD->m_format, size, &bpl, nullptr, &blockDim);
1713 // Everything must be a multiple of the block width and
1714 // height, so e.g. a mip level of size 2x2 will be 4x4 when it
1715 // comes to the actual data.
1716 box.left = UINT(aligned(dp.x(), blockDim.width()));
1717 box.top = UINT(aligned(dp.y(), blockDim.height()));
1718 box.right = UINT(aligned(dp.x() + size.width(), blockDim.width()));
1719 box.bottom = UINT(aligned(dp.y() + size.height(), blockDim.height()));
1720 cmd.args.updateSubRes.hasDstBox = true;
1721 cmd.args.updateSubRes.dstBox = box;
1722 cmd.args.updateSubRes.src = cbD->retainData(subresDesc.data());
1723 cmd.args.updateSubRes.srcRowPitch = bpl;
1724 } else if (!subresDesc.data().isEmpty()) {
1725 const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
1726 : subresDesc.sourceSize();
1727 quint32 bpl = 0;
1728 if (subresDesc.dataStride())
1729 bpl = subresDesc.dataStride();
1730 else
1731 textureFormatInfo(texD->m_format, size, &bpl, nullptr, nullptr);
1732 box.left = UINT(dp.x());
1733 box.top = UINT(dp.y());
1734 box.right = UINT(dp.x() + size.width());
1735 box.bottom = UINT(dp.y() + size.height());
1736 cmd.args.updateSubRes.hasDstBox = true;
1737 cmd.args.updateSubRes.dstBox = box;
1738 cmd.args.updateSubRes.src = cbD->retainData(subresDesc.data());
1739 cmd.args.updateSubRes.srcRowPitch = bpl;
1740 } else {
1741 qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
1742 cbD->commands.unget();
1743 }
1744}
1745
1747{
1750
1751 for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
1752 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
1755 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1756 memcpy(bufD->dynBuf + u.offset, u.data.constData(), size_t(u.data.size()));
1757 bufD->hasPendingDynamicUpdates = true;
1760 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1761 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
1762 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1764 cmd.args.updateSubRes.dst = bufD->buffer;
1765 cmd.args.updateSubRes.dstSubRes = 0;
1766 cmd.args.updateSubRes.src = cbD->retainBufferData(u.data);
1767 cmd.args.updateSubRes.srcRowPitch = 0;
1768 // Specify the region (even when offset is 0 and all data is provided)
1769 // since the ID3D11Buffer's size is rounded up to be a multiple of 256
1770 // while the data we have has the original size.
1771 D3D11_BOX box;
1772 box.left = u.offset;
1773 box.top = box.front = 0;
1774 box.back = box.bottom = 1;
1775 box.right = u.offset + u.data.size(); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
1776 cmd.args.updateSubRes.hasDstBox = true;
1777 cmd.args.updateSubRes.dstBox = box;
1780 if (bufD->m_type == QRhiBuffer::Dynamic) {
1781 u.result->data.resize(u.readSize);
1782 memcpy(u.result->data.data(), bufD->dynBuf + u.offset, size_t(u.readSize));
1783 if (u.result->completed)
1784 u.result->completed();
1785 } else {
1786 BufferReadback readback;
1787 readback.result = u.result;
1788 readback.byteSize = u.readSize;
1789
1790 D3D11_BUFFER_DESC desc = {};
1791 desc.ByteWidth = readback.byteSize;
1792 desc.Usage = D3D11_USAGE_STAGING;
1793 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1794 HRESULT hr = dev->CreateBuffer(&desc, nullptr, &readback.stagingBuf);
1795 if (FAILED(hr)) {
1796 qWarning("Failed to create buffer: %s",
1797 qPrintable(QSystemError::windowsComString(hr)));
1798 continue;
1799 }
1800
1801 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1803 cmd.args.copySubRes.dst = readback.stagingBuf;
1804 cmd.args.copySubRes.dstSubRes = 0;
1805 cmd.args.copySubRes.dstX = 0;
1806 cmd.args.copySubRes.dstY = 0;
1807 cmd.args.copySubRes.dstZ = 0;
1808 cmd.args.copySubRes.src = bufD->buffer;
1809 cmd.args.copySubRes.srcSubRes = 0;
1810 cmd.args.copySubRes.hasSrcBox = true;
1811 D3D11_BOX box;
1812 box.left = u.offset;
1813 box.top = box.front = 0;
1814 box.back = box.bottom = 1;
1815 box.right = u.offset + u.readSize;
1816 cmd.args.copySubRes.srcBox = box;
1817
1818 activeBufferReadbacks.append(readback);
1819 }
1820 }
1821 }
1822 for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
1823 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
1826 for (int layer = 0, maxLayer = u.subresDesc.count(); layer < maxLayer; ++layer) {
1827 for (int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
1828 for (const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
1829 enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
1830 }
1831 }
1833 Q_ASSERT(u.src && u.dst);
1836 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1837 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1838 UINT srcSubRes = D3D11CalcSubresource(UINT(u.desc.sourceLevel()), srcIs3D ? 0u : UINT(u.desc.sourceLayer()), srcD->mipLevelCount);
1839 UINT dstSubRes = D3D11CalcSubresource(UINT(u.desc.destinationLevel()), dstIs3D ? 0u : UINT(u.desc.destinationLayer()), dstD->mipLevelCount);
1840 const QPoint dp = u.desc.destinationTopLeft();
1841 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
1842 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
1843 const QPoint sp = u.desc.sourceTopLeft();
1844 D3D11_BOX srcBox;
1845 srcBox.left = UINT(sp.x());
1846 srcBox.top = UINT(sp.y());
1847 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
1848 // back, right, bottom are exclusive
1849 srcBox.right = srcBox.left + UINT(copySize.width());
1850 srcBox.bottom = srcBox.top + UINT(copySize.height());
1851 srcBox.back = srcBox.front + 1;
1852 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1854 cmd.args.copySubRes.dst = dstD->textureResource();
1855 cmd.args.copySubRes.dstSubRes = dstSubRes;
1856 cmd.args.copySubRes.dstX = UINT(dp.x());
1857 cmd.args.copySubRes.dstY = UINT(dp.y());
1858 cmd.args.copySubRes.dstZ = dstIs3D ? UINT(u.desc.destinationLayer()) : 0u;
1859 cmd.args.copySubRes.src = srcD->textureResource();
1860 cmd.args.copySubRes.srcSubRes = srcSubRes;
1861 cmd.args.copySubRes.hasSrcBox = true;
1862 cmd.args.copySubRes.srcBox = srcBox;
1864 TextureReadback readback;
1865 readback.desc = u.rb;
1866 readback.result = u.result;
1867
1868 ID3D11Resource *src;
1869 DXGI_FORMAT dxgiFormat;
1870 QSize pixelSize;
1872 UINT subres = 0;
1874 QD3D11SwapChain *swapChainD = nullptr;
1875 bool is3D = false;
1876
1877 if (texD) {
1878 if (texD->sampleDesc.Count > 1) {
1879 qWarning("Multisample texture cannot be read back");
1880 continue;
1881 }
1882 src = texD->textureResource();
1883 dxgiFormat = texD->dxgiFormat;
1884 pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
1885 format = texD->m_format;
1886 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1887 subres = D3D11CalcSubresource(UINT(u.rb.level()), UINT(is3D ? 0 : u.rb.layer()), texD->mipLevelCount);
1888 } else {
1889 Q_ASSERT(contextState.currentSwapChain);
1890 swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain);
1891 if (swapChainD->sampleDesc.Count > 1) {
1892 // Unlike with textures, reading back a multisample swapchain image
1893 // has to be supported. Insert a resolve.
1894 QD3D11CommandBuffer::Command &rcmd(cbD->commands.get());
1896 rcmd.args.resolveSubRes.dst = swapChainD->backBufferTex;
1897 rcmd.args.resolveSubRes.dstSubRes = 0;
1898 rcmd.args.resolveSubRes.src = swapChainD->msaaTex[swapChainD->currentFrameSlot];
1899 rcmd.args.resolveSubRes.srcSubRes = 0;
1900 rcmd.args.resolveSubRes.format = swapChainD->colorFormat;
1901 }
1902 src = swapChainD->backBufferTex;
1903 dxgiFormat = swapChainD->colorFormat;
1904 pixelSize = swapChainD->pixelSize;
1905 format = swapchainReadbackTextureFormat(dxgiFormat, nullptr);
1907 continue;
1908 }
1909 quint32 byteSize = 0;
1910 quint32 bpl = 0;
1911 textureFormatInfo(format, pixelSize, &bpl, &byteSize, nullptr);
1912
1913 D3D11_TEXTURE2D_DESC desc = {};
1914 desc.Width = UINT(pixelSize.width());
1915 desc.Height = UINT(pixelSize.height());
1916 desc.MipLevels = 1;
1917 desc.ArraySize = 1;
1918 desc.Format = dxgiFormat;
1919 desc.SampleDesc.Count = 1;
1920 desc.Usage = D3D11_USAGE_STAGING;
1921 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1922 ID3D11Texture2D *stagingTex;
1923 HRESULT hr = dev->CreateTexture2D(&desc, nullptr, &stagingTex);
1924 if (FAILED(hr)) {
1925 qWarning("Failed to create readback staging texture: %s",
1926 qPrintable(QSystemError::windowsComString(hr)));
1927 return;
1928 }
1929
1930 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1932 cmd.args.copySubRes.dst = stagingTex;
1933 cmd.args.copySubRes.dstSubRes = 0;
1934 cmd.args.copySubRes.dstX = 0;
1935 cmd.args.copySubRes.dstY = 0;
1936 cmd.args.copySubRes.dstZ = 0;
1937 cmd.args.copySubRes.src = src;
1938 cmd.args.copySubRes.srcSubRes = subres;
1939 if (is3D) {
1940 D3D11_BOX srcBox = {};
1941 srcBox.front = UINT(u.rb.layer());
1942 srcBox.right = desc.Width; // exclusive
1943 srcBox.bottom = desc.Height;
1944 srcBox.back = srcBox.front + 1;
1945 cmd.args.copySubRes.hasSrcBox = true;
1946 cmd.args.copySubRes.srcBox = srcBox;
1947 } else {
1948 cmd.args.copySubRes.hasSrcBox = false;
1949 }
1950
1951 readback.stagingTex = stagingTex;
1952 readback.byteSize = byteSize;
1953 readback.bpl = bpl;
1954 readback.pixelSize = pixelSize;
1955 readback.format = format;
1956
1957 activeTextureReadbacks.append(readback);
1960 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1962 cmd.args.genMip.srv = QRHI_RES(QD3D11Texture, u.dst)->srv;
1963 }
1964 }
1965
1966 ud->free();
1967}
1968
1970{
1971 QVarLengthArray<std::function<void()>, 4> completedCallbacks;
1972
1973 for (int i = activeTextureReadbacks.count() - 1; i >= 0; --i) {
1975 readback.result->format = readback.format;
1976 readback.result->pixelSize = readback.pixelSize;
1977
1978 D3D11_MAPPED_SUBRESOURCE mp;
1979 HRESULT hr = context->Map(readback.stagingTex, 0, D3D11_MAP_READ, 0, &mp);
1980 if (SUCCEEDED(hr)) {
1981 readback.result->data.resize(int(readback.byteSize));
1982 // nothing says the rows are tightly packed in the texture, must take
1983 // the stride into account
1984 char *dst = readback.result->data.data();
1985 char *src = static_cast<char *>(mp.pData);
1986 for (int y = 0, h = readback.pixelSize.height(); y != h; ++y) {
1987 memcpy(dst, src, readback.bpl);
1988 dst += readback.bpl;
1989 src += mp.RowPitch;
1990 }
1991 context->Unmap(readback.stagingTex, 0);
1992 } else {
1993 qWarning("Failed to map readback staging texture: %s",
1994 qPrintable(QSystemError::windowsComString(hr)));
1995 }
1996
1997 readback.stagingTex->Release();
1998
1999 if (readback.result->completed)
2000 completedCallbacks.append(readback.result->completed);
2001
2002 activeTextureReadbacks.removeLast();
2003 }
2004
2005 for (int i = activeBufferReadbacks.count() - 1; i >= 0; --i) {
2007
2008 D3D11_MAPPED_SUBRESOURCE mp;
2009 HRESULT hr = context->Map(readback.stagingBuf, 0, D3D11_MAP_READ, 0, &mp);
2010 if (SUCCEEDED(hr)) {
2011 readback.result->data.resize(int(readback.byteSize));
2012 memcpy(readback.result->data.data(), mp.pData, readback.byteSize);
2013 context->Unmap(readback.stagingBuf, 0);
2014 } else {
2015 qWarning("Failed to map readback staging texture: %s",
2016 qPrintable(QSystemError::windowsComString(hr)));
2017 }
2018
2019 readback.stagingBuf->Release();
2020
2021 if (readback.result->completed)
2022 completedCallbacks.append(readback.result->completed);
2023
2024 activeBufferReadbacks.removeLast();
2025 }
2026
2027 for (auto f : completedCallbacks)
2028 f();
2029}
2030
2037
2039 QRhiRenderTarget *rt,
2040 const QColor &colorClearValue,
2041 const QRhiDepthStencilClearValue &depthStencilClearValue,
2042 QRhiResourceUpdateBatch *resourceUpdates,
2043 QRhiCommandBuffer::BeginPassFlags)
2044{
2047
2048 if (resourceUpdates)
2049 enqueueResourceUpdates(cb, resourceUpdates);
2050
2051 bool wantsColorClear = true;
2052 bool wantsDsClear = true;
2053 QD3D11RenderTargetData *rtD = rtData(rt);
2056 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2057 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2058 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2059 rtTex->create();
2060 }
2061
2063
2064 QD3D11CommandBuffer::Command &fbCmd(cbD->commands.get());
2066 fbCmd.args.setRenderTarget.rt = rt;
2067
2068 QD3D11CommandBuffer::Command &clearCmd(cbD->commands.get());
2070 clearCmd.args.clear.rt = rt;
2071 clearCmd.args.clear.mask = 0;
2072 if (rtD->colorAttCount && wantsColorClear)
2073 clearCmd.args.clear.mask |= QD3D11CommandBuffer::Command::Color;
2074 if (rtD->dsAttCount && wantsDsClear)
2076
2077 clearCmd.args.clear.c[0] = float(colorClearValue.redF());
2078 clearCmd.args.clear.c[1] = float(colorClearValue.greenF());
2079 clearCmd.args.clear.c[2] = float(colorClearValue.blueF());
2080 clearCmd.args.clear.c[3] = float(colorClearValue.alphaF());
2081 clearCmd.args.clear.d = depthStencilClearValue.depthClearValue();
2082 clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
2083
2085 cbD->currentTarget = rt;
2086
2087 cbD->resetCachedState();
2088}
2089
2091{
2094
2097 for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2098 it != itEnd; ++it)
2099 {
2100 const QRhiColorAttachment &colorAtt(*it);
2101 if (!colorAtt.resolveTexture())
2102 continue;
2103
2104 QD3D11Texture *dstTexD = QRHI_RES(QD3D11Texture, colorAtt.resolveTexture());
2105 QD3D11Texture *srcTexD = QRHI_RES(QD3D11Texture, colorAtt.texture());
2107 Q_ASSERT(srcTexD || srcRbD);
2108 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2110 cmd.args.resolveSubRes.dst = dstTexD->textureResource();
2111 cmd.args.resolveSubRes.dstSubRes = D3D11CalcSubresource(UINT(colorAtt.resolveLevel()),
2112 UINT(colorAtt.resolveLayer()),
2113 dstTexD->mipLevelCount);
2114 if (srcTexD) {
2115 cmd.args.resolveSubRes.src = srcTexD->textureResource();
2116 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2117 qWarning("Resolve source (%d) and destination (%d) formats do not match",
2118 int(srcTexD->dxgiFormat), int(dstTexD->dxgiFormat));
2119 cbD->commands.unget();
2120 continue;
2121 }
2122 if (srcTexD->sampleDesc.Count <= 1) {
2123 qWarning("Cannot resolve a non-multisample texture");
2124 cbD->commands.unget();
2125 continue;
2126 }
2127 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2128 qWarning("Resolve source and destination sizes do not match");
2129 cbD->commands.unget();
2130 continue;
2131 }
2132 } else {
2133 cmd.args.resolveSubRes.src = srcRbD->tex;
2134 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2135 qWarning("Resolve source (%d) and destination (%d) formats do not match",
2136 int(srcRbD->dxgiFormat), int(dstTexD->dxgiFormat));
2137 cbD->commands.unget();
2138 continue;
2139 }
2140 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2141 qWarning("Resolve source and destination sizes do not match");
2142 cbD->commands.unget();
2143 continue;
2144 }
2145 }
2146 cmd.args.resolveSubRes.srcSubRes = D3D11CalcSubresource(0, UINT(colorAtt.layer()), 1);
2147 cmd.args.resolveSubRes.format = dstTexD->dxgiFormat;
2148 }
2149 if (rtTex->m_desc.depthResolveTexture())
2150 qWarning("Resolving multisample depth-stencil buffers is not supported with D3D");
2151 }
2152
2154 cbD->currentTarget = nullptr;
2155
2156 if (resourceUpdates)
2157 enqueueResourceUpdates(cb, resourceUpdates);
2158}
2159
2161 QRhiResourceUpdateBatch *resourceUpdates,
2162 QRhiCommandBuffer::BeginPassFlags)
2163{
2166
2167 if (resourceUpdates)
2168 enqueueResourceUpdates(cb, resourceUpdates);
2169
2170 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2172
2174
2175 cbD->resetCachedState();
2176}
2177
2188
2190{
2194 const bool pipelineChanged = cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation;
2195
2196 if (pipelineChanged) {
2197 cbD->currentGraphicsPipeline = nullptr;
2198 cbD->currentComputePipeline = psD;
2199 cbD->currentPipelineGeneration = psD->generation;
2200
2201 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2203 cmd.args.bindComputePipeline.ps = psD;
2204 }
2205}
2206
2208{
2211
2212 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2214 cmd.args.dispatch.x = UINT(x);
2215 cmd.args.dispatch.y = UINT(y);
2216 cmd.args.dispatch.z = UINT(z);
2217}
2218
2219static inline QPair<int, int> mapBinding(int binding,
2220 int stageIndex,
2221 const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
2222{
2223 const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
2224 if (!map || map->isEmpty())
2225 return { binding, binding }; // assume 1:1 mapping
2226
2227 auto it = map->constFind(binding);
2228 if (it != map->cend())
2229 return *it;
2230
2231 // Hitting this path is normal too. It is not given that the resource is
2232 // present in the shaders for all the stages specified by the visibility
2233 // mask in the QRhiShaderResourceBinding.
2234 return { -1, -1 };
2235}
2236
2238 const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
2239{
2240 srbD->vsUniformBufferBatches.clear();
2241 srbD->hsUniformBufferBatches.clear();
2242 srbD->dsUniformBufferBatches.clear();
2243 srbD->gsUniformBufferBatches.clear();
2244 srbD->fsUniformBufferBatches.clear();
2245 srbD->csUniformBufferBatches.clear();
2246
2247 srbD->vsSamplerBatches.clear();
2248 srbD->hsSamplerBatches.clear();
2249 srbD->dsSamplerBatches.clear();
2250 srbD->gsSamplerBatches.clear();
2251 srbD->fsSamplerBatches.clear();
2252 srbD->csSamplerBatches.clear();
2253
2254 srbD->csUavBatches.clear();
2255
2256 struct Stage {
2257 struct Buffer {
2258 int binding; // stored and sent along in XXorigbindings just for applyDynamicOffsets()
2259 int breg; // b0, b1, ...
2260 ID3D11Buffer *buffer;
2261 uint offsetInConstants;
2262 uint sizeInConstants;
2263 };
2264 struct Texture {
2265 int treg; // t0, t1, ...
2266 ID3D11ShaderResourceView *srv;
2267 };
2268 struct Sampler {
2269 int sreg; // s0, s1, ...
2270 ID3D11SamplerState *sampler;
2271 };
2272 struct Uav {
2273 int ureg;
2274 ID3D11UnorderedAccessView *uav;
2275 };
2276 QVarLengthArray<Buffer, 8> buffers;
2277 QVarLengthArray<Texture, 8> textures;
2278 QVarLengthArray<Sampler, 8> samplers;
2279 QVarLengthArray<Uav, 8> uavs;
2280 void buildBufferBatches(QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches) const
2281 {
2282 for (const Buffer &buf : buffers) {
2283 batches.ubufs.feed(buf.breg, buf.buffer);
2284 batches.ubuforigbindings.feed(buf.breg, UINT(buf.binding));
2285 batches.ubufoffsets.feed(buf.breg, buf.offsetInConstants);
2286 batches.ubufsizes.feed(buf.breg, buf.sizeInConstants);
2287 }
2288 batches.finish();
2289 }
2290 void buildSamplerBatches(QD3D11ShaderResourceBindings::StageSamplerBatches &batches) const
2291 {
2292 for (const Texture &t : textures)
2293 batches.shaderresources.feed(t.treg, t.srv);
2294 for (const Sampler &s : samplers)
2295 batches.samplers.feed(s.sreg, s.sampler);
2296 batches.finish();
2297 }
2298 void buildUavBatches(QD3D11ShaderResourceBindings::StageUavBatches &batches) const
2299 {
2300 for (const Stage::Uav &u : uavs)
2301 batches.uavs.feed(u.ureg, u.uav);
2302 batches.finish();
2303 }
2305
2306 for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
2307 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
2308 QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
2309 switch (b->type) {
2311 {
2312 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
2313 Q_ASSERT(aligned(b->u.ubuf.offset, 256u) == b->u.ubuf.offset);
2314 bd.ubuf.id = bufD->m_id;
2315 bd.ubuf.generation = bufD->generation;
2316 // Dynamic ubuf offsets are not considered here, those are baked in
2317 // at a later stage, which is good as vsubufoffsets and friends are
2318 // per-srb, not per-setShaderResources call. Other backends (GL,
2319 // Metal) are different in this respect since those do not store
2320 // per-srb vsubufoffsets etc. data so life's a bit easier for them.
2321 // But here we have to defer baking in the dynamic offset.
2322 const quint32 offsetInConstants = b->u.ubuf.offset / 16;
2323 // size must be 16 mult. (in constants, i.e. multiple of 256 bytes).
2324 // We can round up if needed since the buffers's actual size
2325 // (ByteWidth) is always a multiple of 256.
2326 const quint32 sizeInConstants = aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256u) / 16;
2327 if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
2328 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
2329 if (nativeBinding.first >= 0)
2330 res[RBM_VERTEX].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2331 }
2333 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps);
2334 if (nativeBinding.first >= 0)
2335 res[RBM_HULL].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2336 }
2338 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps);
2339 if (nativeBinding.first >= 0)
2340 res[RBM_DOMAIN].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2341 }
2342 if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) {
2343 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps);
2344 if (nativeBinding.first >= 0)
2345 res[RBM_GEOMETRY].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2346 }
2347 if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
2348 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
2349 if (nativeBinding.first >= 0)
2350 res[RBM_FRAGMENT].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2351 }
2352 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2353 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2354 if (nativeBinding.first >= 0)
2355 res[RBM_COMPUTE].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2356 }
2357 }
2358 break;
2362 {
2364 bd.stex.count = data->count;
2365 const QPair<int, int> nativeBindingVert = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
2366 const QPair<int, int> nativeBindingHull = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps);
2367 const QPair<int, int> nativeBindingDomain = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps);
2368 const QPair<int, int> nativeBindingGeom = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps);
2369 const QPair<int, int> nativeBindingFrag = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
2370 const QPair<int, int> nativeBindingComp = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2371 // if SPIR-V binding b is mapped to tN and sN in HLSL, and it
2372 // is an array, then it will use tN, tN+1, tN+2, ..., and sN,
2373 // sN+1, sN+2, ...
2374 for (int elem = 0; elem < data->count; ++elem) {
2375 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
2376 QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
2377 bd.stex.d[elem].texId = texD ? texD->m_id : 0;
2378 bd.stex.d[elem].texGeneration = texD ? texD->generation : 0;
2379 bd.stex.d[elem].samplerId = samplerD ? samplerD->m_id : 0;
2380 bd.stex.d[elem].samplerGeneration = samplerD ? samplerD->generation : 0;
2381 // Must handle all three cases (combined, separate, separate):
2382 // first = texture binding, second = sampler binding
2383 // first = texture binding
2384 // first = sampler binding
2385 if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
2386 const int samplerBinding = texD && samplerD ? nativeBindingVert.second
2387 : (samplerD ? nativeBindingVert.first : -1);
2388 if (nativeBindingVert.first >= 0 && texD)
2389 res[RBM_VERTEX].textures.append({ nativeBindingVert.first + elem, texD->srv });
2390 if (samplerBinding >= 0)
2391 res[RBM_VERTEX].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2392 }
2394 const int samplerBinding = texD && samplerD ? nativeBindingHull.second
2395 : (samplerD ? nativeBindingHull.first : -1);
2396 if (nativeBindingHull.first >= 0 && texD)
2397 res[RBM_HULL].textures.append({ nativeBindingHull.first + elem, texD->srv });
2398 if (samplerBinding >= 0)
2399 res[RBM_HULL].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2400 }
2402 const int samplerBinding = texD && samplerD ? nativeBindingDomain.second
2403 : (samplerD ? nativeBindingDomain.first : -1);
2404 if (nativeBindingDomain.first >= 0 && texD)
2405 res[RBM_DOMAIN].textures.append({ nativeBindingDomain.first + elem, texD->srv });
2406 if (samplerBinding >= 0)
2407 res[RBM_DOMAIN].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2408 }
2409 if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) {
2410 const int samplerBinding = texD && samplerD ? nativeBindingGeom.second
2411 : (samplerD ? nativeBindingGeom.first : -1);
2412 if (nativeBindingGeom.first >= 0 && texD)
2413 res[RBM_GEOMETRY].textures.append({ nativeBindingGeom.first + elem, texD->srv });
2414 if (samplerBinding >= 0)
2415 res[RBM_GEOMETRY].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2416 }
2417 if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
2418 const int samplerBinding = texD && samplerD ? nativeBindingFrag.second
2419 : (samplerD ? nativeBindingFrag.first : -1);
2420 if (nativeBindingFrag.first >= 0 && texD)
2421 res[RBM_FRAGMENT].textures.append({ nativeBindingFrag.first + elem, texD->srv });
2422 if (samplerBinding >= 0)
2423 res[RBM_FRAGMENT].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2424 }
2425 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2426 const int samplerBinding = texD && samplerD ? nativeBindingComp.second
2427 : (samplerD ? nativeBindingComp.first : -1);
2428 if (nativeBindingComp.first >= 0 && texD)
2429 res[RBM_COMPUTE].textures.append({ nativeBindingComp.first + elem, texD->srv });
2430 if (samplerBinding >= 0)
2431 res[RBM_COMPUTE].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2432 }
2433 }
2434 }
2435 break;
2439 {
2440 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex);
2441 bd.simage.id = texD->m_id;
2442 bd.simage.generation = texD->generation;
2443 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2444 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2445 if (nativeBinding.first >= 0) {
2446 ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level);
2447 if (uav)
2448 res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
2449 }
2450 } else {
2451 qWarning("Unordered access only supported at compute stage");
2452 }
2453 }
2454 break;
2458 {
2459 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf);
2460 bd.sbuf.id = bufD->m_id;
2461 bd.sbuf.generation = bufD->generation;
2462 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2463 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2464 if (nativeBinding.first >= 0) {
2465 ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(b->u.sbuf.offset);
2466 if (uav)
2467 res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
2468 }
2469 } else {
2470 qWarning("Unordered access only supported at compute stage");
2471 }
2472 }
2473 break;
2474 default:
2475 Q_UNREACHABLE();
2476 break;
2477 }
2478 }
2479
2480 // QRhiBatchedBindings works with the native bindings and expects
2481 // sorted input. The pre-sorted QRhiShaderResourceBinding list (based
2482 // on the QRhi (SPIR-V) binding) is not helpful in this regard, so we
2483 // have to sort here every time.
2484 for (int stage = 0; stage < RBM_SUPPORTED_STAGES; ++stage) {
2485 std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) {
2486 return a.breg < b.breg;
2487 });
2488 std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) {
2489 return a.treg < b.treg;
2490 });
2491 std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) {
2492 return a.sreg < b.sreg;
2493 });
2494 std::sort(res[stage].uavs.begin(), res[stage].uavs.end(), [](const Stage::Uav &a, const Stage::Uav &b) {
2495 return a.ureg < b.ureg;
2496 });
2497 }
2498
2499 res[RBM_VERTEX].buildBufferBatches(srbD->vsUniformBufferBatches);
2500 res[RBM_HULL].buildBufferBatches(srbD->hsUniformBufferBatches);
2501 res[RBM_DOMAIN].buildBufferBatches(srbD->dsUniformBufferBatches);
2502 res[RBM_GEOMETRY].buildBufferBatches(srbD->gsUniformBufferBatches);
2503 res[RBM_FRAGMENT].buildBufferBatches(srbD->fsUniformBufferBatches);
2504 res[RBM_COMPUTE].buildBufferBatches(srbD->csUniformBufferBatches);
2505
2506 res[RBM_VERTEX].buildSamplerBatches(srbD->vsSamplerBatches);
2507 res[RBM_HULL].buildSamplerBatches(srbD->hsSamplerBatches);
2508 res[RBM_DOMAIN].buildSamplerBatches(srbD->dsSamplerBatches);
2509 res[RBM_GEOMETRY].buildSamplerBatches(srbD->gsSamplerBatches);
2510 res[RBM_FRAGMENT].buildSamplerBatches(srbD->fsSamplerBatches);
2511 res[RBM_COMPUTE].buildSamplerBatches(srbD->csSamplerBatches);
2512
2513 res[RBM_COMPUTE].buildUavBatches(srbD->csUavBatches);
2514}
2515
2517{
2518 if (!bufD->hasPendingDynamicUpdates || bufD->m_size < 1)
2519 return;
2520
2521 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
2522 bufD->hasPendingDynamicUpdates = false;
2523 D3D11_MAPPED_SUBRESOURCE mp;
2524 HRESULT hr = context->Map(bufD->buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
2525 if (SUCCEEDED(hr)) {
2526 memcpy(mp.pData, bufD->dynBuf, bufD->m_size);
2527 context->Unmap(bufD->buffer, 0);
2528 } else {
2529 qWarning("Failed to map buffer: %s",
2530 qPrintable(QSystemError::windowsComString(hr)));
2531 }
2532}
2533
2535 int batchIndex,
2536 const QRhiBatchedBindings<UINT> *originalBindings,
2537 const QRhiBatchedBindings<UINT> *staticOffsets,
2538 const uint *dynOfsPairs, int dynOfsPairCount)
2539{
2540 const int count = staticOffsets->batches[batchIndex].resources.count();
2541 // Make a copy of the offset list, the entries that have no corresponding
2542 // dynamic offset will continue to use the existing offset value.
2543 for (int b = 0; b < count; ++b) {
2544 offsets[b] = staticOffsets->batches[batchIndex].resources[b];
2545 for (int di = 0; di < dynOfsPairCount; ++di) {
2546 const uint binding = dynOfsPairs[2 * di];
2547 // binding is the SPIR-V style binding point here, nothing to do
2548 // with the native one.
2549 if (binding == originalBindings->batches[batchIndex].resources[b]) {
2550 const uint offsetInConstants = dynOfsPairs[2 * di + 1];
2551 offsets[b] = offsetInConstants;
2552 break;
2553 }
2554 }
2555 }
2556}
2557
2558static inline uint clampedResourceCount(uint startSlot, int countSlots, uint maxSlots, const char *resType)
2559{
2560 if (startSlot + countSlots > maxSlots) {
2561 qWarning("Not enough D3D11 %s slots to bind %d resources starting at slot %d, max slots is %d",
2562 resType, countSlots, startSlot, maxSlots);
2563 countSlots = maxSlots > startSlot ? maxSlots - startSlot : 0;
2564 }
2565 return countSlots;
2566}
2567
2568#define SETUBUFBATCH(stagePrefixL, stagePrefixU) \
2569 if (srbD->stagePrefixL##UniformBufferBatches.present) { \
2570 const QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches(srbD->stagePrefixL##UniformBufferBatches); \
2571 for (int i = 0, ie = batches.ubufs.batches.count(); i != ie; ++i) { \
2572 const uint count = clampedResourceCount(batches.ubufs.batches[i].startBinding, \
2573 batches.ubufs.batches[i].resources.count(), \
2574 D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, \
2575 #stagePrefixU " cbuf"); \
2576 if (count) { \
2577 if (!dynOfsPairCount) { \
2578 context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \
2579 count, \
2580 batches.ubufs.batches[i].resources.constData(), \
2581 batches.ubufoffsets.batches[i].resources.constData(), \
2582 batches.ubufsizes.batches[i].resources.constData()); \
2583 } else { \
2584 applyDynamicOffsets(offsets, i, \
2585 &batches.ubuforigbindings, &batches.ubufoffsets, \
2586 dynOfsPairs, dynOfsPairCount); \
2587 context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \
2588 count, \
2589 batches.ubufs.batches[i].resources.constData(), \
2590 offsets, \
2591 batches.ubufsizes.batches[i].resources.constData()); \
2592 } \
2593 } \
2594 } \
2595 }
2596
2597#define SETSAMPLERBATCH(stagePrefixL, stagePrefixU) \
2598 if (srbD->stagePrefixL##SamplerBatches.present) { \
2599 for (const auto &batch : srbD->stagePrefixL##SamplerBatches.samplers.batches) { \
2600 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2601 D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, #stagePrefixU " sampler"); \
2602 if (count) \
2603 context->stagePrefixU##SetSamplers(batch.startBinding, count, batch.resources.constData()); \
2604 } \
2605 for (const auto &batch : srbD->stagePrefixL##SamplerBatches.shaderresources.batches) { \
2606 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2607 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, #stagePrefixU " SRV"); \
2608 if (count) { \
2609 context->stagePrefixU##SetShaderResources(batch.startBinding, count, batch.resources.constData()); \
2610 contextState.stagePrefixL##HighestActiveSrvBinding = qMax(contextState.stagePrefixL##HighestActiveSrvBinding, \
2611 int(batch.startBinding + count) - 1); \
2612 } \
2613 } \
2614 }
2615
2616#define SETUAVBATCH(stagePrefixL, stagePrefixU) \
2617 if (srbD->stagePrefixL##UavBatches.present) { \
2618 for (const auto &batch : srbD->stagePrefixL##UavBatches.uavs.batches) { \
2619 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2620 D3D11_1_UAV_SLOT_COUNT, #stagePrefixU " UAV"); \
2621 if (count) { \
2622 context->stagePrefixU##SetUnorderedAccessViews(batch.startBinding, \
2623 count, \
2624 batch.resources.constData(), \
2625 nullptr); \
2626 contextState.stagePrefixL##HighestActiveUavBinding = qMax(contextState.stagePrefixL##HighestActiveUavBinding, \
2627 int(batch.startBinding + count) - 1); \
2628 } \
2629 } \
2630 }
2631
2633 const uint *dynOfsPairs, int dynOfsPairCount,
2634 bool offsetOnlyChange)
2635{
2637
2638 SETUBUFBATCH(vs, VS)
2639 SETUBUFBATCH(hs, HS)
2640 SETUBUFBATCH(ds, DS)
2641 SETUBUFBATCH(gs, GS)
2642 SETUBUFBATCH(fs, PS)
2643 SETUBUFBATCH(cs, CS)
2644
2645 if (!offsetOnlyChange) {
2646 SETSAMPLERBATCH(vs, VS)
2647 SETSAMPLERBATCH(hs, HS)
2648 SETSAMPLERBATCH(ds, DS)
2649 SETSAMPLERBATCH(gs, GS)
2650 SETSAMPLERBATCH(fs, PS)
2651 SETSAMPLERBATCH(cs, CS)
2652
2653 SETUAVBATCH(cs, CS)
2654 }
2655}
2656
2658{
2659 // Output cannot be bound on input etc.
2660
2661 if (contextState.vsHasIndexBufferBound) {
2662 context->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
2663 contextState.vsHasIndexBufferBound = false;
2664 }
2665
2666 if (contextState.vsHighestActiveVertexBufferBinding >= 0) {
2667 const int count = contextState.vsHighestActiveVertexBufferBinding + 1;
2668 QVarLengthArray<ID3D11Buffer *, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nullbufs(count);
2669 for (int i = 0; i < count; ++i)
2670 nullbufs[i] = nullptr;
2671 QVarLengthArray<UINT, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nullstrides(count);
2672 for (int i = 0; i < count; ++i)
2673 nullstrides[i] = 0;
2674 QVarLengthArray<UINT, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nulloffsets(count);
2675 for (int i = 0; i < count; ++i)
2676 nulloffsets[i] = 0;
2677 context->IASetVertexBuffers(0, UINT(count), nullbufs.constData(), nullstrides.constData(), nulloffsets.constData());
2678 contextState.vsHighestActiveVertexBufferBinding = -1;
2679 }
2680
2681 int nullsrvCount = qMax(contextState.vsHighestActiveSrvBinding, contextState.fsHighestActiveSrvBinding);
2682 nullsrvCount = qMax(nullsrvCount, contextState.hsHighestActiveSrvBinding);
2683 nullsrvCount = qMax(nullsrvCount, contextState.dsHighestActiveSrvBinding);
2684 nullsrvCount = qMax(nullsrvCount, contextState.gsHighestActiveSrvBinding);
2685 nullsrvCount = qMax(nullsrvCount, contextState.csHighestActiveSrvBinding);
2686 nullsrvCount += 1;
2687 if (nullsrvCount > 0) {
2688 QVarLengthArray<ID3D11ShaderResourceView *,
2689 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nullsrvs(nullsrvCount);
2690 for (int i = 0; i < nullsrvs.count(); ++i)
2691 nullsrvs[i] = nullptr;
2692 if (contextState.vsHighestActiveSrvBinding >= 0) {
2693 context->VSSetShaderResources(0, UINT(contextState.vsHighestActiveSrvBinding + 1), nullsrvs.constData());
2694 contextState.vsHighestActiveSrvBinding = -1;
2695 }
2696 if (contextState.hsHighestActiveSrvBinding >= 0) {
2697 context->HSSetShaderResources(0, UINT(contextState.hsHighestActiveSrvBinding + 1), nullsrvs.constData());
2698 contextState.hsHighestActiveSrvBinding = -1;
2699 }
2700 if (contextState.dsHighestActiveSrvBinding >= 0) {
2701 context->DSSetShaderResources(0, UINT(contextState.dsHighestActiveSrvBinding + 1), nullsrvs.constData());
2702 contextState.dsHighestActiveSrvBinding = -1;
2703 }
2704 if (contextState.gsHighestActiveSrvBinding >= 0) {
2705 context->GSSetShaderResources(0, UINT(contextState.gsHighestActiveSrvBinding + 1), nullsrvs.constData());
2706 contextState.gsHighestActiveSrvBinding = -1;
2707 }
2708 if (contextState.fsHighestActiveSrvBinding >= 0) {
2709 context->PSSetShaderResources(0, UINT(contextState.fsHighestActiveSrvBinding + 1), nullsrvs.constData());
2710 contextState.fsHighestActiveSrvBinding = -1;
2711 }
2712 if (contextState.csHighestActiveSrvBinding >= 0) {
2713 context->CSSetShaderResources(0, UINT(contextState.csHighestActiveSrvBinding + 1), nullsrvs.constData());
2714 contextState.csHighestActiveSrvBinding = -1;
2715 }
2716 }
2717
2718 if (contextState.csHighestActiveUavBinding >= 0) {
2719 const int nulluavCount = contextState.csHighestActiveUavBinding + 1;
2720 QVarLengthArray<ID3D11UnorderedAccessView *,
2721 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nulluavs(nulluavCount);
2722 for (int i = 0; i < nulluavCount; ++i)
2723 nulluavs[i] = nullptr;
2724 context->CSSetUnorderedAccessViews(0, UINT(nulluavCount), nulluavs.constData(), nullptr);
2725 contextState.csHighestActiveUavBinding = -1;
2726 }
2727}
2728
2729#define SETSHADER(StageL, StageU) \
2730 if (psD->StageL.shader) { \
2731 context->StageU##SetShader(psD->StageL.shader, nullptr, 0); \
2732 currentShaderMask |= StageU##MaskBit; \
2733 } else if (currentShaderMask & StageU##MaskBit) { \
2734 context->StageU##SetShader(nullptr, nullptr, 0); \
2735 currentShaderMask &= ~StageU##MaskBit; \
2736 }
2737
2739{
2740 quint32 stencilRef = 0;
2741 float blendConstants[] = { 1, 1, 1, 1 };
2742 enum ActiveShaderMask {
2743 VSMaskBit = 0x01,
2744 HSMaskBit = 0x02,
2745 DSMaskBit = 0x04,
2746 GSMaskBit = 0x08,
2747 PSMaskBit = 0x10
2748 };
2749 int currentShaderMask = 0xFF;
2750
2751 for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) {
2752 const QD3D11CommandBuffer::Command &cmd(*it);
2753 switch (cmd.cmd) {
2755 if (cmd.args.beginFrame.tsDisjointQuery)
2756 context->Begin(cmd.args.beginFrame.tsDisjointQuery);
2757 if (cmd.args.beginFrame.tsQuery) {
2758 if (cmd.args.beginFrame.swapchainData) {
2759 // The timestamps seem to include vsync time with Present(1), except
2760 // when running on a non-primary gpu. This is not ideal. So try working
2761 // it around by issuing a semi-fake OMSetRenderTargets early and
2762 // writing the first timestamp only afterwards.
2763 QD3D11RenderTargetData *rtD = cmd.args.beginFrame.swapchainData;
2764 context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
2765 }
2766 context->End(cmd.args.beginFrame.tsQuery); // no Begin() for D3D11_QUERY_TIMESTAMP
2767 }
2768 break;
2770 if (cmd.args.endFrame.tsQuery)
2771 context->End(cmd.args.endFrame.tsQuery);
2772 if (cmd.args.endFrame.tsDisjointQuery)
2773 context->End(cmd.args.endFrame.tsDisjointQuery);
2774 break;
2777 break;
2779 {
2780 QD3D11RenderTargetData *rtD = rtData(cmd.args.setRenderTarget.rt);
2781 context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
2782 }
2783 break;
2785 {
2786 QD3D11RenderTargetData *rtD = rtData(cmd.args.clear.rt);
2787 if (cmd.args.clear.mask & QD3D11CommandBuffer::Command::Color) {
2788 for (int i = 0; i < rtD->colorAttCount; ++i)
2789 context->ClearRenderTargetView(rtD->rtv[i], cmd.args.clear.c);
2790 }
2791 uint ds = 0;
2792 if (cmd.args.clear.mask & QD3D11CommandBuffer::Command::Depth)
2793 ds |= D3D11_CLEAR_DEPTH;
2794 if (cmd.args.clear.mask & QD3D11CommandBuffer::Command::Stencil)
2795 ds |= D3D11_CLEAR_STENCIL;
2796 if (ds)
2797 context->ClearDepthStencilView(rtD->dsv, ds, cmd.args.clear.d, UINT8(cmd.args.clear.s));
2798 }
2799 break;
2801 {
2802 D3D11_VIEWPORT v;
2803 v.TopLeftX = cmd.args.viewport.x;
2804 v.TopLeftY = cmd.args.viewport.y;
2805 v.Width = cmd.args.viewport.w;
2806 v.Height = cmd.args.viewport.h;
2807 v.MinDepth = cmd.args.viewport.d0;
2808 v.MaxDepth = cmd.args.viewport.d1;
2809 context->RSSetViewports(1, &v);
2810 }
2811 break;
2813 {
2814 D3D11_RECT r;
2815 r.left = cmd.args.scissor.x;
2816 r.top = cmd.args.scissor.y;
2817 // right and bottom are exclusive
2818 r.right = cmd.args.scissor.x + cmd.args.scissor.w;
2819 r.bottom = cmd.args.scissor.y + cmd.args.scissor.h;
2820 context->RSSetScissorRects(1, &r);
2821 }
2822 break;
2824 contextState.vsHighestActiveVertexBufferBinding = qMax<int>(
2825 contextState.vsHighestActiveVertexBufferBinding,
2826 cmd.args.bindVertexBuffers.startSlot + cmd.args.bindVertexBuffers.slotCount - 1);
2827 context->IASetVertexBuffers(UINT(cmd.args.bindVertexBuffers.startSlot),
2828 UINT(cmd.args.bindVertexBuffers.slotCount),
2829 cmd.args.bindVertexBuffers.buffers,
2830 cmd.args.bindVertexBuffers.strides,
2831 cmd.args.bindVertexBuffers.offsets);
2832 break;
2834 contextState.vsHasIndexBufferBound = true;
2835 context->IASetIndexBuffer(cmd.args.bindIndexBuffer.buffer,
2836 cmd.args.bindIndexBuffer.format,
2837 cmd.args.bindIndexBuffer.offset);
2838 break;
2840 {
2841 QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps;
2842 SETSHADER(vs, VS)
2843 SETSHADER(hs, HS)
2844 SETSHADER(ds, DS)
2845 SETSHADER(gs, GS)
2846 SETSHADER(fs, PS)
2847 context->IASetPrimitiveTopology(psD->d3dTopology);
2848 context->IASetInputLayout(psD->inputLayout); // may be null, that's ok
2849 context->OMSetDepthStencilState(psD->dsState, stencilRef);
2850 context->OMSetBlendState(psD->blendState, blendConstants, 0xffffffff);
2851 context->RSSetState(psD->rastState);
2852 }
2853 break;
2855 bindShaderResources(cmd.args.bindShaderResources.srb,
2856 cmd.args.bindShaderResources.dynamicOffsetPairs,
2857 cmd.args.bindShaderResources.dynamicOffsetCount,
2858 cmd.args.bindShaderResources.offsetOnlyChange);
2859 break;
2861 stencilRef = cmd.args.stencilRef.ref;
2862 context->OMSetDepthStencilState(cmd.args.stencilRef.ps->dsState, stencilRef);
2863 break;
2865 memcpy(blendConstants, cmd.args.blendConstants.c, 4 * sizeof(float));
2866 context->OMSetBlendState(cmd.args.blendConstants.ps->blendState, blendConstants, 0xffffffff);
2867 break;
2869 if (cmd.args.draw.ps) {
2870 if (cmd.args.draw.instanceCount == 1)
2871 context->Draw(cmd.args.draw.vertexCount, cmd.args.draw.firstVertex);
2872 else
2873 context->DrawInstanced(cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
2874 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
2875 } else {
2876 qWarning("No graphics pipeline active for draw; ignored");
2877 }
2878 break;
2880 if (cmd.args.drawIndexed.ps) {
2881 if (cmd.args.drawIndexed.instanceCount == 1)
2882 context->DrawIndexed(cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.firstIndex,
2883 cmd.args.drawIndexed.vertexOffset);
2884 else
2885 context->DrawIndexedInstanced(cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
2886 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
2887 cmd.args.drawIndexed.firstInstance);
2888 } else {
2889 qWarning("No graphics pipeline active for drawIndexed; ignored");
2890 }
2891 break;
2893 context->UpdateSubresource(cmd.args.updateSubRes.dst, cmd.args.updateSubRes.dstSubRes,
2894 cmd.args.updateSubRes.hasDstBox ? &cmd.args.updateSubRes.dstBox : nullptr,
2895 cmd.args.updateSubRes.src, cmd.args.updateSubRes.srcRowPitch, 0);
2896 break;
2898 context->CopySubresourceRegion(cmd.args.copySubRes.dst, cmd.args.copySubRes.dstSubRes,
2899 cmd.args.copySubRes.dstX, cmd.args.copySubRes.dstY, cmd.args.copySubRes.dstZ,
2900 cmd.args.copySubRes.src, cmd.args.copySubRes.srcSubRes,
2901 cmd.args.copySubRes.hasSrcBox ? &cmd.args.copySubRes.srcBox : nullptr);
2902 break;
2904 context->ResolveSubresource(cmd.args.resolveSubRes.dst, cmd.args.resolveSubRes.dstSubRes,
2905 cmd.args.resolveSubRes.src, cmd.args.resolveSubRes.srcSubRes,
2906 cmd.args.resolveSubRes.format);
2907 break;
2909 context->GenerateMips(cmd.args.genMip.srv);
2910 break;
2912 annotations->BeginEvent(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16()));
2913 break;
2915 annotations->EndEvent();
2916 break;
2918 annotations->SetMarker(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16()));
2919 break;
2921 context->CSSetShader(cmd.args.bindComputePipeline.ps->cs.shader, nullptr, 0);
2922 break;
2924 context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z);
2925 break;
2926 default:
2927 break;
2928 }
2929 }
2930}
2931
2936
2941
2943{
2944 if (!buffer)
2945 return;
2946
2947 buffer->Release();
2948 buffer = nullptr;
2949
2950 delete[] dynBuf;
2951 dynBuf = nullptr;
2952
2953 for (auto it = uavs.begin(), end = uavs.end(); it != end; ++it)
2954 it.value()->Release();
2955 uavs.clear();
2956
2958 if (rhiD)
2959 rhiD->unregisterResource(this);
2960}
2961
2962static inline uint toD3DBufferUsage(QRhiBuffer::UsageFlags usage)
2963{
2964 int u = 0;
2965 if (usage.testFlag(QRhiBuffer::VertexBuffer))
2966 u |= D3D11_BIND_VERTEX_BUFFER;
2967 if (usage.testFlag(QRhiBuffer::IndexBuffer))
2968 u |= D3D11_BIND_INDEX_BUFFER;
2969 if (usage.testFlag(QRhiBuffer::UniformBuffer))
2970 u |= D3D11_BIND_CONSTANT_BUFFER;
2971 if (usage.testFlag(QRhiBuffer::StorageBuffer))
2972 u |= D3D11_BIND_UNORDERED_ACCESS;
2973 return uint(u);
2974}
2975
2977{
2978 if (buffer)
2979 destroy();
2980
2981 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
2982 qWarning("UniformBuffer must always be combined with Dynamic on D3D11");
2983 return false;
2984 }
2985
2986 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
2987 qWarning("StorageBuffer cannot be combined with Dynamic");
2988 return false;
2989 }
2990
2991 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
2992 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
2993
2994 D3D11_BUFFER_DESC desc = {};
2995 desc.ByteWidth = roundedSize;
2996 desc.Usage = m_type == Dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
2997 desc.BindFlags = toD3DBufferUsage(m_usage);
2998 desc.CPUAccessFlags = m_type == Dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
2999 desc.MiscFlags = m_usage.testFlag(QRhiBuffer::StorageBuffer) ? D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS : 0;
3000
3002 HRESULT hr = rhiD->dev->CreateBuffer(&desc, nullptr, &buffer);
3003 if (FAILED(hr)) {
3004 qWarning("Failed to create buffer: %s",
3005 qPrintable(QSystemError::windowsComString(hr)));
3006 return false;
3007 }
3008
3009 if (m_type == Dynamic) {
3010 dynBuf = new char[nonZeroSize];
3012 }
3013
3014 if (!m_objectName.isEmpty())
3015 buffer->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3016
3017 generation += 1;
3018 rhiD->registerResource(this);
3019 return true;
3020}
3021
3023{
3024 if (m_type == Dynamic) {
3026 rhiD->executeBufferHostWrites(this);
3027 }
3028 return { { &buffer }, 1 };
3029}
3030
3032{
3033 // Shortcut the entire buffer update mechanism and allow the client to do
3034 // the host writes directly to the buffer. This will lead to unexpected
3035 // results when combined with QRhiResourceUpdateBatch-based updates for the
3036 // buffer, since dynBuf is left untouched and out of sync, but provides a
3037 // fast path for dynamic buffers that have all their content changed in
3038 // every frame.
3040 D3D11_MAPPED_SUBRESOURCE mp;
3042 HRESULT hr = rhiD->context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
3043 if (FAILED(hr)) {
3044 qWarning("Failed to map buffer: %s",
3045 qPrintable(QSystemError::windowsComString(hr)));
3046 return nullptr;
3047 }
3048 return static_cast<char *>(mp.pData);
3049}
3050
3052{
3054 rhiD->context->Unmap(buffer, 0);
3055}
3056
3058{
3059 auto it = uavs.find(offset);
3060 if (it != uavs.end())
3061 return it.value();
3062
3063 // SPIRV-Cross generated HLSL uses RWByteAddressBuffer
3064 D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
3065 desc.Format = DXGI_FORMAT_R32_TYPELESS;
3066 desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
3067 desc.Buffer.FirstElement = offset / 4u;
3068 desc.Buffer.NumElements = aligned(m_size - offset, 4u) / 4u;
3069 desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
3070
3072 ID3D11UnorderedAccessView *uav = nullptr;
3073 HRESULT hr = rhiD->dev->CreateUnorderedAccessView(buffer, &desc, &uav);
3074 if (FAILED(hr)) {
3075 qWarning("Failed to create UAV: %s",
3076 qPrintable(QSystemError::windowsComString(hr)));
3077 return nullptr;
3078 }
3079
3080 uavs[offset] = uav;
3081 return uav;
3082}
3083
3085 int sampleCount, QRhiRenderBuffer::Flags flags,
3086 QRhiTexture::Format backingFormatHint)
3087 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
3088{
3089}
3090
3095
3097{
3098 if (!tex)
3099 return;
3100
3101 if (dsv) {
3102 dsv->Release();
3103 dsv = nullptr;
3104 }
3105
3106 if (rtv) {
3107 rtv->Release();
3108 rtv = nullptr;
3109 }
3110
3111 tex->Release();
3112 tex = nullptr;
3113
3115 if (rhiD)
3116 rhiD->unregisterResource(this);
3117}
3118
3120{
3121 if (tex)
3122 destroy();
3123
3124 if (m_pixelSize.isEmpty())
3125 return false;
3126
3128 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
3129
3130 D3D11_TEXTURE2D_DESC desc = {};
3131 desc.Width = UINT(m_pixelSize.width());
3132 desc.Height = UINT(m_pixelSize.height());
3133 desc.MipLevels = 1;
3134 desc.ArraySize = 1;
3135 desc.SampleDesc = sampleDesc;
3136 desc.Usage = D3D11_USAGE_DEFAULT;
3137
3138 if (m_type == Color) {
3139 dxgiFormat = m_backingFormatHint == QRhiTexture::UnknownFormat ? DXGI_FORMAT_R8G8B8A8_UNORM
3141 desc.Format = dxgiFormat;
3142 desc.BindFlags = D3D11_BIND_RENDER_TARGET;
3143 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3144 if (FAILED(hr)) {
3145 qWarning("Failed to create color renderbuffer: %s",
3146 qPrintable(QSystemError::windowsComString(hr)));
3147 return false;
3148 }
3149 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
3150 rtvDesc.Format = dxgiFormat;
3151 rtvDesc.ViewDimension = desc.SampleDesc.Count > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS
3152 : D3D11_RTV_DIMENSION_TEXTURE2D;
3153 hr = rhiD->dev->CreateRenderTargetView(tex, &rtvDesc, &rtv);
3154 if (FAILED(hr)) {
3155 qWarning("Failed to create rtv: %s",
3156 qPrintable(QSystemError::windowsComString(hr)));
3157 return false;
3158 }
3159 } else if (m_type == DepthStencil) {
3160 dxgiFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
3161 desc.Format = dxgiFormat;
3162 desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
3163 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3164 if (FAILED(hr)) {
3165 qWarning("Failed to create depth-stencil buffer: %s",
3166 qPrintable(QSystemError::windowsComString(hr)));
3167 return false;
3168 }
3169 D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
3170 dsvDesc.Format = dxgiFormat;
3171 dsvDesc.ViewDimension = desc.SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
3172 : D3D11_DSV_DIMENSION_TEXTURE2D;
3173 hr = rhiD->dev->CreateDepthStencilView(tex, &dsvDesc, &dsv);
3174 if (FAILED(hr)) {
3175 qWarning("Failed to create dsv: %s",
3176 qPrintable(QSystemError::windowsComString(hr)));
3177 return false;
3178 }
3179 } else {
3180 return false;
3181 }
3182
3183 if (!m_objectName.isEmpty())
3184 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3185
3186 generation += 1;
3187 rhiD->registerResource(this);
3188 return true;
3189}
3190
3198
3200 int arraySize, int sampleCount, Flags flags)
3201 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
3202{
3203 for (int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
3204 perLevelViews[i] = nullptr;
3205}
3206
3211
3213{
3214 if (!tex && !tex3D && !tex1D)
3215 return;
3216
3217 if (srv) {
3218 srv->Release();
3219 srv = nullptr;
3220 }
3221
3222 for (int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
3223 if (perLevelViews[i]) {
3224 perLevelViews[i]->Release();
3225 perLevelViews[i] = nullptr;
3226 }
3227 }
3228
3229 if (owns) {
3230 if (tex)
3231 tex->Release();
3232 if (tex3D)
3233 tex3D->Release();
3234 if (tex1D)
3235 tex1D->Release();
3236 }
3237
3238 tex = nullptr;
3239 tex3D = nullptr;
3240 tex1D = nullptr;
3241
3243 if (rhiD)
3244 rhiD->unregisterResource(this);
3245}
3246
3248{
3249 switch (format) {
3251 return DXGI_FORMAT_R16_FLOAT;
3253 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3255 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3257 return DXGI_FORMAT_R32_FLOAT;
3258 default:
3259 Q_UNREACHABLE();
3260 return DXGI_FORMAT_R32_FLOAT;
3261 }
3262}
3263
3265{
3266 switch (format) {
3268 return DXGI_FORMAT_D16_UNORM;
3270 return DXGI_FORMAT_D24_UNORM_S8_UINT;
3272 return DXGI_FORMAT_D24_UNORM_S8_UINT;
3274 return DXGI_FORMAT_D32_FLOAT;
3275 default:
3276 Q_UNREACHABLE();
3277 return DXGI_FORMAT_D32_FLOAT;
3278 }
3279}
3280
3282{
3283 if (tex || tex3D || tex1D)
3284 destroy();
3285
3286 const bool isDepth = isDepthTextureFormat(m_format);
3287 const bool isCube = m_flags.testFlag(CubeMap);
3288 const bool is3D = m_flags.testFlag(ThreeDimensional);
3289 const bool isArray = m_flags.testFlag(TextureArray);
3290 const bool hasMipMaps = m_flags.testFlag(MipMapped);
3291 const bool is1D = m_flags.testFlag(OneDimensional);
3292
3293 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
3294 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
3295
3298 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
3299 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
3300 if (sampleDesc.Count > 1) {
3301 if (isCube) {
3302 qWarning("Cubemap texture cannot be multisample");
3303 return false;
3304 }
3305 if (is3D) {
3306 qWarning("3D texture cannot be multisample");
3307 return false;
3308 }
3309 if (hasMipMaps) {
3310 qWarning("Multisample texture cannot have mipmaps");
3311 return false;
3312 }
3313 }
3314 if (isDepth && hasMipMaps) {
3315 qWarning("Depth texture cannot have mipmaps");
3316 return false;
3317 }
3318 if (isCube && is3D) {
3319 qWarning("Texture cannot be both cube and 3D");
3320 return false;
3321 }
3322 if (isArray && is3D) {
3323 qWarning("Texture cannot be both array and 3D");
3324 return false;
3325 }
3326 if (isCube && is1D) {
3327 qWarning("Texture cannot be both cube and 1D");
3328 return false;
3329 }
3330 if (is1D && is3D) {
3331 qWarning("Texture cannot be both 1D and 3D");
3332 return false;
3333 }
3334 if (m_depth > 1 && !is3D) {
3335 qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
3336 return false;
3337 }
3338 if (m_arraySize > 0 && !isArray) {
3339 qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
3340 return false;
3341 }
3342 if (m_arraySize < 1 && isArray) {
3343 qWarning("Texture is an array but array size is %d", m_arraySize);
3344 return false;
3345 }
3346
3347 if (adjustedSize)
3348 *adjustedSize = size;
3349
3350 return true;
3351}
3352
3354{
3356 const bool isDepth = isDepthTextureFormat(m_format);
3357 const bool isCube = m_flags.testFlag(CubeMap);
3358 const bool is3D = m_flags.testFlag(ThreeDimensional);
3359 const bool isArray = m_flags.testFlag(TextureArray);
3360 const bool is1D = m_flags.testFlag(OneDimensional);
3361
3362 D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3363 srvDesc.Format = isDepth ? toD3DDepthTextureSRVFormat(m_format) : dxgiFormat;
3364 if (isCube) {
3365 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
3366 srvDesc.TextureCube.MipLevels = mipLevelCount;
3367 } else {
3368 if (is1D) {
3369 if (isArray) {
3370 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
3371 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
3372 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3373 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
3374 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
3375 } else {
3376 srvDesc.Texture1DArray.FirstArraySlice = 0;
3377 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
3378 }
3379 } else {
3380 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
3381 srvDesc.Texture1D.MipLevels = mipLevelCount;
3382 }
3383 } else if (isArray) {
3384 if (sampleDesc.Count > 1) {
3385 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
3386 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3387 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
3388 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
3389 } else {
3390 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
3391 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
3392 }
3393 } else {
3394 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
3395 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
3396 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3397 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
3398 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
3399 } else {
3400 srvDesc.Texture2DArray.FirstArraySlice = 0;
3401 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
3402 }
3403 }
3404 } else {
3405 if (sampleDesc.Count > 1) {
3406 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
3407 } else if (is3D) {
3408 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
3409 srvDesc.Texture3D.MipLevels = mipLevelCount;
3410 } else {
3411 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
3412 srvDesc.Texture2D.MipLevels = mipLevelCount;
3413 }
3414 }
3415 }
3416
3417 HRESULT hr = rhiD->dev->CreateShaderResourceView(textureResource(), &srvDesc, &srv);
3418 if (FAILED(hr)) {
3419 qWarning("Failed to create srv: %s",
3420 qPrintable(QSystemError::windowsComString(hr)));
3421 return false;
3422 }
3423
3424 generation += 1;
3425 return true;
3426}
3427
3429{
3430 QSize size;
3431 if (!prepareCreate(&size))
3432 return false;
3433
3434 const bool isDepth = isDepthTextureFormat(m_format);
3435 const bool isCube = m_flags.testFlag(CubeMap);
3436 const bool is3D = m_flags.testFlag(ThreeDimensional);
3437 const bool isArray = m_flags.testFlag(TextureArray);
3438 const bool is1D = m_flags.testFlag(OneDimensional);
3439
3440 uint bindFlags = D3D11_BIND_SHADER_RESOURCE;
3441 uint miscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
3442 if (m_flags.testFlag(RenderTarget)) {
3443 if (isDepth)
3444 bindFlags |= D3D11_BIND_DEPTH_STENCIL;
3445 else
3446 bindFlags |= D3D11_BIND_RENDER_TARGET;
3447 }
3448 if (m_flags.testFlag(UsedWithGenerateMips)) {
3449 if (isDepth) {
3450 qWarning("Depth texture cannot have mipmaps generated");
3451 return false;
3452 }
3453 bindFlags |= D3D11_BIND_RENDER_TARGET;
3454 miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS;
3455 }
3456 if (m_flags.testFlag(UsedWithLoadStore))
3457 bindFlags |= D3D11_BIND_UNORDERED_ACCESS;
3458
3460 if (is1D) {
3461 D3D11_TEXTURE1D_DESC desc = {};
3462 desc.Width = UINT(size.width());
3463 desc.MipLevels = mipLevelCount;
3464 desc.ArraySize = isArray ? UINT(qMax(0, m_arraySize)) : 1;
3465 desc.Format = dxgiFormat;
3466 desc.Usage = D3D11_USAGE_DEFAULT;
3467 desc.BindFlags = bindFlags;
3468 desc.MiscFlags = miscFlags;
3469
3470 HRESULT hr = rhiD->dev->CreateTexture1D(&desc, nullptr, &tex1D);
3471 if (FAILED(hr)) {
3472 qWarning("Failed to create 1D texture: %s",
3473 qPrintable(QSystemError::windowsComString(hr)));
3474 return false;
3475 }
3476 if (!m_objectName.isEmpty())
3477 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()),
3479 } else if (!is3D) {
3480 D3D11_TEXTURE2D_DESC desc = {};
3481 desc.Width = UINT(size.width());
3482 desc.Height = UINT(size.height());
3483 desc.MipLevels = mipLevelCount;
3484 desc.ArraySize = isCube ? 6 : (isArray ? UINT(qMax(0, m_arraySize)) : 1);
3485 desc.Format = dxgiFormat;
3486 desc.SampleDesc = sampleDesc;
3487 desc.Usage = D3D11_USAGE_DEFAULT;
3488 desc.BindFlags = bindFlags;
3489 desc.MiscFlags = miscFlags;
3490
3491 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3492 if (FAILED(hr)) {
3493 qWarning("Failed to create 2D texture: %s",
3494 qPrintable(QSystemError::windowsComString(hr)));
3495 return false;
3496 }
3497 if (!m_objectName.isEmpty())
3498 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3499 } else {
3500 D3D11_TEXTURE3D_DESC desc = {};
3501 desc.Width = UINT(size.width());
3502 desc.Height = UINT(size.height());
3503 desc.Depth = UINT(qMax(1, m_depth));
3504 desc.MipLevels = mipLevelCount;
3505 desc.Format = dxgiFormat;
3506 desc.Usage = D3D11_USAGE_DEFAULT;
3507 desc.BindFlags = bindFlags;
3508 desc.MiscFlags = miscFlags;
3509
3510 HRESULT hr = rhiD->dev->CreateTexture3D(&desc, nullptr, &tex3D);
3511 if (FAILED(hr)) {
3512 qWarning("Failed to create 3D texture: %s",
3513 qPrintable(QSystemError::windowsComString(hr)));
3514 return false;
3515 }
3516 if (!m_objectName.isEmpty())
3517 tex3D->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3518 }
3519
3520 if (!finishCreate())
3521 return false;
3522
3523 owns = true;
3524 rhiD->registerResource(this);
3525 return true;
3526}
3527
3529{
3530 if (!src.object)
3531 return false;
3532
3533 if (!prepareCreate())
3534 return false;
3535
3536 if (m_flags.testFlag(ThreeDimensional))
3537 tex3D = reinterpret_cast<ID3D11Texture3D *>(src.object);
3538 else if (m_flags.testFlags(OneDimensional))
3539 tex1D = reinterpret_cast<ID3D11Texture1D *>(src.object);
3540 else
3541 tex = reinterpret_cast<ID3D11Texture2D *>(src.object);
3542
3543 if (!finishCreate())
3544 return false;
3545
3546 owns = false;
3548 rhiD->registerResource(this);
3549 return true;
3550}
3551
3556
3558{
3559 if (perLevelViews[level])
3560 return perLevelViews[level];
3561
3562 const bool isCube = m_flags.testFlag(CubeMap);
3563 const bool isArray = m_flags.testFlag(TextureArray);
3564 const bool is3D = m_flags.testFlag(ThreeDimensional);
3565 D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
3566 desc.Format = dxgiFormat;
3567 if (isCube) {
3568 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
3569 desc.Texture2DArray.MipSlice = UINT(level);
3570 desc.Texture2DArray.FirstArraySlice = 0;
3571 desc.Texture2DArray.ArraySize = 6;
3572 } else if (isArray) {
3573 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
3574 desc.Texture2DArray.MipSlice = UINT(level);
3575 desc.Texture2DArray.FirstArraySlice = 0;
3576 desc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
3577 } else if (is3D) {
3578 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
3579 desc.Texture3D.MipSlice = UINT(level);
3580 } else {
3581 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
3582 desc.Texture2D.MipSlice = UINT(level);
3583 }
3584
3586 ID3D11UnorderedAccessView *uav = nullptr;
3587 HRESULT hr = rhiD->dev->CreateUnorderedAccessView(textureResource(), &desc, &uav);
3588 if (FAILED(hr)) {
3589 qWarning("Failed to create UAV: %s",
3590 qPrintable(QSystemError::windowsComString(hr)));
3591 return nullptr;
3592 }
3593
3594 perLevelViews[level] = uav;
3595 return uav;
3596}
3597
3600 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
3601{
3602}
3603
3608
3610{
3611 if (!samplerState)
3612 return;
3613
3614 samplerState->Release();
3615 samplerState = nullptr;
3616
3618 if (rhiD)
3619 rhiD->unregisterResource(this);
3620}
3621
3622static inline D3D11_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
3623{
3624 if (minFilter == QRhiSampler::Nearest) {
3625 if (magFilter == QRhiSampler::Nearest) {
3626 if (mipFilter == QRhiSampler::Linear)
3627 return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
3628 else
3629 return D3D11_FILTER_MIN_MAG_MIP_POINT;
3630 } else {
3631 if (mipFilter == QRhiSampler::Linear)
3632 return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
3633 else
3634 return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
3635 }
3636 } else {
3637 if (magFilter == QRhiSampler::Nearest) {
3638 if (mipFilter == QRhiSampler::Linear)
3639 return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
3640 else
3641 return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
3642 } else {
3643 if (mipFilter == QRhiSampler::Linear)
3644 return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
3645 else
3646 return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3647 }
3648 }
3649
3650 Q_UNREACHABLE();
3651 return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
3652}
3653
3654static inline D3D11_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
3655{
3656 switch (m) {
3658 return D3D11_TEXTURE_ADDRESS_WRAP;
3660 return D3D11_TEXTURE_ADDRESS_CLAMP;
3662 return D3D11_TEXTURE_ADDRESS_MIRROR;
3663 default:
3664 Q_UNREACHABLE();
3665 return D3D11_TEXTURE_ADDRESS_CLAMP;
3666 }
3667}
3668
3669static inline D3D11_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
3670{
3671 switch (op) {
3672 case QRhiSampler::Never:
3673 return D3D11_COMPARISON_NEVER;
3674 case QRhiSampler::Less:
3675 return D3D11_COMPARISON_LESS;
3676 case QRhiSampler::Equal:
3677 return D3D11_COMPARISON_EQUAL;
3679 return D3D11_COMPARISON_LESS_EQUAL;
3681 return D3D11_COMPARISON_GREATER;
3683 return D3D11_COMPARISON_NOT_EQUAL;
3685 return D3D11_COMPARISON_GREATER_EQUAL;
3687 return D3D11_COMPARISON_ALWAYS;
3688 default:
3689 Q_UNREACHABLE();
3690 return D3D11_COMPARISON_NEVER;
3691 }
3692}
3693
3695{
3696 if (samplerState)
3697 destroy();
3698
3699 D3D11_SAMPLER_DESC desc = {};
3701 if (m_compareOp != Never)
3702 desc.Filter = D3D11_FILTER(desc.Filter | 0x80);
3703 desc.AddressU = toD3DAddressMode(m_addressU);
3704 desc.AddressV = toD3DAddressMode(m_addressV);
3705 desc.AddressW = toD3DAddressMode(m_addressW);
3706 desc.MaxAnisotropy = 1.0f;
3707 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
3708 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 1000.0f;
3709
3711 HRESULT hr = rhiD->dev->CreateSamplerState(&desc, &samplerState);
3712 if (FAILED(hr)) {
3713 qWarning("Failed to create sampler state: %s",
3714 qPrintable(QSystemError::windowsComString(hr)));
3715 return false;
3716 }
3717
3718 generation += 1;
3719 rhiD->registerResource(this);
3720 return true;
3721}
3722
3723// dummy, no Vulkan-style RenderPass+Framebuffer concept here
3728
3733
3735{
3737 if (rhiD)
3738 rhiD->unregisterResource(this);
3739}
3740
3742{
3743 Q_UNUSED(other);
3744 return true;
3745}
3746
3754
3756{
3757 return {};
3758}
3759
3765
3770
3772{
3773 // nothing to do here
3774}
3775
3780
3782{
3783 return d.dpr;
3784}
3785
3787{
3788 return d.sampleCount;
3789}
3790
3793 Flags flags)
3794 : QRhiTextureRenderTarget(rhi, desc, flags),
3795 d(rhi)
3796{
3798 ownsRtv[i] = false;
3799 rtv[i] = nullptr;
3800 }
3801}
3802
3807
3809{
3810 if (!rtv[0] && !dsv)
3811 return;
3812
3813 if (dsv) {
3814 if (ownsDsv)
3815 dsv->Release();
3816 dsv = nullptr;
3817 }
3818
3820 if (rtv[i]) {
3821 if (ownsRtv[i])
3822 rtv[i]->Release();
3823 rtv[i] = nullptr;
3824 }
3825 }
3826
3828 if (rhiD)
3829 rhiD->unregisterResource(this);
3830}
3831
3839
3841{
3842 if (rtv[0] || dsv)
3843 destroy();
3844
3847 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
3848
3850
3851 d.colorAttCount = 0;
3852 int attIndex = 0;
3853 for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
3854 d.colorAttCount += 1;
3855 const QRhiColorAttachment &colorAtt(*it);
3856 QRhiTexture *texture = colorAtt.texture();
3857 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
3858 Q_ASSERT(texture || rb);
3859 if (texture) {
3861 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
3862 rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
3863 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
3864 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
3865 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
3866 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
3867 rtvDesc.Texture2DArray.ArraySize = 1;
3868 } else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
3869 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
3870 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY;
3871 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
3872 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
3873 rtvDesc.Texture1DArray.ArraySize = 1;
3874 } else {
3875 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D;
3876 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
3877 }
3878 } else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
3879 if (texD->sampleDesc.Count > 1) {
3880 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
3881 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
3882 rtvDesc.Texture2DMSArray.ArraySize = 1;
3883 } else {
3884 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
3885 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
3886 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
3887 rtvDesc.Texture2DArray.ArraySize = 1;
3888 }
3889 } else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
3890 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
3891 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
3892 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
3893 rtvDesc.Texture3D.WSize = 1;
3894 } else {
3895 if (texD->sampleDesc.Count > 1) {
3896 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
3897 } else {
3898 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
3899 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
3900 }
3901 }
3902 HRESULT hr = rhiD->dev->CreateRenderTargetView(texD->textureResource(), &rtvDesc, &rtv[attIndex]);
3903 if (FAILED(hr)) {
3904 qWarning("Failed to create rtv: %s",
3905 qPrintable(QSystemError::windowsComString(hr)));
3906 return false;
3907 }
3908 ownsRtv[attIndex] = true;
3909 if (attIndex == 0) {
3910 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
3911 d.sampleCount = int(texD->sampleDesc.Count);
3912 }
3913 } else if (rb) {
3915 ownsRtv[attIndex] = false;
3916 rtv[attIndex] = rbD->rtv;
3917 if (attIndex == 0) {
3918 d.pixelSize = rbD->pixelSize();
3919 d.sampleCount = int(rbD->sampleDesc.Count);
3920 }
3921 }
3922 }
3923 d.dpr = 1;
3924
3925 if (hasDepthStencil) {
3926 if (m_desc.depthTexture()) {
3927 ownsDsv = true;
3929 D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
3930 dsvDesc.Format = toD3DDepthTextureDSVFormat(depthTexD->format());
3931 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
3932 : D3D11_DSV_DIMENSION_TEXTURE2D;
3933 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
3934 if (depthTexD->sampleDesc.Count > 1) {
3935 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
3936 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
3937 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
3938 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
3939 } else {
3940 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
3941 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
3942 }
3943 } else {
3944 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
3945 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
3946 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
3947 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
3948 } else {
3949 dsvDesc.Texture2DArray.FirstArraySlice = 0;
3950 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
3951 }
3952 }
3953 }
3954 HRESULT hr = rhiD->dev->CreateDepthStencilView(depthTexD->tex, &dsvDesc, &dsv);
3955 if (FAILED(hr)) {
3956 qWarning("Failed to create dsv: %s",
3957 qPrintable(QSystemError::windowsComString(hr)));
3958 return false;
3959 }
3960 if (d.colorAttCount == 0) {
3961 d.pixelSize = depthTexD->pixelSize();
3962 d.sampleCount = int(depthTexD->sampleDesc.Count);
3963 }
3964 } else {
3965 ownsDsv = false;
3967 dsv = depthRbD->dsv;
3968 if (d.colorAttCount == 0) {
3970 d.sampleCount = int(depthRbD->sampleDesc.Count);
3971 }
3972 }
3973 d.dsAttCount = 1;
3974 } else {
3975 d.dsAttCount = 0;
3976 }
3977
3979 d.rtv[i] = i < d.colorAttCount ? rtv[i] : nullptr;
3980
3981 d.dsv = dsv;
3983
3984 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D11Texture, QD3D11RenderBuffer>(m_desc, &d.currentResIdList);
3985
3986 rhiD->registerResource(this);
3987 return true;
3988}
3989
3991{
3992 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(m_desc, d.currentResIdList))
3993 const_cast<QD3D11TextureRenderTarget *>(this)->create();
3994
3995 return d.pixelSize;
3996}
3997
3999{
4000 return d.dpr;
4001}
4002
4004{
4005 return d.sampleCount;
4006}
4007
4012
4017
4019{
4021 boundResourceData.clear();
4022
4024 if (rhiD)
4025 rhiD->unregisterResource(this);
4026}
4027
4029{
4030 if (!sortedBindings.isEmpty())
4031 destroy();
4032
4034 if (!rhiD->sanityCheckShaderResourceBindings(this))
4035 return false;
4036
4037 rhiD->updateLayoutDesc(this);
4038
4039 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
4041
4043
4045 memset(&bd, 0, sizeof(BoundResourceData));
4046
4047 hasDynamicOffset = false;
4050 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
4051 hasDynamicOffset = true;
4052 break;
4053 }
4054 }
4055
4056 generation += 1;
4057 rhiD->registerResource(this, false);
4058 return true;
4059}
4060
4062{
4064 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
4065 if (!flags.testFlag(BindingsAreSorted))
4067
4070 memset(&bd, 0, sizeof(BoundResourceData));
4071
4072 generation += 1;
4073}
4074
4079
4084
4085template<typename T>
4087{
4088 if (s.shader) {
4089 s.shader->Release();
4090 s.shader = nullptr;
4091 }
4092 s.nativeResourceBindingMap.clear();
4093}
4094
4096{
4097 if (!dsState)
4098 return;
4099
4100 dsState->Release();
4101 dsState = nullptr;
4102
4103 if (blendState) {
4104 blendState->Release();
4105 blendState = nullptr;
4106 }
4107
4108 if (inputLayout) {
4109 inputLayout->Release();
4110 inputLayout = nullptr;
4111 }
4112
4113 if (rastState) {
4114 rastState->Release();
4115 rastState = nullptr;
4116 }
4117
4123
4125 if (rhiD)
4126 rhiD->unregisterResource(this);
4127}
4128
4129static inline D3D11_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
4130{
4131 switch (c) {
4133 return D3D11_CULL_NONE;
4135 return D3D11_CULL_FRONT;
4137 return D3D11_CULL_BACK;
4138 default:
4139 Q_UNREACHABLE();
4140 return D3D11_CULL_NONE;
4141 }
4142}
4143
4145{
4146 switch (mode) {
4148 return D3D11_FILL_SOLID;
4150 return D3D11_FILL_WIREFRAME;
4151 default:
4152 Q_UNREACHABLE();
4153 return D3D11_FILL_SOLID;
4154 }
4155}
4156
4157static inline D3D11_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
4158{
4159 switch (op) {
4161 return D3D11_COMPARISON_NEVER;
4163 return D3D11_COMPARISON_LESS;
4165 return D3D11_COMPARISON_EQUAL;
4167 return D3D11_COMPARISON_LESS_EQUAL;
4169 return D3D11_COMPARISON_GREATER;
4171 return D3D11_COMPARISON_NOT_EQUAL;
4173 return D3D11_COMPARISON_GREATER_EQUAL;
4175 return D3D11_COMPARISON_ALWAYS;
4176 default:
4177 Q_UNREACHABLE();
4178 return D3D11_COMPARISON_ALWAYS;
4179 }
4180}
4181
4182static inline D3D11_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
4183{
4184 switch (op) {
4186 return D3D11_STENCIL_OP_ZERO;
4188 return D3D11_STENCIL_OP_KEEP;
4190 return D3D11_STENCIL_OP_REPLACE;
4192 return D3D11_STENCIL_OP_INCR_SAT;
4194 return D3D11_STENCIL_OP_DECR_SAT;
4196 return D3D11_STENCIL_OP_INVERT;
4198 return D3D11_STENCIL_OP_INCR;
4200 return D3D11_STENCIL_OP_DECR;
4201 default:
4202 Q_UNREACHABLE();
4203 return D3D11_STENCIL_OP_KEEP;
4204 }
4205}
4206
4208{
4209 switch (format) {
4211 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4213 return DXGI_FORMAT_R32G32B32_FLOAT;
4215 return DXGI_FORMAT_R32G32_FLOAT;
4217 return DXGI_FORMAT_R32_FLOAT;
4219 return DXGI_FORMAT_R8G8B8A8_UNORM;
4221 return DXGI_FORMAT_R8G8_UNORM;
4223 return DXGI_FORMAT_R8_UNORM;
4225 return DXGI_FORMAT_R32G32B32A32_UINT;
4227 return DXGI_FORMAT_R32G32B32_UINT;
4229 return DXGI_FORMAT_R32G32_UINT;
4231 return DXGI_FORMAT_R32_UINT;
4233 return DXGI_FORMAT_R32G32B32A32_SINT;
4235 return DXGI_FORMAT_R32G32B32_SINT;
4237 return DXGI_FORMAT_R32G32_SINT;
4239 return DXGI_FORMAT_R32_SINT;
4241 // Note: D3D does not support half3. Pass through half3 as half4.
4243 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4245 return DXGI_FORMAT_R16G16_FLOAT;
4247 return DXGI_FORMAT_R16_FLOAT;
4249 // Note: D3D does not support UShort3. Pass through UShort3 as UShort4.
4251 return DXGI_FORMAT_R16G16B16A16_UINT;
4253 return DXGI_FORMAT_R16G16_UINT;
4255 return DXGI_FORMAT_R16_UINT;
4257 // Note: D3D does not support SShort3. Pass through SShort3 as SShort4.
4259 return DXGI_FORMAT_R16G16B16A16_SINT;
4261 return DXGI_FORMAT_R16G16_SINT;
4263 return DXGI_FORMAT_R16_SINT;
4264 default:
4265 Q_UNREACHABLE();
4266 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4267 }
4268}
4269
4270static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t, int patchControlPointCount)
4271{
4272 switch (t) {
4274 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
4276 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
4278 return D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
4280 return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP;
4282 return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
4284 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
4285 return D3D11_PRIMITIVE_TOPOLOGY(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
4286 default:
4287 Q_UNREACHABLE();
4288 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
4289 }
4290}
4291
4292static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
4293{
4294 UINT8 f = 0;
4295 if (c.testFlag(QRhiGraphicsPipeline::R))
4296 f |= D3D11_COLOR_WRITE_ENABLE_RED;
4297 if (c.testFlag(QRhiGraphicsPipeline::G))
4298 f |= D3D11_COLOR_WRITE_ENABLE_GREEN;
4299 if (c.testFlag(QRhiGraphicsPipeline::B))
4300 f |= D3D11_COLOR_WRITE_ENABLE_BLUE;
4301 if (c.testFlag(QRhiGraphicsPipeline::A))
4302 f |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
4303 return f;
4304}
4305
4307{
4308 // SrcBlendAlpha and DstBlendAlpha do not accept *_COLOR. With other APIs
4309 // this is handled internally (so that e.g. VK_BLEND_FACTOR_SRC_COLOR is
4310 // accepted and is in effect equivalent to VK_BLEND_FACTOR_SRC_ALPHA when
4311 // set as an alpha src/dest factor), but for D3D we have to take care of it
4312 // ourselves. Hence the rgb argument.
4313
4314 switch (f) {
4316 return D3D11_BLEND_ZERO;
4318 return D3D11_BLEND_ONE;
4320 return rgb ? D3D11_BLEND_SRC_COLOR : D3D11_BLEND_SRC_ALPHA;
4322 return rgb ? D3D11_BLEND_INV_SRC_COLOR : D3D11_BLEND_INV_SRC_ALPHA;
4324 return rgb ? D3D11_BLEND_DEST_COLOR : D3D11_BLEND_DEST_ALPHA;
4326 return rgb ? D3D11_BLEND_INV_DEST_COLOR : D3D11_BLEND_INV_DEST_ALPHA;
4328 return D3D11_BLEND_SRC_ALPHA;
4330 return D3D11_BLEND_INV_SRC_ALPHA;
4332 return D3D11_BLEND_DEST_ALPHA;
4334 return D3D11_BLEND_INV_DEST_ALPHA;
4337 return D3D11_BLEND_BLEND_FACTOR;
4340 return D3D11_BLEND_INV_BLEND_FACTOR;
4342 return D3D11_BLEND_SRC_ALPHA_SAT;
4344 return rgb ? D3D11_BLEND_SRC1_COLOR : D3D11_BLEND_SRC1_ALPHA;
4346 return rgb ? D3D11_BLEND_INV_SRC1_COLOR : D3D11_BLEND_INV_SRC1_ALPHA;
4348 return D3D11_BLEND_SRC1_ALPHA;
4350 return D3D11_BLEND_INV_SRC1_ALPHA;
4351 default:
4352 Q_UNREACHABLE();
4353 return D3D11_BLEND_ZERO;
4354 }
4355}
4356
4357static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
4358{
4359 switch (op) {
4361 return D3D11_BLEND_OP_ADD;
4363 return D3D11_BLEND_OP_SUBTRACT;
4365 return D3D11_BLEND_OP_REV_SUBTRACT;
4367 return D3D11_BLEND_OP_MIN;
4369 return D3D11_BLEND_OP_MAX;
4370 default:
4371 Q_UNREACHABLE();
4372 return D3D11_BLEND_OP_ADD;
4373 }
4374}
4375
4377{
4378 // taken from the GL backend, use the same mechanism to get a key
4380 keyBuilder.addData(source);
4381 return keyBuilder.result().toHex();
4382}
4383
4385 QString *error, QShaderKey *usedShaderKey)
4386{
4387 QShaderKey key = { QShader::DxbcShader, 50, shaderVariant };
4388 QShaderCode dxbc = shader.shader(key);
4389 if (!dxbc.shader().isEmpty()) {
4390 if (usedShaderKey)
4391 *usedShaderKey = key;
4392 return dxbc.shader();
4393 }
4394
4395 key = { QShader::HlslShader, 50, shaderVariant };
4396 QShaderCode hlslSource = shader.shader(key);
4397 if (hlslSource.shader().isEmpty()) {
4398 qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader;
4399 return QByteArray();
4400 }
4401
4402 if (usedShaderKey)
4403 *usedShaderKey = key;
4404
4405 const char *target;
4406 switch (shader.stage()) {
4408 target = "vs_5_0";
4409 break;
4411 target = "hs_5_0";
4412 break;
4414 target = "ds_5_0";
4415 break;
4417 target = "gs_5_0";
4418 break;
4420 target = "ps_5_0";
4421 break;
4423 target = "cs_5_0";
4424 break;
4425 default:
4426 Q_UNREACHABLE();
4427 return QByteArray();
4428 }
4429
4432 cacheKey.sourceHash = sourceHash(hlslSource.shader());
4433 cacheKey.target = target;
4434 cacheKey.entryPoint = hlslSource.entryPoint();
4435 cacheKey.compileFlags = flags;
4436 auto cacheIt = m_bytecodeCache.constFind(cacheKey);
4437 if (cacheIt != m_bytecodeCache.constEnd())
4438 return cacheIt.value();
4439 }
4440
4441 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
4442 if (d3dCompile == nullptr) {
4443 qWarning("Unable to resolve function D3DCompile()");
4444 return QByteArray();
4445 }
4446
4447 ID3DBlob *bytecode = nullptr;
4448 ID3DBlob *errors = nullptr;
4449 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
4450 nullptr, nullptr, nullptr,
4451 hlslSource.entryPoint().constData(), target, flags, 0, &bytecode, &errors);
4452 if (FAILED(hr) || !bytecode) {
4453 qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
4454 if (errors) {
4455 *error = QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()),
4456 int(errors->GetBufferSize()));
4457 errors->Release();
4458 }
4459 return QByteArray();
4460 }
4461
4463 result.resize(int(bytecode->GetBufferSize()));
4464 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
4465 bytecode->Release();
4466
4469
4470 return result;
4471}
4472
4474{
4475 if (dsState)
4476 destroy();
4477
4479 rhiD->pipelineCreationStart();
4480 if (!rhiD->sanityCheckGraphicsPipeline(this))
4481 return false;
4482
4483 D3D11_RASTERIZER_DESC rastDesc = {};
4484 rastDesc.FillMode = toD3DFillMode(m_polygonMode);
4485 rastDesc.CullMode = toD3DCullMode(m_cullMode);
4486 rastDesc.FrontCounterClockwise = m_frontFace == CCW;
4487 rastDesc.DepthBias = m_depthBias;
4488 rastDesc.SlopeScaledDepthBias = m_slopeScaledDepthBias;
4489 rastDesc.DepthClipEnable = true;
4490 rastDesc.ScissorEnable = m_flags.testFlag(UsesScissor);
4491 rastDesc.MultisampleEnable = rhiD->effectiveSampleDesc(m_sampleCount).Count > 1;
4492 HRESULT hr = rhiD->dev->CreateRasterizerState(&rastDesc, &rastState);
4493 if (FAILED(hr)) {
4494 qWarning("Failed to create rasterizer state: %s",
4495 qPrintable(QSystemError::windowsComString(hr)));
4496 return false;
4497 }
4498
4499 D3D11_DEPTH_STENCIL_DESC dsDesc = {};
4500 dsDesc.DepthEnable = m_depthTest;
4501 dsDesc.DepthWriteMask = m_depthWrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
4502 dsDesc.DepthFunc = toD3DCompareOp(m_depthOp);
4503 dsDesc.StencilEnable = m_stencilTest;
4504 if (m_stencilTest) {
4505 dsDesc.StencilReadMask = UINT8(m_stencilReadMask);
4506 dsDesc.StencilWriteMask = UINT8(m_stencilWriteMask);
4507 dsDesc.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
4508 dsDesc.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
4509 dsDesc.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
4510 dsDesc.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
4511 dsDesc.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
4512 dsDesc.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
4513 dsDesc.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
4514 dsDesc.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
4515 }
4516 hr = rhiD->dev->CreateDepthStencilState(&dsDesc, &dsState);
4517 if (FAILED(hr)) {
4518 qWarning("Failed to create depth-stencil state: %s",
4519 qPrintable(QSystemError::windowsComString(hr)));
4520 return false;
4521 }
4522
4523 D3D11_BLEND_DESC blendDesc = {};
4524 blendDesc.IndependentBlendEnable = m_targetBlends.count() > 1;
4525 for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
4527 D3D11_RENDER_TARGET_BLEND_DESC blend = {};
4528 blend.BlendEnable = b.enable;
4529 blend.SrcBlend = toD3DBlendFactor(b.srcColor, true);
4530 blend.DestBlend = toD3DBlendFactor(b.dstColor, true);
4531 blend.BlendOp = toD3DBlendOp(b.opColor);
4532 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha, false);
4533 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha, false);
4534 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
4535 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
4536 blendDesc.RenderTarget[i] = blend;
4537 }
4538 if (m_targetBlends.isEmpty()) {
4539 D3D11_RENDER_TARGET_BLEND_DESC blend = {};
4540 blend.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
4541 blendDesc.RenderTarget[0] = blend;
4542 }
4543 hr = rhiD->dev->CreateBlendState(&blendDesc, &blendState);
4544 if (FAILED(hr)) {
4545 qWarning("Failed to create blend state: %s",
4546 qPrintable(QSystemError::windowsComString(hr)));
4547 return false;
4548 }
4549
4550 QByteArray vsByteCode;
4551 for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
4552 auto cacheIt = rhiD->m_shaderCache.constFind(shaderStage);
4553 if (cacheIt != rhiD->m_shaderCache.constEnd()) {
4554 switch (shaderStage.type()) {
4556 vs.shader = static_cast<ID3D11VertexShader *>(cacheIt->s);
4557 vs.shader->AddRef();
4558 vsByteCode = cacheIt->bytecode;
4559 vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4560 break;
4562 hs.shader = static_cast<ID3D11HullShader *>(cacheIt->s);
4563 hs.shader->AddRef();
4564 hs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4565 break;
4567 ds.shader = static_cast<ID3D11DomainShader *>(cacheIt->s);
4568 ds.shader->AddRef();
4569 ds.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4570 break;
4572 gs.shader = static_cast<ID3D11GeometryShader *>(cacheIt->s);
4573 gs.shader->AddRef();
4574 gs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4575 break;
4577 fs.shader = static_cast<ID3D11PixelShader *>(cacheIt->s);
4578 fs.shader->AddRef();
4579 fs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4580 break;
4581 default:
4582 break;
4583 }
4584 } else {
4585 QString error;
4586 QShaderKey shaderKey;
4587 UINT compileFlags = 0;
4589 compileFlags |= D3DCOMPILE_DEBUG;
4590
4591 const QByteArray bytecode = rhiD->compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), compileFlags,
4592 &error, &shaderKey);
4593 if (bytecode.isEmpty()) {
4594 qWarning("HLSL shader compilation failed: %s", qPrintable(error));
4595 return false;
4596 }
4597
4598 if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) {
4599 // Use the simplest strategy: too many cached shaders -> drop them all.
4600 rhiD->clearShaderCache();
4601 }
4602
4603 switch (shaderStage.type()) {
4605 hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader);
4606 if (FAILED(hr)) {
4607 qWarning("Failed to create vertex shader: %s",
4608 qPrintable(QSystemError::windowsComString(hr)));
4609 return false;
4610 }
4611 vsByteCode = bytecode;
4612 vs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4613 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap));
4614 vs.shader->AddRef();
4615 break;
4617 hr = rhiD->dev->CreateHullShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &hs.shader);
4618 if (FAILED(hr)) {
4619 qWarning("Failed to create hull shader: %s",
4620 qPrintable(QSystemError::windowsComString(hr)));
4621 return false;
4622 }
4623 hs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4624 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(hs.shader, bytecode, hs.nativeResourceBindingMap));
4625 hs.shader->AddRef();
4626 break;
4628 hr = rhiD->dev->CreateDomainShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &ds.shader);
4629 if (FAILED(hr)) {
4630 qWarning("Failed to create domain shader: %s",
4631 qPrintable(QSystemError::windowsComString(hr)));
4632 return false;
4633 }
4634 ds.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4635 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(ds.shader, bytecode, ds.nativeResourceBindingMap));
4636 ds.shader->AddRef();
4637 break;
4639 hr = rhiD->dev->CreateGeometryShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &gs.shader);
4640 if (FAILED(hr)) {
4641 qWarning("Failed to create geometry shader: %s",
4642 qPrintable(QSystemError::windowsComString(hr)));
4643 return false;
4644 }
4645 gs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4646 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(gs.shader, bytecode, gs.nativeResourceBindingMap));
4647 gs.shader->AddRef();
4648 break;
4650 hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader);
4651 if (FAILED(hr)) {
4652 qWarning("Failed to create pixel shader: %s",
4653 qPrintable(QSystemError::windowsComString(hr)));
4654 return false;
4655 }
4656 fs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4657 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap));
4658 fs.shader->AddRef();
4659 break;
4660 default:
4661 break;
4662 }
4663 }
4664 }
4665
4667
4668 if (!vsByteCode.isEmpty()) {
4669 QByteArrayList matrixSliceSemantics;
4670 QVarLengthArray<D3D11_INPUT_ELEMENT_DESC, 4> inputDescs;
4672 it != itEnd; ++it)
4673 {
4674 D3D11_INPUT_ELEMENT_DESC desc = {};
4675 // The output from SPIRV-Cross uses TEXCOORD<location> as the
4676 // semantic, except for matrices that are unrolled into consecutive
4677 // vec2/3/4s attributes and need TEXCOORD<location>_ as
4678 // SemanticName and row/column index as SemanticIndex.
4679 const int matrixSlice = it->matrixSlice();
4680 if (matrixSlice < 0) {
4681 desc.SemanticName = "TEXCOORD";
4682 desc.SemanticIndex = UINT(it->location());
4683 } else {
4685 sem.resize(16);
4686 qsnprintf(sem.data(), sem.size(), "TEXCOORD%d_", it->location() - matrixSlice);
4687 matrixSliceSemantics.append(sem);
4688 desc.SemanticName = matrixSliceSemantics.last().constData();
4689 desc.SemanticIndex = UINT(matrixSlice);
4690 }
4691 desc.Format = toD3DAttributeFormat(it->format());
4692 desc.InputSlot = UINT(it->binding());
4693 desc.AlignedByteOffset = it->offset();
4694 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
4695 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
4696 desc.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
4697 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
4698 } else {
4699 desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
4700 }
4701 inputDescs.append(desc);
4702 }
4703 if (!inputDescs.isEmpty()) {
4704 hr = rhiD->dev->CreateInputLayout(inputDescs.constData(), UINT(inputDescs.count()),
4705 vsByteCode, SIZE_T(vsByteCode.size()), &inputLayout);
4706 if (FAILED(hr)) {
4707 qWarning("Failed to create input layout: %s",
4708 qPrintable(QSystemError::windowsComString(hr)));
4709 return false;
4710 }
4711 } // else leave inputLayout set to nullptr; that's valid and it avoids a debug layer warning about an input layout with 0 elements
4712 }
4713
4714 rhiD->pipelineCreationEnd();
4715 generation += 1;
4716 rhiD->registerResource(this);
4717 return true;
4718}
4719
4724
4729
4731{
4732 if (!cs.shader)
4733 return;
4734
4735 cs.shader->Release();
4736 cs.shader = nullptr;
4737 cs.nativeResourceBindingMap.clear();
4738
4740 if (rhiD)
4741 rhiD->unregisterResource(this);
4742}
4743
4745{
4746 if (cs.shader)
4747 destroy();
4748
4750 rhiD->pipelineCreationStart();
4751
4752 auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage);
4753 if (cacheIt != rhiD->m_shaderCache.constEnd()) {
4754 cs.shader = static_cast<ID3D11ComputeShader *>(cacheIt->s);
4755 cs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4756 } else {
4757 QString error;
4758 QShaderKey shaderKey;
4759 UINT compileFlags = 0;
4761 compileFlags |= D3DCOMPILE_DEBUG;
4762
4763 const QByteArray bytecode = rhiD->compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), compileFlags,
4764 &error, &shaderKey);
4765 if (bytecode.isEmpty()) {
4766 qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
4767 return false;
4768 }
4769
4770 HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader);
4771 if (FAILED(hr)) {
4772 qWarning("Failed to create compute shader: %s",
4773 qPrintable(QSystemError::windowsComString(hr)));
4774 return false;
4775 }
4776
4777 cs.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
4778
4779 if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES)
4780 rhiD->clearShaderCache();
4781
4782 rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs.shader, bytecode, cs.nativeResourceBindingMap));
4783 }
4784
4785 cs.shader->AddRef();
4786
4787 rhiD->pipelineCreationEnd();
4788 generation += 1;
4789 rhiD->registerResource(this);
4790 return true;
4791}
4792
4798
4803
4805{
4806 // nothing to do here
4807}
4808
4810{
4811 // Creates the query objects if not yet done, but otherwise calling this
4812 // function is expected to be a no-op.
4813
4814 D3D11_QUERY_DESC queryDesc = {};
4815 for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
4816 if (!disjointQuery[i]) {
4817 queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
4818 HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &disjointQuery[i]);
4819 if (FAILED(hr)) {
4820 qWarning("Failed to create timestamp disjoint query: %s",
4821 qPrintable(QSystemError::windowsComString(hr)));
4822 return false;
4823 }
4824 }
4825 queryDesc.Query = D3D11_QUERY_TIMESTAMP;
4826 for (int j = 0; j < 2; ++j) {
4827 const int idx = 2 * i + j;
4828 if (!query[idx]) {
4829 HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &query[idx]);
4830 if (FAILED(hr)) {
4831 qWarning("Failed to create timestamp query: %s",
4832 qPrintable(QSystemError::windowsComString(hr)));
4833 return false;
4834 }
4835 }
4836 }
4837 }
4838 return true;
4839}
4840
4842{
4843 for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
4844 active[i] = false;
4845 if (disjointQuery[i]) {
4846 disjointQuery[i]->Release();
4847 disjointQuery[i] = nullptr;
4848 }
4849 for (int j = 0; j < 2; ++j) {
4850 const int idx = TIMESTAMP_PAIRS * i + j;
4851 if (query[idx]) {
4852 query[idx]->Release();
4853 query[idx] = nullptr;
4854 }
4855 }
4856 }
4857}
4858
4859bool QD3D11SwapChainTimestamps::tryQueryTimestamps(int pairIndex, ID3D11DeviceContext *context, double *elapsedSec)
4860{
4861 bool result = false;
4862 if (!active[pairIndex])
4863 return result;
4864
4865 ID3D11Query *tsDisjoint = disjointQuery[pairIndex];
4866 ID3D11Query *tsStart = query[pairIndex * 2];
4867 ID3D11Query *tsEnd = query[pairIndex * 2 + 1];
4868 quint64 timestamps[2];
4869 D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
4870
4871 bool ok = true;
4872 ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4873 ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4874 ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4875
4876 if (ok) {
4877 if (!dj.Disjoint && dj.Frequency) {
4878 const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
4879 *elapsedSec = elapsedMs / 1000.0;
4880 result = true;
4881 }
4882 active[pairIndex] = false;
4883 } // else leave active set, will retry in a subsequent beginFrame
4884
4885 return result;
4886}
4887
4889 : QRhiSwapChain(rhi), rt(rhi, this), rtRight(rhi, this), cb(rhi)
4890{
4891 backBufferTex = nullptr;
4892 backBufferRtv = nullptr;
4893 for (int i = 0; i < BUFFER_COUNT; ++i) {
4894 msaaTex[i] = nullptr;
4895 msaaRtv[i] = nullptr;
4896 }
4897}
4898
4903
4905{
4906 if (backBufferRtv) {
4907 backBufferRtv->Release();
4908 backBufferRtv = nullptr;
4909 }
4910 if (backBufferRtvRight) {
4911 backBufferRtvRight->Release();
4912 backBufferRtvRight = nullptr;
4913 }
4914 if (backBufferTex) {
4915 backBufferTex->Release();
4916 backBufferTex = nullptr;
4917 }
4918 for (int i = 0; i < BUFFER_COUNT; ++i) {
4919 if (msaaRtv[i]) {
4920 msaaRtv[i]->Release();
4921 msaaRtv[i] = nullptr;
4922 }
4923 if (msaaTex[i]) {
4924 msaaTex[i]->Release();
4925 msaaTex[i] = nullptr;
4926 }
4927 }
4928}
4929
4931{
4932 if (!swapChain)
4933 return;
4934
4936
4938
4939 swapChain->Release();
4940 swapChain = nullptr;
4941
4942 if (dcompVisual) {
4943 dcompVisual->Release();
4944 dcompVisual = nullptr;
4945 }
4946
4947 if (dcompTarget) {
4948 dcompTarget->Release();
4949 dcompTarget = nullptr;
4950 }
4951
4953 if (rhiD) {
4954 rhiD->unregisterResource(this);
4955 // See Deferred Destruction Issues with Flip Presentation Swap Chains in
4956 // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-flush
4957 rhiD->context->Flush();
4958 }
4959}
4960
4965
4970
4975
4977{
4979 return m_window->size() * m_window->devicePixelRatio();
4980}
4981
4983{
4984 if (f == SDR)
4985 return true;
4986
4987 if (!m_window) {
4988 qWarning("Attempted to call isFormatSupported() without a window set");
4989 return false;
4990 }
4991
4993 DXGI_OUTPUT_DESC1 desc1;
4994 if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) {
4995 if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
4997 }
4998
4999 return false;
5000}
5001
5003{
5005 // Must use m_window, not window, given this may be called before createOrResize().
5006 if (m_window) {
5008 DXGI_OUTPUT_DESC1 hdrOutputDesc;
5009 if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
5011 info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
5012 info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
5013 info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits
5014 info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc);
5015 }
5016 }
5017 return info;
5018}
5019
5021{
5024 rhiD->registerResource(rpD, false);
5025 return rpD;
5026}
5027
5028bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
5029 ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const
5030{
5031 D3D11_TEXTURE2D_DESC desc = {};
5032 desc.Width = UINT(size.width());
5033 desc.Height = UINT(size.height());
5034 desc.MipLevels = 1;
5035 desc.ArraySize = 1;
5036 desc.Format = format;
5037 desc.SampleDesc = sampleDesc;
5038 desc.Usage = D3D11_USAGE_DEFAULT;
5039 desc.BindFlags = D3D11_BIND_RENDER_TARGET;
5040
5042 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, tex);
5043 if (FAILED(hr)) {
5044 qWarning("Failed to create color buffer texture: %s",
5045 qPrintable(QSystemError::windowsComString(hr)));
5046 return false;
5047 }
5048
5049 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5050 rtvDesc.Format = format;
5051 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
5052 hr = rhiD->dev->CreateRenderTargetView(*tex, &rtvDesc, rtv);
5053 if (FAILED(hr)) {
5054 qWarning("Failed to create color buffer rtv: %s",
5055 qPrintable(QSystemError::windowsComString(hr)));
5056 (*tex)->Release();
5057 *tex = nullptr;
5058 return false;
5059 }
5060
5061 return true;
5062}
5063
5065{
5066 if (dcompDevice)
5067 return true;
5068
5069 qCDebug(QRHI_LOG_INFO, "Creating Direct Composition device (needed for semi-transparent windows)");
5071 return dcompDevice ? true : false;
5072}
5073
5074static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
5075static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
5076
5078{
5079 // Can be called multiple times due to window resizes - that is not the
5080 // same as a simple destroy+create (as with other resources). Just need to
5081 // resize the buffers then.
5082
5083 const bool needsRegistration = !window || window != m_window;
5084 const bool stereo = m_window->format().stereo();
5085
5086 // except if the window actually changes
5087 if (window && window != m_window)
5088 destroy();
5089
5090 window = m_window;
5093
5094 if (pixelSize.isEmpty())
5095 return false;
5096
5097 HWND hwnd = reinterpret_cast<HWND>(window->winId());
5098 HRESULT hr;
5099
5101
5103 if (!rhiD->useLegacySwapchainModel && rhiD->ensureDirectCompositionDevice()) {
5104 if (!dcompTarget) {
5105 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd, false, &dcompTarget);
5106 if (FAILED(hr)) {
5107 qWarning("Failed to create Direct Compsition target for the window: %s",
5108 qPrintable(QSystemError::windowsComString(hr)));
5109 }
5110 }
5111 if (dcompTarget && !dcompVisual) {
5112 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
5113 if (FAILED(hr)) {
5114 qWarning("Failed to create DirectComposition visual: %s",
5115 qPrintable(QSystemError::windowsComString(hr)));
5116 }
5117 }
5118 }
5119 // simple consistency check
5120 if (window->requestedFormat().alphaBufferSize() <= 0)
5121 qWarning("Swapchain says surface has alpha but the window has no alphaBufferSize set. "
5122 "This may lead to problems.");
5123 }
5124
5125 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
5126 swapChainFlags = 0;
5127
5128 // A non-flip swapchain can do Present(0) as expected without
5129 // ALLOW_TEARING, and ALLOW_TEARING is not compatible with it at all so the
5130 // flag must not be set then. Whereas for flip we should use it, if
5131 // supported, to get better results for 'unthrottled' presentation.
5132 if (swapInterval == 0 && rhiD->supportsAllowTearing)
5133 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
5134
5135 if (!swapChain) {
5136 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
5139
5140 DXGI_COLOR_SPACE_TYPE hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR
5141 DXGI_OUTPUT_DESC1 hdrOutputDesc;
5142 if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
5143 // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
5144 if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
5145 switch (m_format) {
5147 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
5148 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
5150 break;
5151 case HDR10:
5152 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
5153 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
5155 break;
5156 default:
5157 break;
5158 }
5159 } else {
5160 // This happens also when Use HDR is set to Off in the Windows
5161 // Display settings. Show a helpful warning, but continue with the
5162 // default non-HDR format.
5163 qWarning("The output associated with the window is not HDR capable "
5164 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
5165 }
5166 }
5167
5168 // We use a FLIP model swapchain which implies a buffer count of 2
5169 // (as opposed to the old DISCARD with back buffer count == 1).
5170 // This makes no difference for the rest of the stuff except that
5171 // automatic MSAA is unsupported and needs to be implemented via a
5172 // custom multisample render target and an explicit resolve.
5173
5174 DXGI_SWAP_CHAIN_DESC1 desc = {};
5175 desc.Width = UINT(pixelSize.width());
5176 desc.Height = UINT(pixelSize.height());
5177 desc.Format = colorFormat;
5178 desc.SampleDesc.Count = 1;
5179 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5180 desc.BufferCount = BUFFER_COUNT;
5181 desc.Flags = swapChainFlags;
5182 desc.Scaling = rhiD->useLegacySwapchainModel ? DXGI_SCALING_STRETCH : DXGI_SCALING_NONE;
5183 desc.SwapEffect = rhiD->useLegacySwapchainModel ? DXGI_SWAP_EFFECT_DISCARD : DXGI_SWAP_EFFECT_FLIP_DISCARD;
5184 desc.Stereo = stereo;
5185
5186 if (dcompVisual) {
5187 // With DirectComposition setting AlphaMode to STRAIGHT fails the
5188 // swapchain creation, whereas the result seems to be identical
5189 // with any of the other values, including IGNORE. (?)
5190 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
5191
5192 // DirectComposition has its own limitations, cannot use
5193 // SCALING_NONE. So with semi-transparency requested we are forced
5194 // to SCALING_STRETCH.
5195 desc.Scaling = DXGI_SCALING_STRETCH;
5196 }
5197
5198 IDXGIFactory2 *fac = static_cast<IDXGIFactory2 *>(rhiD->dxgiFactory);
5199 IDXGISwapChain1 *sc1;
5200
5201 if (dcompVisual)
5202 hr = fac->CreateSwapChainForComposition(rhiD->dev, &desc, nullptr, &sc1);
5203 else
5204 hr = fac->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc, nullptr, nullptr, &sc1);
5205
5206 // If failed and we tried a HDR format, then try with SDR. This
5207 // matches other backends, such as Vulkan where if the format is
5208 // not supported, the default one is used instead.
5209 if (FAILED(hr) && m_format != SDR) {
5211 desc.Format = DEFAULT_FORMAT;
5212 if (dcompVisual)
5213 hr = fac->CreateSwapChainForComposition(rhiD->dev, &desc, nullptr, &sc1);
5214 else
5215 hr = fac->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc, nullptr, nullptr, &sc1);
5216 }
5217
5218 if (SUCCEEDED(hr)) {
5219 swapChain = sc1;
5220 if (m_format != SDR) {
5221 IDXGISwapChain3 *sc3 = nullptr;
5222 if (SUCCEEDED(sc1->QueryInterface(__uuidof(IDXGISwapChain3), reinterpret_cast<void **>(&sc3)))) {
5223 hr = sc3->SetColorSpace1(hdrColorSpace);
5224 if (FAILED(hr))
5225 qWarning("Failed to set color space on swapchain: %s",
5226 qPrintable(QSystemError::windowsComString(hr)));
5227 sc3->Release();
5228 } else {
5229 qWarning("IDXGISwapChain3 not available, HDR swapchain will not work as expected");
5230 }
5231 }
5232 if (dcompVisual) {
5233 hr = dcompVisual->SetContent(sc1);
5234 if (SUCCEEDED(hr)) {
5235 hr = dcompTarget->SetRoot(dcompVisual);
5236 if (FAILED(hr)) {
5237 qWarning("Failed to associate Direct Composition visual with the target: %s",
5238 qPrintable(QSystemError::windowsComString(hr)));
5239 }
5240 } else {
5241 qWarning("Failed to set content for Direct Composition visual: %s",
5242 qPrintable(QSystemError::windowsComString(hr)));
5243 }
5244 } else {
5245 // disable Alt+Enter; not relevant when using DirectComposition
5246 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
5247 }
5248 }
5249 if (FAILED(hr)) {
5250 qWarning("Failed to create D3D11 swapchain: %s"
5251 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
5252 qPrintable(QSystemError::windowsComString(hr)),
5253 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
5254 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
5255 return false;
5256 }
5257 } else {
5259 // flip model -> buffer count is the real buffer count, not 1 like with the legacy modes
5260 hr = swapChain->ResizeBuffers(UINT(BUFFER_COUNT), UINT(pixelSize.width()), UINT(pixelSize.height()),
5262 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
5263 qWarning("Device loss detected in ResizeBuffers()");
5264 rhiD->deviceLost = true;
5265 return false;
5266 } else if (FAILED(hr)) {
5267 qWarning("Failed to resize D3D11 swapchain: %s",
5268 qPrintable(QSystemError::windowsComString(hr)));
5269 return false;
5270 }
5271 }
5272
5273 // This looks odd (for FLIP_*, esp. compared with backends for Vulkan
5274 // & co.) but the backbuffer is always at index 0, with magic underneath.
5275 // Some explanation from
5276 // https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-1-4-improvements
5277 //
5278 // "In Direct3D 11, applications could call GetBuffer( 0, … ) only once.
5279 // Every call to Present implicitly changed the resource identity of the
5280 // returned interface. Direct3D 12 no longer supports that implicit
5281 // resource identity change, due to the CPU overhead required and the
5282 // flexible resource descriptor design. As a result, the application must
5283 // manually call GetBuffer for every each buffer created with the
5284 // swapchain."
5285
5286 // So just query index 0 once (per resize) and be done with it.
5287 hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&backBufferTex));
5288 if (FAILED(hr)) {
5289 qWarning("Failed to query swapchain backbuffer: %s",
5290 qPrintable(QSystemError::windowsComString(hr)));
5291 return false;
5292 }
5293 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5294 rtvDesc.Format = srgbAdjustedColorFormat;
5295 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
5296 hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtv);
5297 if (FAILED(hr)) {
5298 qWarning("Failed to create rtv for swapchain backbuffer: %s",
5299 qPrintable(QSystemError::windowsComString(hr)));
5300 return false;
5301 }
5302
5303 if (stereo) {
5304 // Create a second render target view for the right eye
5305 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
5306 rtvDesc.Texture2DArray.FirstArraySlice = 1;
5307 rtvDesc.Texture2DArray.ArraySize = 1;
5308 hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtvRight);
5309 if (FAILED(hr)) {
5310 qWarning("Failed to create rtv for swapchain backbuffer (right eye): %s",
5311 qPrintable(QSystemError::windowsComString(hr)));
5312 return false;
5313 }
5314 }
5315
5316 // Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer.
5317 for (int i = 0; i < BUFFER_COUNT; ++i) {
5318 if (sampleDesc.Count > 1) {
5320 return false;
5321 }
5322 }
5323
5325 qWarning("Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
5327 }
5331 if (!m_depthStencil->create())
5332 qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
5334 } else {
5335 qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
5338 }
5339 }
5340
5341 currentFrameSlot = 0;
5342 frameCount = 0;
5344
5345 rt.setRenderPassDescriptor(m_renderPassDesc); // for the public getter in QRhiRenderTarget
5348 rtD->d.pixelSize = pixelSize;
5349 rtD->d.dpr = float(window->devicePixelRatio());
5350 rtD->d.sampleCount = int(sampleDesc.Count);
5351 rtD->d.colorAttCount = 1;
5352 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
5353
5354 if (stereo) {
5357 rtD->d.pixelSize = pixelSize;
5358 rtD->d.dpr = float(window->devicePixelRatio());
5359 rtD->d.sampleCount = int(sampleDesc.Count);
5360 rtD->d.colorAttCount = 1;
5361 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
5362 rtD->d.rtv[0] = backBufferRtvRight;
5363 rtD->d.dsv = ds ? ds->dsv : nullptr;
5364 }
5365
5366 if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps)) {
5367 timestamps.prepare(rhiD);
5368 // timestamp queries are optional so we can go on even if they failed
5369 }
5370
5371 if (needsRegistration)
5372 rhiD->registerResource(this);
5373
5374 return true;
5375}
5376
IOBluetoothDevice * device
\inmodule QtCore
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:107
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1291
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
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:951
\inmodule QtGui
Definition qimage.h:37
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition qimage.cpp:1222
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
const_iterator cend() const
Definition qmap.h:605
const_iterator constFind(const Key &key) const
Definition qmap.h:655
bool isEmpty() const
Definition qmap.h:269
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0, otherwise returns false.
Definition qpoint.h:125
quint32 size() const
Definition qrhi_p.h:357
const char * constData() const
Definition qrhi_p.h:353
\inmodule QtGui
Definition qrhi.h:846
UsageFlags m_usage
Definition qrhi.h:888
Type m_type
Definition qrhi.h:887
Type
Specifies storage type of buffer resource.
Definition qrhi.h:848
@ Dynamic
Definition qrhi.h:851
@ IndexBuffer
Definition qrhi.h:856
@ VertexBuffer
Definition qrhi.h:855
@ UniformBuffer
Definition qrhi.h:857
@ StorageBuffer
Definition qrhi.h:858
quint32 m_size
Definition qrhi.h:889
\inmodule QtGui
Definition qrhi.h:576
QRhiRenderBuffer * renderBuffer() const
Definition qrhi.h:585
int resolveLevel() const
Definition qrhi.h:600
QRhiTexture * texture() const
Definition qrhi.h:582
int resolveLayer() const
Definition qrhi.h:597
QRhiTexture * resolveTexture() const
Definition qrhi.h:594
int level() const
Definition qrhi.h:591
int layer() const
Definition qrhi.h:588
\inmodule QtGui
Definition qrhi.h:1651
QPair< int, quint32 > DynamicOffset
Synonym for QPair<int, quint32>.
Definition qrhi.h:1676
QPair< QRhiBuffer *, quint32 > VertexInput
Synonym for QPair<QRhiBuffer *, quint32>.
Definition qrhi.h:1680
IndexFormat
Specifies the index data type.
Definition qrhi.h:1653
\inmodule QtGui
Definition qrhi.h:1622
QRhiShaderStage m_shaderStage
Definition qrhi.h:1644
@ CompileShadersWithDebugInfo
Definition qrhi.h:1625
\inmodule QtGui
\variable QRhiD3D11InitParams::enableDebugLayer
struct QRhiD3D11::@261 contextState
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
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 executeCommandBuffer(QD3D11CommandBuffer *cbD)
void debugMarkEnd(QRhiCommandBuffer *cb) override
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
bool useLegacySwapchainModel
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)
DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount) const
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override
\inmodule QtGui
Definition qrhi.h:44
\inmodule QtGui
Definition qrhi.h:1270
quint32 m_stencilReadMask
Definition qrhi.h:1491
@ CompileShadersWithDebugInfo
Definition qrhi.h:1276
BlendOp
Specifies the blend operation.
Definition qrhi.h:1331
PolygonMode
Specifies the polygon rasterization mode.
Definition qrhi.h:1379
BlendFactor
Specifies the blend factor.
Definition qrhi.h:1309
StencilOpState m_stencilFront
Definition qrhi.h:1489
quint32 m_stencilWriteMask
Definition qrhi.h:1492
CompareOp
Specifies the depth or stencil comparison function.
Definition qrhi.h:1350
Topology m_topology
Definition qrhi.h:1481
CullMode
Specifies the culling mode.
Definition qrhi.h:1290
QVarLengthArray< QRhiShaderStage, 4 > m_shaderStages
Definition qrhi.h:1500
QRhiVertexInputLayout m_vertexInputLayout
Definition qrhi.h:1501
QVarLengthArray< TargetBlend, 8 > m_targetBlends
Definition qrhi.h:1484
PolygonMode m_polygonMode
Definition qrhi.h:1498
float m_slopeScaledDepthBias
Definition qrhi.h:1496
Topology
Specifies the primitive topology.
Definition qrhi.h:1280
StencilOpState m_stencilBack
Definition qrhi.h:1490
FrontFace m_frontFace
Definition qrhi.h:1483
StencilOp
Specifies the stencil operation.
Definition qrhi.h:1361
int m_patchControlPointCount
Definition qrhi.h:1497
CullMode m_cullMode
Definition qrhi.h:1482
CompareOp m_depthOp
Definition qrhi.h:1487
int effectiveSampleCount(int sampleCount) const
Definition qrhi.cpp:8386
bool isCompressedFormat(QRhiTexture::Format format) const
Definition qrhi.cpp:8058
static const QRhiShaderResourceBinding::Data * shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
Definition qrhi_p.h:220
quint32 pipelineCacheRhiId() const
Definition qrhi_p.h:196
void compressedFormatInfo(QRhiTexture::Format format, const QSize &size, quint32 *bpl, quint32 *byteSize, QSize *blockDim) const
Definition qrhi.cpp:8065
static const int MAX_SHADER_CACHE_ENTRIES
Definition qrhi_p.h:239
static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
Definition qrhi_p.h:230
qint64 totalPipelineCreationTime() const
Definition qrhi_p.h:212
void textureFormatInfo(QRhiTexture::Format format, const QSize &size, quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const
Definition qrhi.cpp:8185
int layer() const
Definition qrhi.h:785
QRhiTexture * texture() const
Definition qrhi.h:782
int level() const
Definition qrhi.h:788
\inmodule QtGui
Definition qrhi.h:1094
Flags flags() const
Definition qrhi.h:1121
void setPixelSize(const QSize &sz)
Sets the size (in pixels) to sz.
Definition qrhi.h:1116
QSize pixelSize() const
Definition qrhi.h:1115
int sampleCount() const
Definition qrhi.h:1118
int m_sampleCount
Definition qrhi.h:1134
QRhiTexture::Format m_backingFormatHint
Definition qrhi.h:1136
QSize m_pixelSize
Definition qrhi.h:1133
Type
Specifies the type of the renderbuffer.
Definition qrhi.h:1096
virtual bool create()=0
Creates the corresponding native graphics resources.
@ UsedWithSwapChainOnly
Definition qrhi.h:1102
\inmodule QtGui
Definition qrhi.h:1142
\inmodule QtGui
Definition qrhi.h:1158
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Sets the QRhiRenderPassDescriptor desc for use with this render target.
Definition qrhi.h:1165
virtual QSize pixelSize() const =0
QRhiRenderPassDescriptor * m_renderPassDesc
Definition qrhi.h:1169
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
Definition qrhi_p.h:536
\inmodule QtGui
Definition qrhi.h:1731
QByteArray m_objectName
Definition qrhi.h:842
@ SwapChainRenderTarget
Definition qrhi.h:812
@ TextureRenderTarget
Definition qrhi.h:813
virtual Type resourceType() const =0
QRhiImplementation * m_rhi
Definition qrhi.h:840
\inmodule QtGui
Definition qrhi.h:1030
Filter m_minFilter
Definition qrhi.h:1085
Filter
Specifies the minification, magnification, or mipmap filtering.
Definition qrhi.h:1032
AddressMode m_addressV
Definition qrhi.h:1088
Filter m_mipmapMode
Definition qrhi.h:1086
AddressMode m_addressU
Definition qrhi.h:1087
AddressMode
Specifies the addressing mode.
Definition qrhi.h:1038
@ ClampToEdge
Definition qrhi.h:1040
CompareOp
Specifies the texture comparison function.
Definition qrhi.h:1044
@ LessOrEqual
Definition qrhi.h:1048
@ GreaterOrEqual
Definition qrhi.h:1051
CompareOp m_compareOp
Definition qrhi.h:1090
AddressMode m_addressW
Definition qrhi.h:1089
Filter m_magFilter
Definition qrhi.h:1084
\inmodule QtGui
Definition qrhi.h:138
std::array< int, 4 > scissor() const
Definition qrhi.h:143
\inmodule QtGui
Definition qrhi.h:439
\inmodule QtGui
Definition qrhi.h:1214
QVarLengthArray< QRhiShaderResourceBinding, BINDING_PREALLOC > m_bindings
Definition qrhi.h:1246
\inmodule QtGui
Definition qrhi.h:379
QShader::Variant shaderVariant() const
Definition qrhi.h:400
QShader shader() const
Definition qrhi.h:397
@ TessellationControl
Definition qrhi.h:383
@ TessellationEvaluation
Definition qrhi.h:384
\inmodule QtGui
Definition qrhi.h:1173
\inmodule QtGui
Definition qrhi.h:1549
Format format() const
Definition qrhi.h:1584
QWindow * m_window
Definition qrhi.h:1609
int m_sampleCount
Definition qrhi.h:1613
@ SurfaceHasNonPreMulAlpha
Definition qrhi.h:1553
@ SurfaceHasPreMulAlpha
Definition qrhi.h:1552
QRhiRenderPassDescriptor * m_renderPassDesc
Definition qrhi.h:1614
QSize m_currentPixelSize
Definition qrhi.h:1615
Flags m_flags
Definition qrhi.h:1610
Format
Describes the swapchain format.
Definition qrhi.h:1561
@ HDRExtendedSrgbLinear
Definition qrhi.h:1563
StereoTargetBuffer
Selects the backbuffer to use with a stereoscopic swapchain.
Definition qrhi.h:1568
Format m_format
Definition qrhi.h:1611
virtual QRhiSwapChainHdrInfo hdrInfo()
\variable QRhiSwapChainHdrInfo::limitsType
Definition qrhi.cpp:7797
QRhiRenderBuffer * m_depthStencil
Definition qrhi.h:1612
QPoint destinationTopLeft() const
Definition qrhi.h:761
QPoint sourceTopLeft() const
Definition qrhi.h:752
int destinationLevel() const
Definition qrhi.h:758
int sourceLevel() const
Definition qrhi.h:749
QSize pixelSize() const
Definition qrhi.h:743
int sourceLayer() const
Definition qrhi.h:746
int destinationLayer() const
Definition qrhi.h:755
const QRhiColorAttachment * cbeginColorAttachments() const
Definition qrhi.h:634
QRhiTexture * depthTexture() const
Definition qrhi.h:642
const QRhiColorAttachment * cendColorAttachments() const
Definition qrhi.h:635
QRhiRenderBuffer * depthStencilBuffer() const
Definition qrhi.h:639
qsizetype colorAttachmentCount() const
Definition qrhi.h:637
\inmodule QtGui
Definition qrhi.h:1184
QRhiTextureRenderTargetDescription m_desc
Definition qrhi.h:1207
\inmodule QtGui
Definition qrhi.h:895
QSize m_pixelSize
Definition qrhi.h:1016
int m_arraySize
Definition qrhi.h:1018
int m_depth
Definition qrhi.h:1017
@ ThreeDimensional
Definition qrhi.h:907
@ UsedWithLoadStore
Definition qrhi.h:904
@ UsedWithGenerateMips
Definition qrhi.h:903
@ MipMapped
Definition qrhi.h:900
@ RenderTarget
Definition qrhi.h:898
@ OneDimensional
Definition qrhi.h:910
@ TextureArray
Definition qrhi.h:909
@ CubeMap
Definition qrhi.h:899
int m_arrayRangeLength
Definition qrhi.h:1022
Format
Specifies the texture format.
Definition qrhi.h:914
@ ASTC_10x8
Definition qrhi.h:959
@ ASTC_12x12
Definition qrhi.h:962
@ ASTC_8x5
Definition qrhi.h:954
@ ASTC_10x5
Definition qrhi.h:957
@ RGBA32F
Definition qrhi.h:926
@ ETC2_RGBA8
Definition qrhi.h:947
@ ASTC_5x5
Definition qrhi.h:951
@ ASTC_4x4
Definition qrhi.h:949
@ ASTC_6x6
Definition qrhi.h:953
@ ASTC_12x10
Definition qrhi.h:961
@ ETC2_RGB8
Definition qrhi.h:945
@ ASTC_5x4
Definition qrhi.h:950
@ RED_OR_ALPHA8
Definition qrhi.h:923
@ ASTC_6x5
Definition qrhi.h:952
@ ASTC_8x8
Definition qrhi.h:956
@ RGBA16F
Definition qrhi.h:925
@ RGB10A2
Definition qrhi.h:930
@ ASTC_10x6
Definition qrhi.h:958
@ ASTC_10x10
Definition qrhi.h:960
@ UnknownFormat
Definition qrhi.h:915
@ ETC2_RGB8A1
Definition qrhi.h:946
@ ASTC_8x6
Definition qrhi.h:955
Flags flags() const
Definition qrhi.h:992
Format m_format
Definition qrhi.h:1015
Flags m_flags
Definition qrhi.h:1020
int m_arrayRangeStart
Definition qrhi.h:1021
int m_sampleCount
Definition qrhi.h:1019
Format
Specifies the type of the element data.
Definition qrhi.h:234
\inmodule QtGui
Definition qrhi.h:179
quint32 stride() const
Definition qrhi.h:189
\inmodule QtGui
Definition qrhi.h:321
const QRhiVertexInputBinding * bindingAt(qsizetype index) const
Definition qrhi.h:334
const QRhiVertexInputAttribute * cendAttributes() const
Definition qrhi.h:345
const QRhiVertexInputBinding * cendBindings() const
Definition qrhi.h:333
const QRhiVertexInputAttribute * cbeginAttributes() const
Definition qrhi.h:344
const QRhiVertexInputBinding * cbeginBindings() const
Definition qrhi.h:332
\inmodule QtGui
Definition qrhi.h:85
static constexpr int MAX_MIP_LEVELS
Definition qrhi.h:1997
ResourceLimit
Describes the resource limit to query.
Definition qrhi.h:1886
@ MaxThreadsPerThreadGroup
Definition qrhi.h:1893
@ MaxThreadGroupZ
Definition qrhi.h:1896
@ FramesInFlight
Definition qrhi.h:1890
@ TextureSizeMin
Definition qrhi.h:1887
@ MaxThreadGroupsPerDimension
Definition qrhi.h:1892
@ MaxAsyncReadbackFrames
Definition qrhi.h:1891
@ TextureArraySizeMax
Definition qrhi.h:1897
@ MaxColorAttachments
Definition qrhi.h:1889
@ MaxThreadGroupY
Definition qrhi.h:1895
@ MaxVertexInputs
Definition qrhi.h:1899
@ MaxThreadGroupX
Definition qrhi.h:1894
@ TextureSizeMax
Definition qrhi.h:1888
@ MaxVertexOutputs
Definition qrhi.h:1900
@ MaxUniformBufferRange
Definition qrhi.h:1898
@ SkipPresent
Definition qrhi.h:1882
Feature
Flag values to indicate what features are supported by the backend currently in use.
Definition qrhi.h:1831
@ HalfAttributes
Definition qrhi.h:1869
@ CustomInstanceStepRate
Definition qrhi.h:1837
@ NonDynamicUniformBuffers
Definition qrhi.h:1839
@ ElementIndexUint
Definition qrhi.h:1843
@ RenderToNonBaseMipLevel
Definition qrhi.h:1853
@ MultisampleRenderBuffer
Definition qrhi.h:1833
@ RenderTo3DTextureSlice
Definition qrhi.h:1861
@ Tessellation
Definition qrhi.h:1863
@ IntAttributes
Definition qrhi.h:1854
@ TextureArrays
Definition qrhi.h:1862
@ PipelineCacheDataLoadSave
Definition qrhi.h:1857
@ ReadBackNonUniformBuffer
Definition qrhi.h:1850
@ MultiView
Definition qrhi.h:1872
@ TexelFetch
Definition qrhi.h:1852
@ TextureArrayRange
Definition qrhi.h:1865
@ RenderToOneDimensionalTexture
Definition qrhi.h:1870
@ BaseVertex
Definition qrhi.h:1847
@ GeometryShader
Definition qrhi.h:1864
@ Compute
Definition qrhi.h:1844
@ OneDimensionalTextureMipmaps
Definition qrhi.h:1868
@ WideLines
Definition qrhi.h:1845
@ TriangleFanTopology
Definition qrhi.h:1849
@ OneDimensionalTextures
Definition qrhi.h:1867
@ ImageDataStride
Definition qrhi.h:1858
@ TextureViewFormat
Definition qrhi.h:1873
@ BaseInstance
Definition qrhi.h:1848
@ DebugMarkers
Definition qrhi.h:1834
@ ReadBackNonBaseMipLevel
Definition qrhi.h:1851
@ MultisampleTexture
Definition qrhi.h:1832
@ ThreeDimensionalTextureMipmaps
Definition qrhi.h:1871
@ NonFourAlignedEffectiveIndexBufferOffset
Definition qrhi.h:1840
@ RedOrAlpha8IsRed
Definition qrhi.h:1842
@ NonFillPolygonMode
Definition qrhi.h:1866
@ Timestamps
Definition qrhi.h:1835
@ ThreeDimensionalTextures
Definition qrhi.h:1860
@ PrimitiveRestart
Definition qrhi.h:1838
@ ReadBackAnyTextureFormat
Definition qrhi.h:1856
@ RenderBufferImport
Definition qrhi.h:1859
@ ScreenSpaceDerivatives
Definition qrhi.h:1855
@ VertexShaderPointSize
Definition qrhi.h:1846
@ NPOTTextureRepeat
Definition qrhi.h:1841
@ Instancing
Definition qrhi.h:1836
@ ResolveDepthStencil
Definition qrhi.h:1874
FrameOpResult
Describes the result of operations that can have a soft failure.
Definition qrhi.h:1824
@ FrameOpSuccess
Definition qrhi.h:1825
@ FrameOpDeviceLost
Definition qrhi.h:1828
@ FrameOpError
Definition qrhi.h:1826
@ EnablePipelineCacheDataSave
Definition qrhi.h:1818
@ SuppressSmokeTestWarnings
Definition qrhi.h:1820
@ PreferSoftwareRenderer
Definition qrhi.h:1817
@ EnableTimestamps
Definition qrhi.h:1819
qsizetype size() const
Definition qset.h:50
void clear()
Definition qset.h:61
\inmodule QtGui
Definition qshader.h:60
QByteArray shader() const
Definition qshader.h:65
\inmodule QtGui
Definition qshader.h:178
\inmodule QtGui
Definition qshader.h:81
NativeResourceBindingMap nativeResourceBindingMap(const QShaderKey &key) const
Definition qshader.cpp:1024
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:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
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:124
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition qstring.cpp:6045
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
int alphaBufferSize() const
Get the size in bits of the alpha channel of the color buffer.
bool stereo() const
Returns true if stereo buffering is enabled; otherwise returns false.
bool isEmpty() const
const_iterator cbegin() const noexcept
qsizetype count() const
const_iterator cend() const noexcept
iterator end() noexcept
iterator begin() noexcept
QSurfaceFormat format() const override
Returns the actual format of this window.
Definition qwindow.cpp:946
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
float sdrWhiteLevelInNits(const DXGI_OUTPUT_DESC1 &outputDesc)
pD3DCompile resolveD3DCompile()
bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
IDCompositionDevice * createDirectCompositionDevice()
void fillDriverInfo(QRhiDriverInfo *info, const DXGI_ADAPTER_DESC1 &desc)
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
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
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT layer
Flags
static QByteArray cacheKey(Args &&...args)
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
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
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
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
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
GLdouble s
[6]
Definition qopenglext.h:235
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
GLint limit
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint * samplers
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLsizei len
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 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)
#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:1531
#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)
unsigned int quint32
Definition qtypes.h:50
int qint32
Definition qtypes.h:49
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
long HRESULT
QSemaphore sem(5)
[0]
QSharedPointer< T > other(t)
[5]
view viewport() -> scroll(dx, dy, deviceRect)
QHostInfo info
[0]
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
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)
struct QD3D11ComputePipeline::@238 cs
bool create() override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
struct QD3D11GraphicsPipeline::@236 gs
struct QD3D11GraphicsPipeline::@233 vs
struct QD3D11GraphicsPipeline::@237 fs
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QD3D11GraphicsPipeline(QRhiImplementation *rhi)
struct QD3D11GraphicsPipeline::@234 hs
ID3D11InputLayout * inputLayout
ID3D11BlendState * blendState
ID3D11RasterizerState * rastState
D3D11_PRIMITIVE_TOPOLOGY d3dTopology
bool create() override
Creates the corresponding native graphics resources.
ID3D11DepthStencilState * dsState
struct QD3D11GraphicsPipeline::@235 ds
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
QRhiBatchedBindings< ID3D11SamplerState * > samplers
QRhiBatchedBindings< ID3D11ShaderResourceView * > shaderresources
QRhiBatchedBindings< ID3D11UnorderedAccessView * > uavs
QRhiBatchedBindings< ID3D11Buffer * > ubufs
QVarLengthArray< BoundResourceData, 8 > boundResourceData
QVarLengthArray< QRhiShaderResourceBinding, 8 > sortedBindings
void updateResources(UpdateFlags flags) override
void destroy() override
Releases (or requests deferred releasing of) the underlying native graphics resources.
QD3D11ShaderResourceBindings(QRhiImplementation *rhi)
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
bool prepare(QRhiD3D11 *rhiD)
bool tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec)
bool active[TIMESTAMP_PAIRS]
ID3D11Query * disjointQuery[TIMESTAMP_PAIRS]
static const int TIMESTAMP_PAIRS
QRhiSwapChainHdrInfo hdrInfo() override
\variable QRhiSwapChainHdrInfo::limitsType
QD3D11SwapChainTimestamps timestamps
QD3D11CommandBuffer cb
ID3D11RenderTargetView * backBufferRtv
QWindow * window
QD3D11RenderBuffer * ds
QRhiRenderTarget * currentFrameRenderTarget() override
QD3D11SwapChainRenderTarget rtRight
ID3D11RenderTargetView * backBufferRtvRight
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
void feed(int binding, T resource)
Definition qrhi_p.h:542
\inmodule QtGui
Definition qrhi.h:862
QRhiReadbackResult * result
QRhiReadbackDescription desc
\inmodule QtGui
Definition qrhi.h:1759
\variable QRhiReadbackResult::completed
Definition qrhi.h:800
QByteArray data
Definition qrhi.h:1727
std::function< void()> completed
Definition qrhi.h:1724
QRhiTextureCopyDescription desc
Definition qrhi_p.h:471
QVarLengthArray< MipLevelUploadList, 6 > subresDesc
Definition qrhi_p.h:469
\inmodule QtGui
Definition qrhi.h:1782
\inmodule QtGui
Definition qrhi.h:1511
\inmodule QtGui
Definition qrhi.h:965
Definition moc.h:23