369 m_vertexCount =
mesh.vertices;
370 m_srcStride = lookup.binding->stride;
371 m_srcOffset = lookup.attribute->byte_offset
372 +
static_cast<int32_t
>(lookup.input->byte_offset);
373 m_elementCount = attributeFormatComponents(lookup.attribute->format);
375 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
377 const int32_t outputComponents = m_padToVec4 ? 4 : m_elementCount;
378 m_outputComponents = outputComponents;
380 =
static_cast<int64_t
>(m_vertexCount) * outputComponents *
sizeof(
float);
382 if(m_outputSize == 0)
384 qDebug() <<
"ComputeExtractionStrategy: Zero output size";
389 m_outputBuffer = rhi.newBuffer(
390 QRhiBuffer::Static, QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer,
391 static_cast<quint32
>(m_outputSize));
392 m_outputBuffer->setName(
"ComputeExtractionStrategy::m_outputBuffer");
394 if(!m_outputBuffer || !m_outputBuffer->create())
396 qDebug() <<
"ComputeExtractionStrategy: Failed to create output buffer";
400 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
403 qDebug() <<
"ComputeExtractionStrategy: Null source buffer";
407 return createPipeline(renderState, rhi);
414 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
415 m_srcStride = lookup.binding->stride;
416 m_srcOffset = lookup.attribute->byte_offset
417 +
static_cast<int32_t
>(lookup.input->byte_offset);
419 const bool newPadToVec4
420 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
421 const int32_t newOutputComponents = newPadToVec4 ? 4 : m_elementCount;
422 const int64_t newSize
423 =
static_cast<int64_t
>(
mesh.vertices) * newOutputComponents *
sizeof(
float);
426 if(newSize != m_outputSize ||
mesh.vertices != m_vertexCount
427 || newPadToVec4 != m_padToVec4)
429 m_vertexCount =
mesh.vertices;
430 m_padToVec4 = newPadToVec4;
431 m_outputComponents = newOutputComponents;
432 m_outputSize = newSize;
436 m_outputBuffer->setSize(
static_cast<quint32
>(m_outputSize));
437 m_outputBuffer->create();
445 QRhiShaderResourceBinding::bufferLoad(
446 0, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
447 QRhiShaderResourceBinding::bufferStore(
448 1, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
456 void release()
noexcept
458 delete m_uniformBuffer;
459 m_uniformBuffer =
nullptr;
462 m_pipeline =
nullptr;
467 delete m_outputBuffer;
468 m_outputBuffer =
nullptr;
470 m_srcBuffer =
nullptr;
473 void runCompute(QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch*& res)
475 if(!m_dirty || m_vertexCount == 0 || !m_pipeline)
478 struct alignas(16) Params
480 uint32_t vertexCount;
481 uint32_t srcStrideBytes;
482 uint32_t srcOffsetBytes;
483 uint32_t elementCount;
487 static_cast<uint32_t
>(m_vertexCount),
488 static_cast<uint32_t
>(m_srcStride),
489 static_cast<uint32_t
>(m_srcOffset),
490 static_cast<uint32_t
>(m_elementCount),
491 m_padToVec4 ? 1u : 0u,
494 res->updateDynamicBuffer(m_uniformBuffer, 0,
sizeof(params), ¶ms);
496 cb.beginComputePass(res);
497 cb.setComputePipeline(m_pipeline);
498 cb.setShaderResources(m_srb);
500 const int workgroups = (m_vertexCount + 255) / 256;
501 cb.dispatch(workgroups, 1, 1);
506 res = rhi.nextResourceUpdateBatch();
514 .buffer = m_outputBuffer,
516 .size = m_outputSize,
520 [[nodiscard]]
static constexpr bool needsCompute()
noexcept {
return true; }
525 static const QString shaderCode = QStringLiteral(R
"(#version 450
527layout(local_size_x = 256) in;
529layout(std140, binding = 0) uniform Params {
537layout(std430, binding = 1) readonly buffer SrcBuffer {
541layout(std430, binding = 2) writeonly buffer DstBuffer {
547 uint idx = gl_GlobalInvocationID.x;
548 if (idx >= vertexCount)
551 uint srcBase = (idx * srcStrideBytes + srcOffsetBytes) / 4;
552 uint dstComponents = padToVec4 != 0 ? 4 : elementCount;
553 uint dstBase = idx * dstComponents;
555 for (uint i = 0; i < elementCount; ++i)
556 dst_data[dstBase + i] = src_data[srcBase + i];
560 for (uint i = elementCount; i < 4; ++i)
561 dst_data[dstBase + i] = (i == 3) ? 0x3f800000u : 0u;
567 if(!shader.isValid())
569 qDebug() <<
"ComputeExtractionStrategy: Shader compilation failed";
574 m_uniformBuffer = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
575 m_uniformBuffer->setName(
"ComputeExtractionStrategy::m_uniformBuffer");
577 if(!m_uniformBuffer || !m_uniformBuffer->create())
579 qDebug() <<
"ComputeExtractionStrategy: UBO creation failed";
583 m_srb = rhi.newShaderResourceBindings();
585 QRhiShaderResourceBinding::uniformBuffer(
586 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
587 QRhiShaderResourceBinding::bufferLoad(
588 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
589 QRhiShaderResourceBinding::bufferStore(
590 2, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
595 qDebug() <<
"ComputeExtractionStrategy: SRB creation failed";
599 m_pipeline = rhi.newComputePipeline();
600 m_pipeline->setShaderResourceBindings(m_srb);
601 m_pipeline->setShaderStage({QRhiShaderStage::Compute, shader});
603 if(!m_pipeline->create())
605 qDebug() <<
"ComputeExtractionStrategy: Pipeline creation failed";
613 QRhiBuffer* m_srcBuffer{};
614 QRhiBuffer* m_uniformBuffer{};
615 QRhiBuffer* m_outputBuffer{};
616 QRhiShaderResourceBindings* m_srb{};
617 QRhiComputePipeline* m_pipeline{};
619 int32_t m_vertexCount{};
620 int32_t m_srcStride{};
621 int32_t m_srcOffset{};
622 int32_t m_elementCount{};
623 int32_t m_outputComponents{};
624 int64_t m_outputSize{};
626 bool m_padToVec4{
false};
638 if(
mesh.index.buffer < 0
639 ||
mesh.index.buffer >=
static_cast<int>(
mesh.buffers.size()))
641 qDebug() <<
"IndexedExtractionStrategy: Invalid index buffer";
646 m_indexCount =
mesh.vertices;
647 m_srcStride = lookup.binding->stride;
648 m_srcOffset = lookup.attribute->byte_offset
649 +
static_cast<int32_t
>(lookup.input->byte_offset);
650 m_elementCount = attributeFormatComponents(lookup.attribute->format);
652 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
653 m_indexFormat32 = (
mesh.index.format == halp::index_format::uint32);
654 m_indexOffset =
static_cast<int32_t
>(
mesh.index.byte_offset);
656 const int32_t outputComponents = m_padToVec4 ? 4 : m_elementCount;
657 m_outputComponents = outputComponents;
658 m_outputSize =
static_cast<int64_t
>(m_indexCount) * outputComponents *
sizeof(
float);
660 if(m_outputSize == 0)
662 qDebug() <<
"IndexedExtractionStrategy: Zero output size";
666 m_outputBuffer = rhi.newBuffer(
667 QRhiBuffer::Static, QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer,
668 static_cast<quint32
>(m_outputSize));
669 m_outputBuffer->setName(
"IndexedExtractionStrategy::m_outputBuffer");
671 if(!m_outputBuffer || !m_outputBuffer->create())
673 qDebug() <<
"IndexedExtractionStrategy: Failed to create output buffer";
677 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
678 m_indexBuffer =
static_cast<QRhiBuffer*
>(
mesh.buffers[
mesh.index.buffer].handle);
680 if(!m_srcBuffer || !m_indexBuffer)
682 qDebug() <<
"IndexedExtractionStrategy: Null source or index buffer";
686 return createPipeline(renderState, rhi);
693 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
694 m_srcStride = lookup.binding->stride;
695 m_srcOffset = lookup.attribute->byte_offset
696 +
static_cast<int32_t
>(lookup.input->byte_offset);
698 if(
mesh.index.buffer >= 0
699 &&
mesh.index.buffer <
static_cast<int>(
mesh.buffers.size()))
701 m_indexBuffer =
static_cast<QRhiBuffer*
>(
mesh.buffers[
mesh.index.buffer].handle);
702 m_indexOffset =
static_cast<int32_t
>(
mesh.index.byte_offset);
703 m_indexFormat32 = (
mesh.index.format == halp::index_format::uint32);
706 const bool newPadToVec4
707 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
708 const int32_t newOutputComponents = newPadToVec4 ? 4 : m_elementCount;
709 const int64_t newSize
710 =
static_cast<int64_t
>(
mesh.vertices) * newOutputComponents *
sizeof(
float);
712 if(newSize != m_outputSize ||
mesh.vertices != m_indexCount
713 || newPadToVec4 != m_padToVec4)
715 m_indexCount =
mesh.vertices;
716 m_padToVec4 = newPadToVec4;
717 m_outputComponents = newOutputComponents;
718 m_outputSize = newSize;
722 m_outputBuffer->setSize(
static_cast<quint32
>(m_outputSize));
723 m_outputBuffer->create();
730 QRhiShaderResourceBinding::bufferLoad(
731 0, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
732 QRhiShaderResourceBinding::bufferLoad(
733 1, QRhiShaderResourceBinding::ComputeStage, m_indexBuffer),
734 QRhiShaderResourceBinding::bufferStore(
735 2, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
743 void release()
noexcept
746 m_pipeline =
nullptr;
751 delete m_uniformBuffer;
752 m_uniformBuffer =
nullptr;
754 delete m_outputBuffer;
755 m_outputBuffer =
nullptr;
757 m_srcBuffer =
nullptr;
758 m_indexBuffer =
nullptr;
761 void runCompute(QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch*& res)
763 if(!m_dirty || m_indexCount == 0 || !m_pipeline)
766 struct alignas(16) Params
769 uint32_t srcStrideBytes;
770 uint32_t srcOffsetBytes;
771 uint32_t elementCount;
773 uint32_t indexOffsetBytes;
777 static_cast<uint32_t
>(m_indexCount),
778 static_cast<uint32_t
>(m_srcStride),
779 static_cast<uint32_t
>(m_srcOffset),
780 static_cast<uint32_t
>(m_elementCount),
781 m_padToVec4 ? 1u : 0u,
782 static_cast<uint32_t
>(m_indexOffset),
783 m_indexFormat32 ? 1u : 0u,
786 res->updateDynamicBuffer(m_uniformBuffer, 0,
sizeof(params), ¶ms);
788 cb.beginComputePass(res);
789 cb.setComputePipeline(m_pipeline);
790 cb.setShaderResources(m_srb);
792 const int workgroups = (m_indexCount + 255) / 256;
793 cb.dispatch(workgroups, 1, 1);
797 res = rhi.nextResourceUpdateBatch();
805 .buffer = m_outputBuffer,
807 .size = m_outputSize,
811 [[nodiscard]]
static constexpr bool needsCompute()
noexcept {
return true; }
816 static const QString shaderCode = QStringLiteral(R
"(#version 450
818layout(local_size_x = 256) in;
820layout(std140, binding = 0) uniform Params {
826 uint indexOffsetBytes;
830layout(std430, binding = 1) readonly buffer SrcBuffer {
834layout(std430, binding = 2) readonly buffer IndexBuffer {
838layout(std430, binding = 3) writeonly buffer DstBuffer {
842uint readIndex(uint i)
846 uint wordIndex = (indexOffsetBytes / 4) + i;
847 return index_data[wordIndex];
851 uint bytePos = indexOffsetBytes + i * 2;
852 uint wordIndex = bytePos / 4;
853 uint word = index_data[wordIndex];
854 uint shift = (bytePos % 4) * 8;
855 return (word >> shift) & 0xFFFFu;
861 uint outputIdx = gl_GlobalInvocationID.x;
862 if (outputIdx >= indexCount)
865 uint vertexIdx = readIndex(outputIdx);
866 uint srcBase = (vertexIdx * srcStrideBytes + srcOffsetBytes) / 4;
867 uint dstComponents = padToVec4 != 0 ? 4 : elementCount;
868 uint dstBase = outputIdx * dstComponents;
870 for (uint i = 0; i < elementCount; ++i)
871 dst_data[dstBase + i] = src_data[srcBase + i];
875 for (uint i = elementCount; i < 4; ++i)
876 dst_data[dstBase + i] = (i == 3) ? 0x3f800000u : 0u;
882 if(!shader.isValid())
884 qDebug() <<
"IndexedExtractionStrategy: Shader compilation failed";
888 m_uniformBuffer = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
889 m_uniformBuffer->setName(
"IndexedExtractionStrategy::m_uniformBuffer");
891 if(!m_uniformBuffer || !m_uniformBuffer->create())
893 qDebug() <<
"IndexedExtractionStrategy: UBO creation failed";
897 m_srb = rhi.newShaderResourceBindings();
899 QRhiShaderResourceBinding::uniformBuffer(
900 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
901 QRhiShaderResourceBinding::bufferLoad(
902 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
903 QRhiShaderResourceBinding::bufferLoad(
904 2, QRhiShaderResourceBinding::ComputeStage, m_indexBuffer),
905 QRhiShaderResourceBinding::bufferStore(
906 3, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
911 qDebug() <<
"IndexedExtractionStrategy: SRB creation failed";
915 m_pipeline = rhi.newComputePipeline();
916 m_pipeline->setShaderResourceBindings(m_srb);
917 m_pipeline->setShaderStage({QRhiShaderStage::Compute, shader});
919 if(!m_pipeline->create())
921 qDebug() <<
"IndexedExtractionStrategy: Pipeline creation failed";
929 QRhiBuffer* m_srcBuffer{};
930 QRhiBuffer* m_uniformBuffer{};
931 QRhiBuffer* m_indexBuffer{};
932 QRhiBuffer* m_outputBuffer{};
933 QRhiShaderResourceBindings* m_srb{};
934 QRhiComputePipeline* m_pipeline{};
936 int32_t m_indexCount{};
937 int32_t m_srcStride{};
938 int32_t m_srcOffset{};
939 int32_t m_indexOffset{};
940 int32_t m_elementCount{};
941 int32_t m_outputComponents{};
942 int64_t m_outputSize{};
944 bool m_padToVec4{
false};
945 bool m_indexFormat32{
true};