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;
1559 return DXGI_FORMAT_R32G8X24_TYPELESS;
1560
1561 case QRhiTexture::BC1:
1562 return srgb ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM;
1563 case QRhiTexture::BC2:
1564 return srgb ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM;
1565 case QRhiTexture::BC3:
1566 return srgb ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM;
1567 case QRhiTexture::BC4:
1568 return DXGI_FORMAT_BC4_UNORM;
1569 case QRhiTexture::BC5:
1570 return DXGI_FORMAT_BC5_UNORM;
1571 case QRhiTexture::BC6H:
1572 return DXGI_FORMAT_BC6H_UF16;
1573 case QRhiTexture::BC7:
1574 return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
1575
1579 qWarning("QRhiD3D11 does not support ETC2 textures");
1580 return DXGI_FORMAT_R8G8B8A8_UNORM;
1581
1596 qWarning("QRhiD3D11 does not support ASTC textures");
1597 return DXGI_FORMAT_R8G8B8A8_UNORM;
1598
1599 default:
1600 Q_UNREACHABLE();
1601 return DXGI_FORMAT_R8G8B8A8_UNORM;
1602 }
1603}
1604
1605static inline QRhiTexture::Format swapchainReadbackTextureFormat(DXGI_FORMAT format, QRhiTexture::Flags *flags)
1606{
1607 switch (format) {
1608 case DXGI_FORMAT_R8G8B8A8_UNORM:
1609 return QRhiTexture::RGBA8;
1610 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
1611 if (flags)
1612 (*flags) |= QRhiTexture::sRGB;
1613 return QRhiTexture::RGBA8;
1614 case DXGI_FORMAT_B8G8R8A8_UNORM:
1615 return QRhiTexture::BGRA8;
1616 case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
1617 if (flags)
1618 (*flags) |= QRhiTexture::sRGB;
1619 return QRhiTexture::BGRA8;
1620 case DXGI_FORMAT_R16G16B16A16_FLOAT:
1621 return QRhiTexture::RGBA16F;
1622 case DXGI_FORMAT_R32G32B32A32_FLOAT:
1623 return QRhiTexture::RGBA32F;
1624 case DXGI_FORMAT_R10G10B10A2_UNORM:
1625 return QRhiTexture::RGB10A2;
1626 default:
1627 qWarning("DXGI_FORMAT %d cannot be read back", format);
1628 break;
1629 }
1631}
1632
1634{
1635 switch (format) {
1641 return true;
1642
1643 default:
1644 return false;
1645 }
1646}
1647
1649{
1650 if (inFrame) {
1651 if (ofr.active) {
1652 Q_ASSERT(!contextState.currentSwapChain);
1653 Q_ASSERT(ofr.cbWrapper.recordingPass == QD3D11CommandBuffer::NoPass);
1654 executeCommandBuffer(&ofr.cbWrapper);
1655 ofr.cbWrapper.resetCommands();
1656 } else {
1657 Q_ASSERT(contextState.currentSwapChain);
1658 Q_ASSERT(contextState.currentSwapChain->cb.recordingPass == QD3D11CommandBuffer::NoPass);
1659 executeCommandBuffer(&contextState.currentSwapChain->cb);
1660 contextState.currentSwapChain->cb.resetCommands();
1661 }
1662 }
1663
1665
1666 return QRhi::FrameOpSuccess;
1667}
1668
1670 int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc)
1671{
1672 const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1673 UINT subres = D3D11CalcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
1674 D3D11_BOX box;
1675 box.front = is3D ? UINT(layer) : 0u;
1676 // back, right, bottom are exclusive
1677 box.back = box.front + 1;
1678 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1680 cmd.args.updateSubRes.dst = texD->textureResource();
1681 cmd.args.updateSubRes.dstSubRes = subres;
1682
1683 const QPoint dp = subresDesc.destinationTopLeft();
1684 if (!subresDesc.image().isNull()) {
1685 QImage img = subresDesc.image();
1686 QSize size = img.size();
1687 int bpl = img.bytesPerLine();
1688 if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
1689 const QPoint sp = subresDesc.sourceTopLeft();
1690 if (!subresDesc.sourceSize().isEmpty())
1691 size = subresDesc.sourceSize();
1692 if (img.depth() == 32) {
1693 const int offset = sp.y() * img.bytesPerLine() + sp.x() * 4;
1694 cmd.args.updateSubRes.src = cbD->retainImage(img) + offset;
1695 } else {
1696 img = img.copy(sp.x(), sp.y(), size.width(), size.height());
1697 bpl = img.bytesPerLine();
1698 cmd.args.updateSubRes.src = cbD->retainImage(img);
1699 }
1700 } else {
1701 cmd.args.updateSubRes.src = cbD->retainImage(img);
1702 }
1703 box.left = UINT(dp.x());
1704 box.top = UINT(dp.y());
1705 box.right = UINT(dp.x() + size.width());
1706 box.bottom = UINT(dp.y() + size.height());
1707 cmd.args.updateSubRes.hasDstBox = true;
1708 cmd.args.updateSubRes.dstBox = box;
1709 cmd.args.updateSubRes.srcRowPitch = UINT(bpl);
1710 } else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
1711 const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
1712 : subresDesc.sourceSize();
1713 quint32 bpl = 0;
1714 QSize blockDim;
1715 compressedFormatInfo(texD->m_format, size, &bpl, nullptr, &blockDim);
1716 // Everything must be a multiple of the block width and
1717 // height, so e.g. a mip level of size 2x2 will be 4x4 when it
1718 // comes to the actual data.
1719 box.left = UINT(aligned(dp.x(), blockDim.width()));
1720 box.top = UINT(aligned(dp.y(), blockDim.height()));
1721 box.right = UINT(aligned(dp.x() + size.width(), blockDim.width()));
1722 box.bottom = UINT(aligned(dp.y() + size.height(), blockDim.height()));
1723 cmd.args.updateSubRes.hasDstBox = true;
1724 cmd.args.updateSubRes.dstBox = box;
1725 cmd.args.updateSubRes.src = cbD->retainData(subresDesc.data());
1726 cmd.args.updateSubRes.srcRowPitch = bpl;
1727 } else if (!subresDesc.data().isEmpty()) {
1728 const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
1729 : subresDesc.sourceSize();
1730 quint32 bpl = 0;
1731 if (subresDesc.dataStride())
1732 bpl = subresDesc.dataStride();
1733 else
1734 textureFormatInfo(texD->m_format, size, &bpl, nullptr, nullptr);
1735 box.left = UINT(dp.x());
1736 box.top = UINT(dp.y());
1737 box.right = UINT(dp.x() + size.width());
1738 box.bottom = UINT(dp.y() + size.height());
1739 cmd.args.updateSubRes.hasDstBox = true;
1740 cmd.args.updateSubRes.dstBox = box;
1741 cmd.args.updateSubRes.src = cbD->retainData(subresDesc.data());
1742 cmd.args.updateSubRes.srcRowPitch = bpl;
1743 } else {
1744 qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
1745 cbD->commands.unget();
1746 }
1747}
1748
1750{
1753
1754 for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
1755 const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
1758 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
1759 memcpy(bufD->dynBuf + u.offset, u.data.constData(), size_t(u.data.size()));
1760 bufD->hasPendingDynamicUpdates = true;
1763 Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
1764 Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
1765 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1767 cmd.args.updateSubRes.dst = bufD->buffer;
1768 cmd.args.updateSubRes.dstSubRes = 0;
1769 cmd.args.updateSubRes.src = cbD->retainBufferData(u.data);
1770 cmd.args.updateSubRes.srcRowPitch = 0;
1771 // Specify the region (even when offset is 0 and all data is provided)
1772 // since the ID3D11Buffer's size is rounded up to be a multiple of 256
1773 // while the data we have has the original size.
1774 D3D11_BOX box;
1775 box.left = u.offset;
1776 box.top = box.front = 0;
1777 box.back = box.bottom = 1;
1778 box.right = u.offset + u.data.size(); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
1779 cmd.args.updateSubRes.hasDstBox = true;
1780 cmd.args.updateSubRes.dstBox = box;
1783 if (bufD->m_type == QRhiBuffer::Dynamic) {
1784 u.result->data.resize(u.readSize);
1785 memcpy(u.result->data.data(), bufD->dynBuf + u.offset, size_t(u.readSize));
1786 if (u.result->completed)
1787 u.result->completed();
1788 } else {
1789 BufferReadback readback;
1790 readback.result = u.result;
1791 readback.byteSize = u.readSize;
1792
1793 D3D11_BUFFER_DESC desc = {};
1794 desc.ByteWidth = readback.byteSize;
1795 desc.Usage = D3D11_USAGE_STAGING;
1796 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1797 HRESULT hr = dev->CreateBuffer(&desc, nullptr, &readback.stagingBuf);
1798 if (FAILED(hr)) {
1799 qWarning("Failed to create buffer: %s",
1800 qPrintable(QSystemError::windowsComString(hr)));
1801 continue;
1802 }
1803
1804 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1806 cmd.args.copySubRes.dst = readback.stagingBuf;
1807 cmd.args.copySubRes.dstSubRes = 0;
1808 cmd.args.copySubRes.dstX = 0;
1809 cmd.args.copySubRes.dstY = 0;
1810 cmd.args.copySubRes.dstZ = 0;
1811 cmd.args.copySubRes.src = bufD->buffer;
1812 cmd.args.copySubRes.srcSubRes = 0;
1813 cmd.args.copySubRes.hasSrcBox = true;
1814 D3D11_BOX box;
1815 box.left = u.offset;
1816 box.top = box.front = 0;
1817 box.back = box.bottom = 1;
1818 box.right = u.offset + u.readSize;
1819 cmd.args.copySubRes.srcBox = box;
1820
1821 activeBufferReadbacks.append(readback);
1822 }
1823 }
1824 }
1825 for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
1826 const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
1829 for (int layer = 0, maxLayer = u.subresDesc.count(); layer < maxLayer; ++layer) {
1830 for (int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
1831 for (const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level]))
1832 enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
1833 }
1834 }
1836 Q_ASSERT(u.src && u.dst);
1839 const bool srcIs3D = srcD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1840 const bool dstIs3D = dstD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1841 UINT srcSubRes = D3D11CalcSubresource(UINT(u.desc.sourceLevel()), srcIs3D ? 0u : UINT(u.desc.sourceLayer()), srcD->mipLevelCount);
1842 UINT dstSubRes = D3D11CalcSubresource(UINT(u.desc.destinationLevel()), dstIs3D ? 0u : UINT(u.desc.destinationLayer()), dstD->mipLevelCount);
1843 const QPoint dp = u.desc.destinationTopLeft();
1844 const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
1845 const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
1846 const QPoint sp = u.desc.sourceTopLeft();
1847 D3D11_BOX srcBox;
1848 srcBox.left = UINT(sp.x());
1849 srcBox.top = UINT(sp.y());
1850 srcBox.front = srcIs3D ? UINT(u.desc.sourceLayer()) : 0u;
1851 // back, right, bottom are exclusive
1852 srcBox.right = srcBox.left + UINT(copySize.width());
1853 srcBox.bottom = srcBox.top + UINT(copySize.height());
1854 srcBox.back = srcBox.front + 1;
1855 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1857 cmd.args.copySubRes.dst = dstD->textureResource();
1858 cmd.args.copySubRes.dstSubRes = dstSubRes;
1859 cmd.args.copySubRes.dstX = UINT(dp.x());
1860 cmd.args.copySubRes.dstY = UINT(dp.y());
1861 cmd.args.copySubRes.dstZ = dstIs3D ? UINT(u.desc.destinationLayer()) : 0u;
1862 cmd.args.copySubRes.src = srcD->textureResource();
1863 cmd.args.copySubRes.srcSubRes = srcSubRes;
1864 cmd.args.copySubRes.hasSrcBox = true;
1865 cmd.args.copySubRes.srcBox = srcBox;
1867 TextureReadback readback;
1868 readback.desc = u.rb;
1869 readback.result = u.result;
1870
1871 ID3D11Resource *src;
1872 DXGI_FORMAT dxgiFormat;
1873 QSize pixelSize;
1875 UINT subres = 0;
1877 QD3D11SwapChain *swapChainD = nullptr;
1878 bool is3D = false;
1879
1880 if (texD) {
1881 if (texD->sampleDesc.Count > 1) {
1882 qWarning("Multisample texture cannot be read back");
1883 continue;
1884 }
1885 src = texD->textureResource();
1886 dxgiFormat = texD->dxgiFormat;
1887 pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
1888 format = texD->m_format;
1889 is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
1890 subres = D3D11CalcSubresource(UINT(u.rb.level()), UINT(is3D ? 0 : u.rb.layer()), texD->mipLevelCount);
1891 } else {
1892 Q_ASSERT(contextState.currentSwapChain);
1893 swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain);
1894 if (swapChainD->sampleDesc.Count > 1) {
1895 // Unlike with textures, reading back a multisample swapchain image
1896 // has to be supported. Insert a resolve.
1897 QD3D11CommandBuffer::Command &rcmd(cbD->commands.get());
1899 rcmd.args.resolveSubRes.dst = swapChainD->backBufferTex;
1900 rcmd.args.resolveSubRes.dstSubRes = 0;
1901 rcmd.args.resolveSubRes.src = swapChainD->msaaTex[swapChainD->currentFrameSlot];
1902 rcmd.args.resolveSubRes.srcSubRes = 0;
1903 rcmd.args.resolveSubRes.format = swapChainD->colorFormat;
1904 }
1905 src = swapChainD->backBufferTex;
1906 dxgiFormat = swapChainD->colorFormat;
1907 pixelSize = swapChainD->pixelSize;
1908 format = swapchainReadbackTextureFormat(dxgiFormat, nullptr);
1910 continue;
1911 }
1912 quint32 byteSize = 0;
1913 quint32 bpl = 0;
1914 textureFormatInfo(format, pixelSize, &bpl, &byteSize, nullptr);
1915
1916 D3D11_TEXTURE2D_DESC desc = {};
1917 desc.Width = UINT(pixelSize.width());
1918 desc.Height = UINT(pixelSize.height());
1919 desc.MipLevels = 1;
1920 desc.ArraySize = 1;
1921 desc.Format = dxgiFormat;
1922 desc.SampleDesc.Count = 1;
1923 desc.Usage = D3D11_USAGE_STAGING;
1924 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1925 ID3D11Texture2D *stagingTex;
1926 HRESULT hr = dev->CreateTexture2D(&desc, nullptr, &stagingTex);
1927 if (FAILED(hr)) {
1928 qWarning("Failed to create readback staging texture: %s",
1929 qPrintable(QSystemError::windowsComString(hr)));
1930 return;
1931 }
1932
1933 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1935 cmd.args.copySubRes.dst = stagingTex;
1936 cmd.args.copySubRes.dstSubRes = 0;
1937 cmd.args.copySubRes.dstX = 0;
1938 cmd.args.copySubRes.dstY = 0;
1939 cmd.args.copySubRes.dstZ = 0;
1940 cmd.args.copySubRes.src = src;
1941 cmd.args.copySubRes.srcSubRes = subres;
1942 if (is3D) {
1943 D3D11_BOX srcBox = {};
1944 srcBox.front = UINT(u.rb.layer());
1945 srcBox.right = desc.Width; // exclusive
1946 srcBox.bottom = desc.Height;
1947 srcBox.back = srcBox.front + 1;
1948 cmd.args.copySubRes.hasSrcBox = true;
1949 cmd.args.copySubRes.srcBox = srcBox;
1950 } else {
1951 cmd.args.copySubRes.hasSrcBox = false;
1952 }
1953
1954 readback.stagingTex = stagingTex;
1955 readback.byteSize = byteSize;
1956 readback.bpl = bpl;
1957 readback.pixelSize = pixelSize;
1958 readback.format = format;
1959
1960 activeTextureReadbacks.append(readback);
1963 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
1965 cmd.args.genMip.srv = QRHI_RES(QD3D11Texture, u.dst)->srv;
1966 }
1967 }
1968
1969 ud->free();
1970}
1971
1973{
1974 QVarLengthArray<std::function<void()>, 4> completedCallbacks;
1975
1976 for (int i = activeTextureReadbacks.count() - 1; i >= 0; --i) {
1978 readback.result->format = readback.format;
1979 readback.result->pixelSize = readback.pixelSize;
1980
1981 D3D11_MAPPED_SUBRESOURCE mp;
1982 HRESULT hr = context->Map(readback.stagingTex, 0, D3D11_MAP_READ, 0, &mp);
1983 if (SUCCEEDED(hr)) {
1984 readback.result->data.resize(int(readback.byteSize));
1985 // nothing says the rows are tightly packed in the texture, must take
1986 // the stride into account
1987 char *dst = readback.result->data.data();
1988 char *src = static_cast<char *>(mp.pData);
1989 for (int y = 0, h = readback.pixelSize.height(); y != h; ++y) {
1990 memcpy(dst, src, readback.bpl);
1991 dst += readback.bpl;
1992 src += mp.RowPitch;
1993 }
1994 context->Unmap(readback.stagingTex, 0);
1995 } else {
1996 qWarning("Failed to map readback staging texture: %s",
1997 qPrintable(QSystemError::windowsComString(hr)));
1998 }
1999
2000 readback.stagingTex->Release();
2001
2002 if (readback.result->completed)
2003 completedCallbacks.append(readback.result->completed);
2004
2005 activeTextureReadbacks.removeLast();
2006 }
2007
2008 for (int i = activeBufferReadbacks.count() - 1; i >= 0; --i) {
2010
2011 D3D11_MAPPED_SUBRESOURCE mp;
2012 HRESULT hr = context->Map(readback.stagingBuf, 0, D3D11_MAP_READ, 0, &mp);
2013 if (SUCCEEDED(hr)) {
2014 readback.result->data.resize(int(readback.byteSize));
2015 memcpy(readback.result->data.data(), mp.pData, readback.byteSize);
2016 context->Unmap(readback.stagingBuf, 0);
2017 } else {
2018 qWarning("Failed to map readback staging texture: %s",
2019 qPrintable(QSystemError::windowsComString(hr)));
2020 }
2021
2022 readback.stagingBuf->Release();
2023
2024 if (readback.result->completed)
2025 completedCallbacks.append(readback.result->completed);
2026
2027 activeBufferReadbacks.removeLast();
2028 }
2029
2030 for (auto f : completedCallbacks)
2031 f();
2032}
2033
2040
2042 QRhiRenderTarget *rt,
2043 const QColor &colorClearValue,
2044 const QRhiDepthStencilClearValue &depthStencilClearValue,
2045 QRhiResourceUpdateBatch *resourceUpdates,
2046 QRhiCommandBuffer::BeginPassFlags)
2047{
2050
2051 if (resourceUpdates)
2052 enqueueResourceUpdates(cb, resourceUpdates);
2053
2054 bool wantsColorClear = true;
2055 bool wantsDsClear = true;
2056 QD3D11RenderTargetData *rtD = rtData(rt);
2059 wantsColorClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
2060 wantsDsClear = !rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
2061 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(rtTex->description(), rtD->currentResIdList))
2062 rtTex->create();
2063 }
2064
2066
2067 QD3D11CommandBuffer::Command &fbCmd(cbD->commands.get());
2069 fbCmd.args.setRenderTarget.rt = rt;
2070
2071 QD3D11CommandBuffer::Command &clearCmd(cbD->commands.get());
2073 clearCmd.args.clear.rt = rt;
2074 clearCmd.args.clear.mask = 0;
2075 if (rtD->colorAttCount && wantsColorClear)
2076 clearCmd.args.clear.mask |= QD3D11CommandBuffer::Command::Color;
2077 if (rtD->dsAttCount && wantsDsClear)
2079
2080 clearCmd.args.clear.c[0] = float(colorClearValue.redF());
2081 clearCmd.args.clear.c[1] = float(colorClearValue.greenF());
2082 clearCmd.args.clear.c[2] = float(colorClearValue.blueF());
2083 clearCmd.args.clear.c[3] = float(colorClearValue.alphaF());
2084 clearCmd.args.clear.d = depthStencilClearValue.depthClearValue();
2085 clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
2086
2088 cbD->currentTarget = rt;
2089
2090 cbD->resetCachedState();
2091}
2092
2094{
2097
2100 for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
2101 it != itEnd; ++it)
2102 {
2103 const QRhiColorAttachment &colorAtt(*it);
2104 if (!colorAtt.resolveTexture())
2105 continue;
2106
2107 QD3D11Texture *dstTexD = QRHI_RES(QD3D11Texture, colorAtt.resolveTexture());
2108 QD3D11Texture *srcTexD = QRHI_RES(QD3D11Texture, colorAtt.texture());
2110 Q_ASSERT(srcTexD || srcRbD);
2111 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2113 cmd.args.resolveSubRes.dst = dstTexD->textureResource();
2114 cmd.args.resolveSubRes.dstSubRes = D3D11CalcSubresource(UINT(colorAtt.resolveLevel()),
2115 UINT(colorAtt.resolveLayer()),
2116 dstTexD->mipLevelCount);
2117 if (srcTexD) {
2118 cmd.args.resolveSubRes.src = srcTexD->textureResource();
2119 if (srcTexD->dxgiFormat != dstTexD->dxgiFormat) {
2120 qWarning("Resolve source (%d) and destination (%d) formats do not match",
2121 int(srcTexD->dxgiFormat), int(dstTexD->dxgiFormat));
2122 cbD->commands.unget();
2123 continue;
2124 }
2125 if (srcTexD->sampleDesc.Count <= 1) {
2126 qWarning("Cannot resolve a non-multisample texture");
2127 cbD->commands.unget();
2128 continue;
2129 }
2130 if (srcTexD->m_pixelSize != dstTexD->m_pixelSize) {
2131 qWarning("Resolve source and destination sizes do not match");
2132 cbD->commands.unget();
2133 continue;
2134 }
2135 } else {
2136 cmd.args.resolveSubRes.src = srcRbD->tex;
2137 if (srcRbD->dxgiFormat != dstTexD->dxgiFormat) {
2138 qWarning("Resolve source (%d) and destination (%d) formats do not match",
2139 int(srcRbD->dxgiFormat), int(dstTexD->dxgiFormat));
2140 cbD->commands.unget();
2141 continue;
2142 }
2143 if (srcRbD->m_pixelSize != dstTexD->m_pixelSize) {
2144 qWarning("Resolve source and destination sizes do not match");
2145 cbD->commands.unget();
2146 continue;
2147 }
2148 }
2149 cmd.args.resolveSubRes.srcSubRes = D3D11CalcSubresource(0, UINT(colorAtt.layer()), 1);
2150 cmd.args.resolveSubRes.format = dstTexD->dxgiFormat;
2151 }
2152 if (rtTex->m_desc.depthResolveTexture())
2153 qWarning("Resolving multisample depth-stencil buffers is not supported with D3D");
2154 }
2155
2157 cbD->currentTarget = nullptr;
2158
2159 if (resourceUpdates)
2160 enqueueResourceUpdates(cb, resourceUpdates);
2161}
2162
2164 QRhiResourceUpdateBatch *resourceUpdates,
2165 QRhiCommandBuffer::BeginPassFlags)
2166{
2169
2170 if (resourceUpdates)
2171 enqueueResourceUpdates(cb, resourceUpdates);
2172
2173 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2175
2177
2178 cbD->resetCachedState();
2179}
2180
2191
2193{
2197 const bool pipelineChanged = cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation;
2198
2199 if (pipelineChanged) {
2200 cbD->currentGraphicsPipeline = nullptr;
2201 cbD->currentComputePipeline = psD;
2202 cbD->currentPipelineGeneration = psD->generation;
2203
2204 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2206 cmd.args.bindComputePipeline.ps = psD;
2207 }
2208}
2209
2211{
2214
2215 QD3D11CommandBuffer::Command &cmd(cbD->commands.get());
2217 cmd.args.dispatch.x = UINT(x);
2218 cmd.args.dispatch.y = UINT(y);
2219 cmd.args.dispatch.z = UINT(z);
2220}
2221
2222static inline QPair<int, int> mapBinding(int binding,
2223 int stageIndex,
2224 const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
2225{
2226 const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
2227 if (!map || map->isEmpty())
2228 return { binding, binding }; // assume 1:1 mapping
2229
2230 auto it = map->constFind(binding);
2231 if (it != map->cend())
2232 return *it;
2233
2234 // Hitting this path is normal too. It is not given that the resource is
2235 // present in the shaders for all the stages specified by the visibility
2236 // mask in the QRhiShaderResourceBinding.
2237 return { -1, -1 };
2238}
2239
2241 const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
2242{
2243 srbD->vsUniformBufferBatches.clear();
2244 srbD->hsUniformBufferBatches.clear();
2245 srbD->dsUniformBufferBatches.clear();
2246 srbD->gsUniformBufferBatches.clear();
2247 srbD->fsUniformBufferBatches.clear();
2248 srbD->csUniformBufferBatches.clear();
2249
2250 srbD->vsSamplerBatches.clear();
2251 srbD->hsSamplerBatches.clear();
2252 srbD->dsSamplerBatches.clear();
2253 srbD->gsSamplerBatches.clear();
2254 srbD->fsSamplerBatches.clear();
2255 srbD->csSamplerBatches.clear();
2256
2257 srbD->csUavBatches.clear();
2258
2259 struct Stage {
2260 struct Buffer {
2261 int binding; // stored and sent along in XXorigbindings just for applyDynamicOffsets()
2262 int breg; // b0, b1, ...
2263 ID3D11Buffer *buffer;
2264 uint offsetInConstants;
2265 uint sizeInConstants;
2266 };
2267 struct Texture {
2268 int treg; // t0, t1, ...
2269 ID3D11ShaderResourceView *srv;
2270 };
2271 struct Sampler {
2272 int sreg; // s0, s1, ...
2273 ID3D11SamplerState *sampler;
2274 };
2275 struct Uav {
2276 int ureg;
2277 ID3D11UnorderedAccessView *uav;
2278 };
2279 QVarLengthArray<Buffer, 8> buffers;
2280 QVarLengthArray<Texture, 8> textures;
2281 QVarLengthArray<Sampler, 8> samplers;
2282 QVarLengthArray<Uav, 8> uavs;
2283 void buildBufferBatches(QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches) const
2284 {
2285 for (const Buffer &buf : buffers) {
2286 batches.ubufs.feed(buf.breg, buf.buffer);
2287 batches.ubuforigbindings.feed(buf.breg, UINT(buf.binding));
2288 batches.ubufoffsets.feed(buf.breg, buf.offsetInConstants);
2289 batches.ubufsizes.feed(buf.breg, buf.sizeInConstants);
2290 }
2291 batches.finish();
2292 }
2293 void buildSamplerBatches(QD3D11ShaderResourceBindings::StageSamplerBatches &batches) const
2294 {
2295 for (const Texture &t : textures)
2296 batches.shaderresources.feed(t.treg, t.srv);
2297 for (const Sampler &s : samplers)
2298 batches.samplers.feed(s.sreg, s.sampler);
2299 batches.finish();
2300 }
2301 void buildUavBatches(QD3D11ShaderResourceBindings::StageUavBatches &batches) const
2302 {
2303 for (const Stage::Uav &u : uavs)
2304 batches.uavs.feed(u.ureg, u.uav);
2305 batches.finish();
2306 }
2308
2309 for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
2310 const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings.at(i));
2311 QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
2312 switch (b->type) {
2314 {
2315 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
2316 Q_ASSERT(aligned(b->u.ubuf.offset, 256u) == b->u.ubuf.offset);
2317 bd.ubuf.id = bufD->m_id;
2318 bd.ubuf.generation = bufD->generation;
2319 // Dynamic ubuf offsets are not considered here, those are baked in
2320 // at a later stage, which is good as vsubufoffsets and friends are
2321 // per-srb, not per-setShaderResources call. Other backends (GL,
2322 // Metal) are different in this respect since those do not store
2323 // per-srb vsubufoffsets etc. data so life's a bit easier for them.
2324 // But here we have to defer baking in the dynamic offset.
2325 const quint32 offsetInConstants = b->u.ubuf.offset / 16;
2326 // size must be 16 mult. (in constants, i.e. multiple of 256 bytes).
2327 // We can round up if needed since the buffers's actual size
2328 // (ByteWidth) is always a multiple of 256.
2329 const quint32 sizeInConstants = aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256u) / 16;
2330 if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
2331 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
2332 if (nativeBinding.first >= 0)
2333 res[RBM_VERTEX].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2334 }
2336 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps);
2337 if (nativeBinding.first >= 0)
2338 res[RBM_HULL].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2339 }
2341 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps);
2342 if (nativeBinding.first >= 0)
2343 res[RBM_DOMAIN].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2344 }
2345 if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) {
2346 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps);
2347 if (nativeBinding.first >= 0)
2348 res[RBM_GEOMETRY].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2349 }
2350 if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
2351 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
2352 if (nativeBinding.first >= 0)
2353 res[RBM_FRAGMENT].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2354 }
2355 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2356 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2357 if (nativeBinding.first >= 0)
2358 res[RBM_COMPUTE].buffers.append({ b->binding, nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
2359 }
2360 }
2361 break;
2365 {
2367 bd.stex.count = data->count;
2368 const QPair<int, int> nativeBindingVert = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
2369 const QPair<int, int> nativeBindingHull = mapBinding(b->binding, RBM_HULL, nativeResourceBindingMaps);
2370 const QPair<int, int> nativeBindingDomain = mapBinding(b->binding, RBM_DOMAIN, nativeResourceBindingMaps);
2371 const QPair<int, int> nativeBindingGeom = mapBinding(b->binding, RBM_GEOMETRY, nativeResourceBindingMaps);
2372 const QPair<int, int> nativeBindingFrag = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
2373 const QPair<int, int> nativeBindingComp = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2374 // if SPIR-V binding b is mapped to tN and sN in HLSL, and it
2375 // is an array, then it will use tN, tN+1, tN+2, ..., and sN,
2376 // sN+1, sN+2, ...
2377 for (int elem = 0; elem < data->count; ++elem) {
2378 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
2379 QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
2380 bd.stex.d[elem].texId = texD ? texD->m_id : 0;
2381 bd.stex.d[elem].texGeneration = texD ? texD->generation : 0;
2382 bd.stex.d[elem].samplerId = samplerD ? samplerD->m_id : 0;
2383 bd.stex.d[elem].samplerGeneration = samplerD ? samplerD->generation : 0;
2384 // Must handle all three cases (combined, separate, separate):
2385 // first = texture binding, second = sampler binding
2386 // first = texture binding
2387 // first = sampler binding
2388 if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
2389 const int samplerBinding = texD && samplerD ? nativeBindingVert.second
2390 : (samplerD ? nativeBindingVert.first : -1);
2391 if (nativeBindingVert.first >= 0 && texD)
2392 res[RBM_VERTEX].textures.append({ nativeBindingVert.first + elem, texD->srv });
2393 if (samplerBinding >= 0)
2394 res[RBM_VERTEX].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2395 }
2397 const int samplerBinding = texD && samplerD ? nativeBindingHull.second
2398 : (samplerD ? nativeBindingHull.first : -1);
2399 if (nativeBindingHull.first >= 0 && texD)
2400 res[RBM_HULL].textures.append({ nativeBindingHull.first + elem, texD->srv });
2401 if (samplerBinding >= 0)
2402 res[RBM_HULL].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2403 }
2405 const int samplerBinding = texD && samplerD ? nativeBindingDomain.second
2406 : (samplerD ? nativeBindingDomain.first : -1);
2407 if (nativeBindingDomain.first >= 0 && texD)
2408 res[RBM_DOMAIN].textures.append({ nativeBindingDomain.first + elem, texD->srv });
2409 if (samplerBinding >= 0)
2410 res[RBM_DOMAIN].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2411 }
2412 if (b->stage.testFlag(QRhiShaderResourceBinding::GeometryStage)) {
2413 const int samplerBinding = texD && samplerD ? nativeBindingGeom.second
2414 : (samplerD ? nativeBindingGeom.first : -1);
2415 if (nativeBindingGeom.first >= 0 && texD)
2416 res[RBM_GEOMETRY].textures.append({ nativeBindingGeom.first + elem, texD->srv });
2417 if (samplerBinding >= 0)
2418 res[RBM_GEOMETRY].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2419 }
2420 if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
2421 const int samplerBinding = texD && samplerD ? nativeBindingFrag.second
2422 : (samplerD ? nativeBindingFrag.first : -1);
2423 if (nativeBindingFrag.first >= 0 && texD)
2424 res[RBM_FRAGMENT].textures.append({ nativeBindingFrag.first + elem, texD->srv });
2425 if (samplerBinding >= 0)
2426 res[RBM_FRAGMENT].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2427 }
2428 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2429 const int samplerBinding = texD && samplerD ? nativeBindingComp.second
2430 : (samplerD ? nativeBindingComp.first : -1);
2431 if (nativeBindingComp.first >= 0 && texD)
2432 res[RBM_COMPUTE].textures.append({ nativeBindingComp.first + elem, texD->srv });
2433 if (samplerBinding >= 0)
2434 res[RBM_COMPUTE].samplers.append({ samplerBinding + elem, samplerD->samplerState });
2435 }
2436 }
2437 }
2438 break;
2442 {
2443 QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex);
2444 bd.simage.id = texD->m_id;
2445 bd.simage.generation = texD->generation;
2446 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2447 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2448 if (nativeBinding.first >= 0) {
2449 ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level);
2450 if (uav)
2451 res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
2452 }
2453 } else {
2454 qWarning("Unordered access only supported at compute stage");
2455 }
2456 }
2457 break;
2461 {
2462 QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf);
2463 bd.sbuf.id = bufD->m_id;
2464 bd.sbuf.generation = bufD->generation;
2465 if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
2466 QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
2467 if (nativeBinding.first >= 0) {
2468 ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView(b->u.sbuf.offset);
2469 if (uav)
2470 res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
2471 }
2472 } else {
2473 qWarning("Unordered access only supported at compute stage");
2474 }
2475 }
2476 break;
2477 default:
2478 Q_UNREACHABLE();
2479 break;
2480 }
2481 }
2482
2483 // QRhiBatchedBindings works with the native bindings and expects
2484 // sorted input. The pre-sorted QRhiShaderResourceBinding list (based
2485 // on the QRhi (SPIR-V) binding) is not helpful in this regard, so we
2486 // have to sort here every time.
2487 for (int stage = 0; stage < RBM_SUPPORTED_STAGES; ++stage) {
2488 std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) {
2489 return a.breg < b.breg;
2490 });
2491 std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) {
2492 return a.treg < b.treg;
2493 });
2494 std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) {
2495 return a.sreg < b.sreg;
2496 });
2497 std::sort(res[stage].uavs.begin(), res[stage].uavs.end(), [](const Stage::Uav &a, const Stage::Uav &b) {
2498 return a.ureg < b.ureg;
2499 });
2500 }
2501
2502 res[RBM_VERTEX].buildBufferBatches(srbD->vsUniformBufferBatches);
2503 res[RBM_HULL].buildBufferBatches(srbD->hsUniformBufferBatches);
2504 res[RBM_DOMAIN].buildBufferBatches(srbD->dsUniformBufferBatches);
2505 res[RBM_GEOMETRY].buildBufferBatches(srbD->gsUniformBufferBatches);
2506 res[RBM_FRAGMENT].buildBufferBatches(srbD->fsUniformBufferBatches);
2507 res[RBM_COMPUTE].buildBufferBatches(srbD->csUniformBufferBatches);
2508
2509 res[RBM_VERTEX].buildSamplerBatches(srbD->vsSamplerBatches);
2510 res[RBM_HULL].buildSamplerBatches(srbD->hsSamplerBatches);
2511 res[RBM_DOMAIN].buildSamplerBatches(srbD->dsSamplerBatches);
2512 res[RBM_GEOMETRY].buildSamplerBatches(srbD->gsSamplerBatches);
2513 res[RBM_FRAGMENT].buildSamplerBatches(srbD->fsSamplerBatches);
2514 res[RBM_COMPUTE].buildSamplerBatches(srbD->csSamplerBatches);
2515
2516 res[RBM_COMPUTE].buildUavBatches(srbD->csUavBatches);
2517}
2518
2520{
2521 if (!bufD->hasPendingDynamicUpdates || bufD->m_size < 1)
2522 return;
2523
2524 Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
2525 bufD->hasPendingDynamicUpdates = false;
2526 D3D11_MAPPED_SUBRESOURCE mp;
2527 HRESULT hr = context->Map(bufD->buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
2528 if (SUCCEEDED(hr)) {
2529 memcpy(mp.pData, bufD->dynBuf, bufD->m_size);
2530 context->Unmap(bufD->buffer, 0);
2531 } else {
2532 qWarning("Failed to map buffer: %s",
2533 qPrintable(QSystemError::windowsComString(hr)));
2534 }
2535}
2536
2538 int batchIndex,
2539 const QRhiBatchedBindings<UINT> *originalBindings,
2540 const QRhiBatchedBindings<UINT> *staticOffsets,
2541 const uint *dynOfsPairs, int dynOfsPairCount)
2542{
2543 const int count = staticOffsets->batches[batchIndex].resources.count();
2544 // Make a copy of the offset list, the entries that have no corresponding
2545 // dynamic offset will continue to use the existing offset value.
2546 for (int b = 0; b < count; ++b) {
2547 offsets[b] = staticOffsets->batches[batchIndex].resources[b];
2548 for (int di = 0; di < dynOfsPairCount; ++di) {
2549 const uint binding = dynOfsPairs[2 * di];
2550 // binding is the SPIR-V style binding point here, nothing to do
2551 // with the native one.
2552 if (binding == originalBindings->batches[batchIndex].resources[b]) {
2553 const uint offsetInConstants = dynOfsPairs[2 * di + 1];
2554 offsets[b] = offsetInConstants;
2555 break;
2556 }
2557 }
2558 }
2559}
2560
2561static inline uint clampedResourceCount(uint startSlot, int countSlots, uint maxSlots, const char *resType)
2562{
2563 if (startSlot + countSlots > maxSlots) {
2564 qWarning("Not enough D3D11 %s slots to bind %d resources starting at slot %d, max slots is %d",
2565 resType, countSlots, startSlot, maxSlots);
2566 countSlots = maxSlots > startSlot ? maxSlots - startSlot : 0;
2567 }
2568 return countSlots;
2569}
2570
2571#define SETUBUFBATCH(stagePrefixL, stagePrefixU) \
2572 if (srbD->stagePrefixL##UniformBufferBatches.present) { \
2573 const QD3D11ShaderResourceBindings::StageUniformBufferBatches &batches(srbD->stagePrefixL##UniformBufferBatches); \
2574 for (int i = 0, ie = batches.ubufs.batches.count(); i != ie; ++i) { \
2575 const uint count = clampedResourceCount(batches.ubufs.batches[i].startBinding, \
2576 batches.ubufs.batches[i].resources.count(), \
2577 D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, \
2578 #stagePrefixU " cbuf"); \
2579 if (count) { \
2580 if (!dynOfsPairCount) { \
2581 context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \
2582 count, \
2583 batches.ubufs.batches[i].resources.constData(), \
2584 batches.ubufoffsets.batches[i].resources.constData(), \
2585 batches.ubufsizes.batches[i].resources.constData()); \
2586 } else { \
2587 applyDynamicOffsets(offsets, i, \
2588 &batches.ubuforigbindings, &batches.ubufoffsets, \
2589 dynOfsPairs, dynOfsPairCount); \
2590 context->stagePrefixU##SetConstantBuffers1(batches.ubufs.batches[i].startBinding, \
2591 count, \
2592 batches.ubufs.batches[i].resources.constData(), \
2593 offsets, \
2594 batches.ubufsizes.batches[i].resources.constData()); \
2595 } \
2596 } \
2597 } \
2598 }
2599
2600#define SETSAMPLERBATCH(stagePrefixL, stagePrefixU) \
2601 if (srbD->stagePrefixL##SamplerBatches.present) { \
2602 for (const auto &batch : srbD->stagePrefixL##SamplerBatches.samplers.batches) { \
2603 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2604 D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, #stagePrefixU " sampler"); \
2605 if (count) \
2606 context->stagePrefixU##SetSamplers(batch.startBinding, count, batch.resources.constData()); \
2607 } \
2608 for (const auto &batch : srbD->stagePrefixL##SamplerBatches.shaderresources.batches) { \
2609 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2610 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, #stagePrefixU " SRV"); \
2611 if (count) { \
2612 context->stagePrefixU##SetShaderResources(batch.startBinding, count, batch.resources.constData()); \
2613 contextState.stagePrefixL##HighestActiveSrvBinding = qMax(contextState.stagePrefixL##HighestActiveSrvBinding, \
2614 int(batch.startBinding + count) - 1); \
2615 } \
2616 } \
2617 }
2618
2619#define SETUAVBATCH(stagePrefixL, stagePrefixU) \
2620 if (srbD->stagePrefixL##UavBatches.present) { \
2621 for (const auto &batch : srbD->stagePrefixL##UavBatches.uavs.batches) { \
2622 const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(), \
2623 D3D11_1_UAV_SLOT_COUNT, #stagePrefixU " UAV"); \
2624 if (count) { \
2625 context->stagePrefixU##SetUnorderedAccessViews(batch.startBinding, \
2626 count, \
2627 batch.resources.constData(), \
2628 nullptr); \
2629 contextState.stagePrefixL##HighestActiveUavBinding = qMax(contextState.stagePrefixL##HighestActiveUavBinding, \
2630 int(batch.startBinding + count) - 1); \
2631 } \
2632 } \
2633 }
2634
2636 const uint *dynOfsPairs, int dynOfsPairCount,
2637 bool offsetOnlyChange)
2638{
2640
2641 SETUBUFBATCH(vs, VS)
2642 SETUBUFBATCH(hs, HS)
2643 SETUBUFBATCH(ds, DS)
2644 SETUBUFBATCH(gs, GS)
2645 SETUBUFBATCH(fs, PS)
2646 SETUBUFBATCH(cs, CS)
2647
2648 if (!offsetOnlyChange) {
2649 SETSAMPLERBATCH(vs, VS)
2650 SETSAMPLERBATCH(hs, HS)
2651 SETSAMPLERBATCH(ds, DS)
2652 SETSAMPLERBATCH(gs, GS)
2653 SETSAMPLERBATCH(fs, PS)
2654 SETSAMPLERBATCH(cs, CS)
2655
2656 SETUAVBATCH(cs, CS)
2657 }
2658}
2659
2661{
2662 // Output cannot be bound on input etc.
2663
2664 if (contextState.vsHasIndexBufferBound) {
2665 context->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
2666 contextState.vsHasIndexBufferBound = false;
2667 }
2668
2669 if (contextState.vsHighestActiveVertexBufferBinding >= 0) {
2670 const int count = contextState.vsHighestActiveVertexBufferBinding + 1;
2671 QVarLengthArray<ID3D11Buffer *, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nullbufs(count);
2672 for (int i = 0; i < count; ++i)
2673 nullbufs[i] = nullptr;
2674 QVarLengthArray<UINT, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nullstrides(count);
2675 for (int i = 0; i < count; ++i)
2676 nullstrides[i] = 0;
2677 QVarLengthArray<UINT, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nulloffsets(count);
2678 for (int i = 0; i < count; ++i)
2679 nulloffsets[i] = 0;
2680 context->IASetVertexBuffers(0, UINT(count), nullbufs.constData(), nullstrides.constData(), nulloffsets.constData());
2681 contextState.vsHighestActiveVertexBufferBinding = -1;
2682 }
2683
2684 int nullsrvCount = qMax(contextState.vsHighestActiveSrvBinding, contextState.fsHighestActiveSrvBinding);
2685 nullsrvCount = qMax(nullsrvCount, contextState.hsHighestActiveSrvBinding);
2686 nullsrvCount = qMax(nullsrvCount, contextState.dsHighestActiveSrvBinding);
2687 nullsrvCount = qMax(nullsrvCount, contextState.gsHighestActiveSrvBinding);
2688 nullsrvCount = qMax(nullsrvCount, contextState.csHighestActiveSrvBinding);
2689 nullsrvCount += 1;
2690 if (nullsrvCount > 0) {
2691 QVarLengthArray<ID3D11ShaderResourceView *,
2692 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nullsrvs(nullsrvCount);
2693 for (int i = 0; i < nullsrvs.count(); ++i)
2694 nullsrvs[i] = nullptr;
2695 if (contextState.vsHighestActiveSrvBinding >= 0) {
2696 context->VSSetShaderResources(0, UINT(contextState.vsHighestActiveSrvBinding + 1), nullsrvs.constData());
2697 contextState.vsHighestActiveSrvBinding = -1;
2698 }
2699 if (contextState.hsHighestActiveSrvBinding >= 0) {
2700 context->HSSetShaderResources(0, UINT(contextState.hsHighestActiveSrvBinding + 1), nullsrvs.constData());
2701 contextState.hsHighestActiveSrvBinding = -1;
2702 }
2703 if (contextState.dsHighestActiveSrvBinding >= 0) {
2704 context->DSSetShaderResources(0, UINT(contextState.dsHighestActiveSrvBinding + 1), nullsrvs.constData());
2705 contextState.dsHighestActiveSrvBinding = -1;
2706 }
2707 if (contextState.gsHighestActiveSrvBinding >= 0) {
2708 context->GSSetShaderResources(0, UINT(contextState.gsHighestActiveSrvBinding + 1), nullsrvs.constData());
2709 contextState.gsHighestActiveSrvBinding = -1;
2710 }
2711 if (contextState.fsHighestActiveSrvBinding >= 0) {
2712 context->PSSetShaderResources(0, UINT(contextState.fsHighestActiveSrvBinding + 1), nullsrvs.constData());
2713 contextState.fsHighestActiveSrvBinding = -1;
2714 }
2715 if (contextState.csHighestActiveSrvBinding >= 0) {
2716 context->CSSetShaderResources(0, UINT(contextState.csHighestActiveSrvBinding + 1), nullsrvs.constData());
2717 contextState.csHighestActiveSrvBinding = -1;
2718 }
2719 }
2720
2721 if (contextState.csHighestActiveUavBinding >= 0) {
2722 const int nulluavCount = contextState.csHighestActiveUavBinding + 1;
2723 QVarLengthArray<ID3D11UnorderedAccessView *,
2724 D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nulluavs(nulluavCount);
2725 for (int i = 0; i < nulluavCount; ++i)
2726 nulluavs[i] = nullptr;
2727 context->CSSetUnorderedAccessViews(0, UINT(nulluavCount), nulluavs.constData(), nullptr);
2728 contextState.csHighestActiveUavBinding = -1;
2729 }
2730}
2731
2732#define SETSHADER(StageL, StageU) \
2733 if (psD->StageL.shader) { \
2734 context->StageU##SetShader(psD->StageL.shader, nullptr, 0); \
2735 currentShaderMask |= StageU##MaskBit; \
2736 } else if (currentShaderMask & StageU##MaskBit) { \
2737 context->StageU##SetShader(nullptr, nullptr, 0); \
2738 currentShaderMask &= ~StageU##MaskBit; \
2739 }
2740
2742{
2743 quint32 stencilRef = 0;
2744 float blendConstants[] = { 1, 1, 1, 1 };
2745 enum ActiveShaderMask {
2746 VSMaskBit = 0x01,
2747 HSMaskBit = 0x02,
2748 DSMaskBit = 0x04,
2749 GSMaskBit = 0x08,
2750 PSMaskBit = 0x10
2751 };
2752 int currentShaderMask = 0xFF;
2753
2754 for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) {
2755 const QD3D11CommandBuffer::Command &cmd(*it);
2756 switch (cmd.cmd) {
2758 if (cmd.args.beginFrame.tsDisjointQuery)
2759 context->Begin(cmd.args.beginFrame.tsDisjointQuery);
2760 if (cmd.args.beginFrame.tsQuery) {
2761 if (cmd.args.beginFrame.swapchainData) {
2762 // The timestamps seem to include vsync time with Present(1), except
2763 // when running on a non-primary gpu. This is not ideal. So try working
2764 // it around by issuing a semi-fake OMSetRenderTargets early and
2765 // writing the first timestamp only afterwards.
2766 QD3D11RenderTargetData *rtD = cmd.args.beginFrame.swapchainData;
2767 context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
2768 }
2769 context->End(cmd.args.beginFrame.tsQuery); // no Begin() for D3D11_QUERY_TIMESTAMP
2770 }
2771 break;
2773 if (cmd.args.endFrame.tsQuery)
2774 context->End(cmd.args.endFrame.tsQuery);
2775 if (cmd.args.endFrame.tsDisjointQuery)
2776 context->End(cmd.args.endFrame.tsDisjointQuery);
2777 break;
2780 break;
2782 {
2783 QD3D11RenderTargetData *rtD = rtData(cmd.args.setRenderTarget.rt);
2784 context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
2785 }
2786 break;
2788 {
2789 QD3D11RenderTargetData *rtD = rtData(cmd.args.clear.rt);
2790 if (cmd.args.clear.mask & QD3D11CommandBuffer::Command::Color) {
2791 for (int i = 0; i < rtD->colorAttCount; ++i)
2792 context->ClearRenderTargetView(rtD->rtv[i], cmd.args.clear.c);
2793 }
2794 uint ds = 0;
2795 if (cmd.args.clear.mask & QD3D11CommandBuffer::Command::Depth)
2796 ds |= D3D11_CLEAR_DEPTH;
2797 if (cmd.args.clear.mask & QD3D11CommandBuffer::Command::Stencil)
2798 ds |= D3D11_CLEAR_STENCIL;
2799 if (ds)
2800 context->ClearDepthStencilView(rtD->dsv, ds, cmd.args.clear.d, UINT8(cmd.args.clear.s));
2801 }
2802 break;
2804 {
2805 D3D11_VIEWPORT v;
2806 v.TopLeftX = cmd.args.viewport.x;
2807 v.TopLeftY = cmd.args.viewport.y;
2808 v.Width = cmd.args.viewport.w;
2809 v.Height = cmd.args.viewport.h;
2810 v.MinDepth = cmd.args.viewport.d0;
2811 v.MaxDepth = cmd.args.viewport.d1;
2812 context->RSSetViewports(1, &v);
2813 }
2814 break;
2816 {
2817 D3D11_RECT r;
2818 r.left = cmd.args.scissor.x;
2819 r.top = cmd.args.scissor.y;
2820 // right and bottom are exclusive
2821 r.right = cmd.args.scissor.x + cmd.args.scissor.w;
2822 r.bottom = cmd.args.scissor.y + cmd.args.scissor.h;
2823 context->RSSetScissorRects(1, &r);
2824 }
2825 break;
2827 contextState.vsHighestActiveVertexBufferBinding = qMax<int>(
2828 contextState.vsHighestActiveVertexBufferBinding,
2829 cmd.args.bindVertexBuffers.startSlot + cmd.args.bindVertexBuffers.slotCount - 1);
2830 context->IASetVertexBuffers(UINT(cmd.args.bindVertexBuffers.startSlot),
2831 UINT(cmd.args.bindVertexBuffers.slotCount),
2832 cmd.args.bindVertexBuffers.buffers,
2833 cmd.args.bindVertexBuffers.strides,
2834 cmd.args.bindVertexBuffers.offsets);
2835 break;
2837 contextState.vsHasIndexBufferBound = true;
2838 context->IASetIndexBuffer(cmd.args.bindIndexBuffer.buffer,
2839 cmd.args.bindIndexBuffer.format,
2840 cmd.args.bindIndexBuffer.offset);
2841 break;
2843 {
2844 QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps;
2845 SETSHADER(vs, VS)
2846 SETSHADER(hs, HS)
2847 SETSHADER(ds, DS)
2848 SETSHADER(gs, GS)
2849 SETSHADER(fs, PS)
2850 context->IASetPrimitiveTopology(psD->d3dTopology);
2851 context->IASetInputLayout(psD->inputLayout); // may be null, that's ok
2852 context->OMSetDepthStencilState(psD->dsState, stencilRef);
2853 context->OMSetBlendState(psD->blendState, blendConstants, 0xffffffff);
2854 context->RSSetState(psD->rastState);
2855 }
2856 break;
2858 bindShaderResources(cmd.args.bindShaderResources.srb,
2859 cmd.args.bindShaderResources.dynamicOffsetPairs,
2860 cmd.args.bindShaderResources.dynamicOffsetCount,
2861 cmd.args.bindShaderResources.offsetOnlyChange);
2862 break;
2864 stencilRef = cmd.args.stencilRef.ref;
2865 context->OMSetDepthStencilState(cmd.args.stencilRef.ps->dsState, stencilRef);
2866 break;
2868 memcpy(blendConstants, cmd.args.blendConstants.c, 4 * sizeof(float));
2869 context->OMSetBlendState(cmd.args.blendConstants.ps->blendState, blendConstants, 0xffffffff);
2870 break;
2872 if (cmd.args.draw.ps) {
2873 if (cmd.args.draw.instanceCount == 1)
2874 context->Draw(cmd.args.draw.vertexCount, cmd.args.draw.firstVertex);
2875 else
2876 context->DrawInstanced(cmd.args.draw.vertexCount, cmd.args.draw.instanceCount,
2877 cmd.args.draw.firstVertex, cmd.args.draw.firstInstance);
2878 } else {
2879 qWarning("No graphics pipeline active for draw; ignored");
2880 }
2881 break;
2883 if (cmd.args.drawIndexed.ps) {
2884 if (cmd.args.drawIndexed.instanceCount == 1)
2885 context->DrawIndexed(cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.firstIndex,
2886 cmd.args.drawIndexed.vertexOffset);
2887 else
2888 context->DrawIndexedInstanced(cmd.args.drawIndexed.indexCount, cmd.args.drawIndexed.instanceCount,
2889 cmd.args.drawIndexed.firstIndex, cmd.args.drawIndexed.vertexOffset,
2890 cmd.args.drawIndexed.firstInstance);
2891 } else {
2892 qWarning("No graphics pipeline active for drawIndexed; ignored");
2893 }
2894 break;
2896 context->UpdateSubresource(cmd.args.updateSubRes.dst, cmd.args.updateSubRes.dstSubRes,
2897 cmd.args.updateSubRes.hasDstBox ? &cmd.args.updateSubRes.dstBox : nullptr,
2898 cmd.args.updateSubRes.src, cmd.args.updateSubRes.srcRowPitch, 0);
2899 break;
2901 context->CopySubresourceRegion(cmd.args.copySubRes.dst, cmd.args.copySubRes.dstSubRes,
2902 cmd.args.copySubRes.dstX, cmd.args.copySubRes.dstY, cmd.args.copySubRes.dstZ,
2903 cmd.args.copySubRes.src, cmd.args.copySubRes.srcSubRes,
2904 cmd.args.copySubRes.hasSrcBox ? &cmd.args.copySubRes.srcBox : nullptr);
2905 break;
2907 context->ResolveSubresource(cmd.args.resolveSubRes.dst, cmd.args.resolveSubRes.dstSubRes,
2908 cmd.args.resolveSubRes.src, cmd.args.resolveSubRes.srcSubRes,
2909 cmd.args.resolveSubRes.format);
2910 break;
2912 context->GenerateMips(cmd.args.genMip.srv);
2913 break;
2915 annotations->BeginEvent(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16()));
2916 break;
2918 annotations->EndEvent();
2919 break;
2921 annotations->SetMarker(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16()));
2922 break;
2924 context->CSSetShader(cmd.args.bindComputePipeline.ps->cs.shader, nullptr, 0);
2925 break;
2927 context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z);
2928 break;
2929 default:
2930 break;
2931 }
2932 }
2933}
2934
2939
2944
2946{
2947 if (!buffer)
2948 return;
2949
2950 buffer->Release();
2951 buffer = nullptr;
2952
2953 delete[] dynBuf;
2954 dynBuf = nullptr;
2955
2956 for (auto it = uavs.begin(), end = uavs.end(); it != end; ++it)
2957 it.value()->Release();
2958 uavs.clear();
2959
2961 if (rhiD)
2962 rhiD->unregisterResource(this);
2963}
2964
2965static inline uint toD3DBufferUsage(QRhiBuffer::UsageFlags usage)
2966{
2967 int u = 0;
2968 if (usage.testFlag(QRhiBuffer::VertexBuffer))
2969 u |= D3D11_BIND_VERTEX_BUFFER;
2970 if (usage.testFlag(QRhiBuffer::IndexBuffer))
2971 u |= D3D11_BIND_INDEX_BUFFER;
2972 if (usage.testFlag(QRhiBuffer::UniformBuffer))
2973 u |= D3D11_BIND_CONSTANT_BUFFER;
2974 if (usage.testFlag(QRhiBuffer::StorageBuffer))
2975 u |= D3D11_BIND_UNORDERED_ACCESS;
2976 return uint(u);
2977}
2978
2980{
2981 if (buffer)
2982 destroy();
2983
2984 if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
2985 qWarning("UniformBuffer must always be combined with Dynamic on D3D11");
2986 return false;
2987 }
2988
2989 if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
2990 qWarning("StorageBuffer cannot be combined with Dynamic");
2991 return false;
2992 }
2993
2994 const quint32 nonZeroSize = m_size <= 0 ? 256 : m_size;
2995 const quint32 roundedSize = aligned(nonZeroSize, m_usage.testFlag(QRhiBuffer::UniformBuffer) ? 256u : 4u);
2996
2997 D3D11_BUFFER_DESC desc = {};
2998 desc.ByteWidth = roundedSize;
2999 desc.Usage = m_type == Dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
3000 desc.BindFlags = toD3DBufferUsage(m_usage);
3001 desc.CPUAccessFlags = m_type == Dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
3002 desc.MiscFlags = m_usage.testFlag(QRhiBuffer::StorageBuffer) ? D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS : 0;
3003
3005 HRESULT hr = rhiD->dev->CreateBuffer(&desc, nullptr, &buffer);
3006 if (FAILED(hr)) {
3007 qWarning("Failed to create buffer: %s",
3008 qPrintable(QSystemError::windowsComString(hr)));
3009 return false;
3010 }
3011
3012 if (m_type == Dynamic) {
3013 dynBuf = new char[nonZeroSize];
3015 }
3016
3017 if (!m_objectName.isEmpty())
3018 buffer->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3019
3020 generation += 1;
3021 rhiD->registerResource(this);
3022 return true;
3023}
3024
3026{
3027 if (m_type == Dynamic) {
3029 rhiD->executeBufferHostWrites(this);
3030 }
3031 return { { &buffer }, 1 };
3032}
3033
3035{
3036 // Shortcut the entire buffer update mechanism and allow the client to do
3037 // the host writes directly to the buffer. This will lead to unexpected
3038 // results when combined with QRhiResourceUpdateBatch-based updates for the
3039 // buffer, since dynBuf is left untouched and out of sync, but provides a
3040 // fast path for dynamic buffers that have all their content changed in
3041 // every frame.
3043 D3D11_MAPPED_SUBRESOURCE mp;
3045 HRESULT hr = rhiD->context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
3046 if (FAILED(hr)) {
3047 qWarning("Failed to map buffer: %s",
3048 qPrintable(QSystemError::windowsComString(hr)));
3049 return nullptr;
3050 }
3051 return static_cast<char *>(mp.pData);
3052}
3053
3055{
3057 rhiD->context->Unmap(buffer, 0);
3058}
3059
3061{
3062 auto it = uavs.find(offset);
3063 if (it != uavs.end())
3064 return it.value();
3065
3066 // SPIRV-Cross generated HLSL uses RWByteAddressBuffer
3067 D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
3068 desc.Format = DXGI_FORMAT_R32_TYPELESS;
3069 desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
3070 desc.Buffer.FirstElement = offset / 4u;
3071 desc.Buffer.NumElements = aligned(m_size - offset, 4u) / 4u;
3072 desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
3073
3075 ID3D11UnorderedAccessView *uav = nullptr;
3076 HRESULT hr = rhiD->dev->CreateUnorderedAccessView(buffer, &desc, &uav);
3077 if (FAILED(hr)) {
3078 qWarning("Failed to create UAV: %s",
3079 qPrintable(QSystemError::windowsComString(hr)));
3080 return nullptr;
3081 }
3082
3083 uavs[offset] = uav;
3084 return uav;
3085}
3086
3088 int sampleCount, QRhiRenderBuffer::Flags flags,
3089 QRhiTexture::Format backingFormatHint)
3090 : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint)
3091{
3092}
3093
3098
3100{
3101 if (!tex)
3102 return;
3103
3104 if (dsv) {
3105 dsv->Release();
3106 dsv = nullptr;
3107 }
3108
3109 if (rtv) {
3110 rtv->Release();
3111 rtv = nullptr;
3112 }
3113
3114 tex->Release();
3115 tex = nullptr;
3116
3118 if (rhiD)
3119 rhiD->unregisterResource(this);
3120}
3121
3123{
3124 if (tex)
3125 destroy();
3126
3127 if (m_pixelSize.isEmpty())
3128 return false;
3129
3131 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
3132
3133 D3D11_TEXTURE2D_DESC desc = {};
3134 desc.Width = UINT(m_pixelSize.width());
3135 desc.Height = UINT(m_pixelSize.height());
3136 desc.MipLevels = 1;
3137 desc.ArraySize = 1;
3138 desc.SampleDesc = sampleDesc;
3139 desc.Usage = D3D11_USAGE_DEFAULT;
3140
3141 if (m_type == Color) {
3142 dxgiFormat = m_backingFormatHint == QRhiTexture::UnknownFormat ? DXGI_FORMAT_R8G8B8A8_UNORM
3144 desc.Format = dxgiFormat;
3145 desc.BindFlags = D3D11_BIND_RENDER_TARGET;
3146 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3147 if (FAILED(hr)) {
3148 qWarning("Failed to create color renderbuffer: %s",
3149 qPrintable(QSystemError::windowsComString(hr)));
3150 return false;
3151 }
3152 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
3153 rtvDesc.Format = dxgiFormat;
3154 rtvDesc.ViewDimension = desc.SampleDesc.Count > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS
3155 : D3D11_RTV_DIMENSION_TEXTURE2D;
3156 hr = rhiD->dev->CreateRenderTargetView(tex, &rtvDesc, &rtv);
3157 if (FAILED(hr)) {
3158 qWarning("Failed to create rtv: %s",
3159 qPrintable(QSystemError::windowsComString(hr)));
3160 return false;
3161 }
3162 } else if (m_type == DepthStencil) {
3163 dxgiFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
3164 desc.Format = dxgiFormat;
3165 desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
3166 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3167 if (FAILED(hr)) {
3168 qWarning("Failed to create depth-stencil buffer: %s",
3169 qPrintable(QSystemError::windowsComString(hr)));
3170 return false;
3171 }
3172 D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
3173 dsvDesc.Format = dxgiFormat;
3174 dsvDesc.ViewDimension = desc.SampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
3175 : D3D11_DSV_DIMENSION_TEXTURE2D;
3176 hr = rhiD->dev->CreateDepthStencilView(tex, &dsvDesc, &dsv);
3177 if (FAILED(hr)) {
3178 qWarning("Failed to create dsv: %s",
3179 qPrintable(QSystemError::windowsComString(hr)));
3180 return false;
3181 }
3182 } else {
3183 return false;
3184 }
3185
3186 if (!m_objectName.isEmpty())
3187 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3188
3189 generation += 1;
3190 rhiD->registerResource(this);
3191 return true;
3192}
3193
3201
3203 int arraySize, int sampleCount, Flags flags)
3204 : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags)
3205{
3206 for (int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i)
3207 perLevelViews[i] = nullptr;
3208}
3209
3214
3216{
3217 if (!tex && !tex3D && !tex1D)
3218 return;
3219
3220 if (srv) {
3221 srv->Release();
3222 srv = nullptr;
3223 }
3224
3225 for (int i = 0; i < QRhi::MAX_MIP_LEVELS; ++i) {
3226 if (perLevelViews[i]) {
3227 perLevelViews[i]->Release();
3228 perLevelViews[i] = nullptr;
3229 }
3230 }
3231
3232 if (owns) {
3233 if (tex)
3234 tex->Release();
3235 if (tex3D)
3236 tex3D->Release();
3237 if (tex1D)
3238 tex1D->Release();
3239 }
3240
3241 tex = nullptr;
3242 tex3D = nullptr;
3243 tex1D = nullptr;
3244
3246 if (rhiD)
3247 rhiD->unregisterResource(this);
3248}
3249
3251{
3252 switch (format) {
3254 return DXGI_FORMAT_R16_FLOAT;
3256 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3258 return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
3260 return DXGI_FORMAT_R32_FLOAT;
3262 return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
3263 default:
3264 Q_UNREACHABLE();
3265 return DXGI_FORMAT_R32_FLOAT;
3266 }
3267}
3268
3270{
3271 switch (format) {
3273 return DXGI_FORMAT_D16_UNORM;
3275 return DXGI_FORMAT_D24_UNORM_S8_UINT;
3277 return DXGI_FORMAT_D24_UNORM_S8_UINT;
3279 return DXGI_FORMAT_D32_FLOAT;
3281 return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
3282 default:
3283 Q_UNREACHABLE();
3284 return DXGI_FORMAT_D32_FLOAT;
3285 }
3286}
3287
3289{
3290 if (tex || tex3D || tex1D)
3291 destroy();
3292
3293 const bool isDepth = isDepthTextureFormat(m_format);
3294 const bool isCube = m_flags.testFlag(CubeMap);
3295 const bool is3D = m_flags.testFlag(ThreeDimensional);
3296 const bool isArray = m_flags.testFlag(TextureArray);
3297 const bool hasMipMaps = m_flags.testFlag(MipMapped);
3298 const bool is1D = m_flags.testFlag(OneDimensional);
3299
3300 const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
3301 : (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
3302
3305 mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
3306 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
3307 if (sampleDesc.Count > 1) {
3308 if (isCube) {
3309 qWarning("Cubemap texture cannot be multisample");
3310 return false;
3311 }
3312 if (is3D) {
3313 qWarning("3D texture cannot be multisample");
3314 return false;
3315 }
3316 if (hasMipMaps) {
3317 qWarning("Multisample texture cannot have mipmaps");
3318 return false;
3319 }
3320 }
3321 if (isDepth && hasMipMaps) {
3322 qWarning("Depth texture cannot have mipmaps");
3323 return false;
3324 }
3325 if (isCube && is3D) {
3326 qWarning("Texture cannot be both cube and 3D");
3327 return false;
3328 }
3329 if (isArray && is3D) {
3330 qWarning("Texture cannot be both array and 3D");
3331 return false;
3332 }
3333 if (isCube && is1D) {
3334 qWarning("Texture cannot be both cube and 1D");
3335 return false;
3336 }
3337 if (is1D && is3D) {
3338 qWarning("Texture cannot be both 1D and 3D");
3339 return false;
3340 }
3341 if (m_depth > 1 && !is3D) {
3342 qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
3343 return false;
3344 }
3345 if (m_arraySize > 0 && !isArray) {
3346 qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
3347 return false;
3348 }
3349 if (m_arraySize < 1 && isArray) {
3350 qWarning("Texture is an array but array size is %d", m_arraySize);
3351 return false;
3352 }
3353
3354 if (adjustedSize)
3355 *adjustedSize = size;
3356
3357 return true;
3358}
3359
3361{
3363 const bool isDepth = isDepthTextureFormat(m_format);
3364 const bool isCube = m_flags.testFlag(CubeMap);
3365 const bool is3D = m_flags.testFlag(ThreeDimensional);
3366 const bool isArray = m_flags.testFlag(TextureArray);
3367 const bool is1D = m_flags.testFlag(OneDimensional);
3368
3369 D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
3370 srvDesc.Format = isDepth ? toD3DDepthTextureSRVFormat(m_format) : dxgiFormat;
3371 if (isCube) {
3372 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
3373 srvDesc.TextureCube.MipLevels = mipLevelCount;
3374 } else {
3375 if (is1D) {
3376 if (isArray) {
3377 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
3378 srvDesc.Texture1DArray.MipLevels = mipLevelCount;
3379 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3380 srvDesc.Texture1DArray.FirstArraySlice = UINT(m_arrayRangeStart);
3381 srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
3382 } else {
3383 srvDesc.Texture1DArray.FirstArraySlice = 0;
3384 srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
3385 }
3386 } else {
3387 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
3388 srvDesc.Texture1D.MipLevels = mipLevelCount;
3389 }
3390 } else if (isArray) {
3391 if (sampleDesc.Count > 1) {
3392 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY;
3393 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3394 srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart);
3395 srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
3396 } else {
3397 srvDesc.Texture2DMSArray.FirstArraySlice = 0;
3398 srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
3399 }
3400 } else {
3401 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
3402 srvDesc.Texture2DArray.MipLevels = mipLevelCount;
3403 if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) {
3404 srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart);
3405 srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
3406 } else {
3407 srvDesc.Texture2DArray.FirstArraySlice = 0;
3408 srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
3409 }
3410 }
3411 } else {
3412 if (sampleDesc.Count > 1) {
3413 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
3414 } else if (is3D) {
3415 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
3416 srvDesc.Texture3D.MipLevels = mipLevelCount;
3417 } else {
3418 srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
3419 srvDesc.Texture2D.MipLevels = mipLevelCount;
3420 }
3421 }
3422 }
3423
3424 HRESULT hr = rhiD->dev->CreateShaderResourceView(textureResource(), &srvDesc, &srv);
3425 if (FAILED(hr)) {
3426 qWarning("Failed to create srv: %s",
3427 qPrintable(QSystemError::windowsComString(hr)));
3428 return false;
3429 }
3430
3431 generation += 1;
3432 return true;
3433}
3434
3436{
3437 QSize size;
3438 if (!prepareCreate(&size))
3439 return false;
3440
3441 const bool isDepth = isDepthTextureFormat(m_format);
3442 const bool isCube = m_flags.testFlag(CubeMap);
3443 const bool is3D = m_flags.testFlag(ThreeDimensional);
3444 const bool isArray = m_flags.testFlag(TextureArray);
3445 const bool is1D = m_flags.testFlag(OneDimensional);
3446
3447 uint bindFlags = D3D11_BIND_SHADER_RESOURCE;
3448 uint miscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
3449 if (m_flags.testFlag(RenderTarget)) {
3450 if (isDepth)
3451 bindFlags |= D3D11_BIND_DEPTH_STENCIL;
3452 else
3453 bindFlags |= D3D11_BIND_RENDER_TARGET;
3454 }
3455 if (m_flags.testFlag(UsedWithGenerateMips)) {
3456 if (isDepth) {
3457 qWarning("Depth texture cannot have mipmaps generated");
3458 return false;
3459 }
3460 bindFlags |= D3D11_BIND_RENDER_TARGET;
3461 miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS;
3462 }
3463 if (m_flags.testFlag(UsedWithLoadStore))
3464 bindFlags |= D3D11_BIND_UNORDERED_ACCESS;
3465
3467 if (is1D) {
3468 D3D11_TEXTURE1D_DESC desc = {};
3469 desc.Width = UINT(size.width());
3470 desc.MipLevels = mipLevelCount;
3471 desc.ArraySize = isArray ? UINT(qMax(0, m_arraySize)) : 1;
3472 desc.Format = dxgiFormat;
3473 desc.Usage = D3D11_USAGE_DEFAULT;
3474 desc.BindFlags = bindFlags;
3475 desc.MiscFlags = miscFlags;
3476
3477 HRESULT hr = rhiD->dev->CreateTexture1D(&desc, nullptr, &tex1D);
3478 if (FAILED(hr)) {
3479 qWarning("Failed to create 1D texture: %s",
3480 qPrintable(QSystemError::windowsComString(hr)));
3481 return false;
3482 }
3483 if (!m_objectName.isEmpty())
3484 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()),
3486 } else if (!is3D) {
3487 D3D11_TEXTURE2D_DESC desc = {};
3488 desc.Width = UINT(size.width());
3489 desc.Height = UINT(size.height());
3490 desc.MipLevels = mipLevelCount;
3491 desc.ArraySize = isCube ? 6 : (isArray ? UINT(qMax(0, m_arraySize)) : 1);
3492 desc.Format = dxgiFormat;
3493 desc.SampleDesc = sampleDesc;
3494 desc.Usage = D3D11_USAGE_DEFAULT;
3495 desc.BindFlags = bindFlags;
3496 desc.MiscFlags = miscFlags;
3497
3498 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
3499 if (FAILED(hr)) {
3500 qWarning("Failed to create 2D texture: %s",
3501 qPrintable(QSystemError::windowsComString(hr)));
3502 return false;
3503 }
3504 if (!m_objectName.isEmpty())
3505 tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3506 } else {
3507 D3D11_TEXTURE3D_DESC desc = {};
3508 desc.Width = UINT(size.width());
3509 desc.Height = UINT(size.height());
3510 desc.Depth = UINT(qMax(1, m_depth));
3511 desc.MipLevels = mipLevelCount;
3512 desc.Format = dxgiFormat;
3513 desc.Usage = D3D11_USAGE_DEFAULT;
3514 desc.BindFlags = bindFlags;
3515 desc.MiscFlags = miscFlags;
3516
3517 HRESULT hr = rhiD->dev->CreateTexture3D(&desc, nullptr, &tex3D);
3518 if (FAILED(hr)) {
3519 qWarning("Failed to create 3D texture: %s",
3520 qPrintable(QSystemError::windowsComString(hr)));
3521 return false;
3522 }
3523 if (!m_objectName.isEmpty())
3524 tex3D->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
3525 }
3526
3527 if (!finishCreate())
3528 return false;
3529
3530 owns = true;
3531 rhiD->registerResource(this);
3532 return true;
3533}
3534
3536{
3537 if (!src.object)
3538 return false;
3539
3540 if (!prepareCreate())
3541 return false;
3542
3543 if (m_flags.testFlag(ThreeDimensional))
3544 tex3D = reinterpret_cast<ID3D11Texture3D *>(src.object);
3545 else if (m_flags.testFlags(OneDimensional))
3546 tex1D = reinterpret_cast<ID3D11Texture1D *>(src.object);
3547 else
3548 tex = reinterpret_cast<ID3D11Texture2D *>(src.object);
3549
3550 if (!finishCreate())
3551 return false;
3552
3553 owns = false;
3555 rhiD->registerResource(this);
3556 return true;
3557}
3558
3563
3565{
3566 if (perLevelViews[level])
3567 return perLevelViews[level];
3568
3569 const bool isCube = m_flags.testFlag(CubeMap);
3570 const bool isArray = m_flags.testFlag(TextureArray);
3571 const bool is3D = m_flags.testFlag(ThreeDimensional);
3572 D3D11_UNORDERED_ACCESS_VIEW_DESC desc = {};
3573 desc.Format = dxgiFormat;
3574 if (isCube) {
3575 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
3576 desc.Texture2DArray.MipSlice = UINT(level);
3577 desc.Texture2DArray.FirstArraySlice = 0;
3578 desc.Texture2DArray.ArraySize = 6;
3579 } else if (isArray) {
3580 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
3581 desc.Texture2DArray.MipSlice = UINT(level);
3582 desc.Texture2DArray.FirstArraySlice = 0;
3583 desc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
3584 } else if (is3D) {
3585 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
3586 desc.Texture3D.MipSlice = UINT(level);
3587 } else {
3588 desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
3589 desc.Texture2D.MipSlice = UINT(level);
3590 }
3591
3593 ID3D11UnorderedAccessView *uav = nullptr;
3594 HRESULT hr = rhiD->dev->CreateUnorderedAccessView(textureResource(), &desc, &uav);
3595 if (FAILED(hr)) {
3596 qWarning("Failed to create UAV: %s",
3597 qPrintable(QSystemError::windowsComString(hr)));
3598 return nullptr;
3599 }
3600
3601 perLevelViews[level] = uav;
3602 return uav;
3603}
3604
3607 : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
3608{
3609}
3610
3615
3617{
3618 if (!samplerState)
3619 return;
3620
3621 samplerState->Release();
3622 samplerState = nullptr;
3623
3625 if (rhiD)
3626 rhiD->unregisterResource(this);
3627}
3628
3629static inline D3D11_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
3630{
3631 if (minFilter == QRhiSampler::Nearest) {
3632 if (magFilter == QRhiSampler::Nearest) {
3633 if (mipFilter == QRhiSampler::Linear)
3634 return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
3635 else
3636 return D3D11_FILTER_MIN_MAG_MIP_POINT;
3637 } else {
3638 if (mipFilter == QRhiSampler::Linear)
3639 return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
3640 else
3641 return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
3642 }
3643 } else {
3644 if (magFilter == QRhiSampler::Nearest) {
3645 if (mipFilter == QRhiSampler::Linear)
3646 return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
3647 else
3648 return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
3649 } else {
3650 if (mipFilter == QRhiSampler::Linear)
3651 return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
3652 else
3653 return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
3654 }
3655 }
3656
3657 Q_UNREACHABLE();
3658 return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
3659}
3660
3661static inline D3D11_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMode m)
3662{
3663 switch (m) {
3665 return D3D11_TEXTURE_ADDRESS_WRAP;
3667 return D3D11_TEXTURE_ADDRESS_CLAMP;
3669 return D3D11_TEXTURE_ADDRESS_MIRROR;
3670 default:
3671 Q_UNREACHABLE();
3672 return D3D11_TEXTURE_ADDRESS_CLAMP;
3673 }
3674}
3675
3676static inline D3D11_COMPARISON_FUNC toD3DTextureComparisonFunc(QRhiSampler::CompareOp op)
3677{
3678 switch (op) {
3679 case QRhiSampler::Never:
3680 return D3D11_COMPARISON_NEVER;
3681 case QRhiSampler::Less:
3682 return D3D11_COMPARISON_LESS;
3683 case QRhiSampler::Equal:
3684 return D3D11_COMPARISON_EQUAL;
3686 return D3D11_COMPARISON_LESS_EQUAL;
3688 return D3D11_COMPARISON_GREATER;
3690 return D3D11_COMPARISON_NOT_EQUAL;
3692 return D3D11_COMPARISON_GREATER_EQUAL;
3694 return D3D11_COMPARISON_ALWAYS;
3695 default:
3696 Q_UNREACHABLE();
3697 return D3D11_COMPARISON_NEVER;
3698 }
3699}
3700
3702{
3703 if (samplerState)
3704 destroy();
3705
3706 D3D11_SAMPLER_DESC desc = {};
3708 if (m_compareOp != Never)
3709 desc.Filter = D3D11_FILTER(desc.Filter | 0x80);
3710 desc.AddressU = toD3DAddressMode(m_addressU);
3711 desc.AddressV = toD3DAddressMode(m_addressV);
3712 desc.AddressW = toD3DAddressMode(m_addressW);
3713 desc.MaxAnisotropy = 1.0f;
3714 desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
3715 desc.MaxLOD = m_mipmapMode == None ? 0.0f : 1000.0f;
3716
3718 HRESULT hr = rhiD->dev->CreateSamplerState(&desc, &samplerState);
3719 if (FAILED(hr)) {
3720 qWarning("Failed to create sampler state: %s",
3721 qPrintable(QSystemError::windowsComString(hr)));
3722 return false;
3723 }
3724
3725 generation += 1;
3726 rhiD->registerResource(this);
3727 return true;
3728}
3729
3730// dummy, no Vulkan-style RenderPass+Framebuffer concept here
3735
3740
3742{
3744 if (rhiD)
3745 rhiD->unregisterResource(this);
3746}
3747
3749{
3750 Q_UNUSED(other);
3751 return true;
3752}
3753
3761
3763{
3764 return {};
3765}
3766
3772
3777
3779{
3780 // nothing to do here
3781}
3782
3787
3789{
3790 return d.dpr;
3791}
3792
3794{
3795 return d.sampleCount;
3796}
3797
3800 Flags flags)
3801 : QRhiTextureRenderTarget(rhi, desc, flags),
3802 d(rhi)
3803{
3805 ownsRtv[i] = false;
3806 rtv[i] = nullptr;
3807 }
3808}
3809
3814
3816{
3817 if (!rtv[0] && !dsv)
3818 return;
3819
3820 if (dsv) {
3821 if (ownsDsv)
3822 dsv->Release();
3823 dsv = nullptr;
3824 }
3825
3827 if (rtv[i]) {
3828 if (ownsRtv[i])
3829 rtv[i]->Release();
3830 rtv[i] = nullptr;
3831 }
3832 }
3833
3835 if (rhiD)
3836 rhiD->unregisterResource(this);
3837}
3838
3846
3848{
3849 if (rtv[0] || dsv)
3850 destroy();
3851
3854 const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
3855
3857
3858 d.colorAttCount = 0;
3859 int attIndex = 0;
3860 for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
3861 d.colorAttCount += 1;
3862 const QRhiColorAttachment &colorAtt(*it);
3863 QRhiTexture *texture = colorAtt.texture();
3864 QRhiRenderBuffer *rb = colorAtt.renderBuffer();
3865 Q_ASSERT(texture || rb);
3866 if (texture) {
3868 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
3869 rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
3870 if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
3871 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
3872 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
3873 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
3874 rtvDesc.Texture2DArray.ArraySize = 1;
3875 } else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
3876 if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
3877 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY;
3878 rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
3879 rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
3880 rtvDesc.Texture1DArray.ArraySize = 1;
3881 } else {
3882 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D;
3883 rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
3884 }
3885 } else if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
3886 if (texD->sampleDesc.Count > 1) {
3887 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY;
3888 rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
3889 rtvDesc.Texture2DMSArray.ArraySize = 1;
3890 } else {
3891 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
3892 rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
3893 rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
3894 rtvDesc.Texture2DArray.ArraySize = 1;
3895 }
3896 } else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
3897 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
3898 rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
3899 rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
3900 rtvDesc.Texture3D.WSize = 1;
3901 } else {
3902 if (texD->sampleDesc.Count > 1) {
3903 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
3904 } else {
3905 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
3906 rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
3907 }
3908 }
3909 HRESULT hr = rhiD->dev->CreateRenderTargetView(texD->textureResource(), &rtvDesc, &rtv[attIndex]);
3910 if (FAILED(hr)) {
3911 qWarning("Failed to create rtv: %s",
3912 qPrintable(QSystemError::windowsComString(hr)));
3913 return false;
3914 }
3915 ownsRtv[attIndex] = true;
3916 if (attIndex == 0) {
3917 d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
3918 d.sampleCount = int(texD->sampleDesc.Count);
3919 }
3920 } else if (rb) {
3922 ownsRtv[attIndex] = false;
3923 rtv[attIndex] = rbD->rtv;
3924 if (attIndex == 0) {
3925 d.pixelSize = rbD->pixelSize();
3926 d.sampleCount = int(rbD->sampleDesc.Count);
3927 }
3928 }
3929 }
3930 d.dpr = 1;
3931
3932 if (hasDepthStencil) {
3933 if (m_desc.depthTexture()) {
3934 ownsDsv = true;
3936 D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
3937 dsvDesc.Format = toD3DDepthTextureDSVFormat(depthTexD->format());
3938 dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
3939 : D3D11_DSV_DIMENSION_TEXTURE2D;
3940 if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
3941 if (depthTexD->sampleDesc.Count > 1) {
3942 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
3943 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
3944 dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
3945 dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
3946 } else {
3947 dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
3948 dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
3949 }
3950 } else {
3951 dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
3952 if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
3953 dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
3954 dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
3955 } else {
3956 dsvDesc.Texture2DArray.FirstArraySlice = 0;
3957 dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
3958 }
3959 }
3960 }
3961 HRESULT hr = rhiD->dev->CreateDepthStencilView(depthTexD->tex, &dsvDesc, &dsv);
3962 if (FAILED(hr)) {
3963 qWarning("Failed to create dsv: %s",
3964 qPrintable(QSystemError::windowsComString(hr)));
3965 return false;
3966 }
3967 if (d.colorAttCount == 0) {
3968 d.pixelSize = depthTexD->pixelSize();
3969 d.sampleCount = int(depthTexD->sampleDesc.Count);
3970 }
3971 } else {
3972 ownsDsv = false;
3974 dsv = depthRbD->dsv;
3975 if (d.colorAttCount == 0) {
3977 d.sampleCount = int(depthRbD->sampleDesc.Count);
3978 }
3979 }
3980 d.dsAttCount = 1;
3981 } else {
3982 d.dsAttCount = 0;
3983 }
3984
3986 d.rtv[i] = i < d.colorAttCount ? rtv[i] : nullptr;
3987
3988 d.dsv = dsv;
3990
3991 QRhiRenderTargetAttachmentTracker::updateResIdList<QD3D11Texture, QD3D11RenderBuffer>(m_desc, &d.currentResIdList);
3992
3993 rhiD->registerResource(this);
3994 return true;
3995}
3996
3998{
3999 if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QD3D11Texture, QD3D11RenderBuffer>(m_desc, d.currentResIdList))
4000 const_cast<QD3D11TextureRenderTarget *>(this)->create();
4001
4002 return d.pixelSize;
4003}
4004
4006{
4007 return d.dpr;
4008}
4009
4011{
4012 return d.sampleCount;
4013}
4014
4019
4024
4026{
4028 boundResourceData.clear();
4029
4031 if (rhiD)
4032 rhiD->unregisterResource(this);
4033}
4034
4036{
4037 if (!sortedBindings.isEmpty())
4038 destroy();
4039
4041 if (!rhiD->sanityCheckShaderResourceBindings(this))
4042 return false;
4043
4044 rhiD->updateLayoutDesc(this);
4045
4046 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
4048
4050
4052 memset(&bd, 0, sizeof(BoundResourceData));
4053
4054 hasDynamicOffset = false;
4057 if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
4058 hasDynamicOffset = true;
4059 break;
4060 }
4061 }
4062
4063 generation += 1;
4064 rhiD->registerResource(this, false);
4065 return true;
4066}
4067
4069{
4071 std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
4072 if (!flags.testFlag(BindingsAreSorted))
4074
4077 memset(&bd, 0, sizeof(BoundResourceData));
4078
4079 generation += 1;
4080}
4081
4086
4091
4092template<typename T>
4094{
4095 if (s.shader) {
4096 s.shader->Release();
4097 s.shader = nullptr;
4098 }
4099 s.nativeResourceBindingMap.clear();
4100}
4101
4103{
4104 if (!dsState)
4105 return;
4106
4107 dsState->Release();
4108 dsState = nullptr;
4109
4110 if (blendState) {
4111 blendState->Release();
4112 blendState = nullptr;
4113 }
4114
4115 if (inputLayout) {
4116 inputLayout->Release();
4117 inputLayout = nullptr;
4118 }
4119
4120 if (rastState) {
4121 rastState->Release();
4122 rastState = nullptr;
4123 }
4124
4130
4132 if (rhiD)
4133 rhiD->unregisterResource(this);
4134}
4135
4136static inline D3D11_CULL_MODE toD3DCullMode(QRhiGraphicsPipeline::CullMode c)
4137{
4138 switch (c) {
4140 return D3D11_CULL_NONE;
4142 return D3D11_CULL_FRONT;
4144 return D3D11_CULL_BACK;
4145 default:
4146 Q_UNREACHABLE();
4147 return D3D11_CULL_NONE;
4148 }
4149}
4150
4152{
4153 switch (mode) {
4155 return D3D11_FILL_SOLID;
4157 return D3D11_FILL_WIREFRAME;
4158 default:
4159 Q_UNREACHABLE();
4160 return D3D11_FILL_SOLID;
4161 }
4162}
4163
4164static inline D3D11_COMPARISON_FUNC toD3DCompareOp(QRhiGraphicsPipeline::CompareOp op)
4165{
4166 switch (op) {
4168 return D3D11_COMPARISON_NEVER;
4170 return D3D11_COMPARISON_LESS;
4172 return D3D11_COMPARISON_EQUAL;
4174 return D3D11_COMPARISON_LESS_EQUAL;
4176 return D3D11_COMPARISON_GREATER;
4178 return D3D11_COMPARISON_NOT_EQUAL;
4180 return D3D11_COMPARISON_GREATER_EQUAL;
4182 return D3D11_COMPARISON_ALWAYS;
4183 default:
4184 Q_UNREACHABLE();
4185 return D3D11_COMPARISON_ALWAYS;
4186 }
4187}
4188
4189static inline D3D11_STENCIL_OP toD3DStencilOp(QRhiGraphicsPipeline::StencilOp op)
4190{
4191 switch (op) {
4193 return D3D11_STENCIL_OP_ZERO;
4195 return D3D11_STENCIL_OP_KEEP;
4197 return D3D11_STENCIL_OP_REPLACE;
4199 return D3D11_STENCIL_OP_INCR_SAT;
4201 return D3D11_STENCIL_OP_DECR_SAT;
4203 return D3D11_STENCIL_OP_INVERT;
4205 return D3D11_STENCIL_OP_INCR;
4207 return D3D11_STENCIL_OP_DECR;
4208 default:
4209 Q_UNREACHABLE();
4210 return D3D11_STENCIL_OP_KEEP;
4211 }
4212}
4213
4215{
4216 switch (format) {
4218 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4220 return DXGI_FORMAT_R32G32B32_FLOAT;
4222 return DXGI_FORMAT_R32G32_FLOAT;
4224 return DXGI_FORMAT_R32_FLOAT;
4226 return DXGI_FORMAT_R8G8B8A8_UNORM;
4228 return DXGI_FORMAT_R8G8_UNORM;
4230 return DXGI_FORMAT_R8_UNORM;
4232 return DXGI_FORMAT_R32G32B32A32_UINT;
4234 return DXGI_FORMAT_R32G32B32_UINT;
4236 return DXGI_FORMAT_R32G32_UINT;
4238 return DXGI_FORMAT_R32_UINT;
4240 return DXGI_FORMAT_R32G32B32A32_SINT;
4242 return DXGI_FORMAT_R32G32B32_SINT;
4244 return DXGI_FORMAT_R32G32_SINT;
4246 return DXGI_FORMAT_R32_SINT;
4248 // Note: D3D does not support half3. Pass through half3 as half4.
4250 return DXGI_FORMAT_R16G16B16A16_FLOAT;
4252 return DXGI_FORMAT_R16G16_FLOAT;
4254 return DXGI_FORMAT_R16_FLOAT;
4256 // Note: D3D does not support UShort3. Pass through UShort3 as UShort4.
4258 return DXGI_FORMAT_R16G16B16A16_UINT;
4260 return DXGI_FORMAT_R16G16_UINT;
4262 return DXGI_FORMAT_R16_UINT;
4264 // Note: D3D does not support SShort3. Pass through SShort3 as SShort4.
4266 return DXGI_FORMAT_R16G16B16A16_SINT;
4268 return DXGI_FORMAT_R16G16_SINT;
4270 return DXGI_FORMAT_R16_SINT;
4271 default:
4272 Q_UNREACHABLE();
4273 return DXGI_FORMAT_R32G32B32A32_FLOAT;
4274 }
4275}
4276
4277static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topology t, int patchControlPointCount)
4278{
4279 switch (t) {
4281 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
4283 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
4285 return D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
4287 return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP;
4289 return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
4291 Q_ASSERT(patchControlPointCount >= 1 && patchControlPointCount <= 32);
4292 return D3D11_PRIMITIVE_TOPOLOGY(D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (patchControlPointCount - 1));
4293 default:
4294 Q_UNREACHABLE();
4295 return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
4296 }
4297}
4298
4299static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
4300{
4301 UINT8 f = 0;
4302 if (c.testFlag(QRhiGraphicsPipeline::R))
4303 f |= D3D11_COLOR_WRITE_ENABLE_RED;
4304 if (c.testFlag(QRhiGraphicsPipeline::G))
4305 f |= D3D11_COLOR_WRITE_ENABLE_GREEN;
4306 if (c.testFlag(QRhiGraphicsPipeline::B))
4307 f |= D3D11_COLOR_WRITE_ENABLE_BLUE;
4308 if (c.testFlag(QRhiGraphicsPipeline::A))
4309 f |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
4310 return f;
4311}
4312
4314{
4315 // SrcBlendAlpha and DstBlendAlpha do not accept *_COLOR. With other APIs
4316 // this is handled internally (so that e.g. VK_BLEND_FACTOR_SRC_COLOR is
4317 // accepted and is in effect equivalent to VK_BLEND_FACTOR_SRC_ALPHA when
4318 // set as an alpha src/dest factor), but for D3D we have to take care of it
4319 // ourselves. Hence the rgb argument.
4320
4321 switch (f) {
4323 return D3D11_BLEND_ZERO;
4325 return D3D11_BLEND_ONE;
4327 return rgb ? D3D11_BLEND_SRC_COLOR : D3D11_BLEND_SRC_ALPHA;
4329 return rgb ? D3D11_BLEND_INV_SRC_COLOR : D3D11_BLEND_INV_SRC_ALPHA;
4331 return rgb ? D3D11_BLEND_DEST_COLOR : D3D11_BLEND_DEST_ALPHA;
4333 return rgb ? D3D11_BLEND_INV_DEST_COLOR : D3D11_BLEND_INV_DEST_ALPHA;
4335 return D3D11_BLEND_SRC_ALPHA;
4337 return D3D11_BLEND_INV_SRC_ALPHA;
4339 return D3D11_BLEND_DEST_ALPHA;
4341 return D3D11_BLEND_INV_DEST_ALPHA;
4344 return D3D11_BLEND_BLEND_FACTOR;
4347 return D3D11_BLEND_INV_BLEND_FACTOR;
4349 return D3D11_BLEND_SRC_ALPHA_SAT;
4351 return rgb ? D3D11_BLEND_SRC1_COLOR : D3D11_BLEND_SRC1_ALPHA;
4353 return rgb ? D3D11_BLEND_INV_SRC1_COLOR : D3D11_BLEND_INV_SRC1_ALPHA;
4355 return D3D11_BLEND_SRC1_ALPHA;
4357 return D3D11_BLEND_INV_SRC1_ALPHA;
4358 default:
4359 Q_UNREACHABLE();
4360 return D3D11_BLEND_ZERO;
4361 }
4362}
4363
4364static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
4365{
4366 switch (op) {
4368 return D3D11_BLEND_OP_ADD;
4370 return D3D11_BLEND_OP_SUBTRACT;
4372 return D3D11_BLEND_OP_REV_SUBTRACT;
4374 return D3D11_BLEND_OP_MIN;
4376 return D3D11_BLEND_OP_MAX;
4377 default:
4378 Q_UNREACHABLE();
4379 return D3D11_BLEND_OP_ADD;
4380 }
4381}
4382
4384{
4385 // taken from the GL backend, use the same mechanism to get a key
4387 keyBuilder.addData(source);
4388 return keyBuilder.result().toHex();
4389}
4390
4392 QString *error, QShaderKey *usedShaderKey)
4393{
4394 QShaderKey key = { QShader::DxbcShader, 50, shaderVariant };
4395 QShaderCode dxbc = shader.shader(key);
4396 if (!dxbc.shader().isEmpty()) {
4397 if (usedShaderKey)
4398 *usedShaderKey = key;
4399 return dxbc.shader();
4400 }
4401
4402 key = { QShader::HlslShader, 50, shaderVariant };
4403 QShaderCode hlslSource = shader.shader(key);
4404 if (hlslSource.shader().isEmpty()) {
4405 qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader;
4406 return QByteArray();
4407 }
4408
4409 if (usedShaderKey)
4410 *usedShaderKey = key;
4411
4412 const char *target;
4413 switch (shader.stage()) {
4415 target = "vs_5_0";
4416 break;
4418 target = "hs_5_0";
4419 break;
4421 target = "ds_5_0";
4422 break;
4424 target = "gs_5_0";
4425 break;
4427 target = "ps_5_0";
4428 break;
4430 target = "cs_5_0";
4431 break;
4432 default:
4433 Q_UNREACHABLE();
4434 return QByteArray();
4435 }
4436
4439 cacheKey.sourceHash = sourceHash(hlslSource.shader());
4440 cacheKey.target = target;
4441 cacheKey.entryPoint = hlslSource.entryPoint();
4442 cacheKey.compileFlags = flags;
4443 auto cacheIt = m_bytecodeCache.constFind(cacheKey);
4444 if (cacheIt != m_bytecodeCache.constEnd())
4445 return cacheIt.value();
4446 }
4447
4448 static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
4449 if (d3dCompile == nullptr) {
4450 qWarning("Unable to resolve function D3DCompile()");
4451 return QByteArray();
4452 }
4453
4454 ID3DBlob *bytecode = nullptr;
4455 ID3DBlob *errors = nullptr;
4456 HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
4457 nullptr, nullptr, nullptr,
4458 hlslSource.entryPoint().constData(), target, flags, 0, &bytecode, &errors);
4459 if (FAILED(hr) || !bytecode) {
4460 qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
4461 if (errors) {
4462 *error = QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()),
4463 int(errors->GetBufferSize()));
4464 errors->Release();
4465 }
4466 return QByteArray();
4467 }
4468
4470 result.resize(int(bytecode->GetBufferSize()));
4471 memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
4472 bytecode->Release();
4473
4476
4477 return result;
4478}
4479
4481{
4482 if (dsState)
4483 destroy();
4484
4486 rhiD->pipelineCreationStart();
4487 if (!rhiD->sanityCheckGraphicsPipeline(this))
4488 return false;
4489
4490 D3D11_RASTERIZER_DESC rastDesc = {};
4491 rastDesc.FillMode = toD3DFillMode(m_polygonMode);
4492 rastDesc.CullMode = toD3DCullMode(m_cullMode);
4493 rastDesc.FrontCounterClockwise = m_frontFace == CCW;
4494 rastDesc.DepthBias = m_depthBias;
4495 rastDesc.SlopeScaledDepthBias = m_slopeScaledDepthBias;
4496 rastDesc.DepthClipEnable = true;
4497 rastDesc.ScissorEnable = m_flags.testFlag(UsesScissor);
4498 rastDesc.MultisampleEnable = rhiD->effectiveSampleDesc(m_sampleCount).Count > 1;
4499 HRESULT hr = rhiD->dev->CreateRasterizerState(&rastDesc, &rastState);
4500 if (FAILED(hr)) {
4501 qWarning("Failed to create rasterizer state: %s",
4502 qPrintable(QSystemError::windowsComString(hr)));
4503 return false;
4504 }
4505
4506 D3D11_DEPTH_STENCIL_DESC dsDesc = {};
4507 dsDesc.DepthEnable = m_depthTest;
4508 dsDesc.DepthWriteMask = m_depthWrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
4509 dsDesc.DepthFunc = toD3DCompareOp(m_depthOp);
4510 dsDesc.StencilEnable = m_stencilTest;
4511 if (m_stencilTest) {
4512 dsDesc.StencilReadMask = UINT8(m_stencilReadMask);
4513 dsDesc.StencilWriteMask = UINT8(m_stencilWriteMask);
4514 dsDesc.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
4515 dsDesc.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
4516 dsDesc.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
4517 dsDesc.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
4518 dsDesc.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
4519 dsDesc.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
4520 dsDesc.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
4521 dsDesc.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
4522 }
4523 hr = rhiD->dev->CreateDepthStencilState(&dsDesc, &dsState);
4524 if (FAILED(hr)) {
4525 qWarning("Failed to create depth-stencil state: %s",
4526 qPrintable(QSystemError::windowsComString(hr)));
4527 return false;
4528 }
4529
4530 D3D11_BLEND_DESC blendDesc = {};
4531 blendDesc.IndependentBlendEnable = m_targetBlends.count() > 1;
4532 for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
4534 D3D11_RENDER_TARGET_BLEND_DESC blend = {};
4535 blend.BlendEnable = b.enable;
4536 blend.SrcBlend = toD3DBlendFactor(b.srcColor, true);
4537 blend.DestBlend = toD3DBlendFactor(b.dstColor, true);
4538 blend.BlendOp = toD3DBlendOp(b.opColor);
4539 blend.SrcBlendAlpha = toD3DBlendFactor(b.srcAlpha, false);
4540 blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha, false);
4541 blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
4542 blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
4543 blendDesc.RenderTarget[i] = blend;
4544 }
4545 if (m_targetBlends.isEmpty()) {
4546 D3D11_RENDER_TARGET_BLEND_DESC blend = {};
4547 blend.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
4548 blendDesc.RenderTarget[0] = blend;
4549 }
4550 hr = rhiD->dev->CreateBlendState(&blendDesc, &blendState);
4551 if (FAILED(hr)) {
4552 qWarning("Failed to create blend state: %s",
4553 qPrintable(QSystemError::windowsComString(hr)));
4554 return false;
4555 }
4556
4557 QByteArray vsByteCode;
4558 for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
4559 auto cacheIt = rhiD->m_shaderCache.constFind(shaderStage);
4560 if (cacheIt != rhiD->m_shaderCache.constEnd()) {
4561 switch (shaderStage.type()) {
4563 vs.shader = static_cast<ID3D11VertexShader *>(cacheIt->s);
4564 vs.shader->AddRef();
4565 vsByteCode = cacheIt->bytecode;
4566 vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4567 break;
4569 hs.shader = static_cast<ID3D11HullShader *>(cacheIt->s);
4570 hs.shader->AddRef();
4571 hs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4572 break;
4574 ds.shader = static_cast<ID3D11DomainShader *>(cacheIt->s);
4575 ds.shader->AddRef();
4576 ds.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4577 break;
4579 gs.shader = static_cast<ID3D11GeometryShader *>(cacheIt->s);
4580 gs.shader->AddRef();
4581 gs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4582 break;
4584 fs.shader = static_cast<ID3D11PixelShader *>(cacheIt->s);
4585 fs.shader->AddRef();
4586 fs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4587 break;
4588 default:
4589 break;
4590 }
4591 } else {
4592 QString error;
4593 QShaderKey shaderKey;
4594 UINT compileFlags = 0;
4596 compileFlags |= D3DCOMPILE_DEBUG;
4597
4598 const QByteArray bytecode = rhiD->compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), compileFlags,
4599 &error, &shaderKey);
4600 if (bytecode.isEmpty()) {
4601 qWarning("HLSL shader compilation failed: %s", qPrintable(error));
4602 return false;
4603 }
4604
4605 if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) {
4606 // Use the simplest strategy: too many cached shaders -> drop them all.
4607 rhiD->clearShaderCache();
4608 }
4609
4610 switch (shaderStage.type()) {
4612 hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader);
4613 if (FAILED(hr)) {
4614 qWarning("Failed to create vertex shader: %s",
4615 qPrintable(QSystemError::windowsComString(hr)));
4616 return false;
4617 }
4618 vsByteCode = bytecode;
4619 vs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4620 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap));
4621 vs.shader->AddRef();
4622 break;
4624 hr = rhiD->dev->CreateHullShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &hs.shader);
4625 if (FAILED(hr)) {
4626 qWarning("Failed to create hull shader: %s",
4627 qPrintable(QSystemError::windowsComString(hr)));
4628 return false;
4629 }
4630 hs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4631 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(hs.shader, bytecode, hs.nativeResourceBindingMap));
4632 hs.shader->AddRef();
4633 break;
4635 hr = rhiD->dev->CreateDomainShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &ds.shader);
4636 if (FAILED(hr)) {
4637 qWarning("Failed to create domain shader: %s",
4638 qPrintable(QSystemError::windowsComString(hr)));
4639 return false;
4640 }
4641 ds.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4642 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(ds.shader, bytecode, ds.nativeResourceBindingMap));
4643 ds.shader->AddRef();
4644 break;
4646 hr = rhiD->dev->CreateGeometryShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &gs.shader);
4647 if (FAILED(hr)) {
4648 qWarning("Failed to create geometry shader: %s",
4649 qPrintable(QSystemError::windowsComString(hr)));
4650 return false;
4651 }
4652 gs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4653 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(gs.shader, bytecode, gs.nativeResourceBindingMap));
4654 gs.shader->AddRef();
4655 break;
4657 hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader);
4658 if (FAILED(hr)) {
4659 qWarning("Failed to create pixel shader: %s",
4660 qPrintable(QSystemError::windowsComString(hr)));
4661 return false;
4662 }
4663 fs.nativeResourceBindingMap = shaderStage.shader().nativeResourceBindingMap(shaderKey);
4664 rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap));
4665 fs.shader->AddRef();
4666 break;
4667 default:
4668 break;
4669 }
4670 }
4671 }
4672
4674
4675 if (!vsByteCode.isEmpty()) {
4676 QByteArrayList matrixSliceSemantics;
4677 QVarLengthArray<D3D11_INPUT_ELEMENT_DESC, 4> inputDescs;
4679 it != itEnd; ++it)
4680 {
4681 D3D11_INPUT_ELEMENT_DESC desc = {};
4682 // The output from SPIRV-Cross uses TEXCOORD<location> as the
4683 // semantic, except for matrices that are unrolled into consecutive
4684 // vec2/3/4s attributes and need TEXCOORD<location>_ as
4685 // SemanticName and row/column index as SemanticIndex.
4686 const int matrixSlice = it->matrixSlice();
4687 if (matrixSlice < 0) {
4688 desc.SemanticName = "TEXCOORD";
4689 desc.SemanticIndex = UINT(it->location());
4690 } else {
4692 sem.resize(16);
4693 qsnprintf(sem.data(), sem.size(), "TEXCOORD%d_", it->location() - matrixSlice);
4694 matrixSliceSemantics.append(sem);
4695 desc.SemanticName = matrixSliceSemantics.last().constData();
4696 desc.SemanticIndex = UINT(matrixSlice);
4697 }
4698 desc.Format = toD3DAttributeFormat(it->format());
4699 desc.InputSlot = UINT(it->binding());
4700 desc.AlignedByteOffset = it->offset();
4701 const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
4702 if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
4703 desc.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
4704 desc.InstanceDataStepRate = inputBinding->instanceStepRate();
4705 } else {
4706 desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
4707 }
4708 inputDescs.append(desc);
4709 }
4710 if (!inputDescs.isEmpty()) {
4711 hr = rhiD->dev->CreateInputLayout(inputDescs.constData(), UINT(inputDescs.count()),
4712 vsByteCode, SIZE_T(vsByteCode.size()), &inputLayout);
4713 if (FAILED(hr)) {
4714 qWarning("Failed to create input layout: %s",
4715 qPrintable(QSystemError::windowsComString(hr)));
4716 return false;
4717 }
4718 } // else leave inputLayout set to nullptr; that's valid and it avoids a debug layer warning about an input layout with 0 elements
4719 }
4720
4721 rhiD->pipelineCreationEnd();
4722 generation += 1;
4723 rhiD->registerResource(this);
4724 return true;
4725}
4726
4731
4736
4738{
4739 if (!cs.shader)
4740 return;
4741
4742 cs.shader->Release();
4743 cs.shader = nullptr;
4744 cs.nativeResourceBindingMap.clear();
4745
4747 if (rhiD)
4748 rhiD->unregisterResource(this);
4749}
4750
4752{
4753 if (cs.shader)
4754 destroy();
4755
4757 rhiD->pipelineCreationStart();
4758
4759 auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage);
4760 if (cacheIt != rhiD->m_shaderCache.constEnd()) {
4761 cs.shader = static_cast<ID3D11ComputeShader *>(cacheIt->s);
4762 cs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
4763 } else {
4764 QString error;
4765 QShaderKey shaderKey;
4766 UINT compileFlags = 0;
4768 compileFlags |= D3DCOMPILE_DEBUG;
4769
4770 const QByteArray bytecode = rhiD->compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), compileFlags,
4771 &error, &shaderKey);
4772 if (bytecode.isEmpty()) {
4773 qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
4774 return false;
4775 }
4776
4777 HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader);
4778 if (FAILED(hr)) {
4779 qWarning("Failed to create compute shader: %s",
4780 qPrintable(QSystemError::windowsComString(hr)));
4781 return false;
4782 }
4783
4784 cs.nativeResourceBindingMap = m_shaderStage.shader().nativeResourceBindingMap(shaderKey);
4785
4786 if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES)
4787 rhiD->clearShaderCache();
4788
4789 rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs.shader, bytecode, cs.nativeResourceBindingMap));
4790 }
4791
4792 cs.shader->AddRef();
4793
4794 rhiD->pipelineCreationEnd();
4795 generation += 1;
4796 rhiD->registerResource(this);
4797 return true;
4798}
4799
4805
4810
4812{
4813 // nothing to do here
4814}
4815
4817{
4818 // Creates the query objects if not yet done, but otherwise calling this
4819 // function is expected to be a no-op.
4820
4821 D3D11_QUERY_DESC queryDesc = {};
4822 for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
4823 if (!disjointQuery[i]) {
4824 queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
4825 HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &disjointQuery[i]);
4826 if (FAILED(hr)) {
4827 qWarning("Failed to create timestamp disjoint query: %s",
4828 qPrintable(QSystemError::windowsComString(hr)));
4829 return false;
4830 }
4831 }
4832 queryDesc.Query = D3D11_QUERY_TIMESTAMP;
4833 for (int j = 0; j < 2; ++j) {
4834 const int idx = 2 * i + j;
4835 if (!query[idx]) {
4836 HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &query[idx]);
4837 if (FAILED(hr)) {
4838 qWarning("Failed to create timestamp query: %s",
4839 qPrintable(QSystemError::windowsComString(hr)));
4840 return false;
4841 }
4842 }
4843 }
4844 }
4845 return true;
4846}
4847
4849{
4850 for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
4851 active[i] = false;
4852 if (disjointQuery[i]) {
4853 disjointQuery[i]->Release();
4854 disjointQuery[i] = nullptr;
4855 }
4856 for (int j = 0; j < 2; ++j) {
4857 const int idx = TIMESTAMP_PAIRS * i + j;
4858 if (query[idx]) {
4859 query[idx]->Release();
4860 query[idx] = nullptr;
4861 }
4862 }
4863 }
4864}
4865
4866bool QD3D11SwapChainTimestamps::tryQueryTimestamps(int pairIndex, ID3D11DeviceContext *context, double *elapsedSec)
4867{
4868 bool result = false;
4869 if (!active[pairIndex])
4870 return result;
4871
4872 ID3D11Query *tsDisjoint = disjointQuery[pairIndex];
4873 ID3D11Query *tsStart = query[pairIndex * 2];
4874 ID3D11Query *tsEnd = query[pairIndex * 2 + 1];
4875 quint64 timestamps[2];
4876 D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
4877
4878 bool ok = true;
4879 ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4880 ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4881 ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
4882
4883 if (ok) {
4884 if (!dj.Disjoint && dj.Frequency) {
4885 const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
4886 *elapsedSec = elapsedMs / 1000.0;
4887 result = true;
4888 }
4889 active[pairIndex] = false;
4890 } // else leave active set, will retry in a subsequent beginFrame
4891
4892 return result;
4893}
4894
4896 : QRhiSwapChain(rhi), rt(rhi, this), rtRight(rhi, this), cb(rhi)
4897{
4898 backBufferTex = nullptr;
4899 backBufferRtv = nullptr;
4900 for (int i = 0; i < BUFFER_COUNT; ++i) {
4901 msaaTex[i] = nullptr;
4902 msaaRtv[i] = nullptr;
4903 }
4904}
4905
4910
4912{
4913 if (backBufferRtv) {
4914 backBufferRtv->Release();
4915 backBufferRtv = nullptr;
4916 }
4917 if (backBufferRtvRight) {
4918 backBufferRtvRight->Release();
4919 backBufferRtvRight = nullptr;
4920 }
4921 if (backBufferTex) {
4922 backBufferTex->Release();
4923 backBufferTex = nullptr;
4924 }
4925 for (int i = 0; i < BUFFER_COUNT; ++i) {
4926 if (msaaRtv[i]) {
4927 msaaRtv[i]->Release();
4928 msaaRtv[i] = nullptr;
4929 }
4930 if (msaaTex[i]) {
4931 msaaTex[i]->Release();
4932 msaaTex[i] = nullptr;
4933 }
4934 }
4935}
4936
4938{
4939 if (!swapChain)
4940 return;
4941
4943
4945
4946 swapChain->Release();
4947 swapChain = nullptr;
4948
4949 if (dcompVisual) {
4950 dcompVisual->Release();
4951 dcompVisual = nullptr;
4952 }
4953
4954 if (dcompTarget) {
4955 dcompTarget->Release();
4956 dcompTarget = nullptr;
4957 }
4958
4960 if (rhiD) {
4961 rhiD->unregisterResource(this);
4962 // See Deferred Destruction Issues with Flip Presentation Swap Chains in
4963 // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-flush
4964 rhiD->context->Flush();
4965 }
4966}
4967
4972
4977
4982
4984{
4986 return m_window->size() * m_window->devicePixelRatio();
4987}
4988
4990{
4991 if (f == SDR)
4992 return true;
4993
4994 if (!m_window) {
4995 qWarning("Attempted to call isFormatSupported() without a window set");
4996 return false;
4997 }
4998
5000 DXGI_OUTPUT_DESC1 desc1;
5001 if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) {
5002 if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
5004 }
5005
5006 return false;
5007}
5008
5010{
5012 // Must use m_window, not window, given this may be called before createOrResize().
5013 if (m_window) {
5015 DXGI_OUTPUT_DESC1 hdrOutputDesc;
5016 if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
5018 info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
5019 info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
5020 info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits
5021 info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc);
5022 }
5023 }
5024 return info;
5025}
5026
5028{
5031 rhiD->registerResource(rpD, false);
5032 return rpD;
5033}
5034
5035bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
5036 ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const
5037{
5038 D3D11_TEXTURE2D_DESC desc = {};
5039 desc.Width = UINT(size.width());
5040 desc.Height = UINT(size.height());
5041 desc.MipLevels = 1;
5042 desc.ArraySize = 1;
5043 desc.Format = format;
5044 desc.SampleDesc = sampleDesc;
5045 desc.Usage = D3D11_USAGE_DEFAULT;
5046 desc.BindFlags = D3D11_BIND_RENDER_TARGET;
5047
5049 HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, tex);
5050 if (FAILED(hr)) {
5051 qWarning("Failed to create color buffer texture: %s",
5052 qPrintable(QSystemError::windowsComString(hr)));
5053 return false;
5054 }
5055
5056 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5057 rtvDesc.Format = format;
5058 rtvDesc.ViewDimension = sampleDesc.Count > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
5059 hr = rhiD->dev->CreateRenderTargetView(*tex, &rtvDesc, rtv);
5060 if (FAILED(hr)) {
5061 qWarning("Failed to create color buffer rtv: %s",
5062 qPrintable(QSystemError::windowsComString(hr)));
5063 (*tex)->Release();
5064 *tex = nullptr;
5065 return false;
5066 }
5067
5068 return true;
5069}
5070
5072{
5073 if (dcompDevice)
5074 return true;
5075
5076 qCDebug(QRHI_LOG_INFO, "Creating Direct Composition device (needed for semi-transparent windows)");
5078 return dcompDevice ? true : false;
5079}
5080
5081static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
5082static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
5083
5085{
5086 // Can be called multiple times due to window resizes - that is not the
5087 // same as a simple destroy+create (as with other resources). Just need to
5088 // resize the buffers then.
5089
5090 const bool needsRegistration = !window || window != m_window;
5091 const bool stereo = m_window->format().stereo();
5092
5093 // except if the window actually changes
5094 if (window && window != m_window)
5095 destroy();
5096
5097 window = m_window;
5100
5101 if (pixelSize.isEmpty())
5102 return false;
5103
5104 HWND hwnd = reinterpret_cast<HWND>(window->winId());
5105 HRESULT hr;
5106
5108
5110 if (!rhiD->useLegacySwapchainModel && rhiD->ensureDirectCompositionDevice()) {
5111 if (!dcompTarget) {
5112 hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd, false, &dcompTarget);
5113 if (FAILED(hr)) {
5114 qWarning("Failed to create Direct Compsition target for the window: %s",
5115 qPrintable(QSystemError::windowsComString(hr)));
5116 }
5117 }
5118 if (dcompTarget && !dcompVisual) {
5119 hr = rhiD->dcompDevice->CreateVisual(&dcompVisual);
5120 if (FAILED(hr)) {
5121 qWarning("Failed to create DirectComposition visual: %s",
5122 qPrintable(QSystemError::windowsComString(hr)));
5123 }
5124 }
5125 }
5126 // simple consistency check
5127 if (window->requestedFormat().alphaBufferSize() <= 0)
5128 qWarning("Swapchain says surface has alpha but the window has no alphaBufferSize set. "
5129 "This may lead to problems.");
5130 }
5131
5132 swapInterval = m_flags.testFlag(QRhiSwapChain::NoVSync) ? 0 : 1;
5133 swapChainFlags = 0;
5134
5135 // A non-flip swapchain can do Present(0) as expected without
5136 // ALLOW_TEARING, and ALLOW_TEARING is not compatible with it at all so the
5137 // flag must not be set then. Whereas for flip we should use it, if
5138 // supported, to get better results for 'unthrottled' presentation.
5139 if (swapInterval == 0 && rhiD->supportsAllowTearing)
5140 swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
5141
5142 if (!swapChain) {
5143 sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
5146
5147 DXGI_COLOR_SPACE_TYPE hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR
5148 DXGI_OUTPUT_DESC1 hdrOutputDesc;
5149 if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
5150 // https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
5151 if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
5152 switch (m_format) {
5154 colorFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
5155 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
5157 break;
5158 case HDR10:
5159 colorFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
5160 hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
5162 break;
5163 default:
5164 break;
5165 }
5166 } else {
5167 // This happens also when Use HDR is set to Off in the Windows
5168 // Display settings. Show a helpful warning, but continue with the
5169 // default non-HDR format.
5170 qWarning("The output associated with the window is not HDR capable "
5171 "(or Use HDR is Off in the Display Settings), ignoring HDR format request");
5172 }
5173 }
5174
5175 // We use a FLIP model swapchain which implies a buffer count of 2
5176 // (as opposed to the old DISCARD with back buffer count == 1).
5177 // This makes no difference for the rest of the stuff except that
5178 // automatic MSAA is unsupported and needs to be implemented via a
5179 // custom multisample render target and an explicit resolve.
5180
5181 DXGI_SWAP_CHAIN_DESC1 desc = {};
5182 desc.Width = UINT(pixelSize.width());
5183 desc.Height = UINT(pixelSize.height());
5184 desc.Format = colorFormat;
5185 desc.SampleDesc.Count = 1;
5186 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5187 desc.BufferCount = BUFFER_COUNT;
5188 desc.Flags = swapChainFlags;
5189 desc.Scaling = rhiD->useLegacySwapchainModel ? DXGI_SCALING_STRETCH : DXGI_SCALING_NONE;
5190 desc.SwapEffect = rhiD->useLegacySwapchainModel ? DXGI_SWAP_EFFECT_DISCARD : DXGI_SWAP_EFFECT_FLIP_DISCARD;
5191 desc.Stereo = stereo;
5192
5193 if (dcompVisual) {
5194 // With DirectComposition setting AlphaMode to STRAIGHT fails the
5195 // swapchain creation, whereas the result seems to be identical
5196 // with any of the other values, including IGNORE. (?)
5197 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
5198
5199 // DirectComposition has its own limitations, cannot use
5200 // SCALING_NONE. So with semi-transparency requested we are forced
5201 // to SCALING_STRETCH.
5202 desc.Scaling = DXGI_SCALING_STRETCH;
5203 }
5204
5205 IDXGIFactory2 *fac = static_cast<IDXGIFactory2 *>(rhiD->dxgiFactory);
5206 IDXGISwapChain1 *sc1;
5207
5208 if (dcompVisual)
5209 hr = fac->CreateSwapChainForComposition(rhiD->dev, &desc, nullptr, &sc1);
5210 else
5211 hr = fac->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc, nullptr, nullptr, &sc1);
5212
5213 // If failed and we tried a HDR format, then try with SDR. This
5214 // matches other backends, such as Vulkan where if the format is
5215 // not supported, the default one is used instead.
5216 if (FAILED(hr) && m_format != SDR) {
5218 desc.Format = DEFAULT_FORMAT;
5219 if (dcompVisual)
5220 hr = fac->CreateSwapChainForComposition(rhiD->dev, &desc, nullptr, &sc1);
5221 else
5222 hr = fac->CreateSwapChainForHwnd(rhiD->dev, hwnd, &desc, nullptr, nullptr, &sc1);
5223 }
5224
5225 if (SUCCEEDED(hr)) {
5226 swapChain = sc1;
5227 if (m_format != SDR) {
5228 IDXGISwapChain3 *sc3 = nullptr;
5229 if (SUCCEEDED(sc1->QueryInterface(__uuidof(IDXGISwapChain3), reinterpret_cast<void **>(&sc3)))) {
5230 hr = sc3->SetColorSpace1(hdrColorSpace);
5231 if (FAILED(hr))
5232 qWarning("Failed to set color space on swapchain: %s",
5233 qPrintable(QSystemError::windowsComString(hr)));
5234 sc3->Release();
5235 } else {
5236 qWarning("IDXGISwapChain3 not available, HDR swapchain will not work as expected");
5237 }
5238 }
5239 if (dcompVisual) {
5240 hr = dcompVisual->SetContent(sc1);
5241 if (SUCCEEDED(hr)) {
5242 hr = dcompTarget->SetRoot(dcompVisual);
5243 if (FAILED(hr)) {
5244 qWarning("Failed to associate Direct Composition visual with the target: %s",
5245 qPrintable(QSystemError::windowsComString(hr)));
5246 }
5247 } else {
5248 qWarning("Failed to set content for Direct Composition visual: %s",
5249 qPrintable(QSystemError::windowsComString(hr)));
5250 }
5251 } else {
5252 // disable Alt+Enter; not relevant when using DirectComposition
5253 rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
5254 }
5255 }
5256 if (FAILED(hr)) {
5257 qWarning("Failed to create D3D11 swapchain: %s"
5258 " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
5259 qPrintable(QSystemError::windowsComString(hr)),
5260 desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
5261 desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
5262 return false;
5263 }
5264 } else {
5266 // flip model -> buffer count is the real buffer count, not 1 like with the legacy modes
5267 hr = swapChain->ResizeBuffers(UINT(BUFFER_COUNT), UINT(pixelSize.width()), UINT(pixelSize.height()),
5269 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
5270 qWarning("Device loss detected in ResizeBuffers()");
5271 rhiD->deviceLost = true;
5272 return false;
5273 } else if (FAILED(hr)) {
5274 qWarning("Failed to resize D3D11 swapchain: %s",
5275 qPrintable(QSystemError::windowsComString(hr)));
5276 return false;
5277 }
5278 }
5279
5280 // This looks odd (for FLIP_*, esp. compared with backends for Vulkan
5281 // & co.) but the backbuffer is always at index 0, with magic underneath.
5282 // Some explanation from
5283 // https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-1-4-improvements
5284 //
5285 // "In Direct3D 11, applications could call GetBuffer( 0, … ) only once.
5286 // Every call to Present implicitly changed the resource identity of the
5287 // returned interface. Direct3D 12 no longer supports that implicit
5288 // resource identity change, due to the CPU overhead required and the
5289 // flexible resource descriptor design. As a result, the application must
5290 // manually call GetBuffer for every each buffer created with the
5291 // swapchain."
5292
5293 // So just query index 0 once (per resize) and be done with it.
5294 hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&backBufferTex));
5295 if (FAILED(hr)) {
5296 qWarning("Failed to query swapchain backbuffer: %s",
5297 qPrintable(QSystemError::windowsComString(hr)));
5298 return false;
5299 }
5300 D3D11_RENDER_TARGET_VIEW_DESC rtvDesc = {};
5301 rtvDesc.Format = srgbAdjustedColorFormat;
5302 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
5303 hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtv);
5304 if (FAILED(hr)) {
5305 qWarning("Failed to create rtv for swapchain backbuffer: %s",
5306 qPrintable(QSystemError::windowsComString(hr)));
5307 return false;
5308 }
5309
5310 if (stereo) {
5311 // Create a second render target view for the right eye
5312 rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
5313 rtvDesc.Texture2DArray.FirstArraySlice = 1;
5314 rtvDesc.Texture2DArray.ArraySize = 1;
5315 hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtvRight);
5316 if (FAILED(hr)) {
5317 qWarning("Failed to create rtv for swapchain backbuffer (right eye): %s",
5318 qPrintable(QSystemError::windowsComString(hr)));
5319 return false;
5320 }
5321 }
5322
5323 // Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer.
5324 for (int i = 0; i < BUFFER_COUNT; ++i) {
5325 if (sampleDesc.Count > 1) {
5327 return false;
5328 }
5329 }
5330
5332 qWarning("Depth-stencil buffer's sampleCount (%d) does not match color buffers' sample count (%d). Expect problems.",
5334 }
5338 if (!m_depthStencil->create())
5339 qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
5341 } else {
5342 qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
5345 }
5346 }
5347
5348 currentFrameSlot = 0;
5349 frameCount = 0;
5351
5352 rt.setRenderPassDescriptor(m_renderPassDesc); // for the public getter in QRhiRenderTarget
5355 rtD->d.pixelSize = pixelSize;
5356 rtD->d.dpr = float(window->devicePixelRatio());
5357 rtD->d.sampleCount = int(sampleDesc.Count);
5358 rtD->d.colorAttCount = 1;
5359 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
5360
5361 if (stereo) {
5364 rtD->d.pixelSize = pixelSize;
5365 rtD->d.dpr = float(window->devicePixelRatio());
5366 rtD->d.sampleCount = int(sampleDesc.Count);
5367 rtD->d.colorAttCount = 1;
5368 rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
5369 rtD->d.rtv[0] = backBufferRtvRight;
5370 rtD->d.dsv = ds ? ds->dsv : nullptr;
5371 }
5372
5373 if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps)) {
5374 timestamps.prepare(rhiD);
5375 // timestamp queries are optional so we can go on even if they failed
5376 }
5377
5378 if (needsRegistration)
5379 rhiD->registerResource(this);
5380
5381 return true;
5382}
5383
IOBluetoothDevice * device
\inmodule QtCore
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:612
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:495
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:1213
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1292
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1217
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:952
\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:689
const_iterator cend() const
Definition qmap.h:606
const_iterator constFind(const Key &key) const
Definition qmap.h:656
bool isEmpty() const
Definition qmap.h:270
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:1652
QPair< int, quint32 > DynamicOffset
Synonym for QPair<int, quint32>.
Definition qrhi.h:1677
QPair< QRhiBuffer *, quint32 > VertexInput
Synonym for QPair<QRhiBuffer *, quint32>.
Definition qrhi.h:1681
IndexFormat
Specifies the index data type.
Definition qrhi.h:1654
\inmodule QtGui
Definition qrhi.h:1623
QRhiShaderStage m_shaderStage
Definition qrhi.h:1645
@ CompileShadersWithDebugInfo
Definition qrhi.h:1626
\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:1271
quint32 m_stencilReadMask
Definition qrhi.h:1492
@ CompileShadersWithDebugInfo
Definition qrhi.h:1277
BlendOp
Specifies the blend operation.
Definition qrhi.h:1332
PolygonMode
Specifies the polygon rasterization mode.
Definition qrhi.h:1380
BlendFactor
Specifies the blend factor.
Definition qrhi.h:1310
StencilOpState m_stencilFront
Definition qrhi.h:1490
quint32 m_stencilWriteMask
Definition qrhi.h:1493
CompareOp
Specifies the depth or stencil comparison function.
Definition qrhi.h:1351
Topology m_topology
Definition qrhi.h:1482
CullMode
Specifies the culling mode.
Definition qrhi.h:1291
QVarLengthArray< QRhiShaderStage, 4 > m_shaderStages
Definition qrhi.h:1501
QRhiVertexInputLayout m_vertexInputLayout
Definition qrhi.h:1502
QVarLengthArray< TargetBlend, 8 > m_targetBlends
Definition qrhi.h:1485
PolygonMode m_polygonMode
Definition qrhi.h:1499
float m_slopeScaledDepthBias
Definition qrhi.h:1497
Topology
Specifies the primitive topology.
Definition qrhi.h:1281
StencilOpState m_stencilBack
Definition qrhi.h:1491
FrontFace m_frontFace
Definition qrhi.h:1484
StencilOp
Specifies the stencil operation.
Definition qrhi.h:1362
int m_patchControlPointCount
Definition qrhi.h:1498
CullMode m_cullMode
Definition qrhi.h:1483
CompareOp m_depthOp
Definition qrhi.h:1488
int effectiveSampleCount(int sampleCount) const
Definition qrhi.cpp:8394
bool isCompressedFormat(QRhiTexture::Format format) const
Definition qrhi.cpp:8061
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:8068
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:8188
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:1095
Flags flags() const
Definition qrhi.h:1122
void setPixelSize(const QSize &sz)
Sets the size (in pixels) to sz.
Definition qrhi.h:1117
QSize pixelSize() const
Definition qrhi.h:1116
int sampleCount() const
Definition qrhi.h:1119
int m_sampleCount
Definition qrhi.h:1135
QRhiTexture::Format m_backingFormatHint
Definition qrhi.h:1137
QSize m_pixelSize
Definition qrhi.h:1134
Type
Specifies the type of the renderbuffer.
Definition qrhi.h:1097
virtual bool create()=0
Creates the corresponding native graphics resources.
@ UsedWithSwapChainOnly
Definition qrhi.h:1103
\inmodule QtGui
Definition qrhi.h:1143
\inmodule QtGui
Definition qrhi.h:1159
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Sets the QRhiRenderPassDescriptor desc for use with this render target.
Definition qrhi.h:1166
virtual QSize pixelSize() const =0
QRhiRenderPassDescriptor * m_renderPassDesc
Definition qrhi.h:1170
static QRhiResourceUpdateBatchPrivate * get(QRhiResourceUpdateBatch *b)
Definition qrhi_p.h:536
\inmodule QtGui
Definition qrhi.h:1732
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:1031
Filter m_minFilter
Definition qrhi.h:1086
Filter
Specifies the minification, magnification, or mipmap filtering.
Definition qrhi.h:1033
AddressMode m_addressV
Definition qrhi.h:1089
Filter m_mipmapMode
Definition qrhi.h:1087
AddressMode m_addressU
Definition qrhi.h:1088
AddressMode
Specifies the addressing mode.
Definition qrhi.h:1039
@ ClampToEdge
Definition qrhi.h:1041
CompareOp
Specifies the texture comparison function.
Definition qrhi.h:1045
@ LessOrEqual
Definition qrhi.h:1049
@ GreaterOrEqual
Definition qrhi.h:1052
CompareOp m_compareOp
Definition qrhi.h:1091
AddressMode m_addressW
Definition qrhi.h:1090
Filter m_magFilter
Definition qrhi.h:1085
\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:1215
QVarLengthArray< QRhiShaderResourceBinding, BINDING_PREALLOC > m_bindings
Definition qrhi.h:1247
\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:1174
\inmodule QtGui
Definition qrhi.h:1550
Format format() const
Definition qrhi.h:1585
QWindow * m_window
Definition qrhi.h:1610
int m_sampleCount
Definition qrhi.h:1614
@ SurfaceHasNonPreMulAlpha
Definition qrhi.h:1554
@ SurfaceHasPreMulAlpha
Definition qrhi.h:1553
QRhiRenderPassDescriptor * m_renderPassDesc
Definition qrhi.h:1615
QSize m_currentPixelSize
Definition qrhi.h:1616
Flags m_flags
Definition qrhi.h:1611
Format
Describes the swapchain format.
Definition qrhi.h:1562
@ HDRExtendedSrgbLinear
Definition qrhi.h:1564
StereoTargetBuffer
Selects the backbuffer to use with a stereoscopic swapchain.
Definition qrhi.h:1569
Format m_format
Definition qrhi.h:1612
virtual QRhiSwapChainHdrInfo hdrInfo()
\variable QRhiSwapChainHdrInfo::limitsType
Definition qrhi.cpp:7800
QRhiRenderBuffer * m_depthStencil
Definition qrhi.h:1613
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:1185
QRhiTextureRenderTargetDescription m_desc
Definition qrhi.h:1208
\inmodule QtGui
Definition qrhi.h:895
QSize m_pixelSize
Definition qrhi.h:1017
int m_arraySize
Definition qrhi.h:1019
int m_depth
Definition qrhi.h:1018
@ 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:1023
Format
Specifies the texture format.
Definition qrhi.h:914
@ ASTC_10x8
Definition qrhi.h:960
@ ASTC_12x12
Definition qrhi.h:963
@ ASTC_8x5
Definition qrhi.h:955
@ ASTC_10x5
Definition qrhi.h:958
@ RGBA32F
Definition qrhi.h:926
@ ETC2_RGBA8
Definition qrhi.h:948
@ ASTC_5x5
Definition qrhi.h:952
@ ASTC_4x4
Definition qrhi.h:950
@ ASTC_6x6
Definition qrhi.h:954
@ ASTC_12x10
Definition qrhi.h:962
@ ETC2_RGB8
Definition qrhi.h:946
@ ASTC_5x4
Definition qrhi.h:951
@ RED_OR_ALPHA8
Definition qrhi.h:923
@ ASTC_6x5
Definition qrhi.h:953
@ ASTC_8x8
Definition qrhi.h:957
@ RGBA16F
Definition qrhi.h:925
@ RGB10A2
Definition qrhi.h:930
@ ASTC_10x6
Definition qrhi.h:959
@ ASTC_10x10
Definition qrhi.h:961
@ UnknownFormat
Definition qrhi.h:915
@ ETC2_RGB8A1
Definition qrhi.h:947
@ ASTC_8x6
Definition qrhi.h:956
Flags flags() const
Definition qrhi.h:993
Format m_format
Definition qrhi.h:1016
Flags m_flags
Definition qrhi.h:1021
int m_arrayRangeStart
Definition qrhi.h:1022
int m_sampleCount
Definition qrhi.h:1020
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:1998
ResourceLimit
Describes the resource limit to query.
Definition qrhi.h:1887
@ MaxThreadsPerThreadGroup
Definition qrhi.h:1894
@ MaxThreadGroupZ
Definition qrhi.h:1897
@ FramesInFlight
Definition qrhi.h:1891
@ TextureSizeMin
Definition qrhi.h:1888
@ MaxThreadGroupsPerDimension
Definition qrhi.h:1893
@ MaxAsyncReadbackFrames
Definition qrhi.h:1892
@ TextureArraySizeMax
Definition qrhi.h:1898
@ MaxColorAttachments
Definition qrhi.h:1890
@ MaxThreadGroupY
Definition qrhi.h:1896
@ MaxVertexInputs
Definition qrhi.h:1900
@ MaxThreadGroupX
Definition qrhi.h:1895
@ TextureSizeMax
Definition qrhi.h:1889
@ MaxVertexOutputs
Definition qrhi.h:1901
@ MaxUniformBufferRange
Definition qrhi.h:1899
@ SkipPresent
Definition qrhi.h:1883
Feature
Flag values to indicate what features are supported by the backend currently in use.
Definition qrhi.h:1832
@ HalfAttributes
Definition qrhi.h:1870
@ CustomInstanceStepRate
Definition qrhi.h:1838
@ NonDynamicUniformBuffers
Definition qrhi.h:1840
@ ElementIndexUint
Definition qrhi.h:1844
@ RenderToNonBaseMipLevel
Definition qrhi.h:1854
@ MultisampleRenderBuffer
Definition qrhi.h:1834
@ RenderTo3DTextureSlice
Definition qrhi.h:1862
@ Tessellation
Definition qrhi.h:1864
@ IntAttributes
Definition qrhi.h:1855
@ TextureArrays
Definition qrhi.h:1863
@ PipelineCacheDataLoadSave
Definition qrhi.h:1858
@ ReadBackNonUniformBuffer
Definition qrhi.h:1851
@ MultiView
Definition qrhi.h:1873
@ TexelFetch
Definition qrhi.h:1853
@ TextureArrayRange
Definition qrhi.h:1866
@ RenderToOneDimensionalTexture
Definition qrhi.h:1871
@ BaseVertex
Definition qrhi.h:1848
@ GeometryShader
Definition qrhi.h:1865
@ Compute
Definition qrhi.h:1845
@ OneDimensionalTextureMipmaps
Definition qrhi.h:1869
@ WideLines
Definition qrhi.h:1846
@ TriangleFanTopology
Definition qrhi.h:1850
@ OneDimensionalTextures
Definition qrhi.h:1868
@ ImageDataStride
Definition qrhi.h:1859
@ TextureViewFormat
Definition qrhi.h:1874
@ BaseInstance
Definition qrhi.h:1849
@ DebugMarkers
Definition qrhi.h:1835
@ ReadBackNonBaseMipLevel
Definition qrhi.h:1852
@ MultisampleTexture
Definition qrhi.h:1833
@ ThreeDimensionalTextureMipmaps
Definition qrhi.h:1872
@ NonFourAlignedEffectiveIndexBufferOffset
Definition qrhi.h:1841
@ RedOrAlpha8IsRed
Definition qrhi.h:1843
@ NonFillPolygonMode
Definition qrhi.h:1867
@ Timestamps
Definition qrhi.h:1836
@ ThreeDimensionalTextures
Definition qrhi.h:1861
@ PrimitiveRestart
Definition qrhi.h:1839
@ ReadBackAnyTextureFormat
Definition qrhi.h:1857
@ RenderBufferImport
Definition qrhi.h:1860
@ ScreenSpaceDerivatives
Definition qrhi.h:1856
@ VertexShaderPointSize
Definition qrhi.h:1847
@ NPOTTextureRepeat
Definition qrhi.h:1842
@ Instancing
Definition qrhi.h:1837
@ ResolveDepthStencil
Definition qrhi.h:1875
FrameOpResult
Describes the result of operations that can have a soft failure.
Definition qrhi.h:1825
@ FrameOpSuccess
Definition qrhi.h:1826
@ FrameOpDeviceLost
Definition qrhi.h:1829
@ FrameOpError
Definition qrhi.h:1827
@ EnablePipelineCacheDataSave
Definition qrhi.h:1819
@ SuppressSmokeTestWarnings
Definition qrhi.h:1821
@ PreferSoftwareRenderer
Definition qrhi.h:1818
@ EnableTimestamps
Definition qrhi.h:1820
qsizetype size() const
Definition qset.h:51
void clear()
Definition qset.h:62
\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:5881
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition qstring.cpp:6055
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6028
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:956
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
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:167
#define qCDebug(category,...)
QT_BEGIN_NAMESPACE constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:19
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:21
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:1760
\variable QRhiReadbackResult::completed
Definition qrhi.h:800
QByteArray data
Definition qrhi.h:1728
std::function< void()> completed
Definition qrhi.h:1725
QRhiTextureCopyDescription desc
Definition qrhi_p.h:471
QVarLengthArray< MipLevelUploadList, 6 > subresDesc
Definition qrhi_p.h:469
\inmodule QtGui
Definition qrhi.h:1783
\inmodule QtGui
Definition qrhi.h:1512
\inmodule QtGui
Definition qrhi.h:966
Definition moc.h:23