diff options
author | Ben Fletcher <ben.fletcher@me.com> | 2022-12-08 21:34:12 -0800 |
---|---|---|
committer | Ben Fletcher <ben.fletcher@me.com> | 2022-12-14 17:29:53 -0800 |
commit | 509fd9f2bbe015c677adfd5381a91b3c808ca36d (patch) | |
tree | a9e908ec313eaa7f55c5e922371f225051c7a726 /tests/auto/gui/rhi/qrhi/tst_qrhi.cpp | |
parent | 2946447f50bc03ae5c9b5b9668d43ca7223a53c1 (diff) |
RHI: Buffer readback fixes and unit test
Fixes issues with readback of storage buffers modified on GPU for D3D
and Metal. Adds unit test for storage buffer readback.
D3D
* Fixes issue where QRhiBufferReadbackResult::completed callback could
be called twice on buffer readback completion.
Metal
* Fixes issue where buffer readback occurred prior to command buffer
being committed.
Change-Id: If55ac005f4438d66d2f65ea2e1ee0d5686c884ff
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'tests/auto/gui/rhi/qrhi/tst_qrhi.cpp')
-rw-r--r-- | tests/auto/gui/rhi/qrhi/tst_qrhi.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index cf67708bca..9a5ce3c5a3 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -141,6 +141,9 @@ private slots: void tessellation_data(); void tessellation(); + void storageBuffer_data(); + void storageBuffer(); + private: void setWindowType(QWindow *window, QRhi::Implementation impl); @@ -5572,5 +5575,125 @@ void tst_QRhi::tessellation() QVERIFY(greenCount > 50); } +void tst_QRhi::storageBuffer_data() +{ + rhiTestData(); +} + +void tst_QRhi::storageBuffer() +{ + // Use a compute shader to copy from one storage buffer of float types to + // another of int types. We fill the "toGpu" buffer with known float type + // data generated and uploaded from the CPU, then dispatch a compute shader + // to copy from the "toGpu" buffer to the "fromGpu" buffer. We then + // readback the "fromGpu" buffer and verify that the results are as + // expected. + + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + // we can't test with Null as there is no compute + if (impl == QRhi::Null) + return; + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing"); + + if (!rhi->isFeatureSupported(QRhi::Feature::Compute)) + QSKIP("Compute is not supported with this graphics API, skipping test"); + + QShader s = loadShader(":/data/storagebuffer.comp.qsb"); + QVERIFY(s.isValid()); + QCOMPARE(s.description().storageBlocks().size(), 2); + + QMap<QByteArray, QShaderDescription::StorageBlock> blocks; + for (const QShaderDescription::StorageBlock &block : s.description().storageBlocks()) + blocks[block.blockName] = block; + + QMap<QByteArray, QShaderDescription::BlockVariable> toGpuMembers; + for (const QShaderDescription::BlockVariable &member: blocks["toGpu"].members) + toGpuMembers[member.name] = member; + + QMap<QByteArray, QShaderDescription::BlockVariable> fromGpuMembers; + for (const QShaderDescription::BlockVariable &member: blocks["fromGpu"].members) + fromGpuMembers[member.name] = member; + + for (QRhiBuffer::Type type : {QRhiBuffer::Type::Immutable, QRhiBuffer::Type::Static}) { + + QRhiCommandBuffer *cb = nullptr; + rhi->beginOffscreenFrame(&cb); + QVERIFY(cb); + + QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); + QVERIFY(u); + + QScopedPointer<QRhiBuffer> toGpuBuffer(rhi->newBuffer(type, QRhiBuffer::UsageFlag::StorageBuffer, blocks["toGpu"].knownSize)); + QVERIFY(toGpuBuffer->create()); + + QScopedPointer<QRhiBuffer> fromGpuBuffer(rhi->newBuffer(type, QRhiBuffer::UsageFlag::StorageBuffer, blocks["fromGpu"].knownSize)); + QVERIFY(fromGpuBuffer->create()); + + QByteArray toGpuData(blocks["toGpu"].knownSize, 0); + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_float"].offset])[0] = 1.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec2"].offset])[0] = 2.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec2"].offset])[1] = 3.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec3"].offset])[0] = 4.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec3"].offset])[1] = 5.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec3"].offset])[2] = 6.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec4"].offset])[0] = 7.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec4"].offset])[1] = 8.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec4"].offset])[2] = 9.0f; + reinterpret_cast<float *>(&toGpuData.data()[toGpuMembers["_vec4"].offset])[3] = 10.0f; + + u->uploadStaticBuffer(toGpuBuffer.data(), 0, toGpuData.size(), toGpuData.constData()); + u->uploadStaticBuffer(fromGpuBuffer.data(), 0, blocks["fromGpu"].knownSize, QByteArray(blocks["fromGpu"].knownSize, 0).constData()); + + QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings()); + srb->setBindings({QRhiShaderResourceBinding::bufferLoadStore(blocks["toGpu"].binding, QRhiShaderResourceBinding::ComputeStage, toGpuBuffer.data()), + QRhiShaderResourceBinding::bufferLoadStore(blocks["fromGpu"].binding, QRhiShaderResourceBinding::ComputeStage, fromGpuBuffer.data())}); + + QVERIFY(srb->create()); + + QScopedPointer<QRhiComputePipeline> pipeline(rhi->newComputePipeline()); + pipeline->setShaderStage({QRhiShaderStage::Compute, s}); + pipeline->setShaderResourceBindings(srb.data()); + QVERIFY(pipeline->create()); + + cb->beginComputePass(u); + + cb->setComputePipeline(pipeline.data()); + cb->setShaderResources(); + cb->dispatch(1, 1, 1); + + u = rhi->nextResourceUpdateBatch(); + QVERIFY(u); + + int readCompletedNotifications = 0; + QRhiBufferReadbackResult result; + result.completed = [&readCompletedNotifications]() { readCompletedNotifications++; }; + u->readBackBuffer(fromGpuBuffer.data(), 0, blocks["fromGpu"].knownSize, &result); + + cb->endComputePass(u); + + rhi->endOffscreenFrame(); + + QCOMPARE(readCompletedNotifications, 1); + + QCOMPARE(result.data.size(), blocks["fromGpu"].knownSize); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_int"].offset])[0], 1); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec2"].offset])[0], 2); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec2"].offset])[1], 3); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec3"].offset])[0], 4); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec3"].offset])[1], 5); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec3"].offset])[2], 6); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec4"].offset])[0], 7); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec4"].offset])[1], 8); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec4"].offset])[2], 9); + QCOMPARE(reinterpret_cast<const int *>(&result.data.constData()[fromGpuMembers["_ivec4"].offset])[3], 10); + + } +} + #include <tst_qrhi.moc> QTEST_MAIN(tst_QRhi) |