382 m_vertexCount =
mesh.vertices;
383 m_srcStride = lookup.binding->stride;
384 m_srcOffset = lookup.attribute->byte_offset
385 +
static_cast<int32_t
>(lookup.input->byte_offset);
386 m_elementCount = attributeFormatComponents(lookup.attribute->format);
388 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
390 const int32_t outputComponents = m_padToVec4 ? 4 : m_elementCount;
391 m_outputComponents = outputComponents;
393 =
static_cast<int64_t
>(m_vertexCount) * outputComponents *
sizeof(
float);
395 if(m_outputSize == 0)
397 qDebug() <<
"ComputeExtractionStrategy: Zero output size";
402 m_outputBuffer = rhi.newBuffer(
403 QRhiBuffer::Static, QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer,
404 static_cast<quint32
>(m_outputSize));
405 m_outputBuffer->setName(
"ComputeExtractionStrategy::m_outputBuffer");
407 if(!m_outputBuffer || !m_outputBuffer->create())
409 qDebug() <<
"ComputeExtractionStrategy: Failed to create output buffer";
413 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
416 qDebug() <<
"ComputeExtractionStrategy: Null source buffer";
420 return createPipeline(renderState, rhi);
427 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
428 m_srcStride = lookup.binding->stride;
429 m_srcOffset = lookup.attribute->byte_offset
430 +
static_cast<int32_t
>(lookup.input->byte_offset);
432 const bool newPadToVec4
433 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
434 const int32_t newOutputComponents = newPadToVec4 ? 4 : m_elementCount;
435 const int64_t newSize
436 =
static_cast<int64_t
>(
mesh.vertices) * newOutputComponents *
sizeof(
float);
439 if(newSize != m_outputSize ||
mesh.vertices != m_vertexCount
440 || newPadToVec4 != m_padToVec4)
442 m_vertexCount =
mesh.vertices;
443 m_padToVec4 = newPadToVec4;
444 m_outputComponents = newOutputComponents;
445 m_outputSize = newSize;
449 m_outputBuffer->setSize(
static_cast<quint32
>(m_outputSize));
450 m_outputBuffer->create();
460 QRhiShaderResourceBinding::uniformBuffer(
461 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
462 QRhiShaderResourceBinding::bufferLoad(
463 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
464 QRhiShaderResourceBinding::bufferStore(
465 2, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
473 void release()
noexcept
475 delete m_uniformBuffer;
476 m_uniformBuffer =
nullptr;
479 m_pipeline =
nullptr;
484 delete m_outputBuffer;
485 m_outputBuffer =
nullptr;
487 m_srcBuffer =
nullptr;
490 void runCompute(QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch*& res)
492 if(!m_dirty || m_vertexCount == 0 || !m_pipeline)
495 struct alignas(16) Params
497 uint32_t vertexCount;
498 uint32_t srcStrideBytes;
499 uint32_t srcOffsetBytes;
500 uint32_t elementCount;
504 static_cast<uint32_t
>(m_vertexCount),
505 static_cast<uint32_t
>(m_srcStride),
506 static_cast<uint32_t
>(m_srcOffset),
507 static_cast<uint32_t
>(m_elementCount),
508 m_padToVec4 ? 1u : 0u,
511 res->updateDynamicBuffer(m_uniformBuffer, 0,
sizeof(params), ¶ms);
513 cb.beginComputePass(res);
514 cb.setComputePipeline(m_pipeline);
515 cb.setShaderResources(m_srb);
517 const int workgroups = (m_vertexCount + 255) / 256;
518 cb.dispatch(workgroups, 1, 1);
523 res = rhi.nextResourceUpdateBatch();
531 .buffer = m_outputBuffer,
533 .size = m_outputSize,
537 [[nodiscard]]
static constexpr bool needsCompute()
noexcept {
return true; }
542 static const QString shaderCode = QStringLiteral(R
"(#version 450
544layout(local_size_x = 256) in;
546layout(std140, binding = 0) uniform Params {
554layout(std430, binding = 1) readonly buffer SrcBuffer {
558layout(std430, binding = 2) writeonly buffer DstBuffer {
564 uint idx = gl_GlobalInvocationID.x;
565 if (idx >= vertexCount)
568 uint srcBase = (idx * srcStrideBytes + srcOffsetBytes) / 4;
569 uint dstComponents = padToVec4 != 0 ? 4 : elementCount;
570 uint dstBase = idx * dstComponents;
572 for (uint i = 0; i < elementCount; ++i)
573 dst_data[dstBase + i] = src_data[srcBase + i];
577 for (uint i = elementCount; i < 4; ++i)
578 dst_data[dstBase + i] = (i == 3) ? 0x3f800000u : 0u;
584 if(!shader.isValid())
586 qDebug() <<
"ComputeExtractionStrategy: Shader compilation failed";
591 m_uniformBuffer = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
592 m_uniformBuffer->setName(
"ComputeExtractionStrategy::m_uniformBuffer");
594 if(!m_uniformBuffer || !m_uniformBuffer->create())
596 qDebug() <<
"ComputeExtractionStrategy: UBO creation failed";
600 m_srb = rhi.newShaderResourceBindings();
602 QRhiShaderResourceBinding::uniformBuffer(
603 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
604 QRhiShaderResourceBinding::bufferLoad(
605 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
606 QRhiShaderResourceBinding::bufferStore(
607 2, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
612 qDebug() <<
"ComputeExtractionStrategy: SRB creation failed";
616 m_pipeline = rhi.newComputePipeline();
617 m_pipeline->setShaderResourceBindings(m_srb);
618 m_pipeline->setShaderStage({QRhiShaderStage::Compute, shader});
620 if(!m_pipeline->create())
622 qDebug() <<
"ComputeExtractionStrategy: Pipeline creation failed";
630 QRhiBuffer* m_srcBuffer{};
631 QRhiBuffer* m_uniformBuffer{};
632 QRhiBuffer* m_outputBuffer{};
633 QRhiShaderResourceBindings* m_srb{};
634 QRhiComputePipeline* m_pipeline{};
636 int32_t m_vertexCount{};
637 int32_t m_srcStride{};
638 int32_t m_srcOffset{};
639 int32_t m_elementCount{};
640 int32_t m_outputComponents{};
641 int64_t m_outputSize{};
643 bool m_padToVec4{
false};
655 if(
mesh.index.buffer < 0
656 ||
mesh.index.buffer >=
static_cast<int>(
mesh.buffers.size()))
658 qDebug() <<
"IndexedExtractionStrategy: Invalid index buffer";
663 m_indexCount =
mesh.vertices;
664 m_srcStride = lookup.binding->stride;
665 m_srcOffset = lookup.attribute->byte_offset
666 +
static_cast<int32_t
>(lookup.input->byte_offset);
667 m_elementCount = attributeFormatComponents(lookup.attribute->format);
669 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
670 m_indexFormat32 = (
mesh.index.format == halp::index_format::uint32);
671 m_indexOffset =
static_cast<int32_t
>(
mesh.index.byte_offset);
673 const int32_t outputComponents = m_padToVec4 ? 4 : m_elementCount;
674 m_outputComponents = outputComponents;
675 m_outputSize =
static_cast<int64_t
>(m_indexCount) * outputComponents *
sizeof(
float);
677 if(m_outputSize == 0)
679 qDebug() <<
"IndexedExtractionStrategy: Zero output size";
683 m_outputBuffer = rhi.newBuffer(
684 QRhiBuffer::Static, QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer,
685 static_cast<quint32
>(m_outputSize));
686 m_outputBuffer->setName(
"IndexedExtractionStrategy::m_outputBuffer");
688 if(!m_outputBuffer || !m_outputBuffer->create())
690 qDebug() <<
"IndexedExtractionStrategy: Failed to create output buffer";
694 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
695 m_indexBuffer =
static_cast<QRhiBuffer*
>(
mesh.buffers[
mesh.index.buffer].handle);
697 if(!m_srcBuffer || !m_indexBuffer)
699 qDebug() <<
"IndexedExtractionStrategy: Null source or index buffer";
703 return createPipeline(renderState, rhi);
710 m_srcBuffer =
static_cast<QRhiBuffer*
>(lookup.buffer->handle);
711 m_srcStride = lookup.binding->stride;
712 m_srcOffset = lookup.attribute->byte_offset
713 +
static_cast<int32_t
>(lookup.input->byte_offset);
715 if(
mesh.index.buffer >= 0
716 &&
mesh.index.buffer <
static_cast<int>(
mesh.buffers.size()))
718 m_indexBuffer =
static_cast<QRhiBuffer*
>(
mesh.buffers[
mesh.index.buffer].handle);
719 m_indexOffset =
static_cast<int32_t
>(
mesh.index.byte_offset);
720 m_indexFormat32 = (
mesh.index.format == halp::index_format::uint32);
723 const bool newPadToVec4
724 = padToVec4 && m_elementCount < 4 && isFloatFormat(lookup.attribute->format);
725 const int32_t newOutputComponents = newPadToVec4 ? 4 : m_elementCount;
726 const int64_t newSize
727 =
static_cast<int64_t
>(
mesh.vertices) * newOutputComponents *
sizeof(
float);
729 if(newSize != m_outputSize ||
mesh.vertices != m_indexCount
730 || newPadToVec4 != m_padToVec4)
732 m_indexCount =
mesh.vertices;
733 m_padToVec4 = newPadToVec4;
734 m_outputComponents = newOutputComponents;
735 m_outputSize = newSize;
739 m_outputBuffer->setSize(
static_cast<quint32
>(m_outputSize));
740 m_outputBuffer->create();
751 QRhiShaderResourceBinding::uniformBuffer(
752 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
753 QRhiShaderResourceBinding::bufferLoad(
754 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
755 QRhiShaderResourceBinding::bufferLoad(
756 2, QRhiShaderResourceBinding::ComputeStage, m_indexBuffer),
757 QRhiShaderResourceBinding::bufferStore(
758 3, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
766 void release()
noexcept
769 m_pipeline =
nullptr;
774 delete m_uniformBuffer;
775 m_uniformBuffer =
nullptr;
777 delete m_outputBuffer;
778 m_outputBuffer =
nullptr;
780 m_srcBuffer =
nullptr;
781 m_indexBuffer =
nullptr;
784 void runCompute(QRhi& rhi, QRhiCommandBuffer& cb, QRhiResourceUpdateBatch*& res)
786 if(!m_dirty || m_indexCount == 0 || !m_pipeline)
789 struct alignas(16) Params
792 uint32_t srcStrideBytes;
793 uint32_t srcOffsetBytes;
794 uint32_t elementCount;
796 uint32_t indexOffsetBytes;
800 static_cast<uint32_t
>(m_indexCount),
801 static_cast<uint32_t
>(m_srcStride),
802 static_cast<uint32_t
>(m_srcOffset),
803 static_cast<uint32_t
>(m_elementCount),
804 m_padToVec4 ? 1u : 0u,
805 static_cast<uint32_t
>(m_indexOffset),
806 m_indexFormat32 ? 1u : 0u,
809 res->updateDynamicBuffer(m_uniformBuffer, 0,
sizeof(params), ¶ms);
811 cb.beginComputePass(res);
812 cb.setComputePipeline(m_pipeline);
813 cb.setShaderResources(m_srb);
815 const int workgroups = (m_indexCount + 255) / 256;
816 cb.dispatch(workgroups, 1, 1);
820 res = rhi.nextResourceUpdateBatch();
828 .buffer = m_outputBuffer,
830 .size = m_outputSize,
834 [[nodiscard]]
static constexpr bool needsCompute()
noexcept {
return true; }
839 static const QString shaderCode = QStringLiteral(R
"(#version 450
841layout(local_size_x = 256) in;
843layout(std140, binding = 0) uniform Params {
849 uint indexOffsetBytes;
853layout(std430, binding = 1) readonly buffer SrcBuffer {
857layout(std430, binding = 2) readonly buffer IndexBuffer {
861layout(std430, binding = 3) writeonly buffer DstBuffer {
865uint readIndex(uint i)
869 uint wordIndex = (indexOffsetBytes / 4) + i;
870 return index_data[wordIndex];
874 uint bytePos = indexOffsetBytes + i * 2;
875 uint wordIndex = bytePos / 4;
876 uint word = index_data[wordIndex];
877 uint shift = (bytePos % 4) * 8;
878 return (word >> shift) & 0xFFFFu;
884 uint outputIdx = gl_GlobalInvocationID.x;
885 if (outputIdx >= indexCount)
888 uint vertexIdx = readIndex(outputIdx);
889 uint srcBase = (vertexIdx * srcStrideBytes + srcOffsetBytes) / 4;
890 uint dstComponents = padToVec4 != 0 ? 4 : elementCount;
891 uint dstBase = outputIdx * dstComponents;
893 for (uint i = 0; i < elementCount; ++i)
894 dst_data[dstBase + i] = src_data[srcBase + i];
898 for (uint i = elementCount; i < 4; ++i)
899 dst_data[dstBase + i] = (i == 3) ? 0x3f800000u : 0u;
905 if(!shader.isValid())
907 qDebug() <<
"IndexedExtractionStrategy: Shader compilation failed";
911 m_uniformBuffer = rhi.newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
912 m_uniformBuffer->setName(
"IndexedExtractionStrategy::m_uniformBuffer");
914 if(!m_uniformBuffer || !m_uniformBuffer->create())
916 qDebug() <<
"IndexedExtractionStrategy: UBO creation failed";
920 m_srb = rhi.newShaderResourceBindings();
922 QRhiShaderResourceBinding::uniformBuffer(
923 0, QRhiShaderResourceBinding::ComputeStage, m_uniformBuffer),
924 QRhiShaderResourceBinding::bufferLoad(
925 1, QRhiShaderResourceBinding::ComputeStage, m_srcBuffer),
926 QRhiShaderResourceBinding::bufferLoad(
927 2, QRhiShaderResourceBinding::ComputeStage, m_indexBuffer),
928 QRhiShaderResourceBinding::bufferStore(
929 3, QRhiShaderResourceBinding::ComputeStage, m_outputBuffer),
934 qDebug() <<
"IndexedExtractionStrategy: SRB creation failed";
938 m_pipeline = rhi.newComputePipeline();
939 m_pipeline->setShaderResourceBindings(m_srb);
940 m_pipeline->setShaderStage({QRhiShaderStage::Compute, shader});
942 if(!m_pipeline->create())
944 qDebug() <<
"IndexedExtractionStrategy: Pipeline creation failed";
952 QRhiBuffer* m_srcBuffer{};
953 QRhiBuffer* m_uniformBuffer{};
954 QRhiBuffer* m_indexBuffer{};
955 QRhiBuffer* m_outputBuffer{};
956 QRhiShaderResourceBindings* m_srb{};
957 QRhiComputePipeline* m_pipeline{};
959 int32_t m_indexCount{};
960 int32_t m_srcStride{};
961 int32_t m_srcOffset{};
962 int32_t m_indexOffset{};
963 int32_t m_elementCount{};
964 int32_t m_outputComponents{};
965 int64_t m_outputSize{};
967 bool m_padToVec4{
false};
968 bool m_indexFormat32{
true};