GAS sbtIndexOffsetBuffer overridden by OptixIntance sbt offset?

I’m trying to use IAS to manage mesh instances in my scene, one level IAS and one GAS for each instance. Each of my mesh instance has MULTIPLE sbt records (i.e. multiple sub-meshes in a mesh, one material for each sub-mesh). I’m using one triangle build input for each mesh instance.
But it seems that buildInput.triangleArray.sbtIndexOffsetBuffer become useless after using IAS. All triangles are shaded with the same material 0. (I’ve checked the data of vertexBuffer/indexBuffer/sbtIndexOffsetBuffer).

  • Question: Should I modify my codes to map one SUB-MESH to one IAS OptixInstance::sbtOffset? Should I abandon GAS buildInput.triangleArray.sbtIndexOffsetBuffer if I use IAS?

From my point of view, it’s reasonable that in closest hit shader:
currentHitSbtOffset = instanceSbtOffset + primitiveSbtOffset
But now my primitiveSbtOffset seems to be all 0s no matter how i change the content of GAS sbtIndexOffsetBuffer, that’s really weird.


Should I abandon GAS buildInput.triangleArray.sbtIndexOffsetBuffer if I use IAS?

If you have any GAS with build inputs which use more than one SBT record, you must use an sbtIndexOffsetBuffer for such build inputs to be able to specify which SBT record to use per primitive.
If there is only one SBT record per build input there is no use for an sbtIndexOffsetBuffer.

I’m doing the latter in my OptiX examples:
Here’s a related post which explains the SBT indexing for that case:

Should I modify my codes to map one SUB-MESH to one IAS OptixInstance::sbtOffset?

That shouldn’t be required. Sounds more like you didn’t set the instance SBT index correctly. It needs to take the number of SBT records per underlying GAS of the previous instances into account.

Please have a look at how the SBT index is calculated exactly in this formula:

Then check the basic GAS SBT record indexing for the simple and your multiple SBT record case.

Then compare your implementation with the example in the OptiX 7 programming guide which shows a case of instancing a GAS with multiple build inputs of which one has two SBT records:

Specifically look at the SBT instance offset described in the table below that scene graph image.
Note that the second instance sbtIndex starts at 6 because that is the number of SBT records used by the first instance already.

If that’s not it, more information about how you setup your SBT exactly would be required.

Hi Detlef,
I’ve checked the instance SBT offset, and it seems ok.

I’ve tried a really simple test case:
1 mesh instance with 3 Boxes with different materials (3 sub-meshes, 1 vertex buffer, 1 index buffer)
—> 3 different SBT records, where i put different submeshID inside.
—> in this case, instanceOffset can be set to 0, right?
—> instanceId == 0, and this should be irrelevant.
in this case, there are 12 triangles per box, that means 3 x 12 primitives in the only build input.
—> 36 sbtIndexOffsets, the first 12 offsets are 0, the second 12 offsets are 1, then the third 12 offsets are 2.

But it turns out that all triangles use SBT record 0. Only instanceSbtOffset are effective.

And there is something even more weird, I’ve set all sbtIndexOffset elements to some ARBITRARY value like 0xabcd1234, but all triangles STILL use SBT record 0. No error reported at all. It seems to me that the GAS build process doesn’t even make use of the sbtIndexOffsetBuffer at all.

I’ve look into the basic optixCutouts sample in OptixSDK, it uses both IAS and GAS but works well. What might cause such weird result?

Is it even possible to cudaMemcpy the GAS output buffer back to host side to have a look at the GAS raw data, to have a glance at the sbtIndexOffsets?


Your description of the setup sounds alright so far.

What might cause such weird result?

The only thing I can think of to produce that result would be if the OptixBuildInput::triangleArray.numSbtRecords is set to 1 instead of 3 in the failing case.

Also mind that the OptixGeometryFlags in there is an array which size must match the numSbtRecord value.

Make sure the sbtIndexOffsetStrideInBytes matches the data format in sbtIndexOffsetBuffer.
If the stride is zero, it would also always use the first index, but you said a random value outside the range [0, 2] didn’t crash.

Other than that, I cannot say what else might be incorrect without minimal complete reproducer sources in failing state.
If that is required for further analysis, please provide the following system configuration information along with all OptiX problem reports:
OS version, installed GPU(s), VRAM amount, display driver version, OptiX version (major.minor.micro), CUDA toolkit version used to produce the input PTX code, Streaming Multiprocessor target used in the PTX, host compiler version.

Environment: Optix7, Win10, Optix7.0, Nvidia Geforce GTX1060, 6G VRAM, VS2017 (cl.exe),

NVCC command: nvcc -Xcompiler “/wd 4819” -O3 --Werror all-warnings -I %optix_include_path%,%optix_SDK_path% --use_fast_math -ptx -o …......\Data\CudaPTX%%f.ptx

The native Optix sbtIndexOffsetBuffer still won’t work, I can’t tell whether it’s a GAS building problem or internal pipeline intersection problem, or just my problem…

But I’ve managed to support multiple materials in a mesh by passing the ptr to sbtIndexOffsetBuffer and material array in each per-mesh SBT record (which means the per-primitive sbt inde offset job is done on my own). Now each mesh use only one SBT record.

Thanks anyway.

It would still be nice to have a failing reproducer for this to analyze if there is actually a problem in OptiX 7.
The simple test case you did sounds perfect for that.

What’s your display driver version? (This is mandatory information for any problem report.)

CUDA version = 10.2.89_441.22 , Driver version = 442.59, targetMachine = x64
The program is involved with a lot of render engine infrastructures, I’ll try to sort out a minimal reproducer code, but it might take some time.

other possible cause:

  1. using OpenCL 1.2 & CUDA 10.2.141 (but turning OpenCL off doesn’t seem to help)
  2. using OpenGL 3.3.0
  3. SBT record. I’ve print the sbt headers, and all 3 hit group sbt record header (32bytes) values are the same, it’s something like 22u64 0u64 0xcdcdcdcd 0xcdcdcdcd, it is right?
  4. should I build GAS first or configure SBT first? (but i’ve tried to swap their exec order, nothing changes.)

There exist OptiX unit tests which exercise instanced GAS with single and multiple SBT records with sbtIndexOffsetBuffer and they worked internally. (Newer driver and newer board though.)

In case this is an issue inside your implementation there is nothing to be done about that without a reproducer in failing state. All code which contributes to the SBT index calculation would need to be known.

If this turns out to be a problem inside OptiX 7, the only solution would be to update display drivers.
You’re currently running a driver from the R440 branch and all drivers up to version 444.99 would come from the same branch.
Try newer drivers of the same branch first before switching branches. There are at least two newer releases already. (I wouldn’t expect R445 drivers to behave differently.)