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();
448 QRhiShaderResourceBinding::uniformBuffer(
449 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
450 QRhiShaderResourceBinding::bufferLoad(
451 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
452 QRhiShaderResourceBinding::bufferStore(
453 2, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
461 void release()
noexcept
463 delete m_uniformBuffer;
464 m_uniformBuffer =
nullptr;
467 m_pipeline =
nullptr;
472 delete m_outputBuffer;
473 m_outputBuffer =
nullptr;
475 m_srcBuffer =
nullptr;
478 void runCompute(QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch*& res)
480 if(!m_dirty || m_vertexCount == 0 || !m_pipeline)
483 struct alignas(16) Params
485 uint32_t vertexCount;
486 uint32_t srcStrideBytes;
487 uint32_t srcOffsetBytes;
488 uint32_t elementCount;
492 static_cast<uint32_t
>(m_vertexCount),
493 static_cast<uint32_t
>(m_srcStride),
494 static_cast<uint32_t
>(m_srcOffset),
495 static_cast<uint32_t
>(m_elementCount),
496 m_padToVec4 ? 1u : 0u,
499 res->updateDynamicBuffer(m_uniformBuffer, 0,
sizeof(params), ¶ms);
501 cb.beginComputePass(res);
502 cb.setComputePipeline(m_pipeline);
503 cb.setShaderResources(m_srb);
505 const int workgroups = (m_vertexCount + 255) / 256;
506 cb.dispatch(workgroups, 1, 1);
511 res = rhi.nextResourceUpdateBatch();
519 .buffer = m_outputBuffer,
521 .size = m_outputSize,
525 [[nodiscard]]
static constexpr bool needsCompute()
noexcept {
return true; }
530 static const QString shaderCode = QStringLiteral(R
"(#version 450
532layout(local_size_x = 256) in;
534layout(std140, binding = 0) uniform Params {
542layout(std430, binding = 1) readonly buffer SrcBuffer {
546layout(std430, binding = 2) writeonly buffer DstBuffer {
552 uint idx = gl_GlobalInvocationID.x;
553 if (idx >= vertexCount)
556 uint srcBase = (idx * srcStrideBytes + srcOffsetBytes) / 4;
557 uint dstComponents = padToVec4 != 0 ? 4 : elementCount;
558 uint dstBase = idx * dstComponents;
560 for (uint i = 0; i < elementCount; ++i)
561 dst_data[dstBase + i] = src_data[srcBase + i];
565 for (uint i = elementCount; i < 4; ++i)
566 dst_data[dstBase + i] = (i == 3) ? 0x3f800000u : 0u;
572 if(!shader.isValid())
574 qDebug() <<
"ComputeExtractionStrategy: Shader compilation failed";
579 m_uniformBuffer = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
580 m_uniformBuffer->setName(
"ComputeExtractionStrategy::m_uniformBuffer");
582 if(!m_uniformBuffer || !m_uniformBuffer->create())
584 qDebug() <<
"ComputeExtractionStrategy: UBO creation failed";
588 m_srb = rhi.newShaderResourceBindings();
590 QRhiShaderResourceBinding::uniformBuffer(
591 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
592 QRhiShaderResourceBinding::bufferLoad(
593 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
594 QRhiShaderResourceBinding::bufferStore(
595 2, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
600 qDebug() <<
"ComputeExtractionStrategy: SRB creation failed";
604 m_pipeline = rhi.newComputePipeline();
605 m_pipeline->setShaderResourceBindings(m_srb);
606 m_pipeline->setShaderStage({QRhiShaderStage::Compute, shader});
608 if(!m_pipeline->create())
610 qDebug() <<
"ComputeExtractionStrategy: Pipeline creation failed";
618 QRhiBuffer* m_srcBuffer{};
619 QRhiBuffer* m_uniformBuffer{};
620 QRhiBuffer* m_outputBuffer{};
621 QRhiShaderResourceBindings* m_srb{};
622 QRhiComputePipeline* m_pipeline{};
624 int32_t m_vertexCount{};
625 int32_t m_srcStride{};
626 int32_t m_srcOffset{};
627 int32_t m_elementCount{};
628 int32_t m_outputComponents{};
629 int64_t m_outputSize{};
631 bool m_padToVec4{
false};
643 if(
mesh.index.buffer < 0
644 ||
mesh.index.buffer >=
static_cast<int>(
mesh.buffers.size()))
646 qDebug() <<
"IndexedExtractionStrategy: Invalid index buffer";
651 m_indexCount =
mesh.vertices;
652 m_srcStride = lookup.binding->stride;
653 m_srcOffset = lookup.attribute->byte_offset
654 +
static_cast<int32_t
>(lookup.input->byte_offset);
655 m_elementCount = attributeFormatComponents(lookup.attribute->format);
657 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
658 m_indexFormat32 = (
mesh.index.format == halp::index_format::uint32);
659 m_indexOffset =
static_cast<int32_t
>(
mesh.index.byte_offset);
661 const int32_t outputComponents = m_padToVec4 ? 4 : m_elementCount;
662 m_outputComponents = outputComponents;
663 m_outputSize =
static_cast<int64_t
>(m_indexCount) * outputComponents *
sizeof(
float);
665 if(m_outputSize == 0)
667 qDebug() <<
"IndexedExtractionStrategy: Zero output size";
671 m_outputBuffer = rhi.newBuffer(
672 QRhiBuffer::Static, QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer,
673 static_cast<quint32
>(m_outputSize));
674 m_outputBuffer->setName(
"IndexedExtractionStrategy::m_outputBuffer");
676 if(!m_outputBuffer || !m_outputBuffer->create())
678 qDebug() <<
"IndexedExtractionStrategy: Failed to create output buffer";
682 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
683 m_indexBuffer =
static_cast<QRhiBuffer*
>(
mesh.buffers[
mesh.index.buffer].handle);
685 if(!m_srcBuffer || !m_indexBuffer)
687 qDebug() <<
"IndexedExtractionStrategy: Null source or index buffer";
691 return createPipeline(renderState, rhi);
698 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
699 m_srcStride = lookup.binding->stride;
700 m_srcOffset = lookup.attribute->byte_offset
701 +
static_cast<int32_t
>(lookup.input->byte_offset);
703 if(
mesh.index.buffer >= 0
704 &&
mesh.index.buffer <
static_cast<int>(
mesh.buffers.size()))
706 m_indexBuffer =
static_cast<QRhiBuffer*
>(
mesh.buffers[
mesh.index.buffer].handle);
707 m_indexOffset =
static_cast<int32_t
>(
mesh.index.byte_offset);
708 m_indexFormat32 = (
mesh.index.format == halp::index_format::uint32);
711 const bool newPadToVec4
712 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
713 const int32_t newOutputComponents = newPadToVec4 ? 4 : m_elementCount;
714 const int64_t newSize
715 =
static_cast<int64_t
>(
mesh.vertices) * newOutputComponents *
sizeof(
float);
717 if(newSize != m_outputSize ||
mesh.vertices != m_indexCount
718 || newPadToVec4 != m_padToVec4)
720 m_indexCount =
mesh.vertices;
721 m_padToVec4 = newPadToVec4;
722 m_outputComponents = newOutputComponents;
723 m_outputSize = newSize;
727 m_outputBuffer->setSize(
static_cast<quint32
>(m_outputSize));
728 m_outputBuffer->create();
739 QRhiShaderResourceBinding::uniformBuffer(
740 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
741 QRhiShaderResourceBinding::bufferLoad(
742 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
743 QRhiShaderResourceBinding::bufferLoad(
744 2, QRhiShaderResourceBinding::ComputeStage, m_indexBuffer),
745 QRhiShaderResourceBinding::bufferStore(
746 3, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
754 void release()
noexcept
757 m_pipeline =
nullptr;
762 delete m_uniformBuffer;
763 m_uniformBuffer =
nullptr;
765 delete m_outputBuffer;
766 m_outputBuffer =
nullptr;
768 m_srcBuffer =
nullptr;
769 m_indexBuffer =
nullptr;
772 void runCompute(QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch*& res)
774 if(!m_dirty || m_indexCount == 0 || !m_pipeline)
777 struct alignas(16) Params
780 uint32_t srcStrideBytes;
781 uint32_t srcOffsetBytes;
782 uint32_t elementCount;
784 uint32_t indexOffsetBytes;
788 static_cast<uint32_t
>(m_indexCount),
789 static_cast<uint32_t
>(m_srcStride),
790 static_cast<uint32_t
>(m_srcOffset),
791 static_cast<uint32_t
>(m_elementCount),
792 m_padToVec4 ? 1u : 0u,
793 static_cast<uint32_t
>(m_indexOffset),
794 m_indexFormat32 ? 1u : 0u,
797 res->updateDynamicBuffer(m_uniformBuffer, 0,
sizeof(params), ¶ms);
799 cb.beginComputePass(res);
800 cb.setComputePipeline(m_pipeline);
801 cb.setShaderResources(m_srb);
803 const int workgroups = (m_indexCount + 255) / 256;
804 cb.dispatch(workgroups, 1, 1);
808 res = rhi.nextResourceUpdateBatch();
816 .buffer = m_outputBuffer,
818 .size = m_outputSize,
822 [[nodiscard]]
static constexpr bool needsCompute()
noexcept {
return true; }
827 static const QString shaderCode = QStringLiteral(R
"(#version 450
829layout(local_size_x = 256) in;
831layout(std140, binding = 0) uniform Params {
837 uint indexOffsetBytes;
841layout(std430, binding = 1) readonly buffer SrcBuffer {
845layout(std430, binding = 2) readonly buffer IndexBuffer {
849layout(std430, binding = 3) writeonly buffer DstBuffer {
853uint readIndex(uint i)
857 uint wordIndex = (indexOffsetBytes / 4) + i;
858 return index_data[wordIndex];
862 uint bytePos = indexOffsetBytes + i * 2;
863 uint wordIndex = bytePos / 4;
864 uint word = index_data[wordIndex];
865 uint shift = (bytePos % 4) * 8;
866 return (word >> shift) & 0xFFFFu;
872 uint outputIdx = gl_GlobalInvocationID.x;
873 if (outputIdx >= indexCount)
876 uint vertexIdx = readIndex(outputIdx);
877 uint srcBase = (vertexIdx * srcStrideBytes + srcOffsetBytes) / 4;
878 uint dstComponents = padToVec4 != 0 ? 4 : elementCount;
879 uint dstBase = outputIdx * dstComponents;
881 for (uint i = 0; i < elementCount; ++i)
882 dst_data[dstBase + i] = src_data[srcBase + i];
886 for (uint i = elementCount; i < 4; ++i)
887 dst_data[dstBase + i] = (i == 3) ? 0x3f800000u : 0u;
893 if(!shader.isValid())
895 qDebug() <<
"IndexedExtractionStrategy: Shader compilation failed";
899 m_uniformBuffer = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
900 m_uniformBuffer->setName(
"IndexedExtractionStrategy::m_uniformBuffer");
902 if(!m_uniformBuffer || !m_uniformBuffer->create())
904 qDebug() <<
"IndexedExtractionStrategy: UBO creation failed";
908 m_srb = rhi.newShaderResourceBindings();
910 QRhiShaderResourceBinding::uniformBuffer(
911 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
912 QRhiShaderResourceBinding::bufferLoad(
913 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
914 QRhiShaderResourceBinding::bufferLoad(
915 2, QRhiShaderResourceBinding::ComputeStage, m_indexBuffer),
916 QRhiShaderResourceBinding::bufferStore(
917 3, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
922 qDebug() <<
"IndexedExtractionStrategy: SRB creation failed";
926 m_pipeline = rhi.newComputePipeline();
927 m_pipeline->setShaderResourceBindings(m_srb);
928 m_pipeline->setShaderStage({QRhiShaderStage::Compute, shader});
930 if(!m_pipeline->create())
932 qDebug() <<
"IndexedExtractionStrategy: Pipeline creation failed";
940 QRhiBuffer* m_srcBuffer{};
941 QRhiBuffer* m_uniformBuffer{};
942 QRhiBuffer* m_indexBuffer{};
943 QRhiBuffer* m_outputBuffer{};
944 QRhiShaderResourceBindings* m_srb{};
945 QRhiComputePipeline* m_pipeline{};
947 int32_t m_indexCount{};
948 int32_t m_srcStride{};
949 int32_t m_srcOffset{};
950 int32_t m_indexOffset{};
951 int32_t m_elementCount{};
952 int32_t m_outputComponents{};
953 int64_t m_outputSize{};
955 bool m_padToVec4{
false};
956 bool m_indexFormat32{
true};