370 m_vertexCount =
mesh.vertices;
371 m_srcStride = lookup.binding->stride;
372 m_srcOffset = lookup.attribute->byte_offset
373 +
static_cast<int32_t
>(lookup.input->byte_offset);
374 m_elementCount = attributeFormatComponents(lookup.attribute->format);
376 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
378 const int32_t outputComponents = m_padToVec4 ? 4 : m_elementCount;
379 m_outputComponents = outputComponents;
381 =
static_cast<int64_t
>(m_vertexCount) * outputComponents *
sizeof(
float);
383 if(m_outputSize == 0)
385 qDebug() <<
"ComputeExtractionStrategy: Zero output size";
390 m_outputBuffer = rhi.newBuffer(
391 QRhiBuffer::Static, QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer,
392 static_cast<quint32
>(m_outputSize));
393 m_outputBuffer->setName(
"ComputeExtractionStrategy::m_outputBuffer");
395 if(!m_outputBuffer || !m_outputBuffer->create())
397 qDebug() <<
"ComputeExtractionStrategy: Failed to create output buffer";
401 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
404 qDebug() <<
"ComputeExtractionStrategy: Null source buffer";
408 return createPipeline(renderState, rhi);
415 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
416 m_srcStride = lookup.binding->stride;
417 m_srcOffset = lookup.attribute->byte_offset
418 +
static_cast<int32_t
>(lookup.input->byte_offset);
420 const bool newPadToVec4
421 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
422 const int32_t newOutputComponents = newPadToVec4 ? 4 : m_elementCount;
423 const int64_t newSize
424 =
static_cast<int64_t
>(
mesh.vertices) * newOutputComponents *
sizeof(
float);
427 if(newSize != m_outputSize ||
mesh.vertices != m_vertexCount
428 || newPadToVec4 != m_padToVec4)
430 m_vertexCount =
mesh.vertices;
431 m_padToVec4 = newPadToVec4;
432 m_outputComponents = newOutputComponents;
433 m_outputSize = newSize;
437 m_outputBuffer->setSize(
static_cast<quint32
>(m_outputSize));
438 m_outputBuffer->create();
446 QRhiShaderResourceBinding::bufferLoad(
447 0, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
448 QRhiShaderResourceBinding::bufferStore(
449 1, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
457 void release()
noexcept
459 delete m_uniformBuffer;
460 m_uniformBuffer =
nullptr;
463 m_pipeline =
nullptr;
468 delete m_outputBuffer;
469 m_outputBuffer =
nullptr;
471 m_srcBuffer =
nullptr;
474 void runCompute(QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch*& res)
476 if(!m_dirty || m_vertexCount == 0 || !m_pipeline)
479 struct alignas(16) Params
481 uint32_t vertexCount;
482 uint32_t srcStrideBytes;
483 uint32_t srcOffsetBytes;
484 uint32_t elementCount;
488 static_cast<uint32_t
>(m_vertexCount),
489 static_cast<uint32_t
>(m_srcStride),
490 static_cast<uint32_t
>(m_srcOffset),
491 static_cast<uint32_t
>(m_elementCount),
492 m_padToVec4 ? 1u : 0u,
495 res->updateDynamicBuffer(m_uniformBuffer, 0,
sizeof(params), ¶ms);
497 cb.beginComputePass(res);
498 cb.setComputePipeline(m_pipeline);
499 cb.setShaderResources(m_srb);
501 const int workgroups = (m_vertexCount + 255) / 256;
502 cb.dispatch(workgroups, 1, 1);
507 res = rhi.nextResourceUpdateBatch();
515 .buffer = m_outputBuffer,
517 .size = m_outputSize,
521 [[nodiscard]]
static constexpr bool needsCompute()
noexcept {
return true; }
526 static const QString shaderCode = QStringLiteral(R
"(#version 450
528layout(local_size_x = 256) in;
530layout(std140, binding = 0) uniform Params {
538layout(std430, binding = 1) readonly buffer SrcBuffer {
542layout(std430, binding = 2) writeonly buffer DstBuffer {
548 uint idx = gl_GlobalInvocationID.x;
549 if (idx >= vertexCount)
552 uint srcBase = (idx * srcStrideBytes + srcOffsetBytes) / 4;
553 uint dstComponents = padToVec4 != 0 ? 4 : elementCount;
554 uint dstBase = idx * dstComponents;
556 for (uint i = 0; i < elementCount; ++i)
557 dst_data[dstBase + i] = src_data[srcBase + i];
561 for (uint i = elementCount; i < 4; ++i)
562 dst_data[dstBase + i] = (i == 3) ? 0x3f800000u : 0u;
568 if(!shader.isValid())
570 qDebug() <<
"ComputeExtractionStrategy: Shader compilation failed";
575 m_uniformBuffer = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
576 m_uniformBuffer->setName(
"ComputeExtractionStrategy::m_uniformBuffer");
578 if(!m_uniformBuffer || !m_uniformBuffer->create())
580 qDebug() <<
"ComputeExtractionStrategy: UBO creation failed";
584 m_srb = rhi.newShaderResourceBindings();
586 QRhiShaderResourceBinding::uniformBuffer(
587 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
588 QRhiShaderResourceBinding::bufferLoad(
589 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
590 QRhiShaderResourceBinding::bufferStore(
591 2, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
596 qDebug() <<
"ComputeExtractionStrategy: SRB creation failed";
600 m_pipeline = rhi.newComputePipeline();
601 m_pipeline->setShaderResourceBindings(m_srb);
602 m_pipeline->setShaderStage({QRhiShaderStage::Compute, shader});
604 if(!m_pipeline->create())
606 qDebug() <<
"ComputeExtractionStrategy: Pipeline creation failed";
614 QRhiBuffer* m_srcBuffer{};
615 QRhiBuffer* m_uniformBuffer{};
616 QRhiBuffer* m_outputBuffer{};
617 QRhiShaderResourceBindings* m_srb{};
618 QRhiComputePipeline* m_pipeline{};
620 int32_t m_vertexCount{};
621 int32_t m_srcStride{};
622 int32_t m_srcOffset{};
623 int32_t m_elementCount{};
624 int32_t m_outputComponents{};
625 int64_t m_outputSize{};
627 bool m_padToVec4{
false};
639 if(
mesh.index.buffer < 0
640 ||
mesh.index.buffer >=
static_cast<int>(
mesh.buffers.size()))
642 qDebug() <<
"IndexedExtractionStrategy: Invalid index buffer";
647 m_indexCount =
mesh.vertices;
648 m_srcStride = lookup.binding->stride;
649 m_srcOffset = lookup.attribute->byte_offset
650 +
static_cast<int32_t
>(lookup.input->byte_offset);
651 m_elementCount = attributeFormatComponents(lookup.attribute->format);
653 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
654 m_indexFormat32 = (
mesh.index.format == halp::index_format::uint32);
655 m_indexOffset =
static_cast<int32_t
>(
mesh.index.byte_offset);
657 const int32_t outputComponents = m_padToVec4 ? 4 : m_elementCount;
658 m_outputComponents = outputComponents;
659 m_outputSize =
static_cast<int64_t
>(m_indexCount) * outputComponents *
sizeof(
float);
661 if(m_outputSize == 0)
663 qDebug() <<
"IndexedExtractionStrategy: Zero output size";
667 m_outputBuffer = rhi.newBuffer(
668 QRhiBuffer::Static, QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer,
669 static_cast<quint32
>(m_outputSize));
670 m_outputBuffer->setName(
"IndexedExtractionStrategy::m_outputBuffer");
672 if(!m_outputBuffer || !m_outputBuffer->create())
674 qDebug() <<
"IndexedExtractionStrategy: Failed to create output buffer";
678 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
679 m_indexBuffer =
static_cast<QRhiBuffer*
>(
mesh.buffers[
mesh.index.buffer].handle);
681 if(!m_srcBuffer || !m_indexBuffer)
683 qDebug() <<
"IndexedExtractionStrategy: Null source or index buffer";
687 return createPipeline(renderState, rhi);
694 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
695 m_srcStride = lookup.binding->stride;
696 m_srcOffset = lookup.attribute->byte_offset
697 +
static_cast<int32_t
>(lookup.input->byte_offset);
699 if(
mesh.index.buffer >= 0
700 &&
mesh.index.buffer <
static_cast<int>(
mesh.buffers.size()))
702 m_indexBuffer =
static_cast<QRhiBuffer*
>(
mesh.buffers[
mesh.index.buffer].handle);
703 m_indexOffset =
static_cast<int32_t
>(
mesh.index.byte_offset);
704 m_indexFormat32 = (
mesh.index.format == halp::index_format::uint32);
707 const bool newPadToVec4
708 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
709 const int32_t newOutputComponents = newPadToVec4 ? 4 : m_elementCount;
710 const int64_t newSize
711 =
static_cast<int64_t
>(
mesh.vertices) * newOutputComponents *
sizeof(
float);
713 if(newSize != m_outputSize ||
mesh.vertices != m_indexCount
714 || newPadToVec4 != m_padToVec4)
716 m_indexCount =
mesh.vertices;
717 m_padToVec4 = newPadToVec4;
718 m_outputComponents = newOutputComponents;
719 m_outputSize = newSize;
723 m_outputBuffer->setSize(
static_cast<quint32
>(m_outputSize));
724 m_outputBuffer->create();
731 QRhiShaderResourceBinding::bufferLoad(
732 0, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
733 QRhiShaderResourceBinding::bufferLoad(
734 1, QRhiShaderResourceBinding::ComputeStage, m_indexBuffer),
735 QRhiShaderResourceBinding::bufferStore(
736 2, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
744 void release()
noexcept
747 m_pipeline =
nullptr;
752 delete m_uniformBuffer;
753 m_uniformBuffer =
nullptr;
755 delete m_outputBuffer;
756 m_outputBuffer =
nullptr;
758 m_srcBuffer =
nullptr;
759 m_indexBuffer =
nullptr;
762 void runCompute(QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch*& res)
764 if(!m_dirty || m_indexCount == 0 || !m_pipeline)
767 struct alignas(16) Params
770 uint32_t srcStrideBytes;
771 uint32_t srcOffsetBytes;
772 uint32_t elementCount;
774 uint32_t indexOffsetBytes;
778 static_cast<uint32_t
>(m_indexCount),
779 static_cast<uint32_t
>(m_srcStride),
780 static_cast<uint32_t
>(m_srcOffset),
781 static_cast<uint32_t
>(m_elementCount),
782 m_padToVec4 ? 1u : 0u,
783 static_cast<uint32_t
>(m_indexOffset),
784 m_indexFormat32 ? 1u : 0u,
787 res->updateDynamicBuffer(m_uniformBuffer, 0,
sizeof(params), ¶ms);
789 cb.beginComputePass(res);
790 cb.setComputePipeline(m_pipeline);
791 cb.setShaderResources(m_srb);
793 const int workgroups = (m_indexCount + 255) / 256;
794 cb.dispatch(workgroups, 1, 1);
798 res = rhi.nextResourceUpdateBatch();
806 .buffer = m_outputBuffer,
808 .size = m_outputSize,
812 [[nodiscard]]
static constexpr bool needsCompute()
noexcept {
return true; }
817 static const QString shaderCode = QStringLiteral(R
"(#version 450
819layout(local_size_x = 256) in;
821layout(std140, binding = 0) uniform Params {
827 uint indexOffsetBytes;
831layout(std430, binding = 1) readonly buffer SrcBuffer {
835layout(std430, binding = 2) readonly buffer IndexBuffer {
839layout(std430, binding = 3) writeonly buffer DstBuffer {
843uint readIndex(uint i)
847 uint wordIndex = (indexOffsetBytes / 4) + i;
848 return index_data[wordIndex];
852 uint bytePos = indexOffsetBytes + i * 2;
853 uint wordIndex = bytePos / 4;
854 uint word = index_data[wordIndex];
855 uint shift = (bytePos % 4) * 8;
856 return (word >> shift) & 0xFFFFu;
862 uint outputIdx = gl_GlobalInvocationID.x;
863 if (outputIdx >= indexCount)
866 uint vertexIdx = readIndex(outputIdx);
867 uint srcBase = (vertexIdx * srcStrideBytes + srcOffsetBytes) / 4;
868 uint dstComponents = padToVec4 != 0 ? 4 : elementCount;
869 uint dstBase = outputIdx * dstComponents;
871 for (uint i = 0; i < elementCount; ++i)
872 dst_data[dstBase + i] = src_data[srcBase + i];
876 for (uint i = elementCount; i < 4; ++i)
877 dst_data[dstBase + i] = (i == 3) ? 0x3f800000u : 0u;
883 if(!shader.isValid())
885 qDebug() <<
"IndexedExtractionStrategy: Shader compilation failed";
889 m_uniformBuffer = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
890 m_uniformBuffer->setName(
"IndexedExtractionStrategy::m_uniformBuffer");
892 if(!m_uniformBuffer || !m_uniformBuffer->create())
894 qDebug() <<
"IndexedExtractionStrategy: UBO creation failed";
898 m_srb = rhi.newShaderResourceBindings();
900 QRhiShaderResourceBinding::uniformBuffer(
901 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
902 QRhiShaderResourceBinding::bufferLoad(
903 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
904 QRhiShaderResourceBinding::bufferLoad(
905 2, QRhiShaderResourceBinding::ComputeStage, m_indexBuffer),
906 QRhiShaderResourceBinding::bufferStore(
907 3, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
912 qDebug() <<
"IndexedExtractionStrategy: SRB creation failed";
916 m_pipeline = rhi.newComputePipeline();
917 m_pipeline->setShaderResourceBindings(m_srb);
918 m_pipeline->setShaderStage({QRhiShaderStage::Compute, shader});
920 if(!m_pipeline->create())
922 qDebug() <<
"IndexedExtractionStrategy: Pipeline creation failed";
930 QRhiBuffer* m_srcBuffer{};
931 QRhiBuffer* m_uniformBuffer{};
932 QRhiBuffer* m_indexBuffer{};
933 QRhiBuffer* m_outputBuffer{};
934 QRhiShaderResourceBindings* m_srb{};
935 QRhiComputePipeline* m_pipeline{};
937 int32_t m_indexCount{};
938 int32_t m_srcStride{};
939 int32_t m_srcOffset{};
940 int32_t m_indexOffset{};
941 int32_t m_elementCount{};
942 int32_t m_outputComponents{};
943 int64_t m_outputSize{};
945 bool m_padToVec4{
false};
946 bool m_indexFormat32{
true};