microsoft / microsoft/hlsl-specs

RayQuery: Clarify semantics of object lifetime and stale references

Open
#656 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TeX
Stars
222
Forks
57
Avg merge
4d 16h
Merged PRs (30d)
5

Description

The DXR spec states that RayQuery objects have reference semantics upon assignment:

If a variable of type RayQuery is assigned to another (which must have been declared with a matching template specification), a reference to the original is passed (rather than a clone), so they are both now operating on the same shared state machine. If a variable of type RayQuery is passed into a function as a parameter, it is passed by reference. If a variable of type RayQuery is overwritten by another (such as by assignment), the overwritten object disappears.

However, detailed semantics of these references, in particular with respect to object lifetime, are not defined.

Per my understanding, the intention of the spec seems to be that if the lifetime of a RayQuery object A ends at the end of a scope,
then all other RayQuery objects currently referencing A become implicitly invalidated, making further use except for reassignment UB.
This rule would be consistent of e.g. C++ references, but it is nowhere explicitly written down.
This issue requests to add such a clarification.

Note that if we don't have such a rule, then pending references would need to take over ownership, turning RayQuery objects into some kind of smart pointers like C++'s std::shared_ptr, requiring dynamic allocation and reference counting, which I'm quite confident we don't want to require from drivers.

To give an example, consider the following that is compiled without warnings by DXC (1.9(dev;4944-98c9a93c), dxc -T lib_6_6 rq.hlsl), that would require such dynamic RayQuery object management if RayQuery objects can leak out of loop iterations.
In the resulting DXIL, there are just two calls to dx.op.allocateRayQuery, but four different RayQuery objects created in different loop iterations could be live at the end.

RaytracingAccelerationStructure myAccelerationStructure : register(t3);
RWBuffer<uint> gOutput : register(u0);

// On every invocation, return a new opaque value the compiler cannot reason about
uint GetOpaque() { return gOutput[gOutput[0]++]; }

float UseRayQuery(RayQuery<RAY_FLAG_NONE> q, RayDesc ray) {
    while (q.Proceed()) {
        if (q.CandidateType() == CANDIDATE_NON_OPAQUE_TRIANGLE) {
            q.CommitNonOpaqueTriangleHit();
        }
    }
    return (q.CommittedStatus() == COMMITTED_TRIANGLE_HIT) ? 0.0 : 1.0;
}

[shader("raygeneration")]
void RayGen()
{
    RayDesc ray = { float3(0., 0., 0.), 0., float3(0., 0., 0.), 1.0};

    RayQuery<RAY_FLAG_NONE> q1;
    RayQuery<RAY_FLAG_NONE> q2 = q1;
    RayQuery<RAY_FLAG_NONE> q3 = q1;
    RayQuery<RAY_FLAG_NONE> q4 = q1;

    for (uint opaque = GetOpaque(); opaque !=0; opaque = GetOpaque()) {
        RayQuery<RAY_FLAG_NONE> tmp;
        tmp.TraceRayInline(myAccelerationStructure, /*flags=*/ opaque, 0xff, ray);
        if (opaque & 0x1) { q1 = tmp; }
        if (opaque & 0x2) { q2 = tmp; }
        if (opaque & 0x4) { q3 = tmp; }
        if (opaque & 0x8) { q4 = tmp; }
    }

    float result = 0;
    result += UseRayQuery(q1, ray);
    result += UseRayQuery(q2, ray);
    result += UseRayQuery(q3, ray);
    result += UseRayQuery(q4, ray);

    gOutput[DispatchRaysIndex().x] = result;
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read the DXR spec's RayQuery section and the HLSL example in the issue first. Done means the specification explicitly defines what happens to aliases when a RayQuery object's lifetime ends, including whether later use is invalid, and resolves the loop and assignment case.

Written by the indexing model from the issue text.

Assessment

Domain
computer-graphics, documentation
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.