Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add resource chapter documenting buffers and bindings #344

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

pow2clk
Copy link
Member

@pow2clk pow2clk commented Oct 22, 2024

This adds a resource chapter that documents typed and raw buffers including their methods and compatible operators along with short descriptions of their functionality. It also adds a description of binding annotations for all types. Stub sections are included for constant buffers and samplers, but no information is provided as yet.

Fixes llvm/wg-hlsl#55
Fixes llvm/wg-hlsl#56

This adds a resource chapter that documents typed and raw buffers including their methods and compatible operators along with short descriptions of their functionality. It also adds a description of binding annotations for all types. Stub sections are included for constant buffers and samplers, but no information is provided as yet.

Fixes llvm/wg-hlsl#55
Fixes llvm/wg-hlsl#56
@damyanp damyanp requested a review from llvm-beanz October 22, 2024 16:56
Copy link
Member

@damyanp damyanp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial thoughts.

specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Show resolved Hide resolved
Strip mention of UAVs and SRVs

Remove some legacy text mistakenly left in as notes, mischaracterization of tiled memory, leftover sentences from moved or deleted segments, and elements of code examples.

Better summarize typed buffers upfront.

Add description of UDT register annotations.
\texttt{T[]}, or an object of type \texttt{T} where \texttt{T} provides an
the form \texttt{E1[E2]}, \texttt{E1} must either be a variable of array,
vector, matrix, typed buffer (\ref{Resources.tybuf}), or structured buffer
(\ref{Resources.stbufs}), with elements of type \texttt{T[]} or an
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource types have overloads for operator[] even in DXC. The original language did miss vector and matrix types, but the addition of resources is redundant.

// element access
T operator[](uint pos);
T Load(in int pos);
T Load(in int pos, out uint status);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some (maybe all) of these methods should probably be const.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

\begin{HLSL}
template <typename T = float4>
class Buffer {
Buffer();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need a copy constructor.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the copy constructors take references?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was hesitant to suggest references since we don't make them visible to the users, but I suppose that's the way the are in C++ and that's the metaphor we're using here even in cases where it doesn't reflect the actual implementation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use references elsewhere and when we do add references to the language I think it'll mean that this documentation just becomes correct.

I think that the copy constructors should take const references though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

specs/language/resources.tex Outdated Show resolved Hide resolved
Copy link
Member Author

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Responded to Damyan's comments

specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Show resolved Hide resolved
consolidate typed, byte-address, and structured buffers into common
sections sharing documentation of their common elements and using inheritance
and variant-specific sections to describe differences.

Make const all methods that should be

Add copy constructors to all buffer types.

Revise expressions changes.
Copy link
Member Author

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Respond to @llvm-beanz comments. The extend of the changes merging many of the buffer descriptions made me unable to respond to some of the comments directly. I used the class inheritance metaphor to represent the relation between some buffer types.

\begin{HLSL}
template <typename T = float4>
class Buffer {
Buffer();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

// element access
T operator[](uint pos);
T Load(in int pos);
T Load(in int pos, out uint status);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

@damyanp damyanp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't fully read this yet, but I had a look through the changes that were directly in response to my previous feedback (thanks!)

specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
In response to Damyan's comments
Corrected some mistaken syntax in buffer declarations.
Revise the description of CheckAccessFullyMapped, giving it its own section that other parts refer to.
correct sign of parameters to the subscript operator
Comment on lines 37 to 39
T operator[](int pos) const;
T Load(in int pos) const;
T Load(in int pos, out uint status) const;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I was suggesting that we should change the spec here, only call out that this somewhat surprising definition is actually what is intended and isn't a mistake.

Somehow I was unable to respond to this comment from @damyanp about similar lines of text directly. Probably a consequence of the consolidation I did.

I suspect perhaps the intent was to say "I wasn't suggesting that we should change the spec here"? That seems more consistent with the rest of the sentence. I could be persuaded either way, but I've brought all subscript ops and loads into line with a signed integer parameter for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, yes, your interpretation is correct.

@bogner - do the parameter types in this spec match what you've/'re implementing?

\begin{HLSL}
template <typename T = float4>
class Buffer {
Buffer();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the copy constructors take references?

Comment on lines 37 to 39
T operator[](int pos) const;
T Load(in int pos) const;
T Load(in int pos, out uint status) const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, yes, your interpretation is correct.

@bogner - do the parameter types in this spec match what you've/'re implementing?

specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
Comment on lines 253 to 255
When defined at local scope, ByteAccessBuffers represent local references
that can be associated with global ByteAccessBuffers when assigned,
but must be resolvable to a unique global buffer.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must be resolvable to a unique global buffer

Just checking this is the case. So I couldn't do something like:

ByteAddressBuffer myBuf = globalBuffersArray[threadId];

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource arrays are different. If you can unambiguously map to the same resource array, that's fine. It's if you cross over into a separate resource entirely that you have problems:

https://godbolt.org/z/9Whzssxr1

ByteAddressBuffer globalBuffersArray[10];
ByteAddressBuffer globalBuffer;
RWBuffer<float4> outbuf;
[numthreads(8,1,1)]
void main(uint threadId: SV_GroupThreadID) {
  ByteAddressBuffer myBuf;
  myBuf = globalBuffersArray[threadId]; // This is fine
  if (threadId > 10)
    myBuf = globalBuffer; // This is not
outbuf[threadId] = myBuf.Load<float4>(0);
}

I'll try to come up with some wording that makes this clear and maybe add a note for the specific case

specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
RWBuffer<float> herbuf : register(u0, space1);
\end{HLSL}

Resource aggregates structs containing multiple resources types or arrays of resource types or structs containing one or more resource types.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource aggregates structs containing multiple resources types or arrays of resource types or structs containing one or more resource types.

I might be tired, but I'm having a hard time parsing this one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refactored it into a self-referential list of what constitutes an aggregate resource type. I think it's much clearer now.

Corrected a few parameter names and types
This led to significant rewording of the atomic operation descriptions.

Clarified unique global resource mapping.

Refactored description of aggregate resource types for purposes of binding
Copy link
Member Author

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Damyan! Responses in relation to the latest commit.

\begin{HLSL}
template <typename T = float4>
class Buffer {
Buffer();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was hesitant to suggest references since we don't make them visible to the users, but I suppose that's the way the are in C++ and that's the metaphor we're using here even in cases where it doesn't reflect the actual implementation.

specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
Comment on lines 253 to 255
When defined at local scope, ByteAccessBuffers represent local references
that can be associated with global ByteAccessBuffers when assigned,
but must be resolvable to a unique global buffer.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource arrays are different. If you can unambiguously map to the same resource array, that's fine. It's if you cross over into a separate resource entirely that you have problems:

https://godbolt.org/z/9Whzssxr1

ByteAddressBuffer globalBuffersArray[10];
ByteAddressBuffer globalBuffer;
RWBuffer<float4> outbuf;
[numthreads(8,1,1)]
void main(uint threadId: SV_GroupThreadID) {
  ByteAddressBuffer myBuf;
  myBuf = globalBuffersArray[threadId]; // This is fine
  if (threadId > 10)
    myBuf = globalBuffer; // This is not
outbuf[threadId] = myBuf.Load<float4>(0);
}

I'll try to come up with some wording that makes this clear and maybe add a note for the specific case

specs/language/resources.tex Outdated Show resolved Hide resolved
specs/language/resources.tex Show resolved Hide resolved
specs/language/resources.tex Outdated Show resolved Hide resolved
RWBuffer<float> herbuf : register(u0, space1);
\end{HLSL}

Resource aggregates structs containing multiple resources types or arrays of resource types or structs containing one or more resource types.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refactored it into a self-referential list of what constitutes an aggregate resource type. I think it's much clearer now.

@llvm-beanz llvm-beanz added the Design Meeting Agenda item for the design meeting label Nov 12, 2024
Copy link
Member

@damyanp damyanp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - a few nits in the comments, but I think this is pretty much ready to go in.

RWBuffer<float> herbuf : register(u0, space1);
\end{HLSL}

A aggregate resource type can be:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A aggregate resource type can be:
An aggregate resource type can be:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

\end{itemize}

When aggregate resource types have register annotations,
they occupy the first register they specify as well as however many additional sequential registers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
they occupy the first register they specify as well as however many additional sequential registers
they occupy the first register they specify, as well as however many additional sequential registers

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think a comma is required here. "as well as" serves the same function as "and". In retrospect, I'll change it to "and" for simplicity. I think that makes it clearer that the comma isn't needed since it's just a single conjunction.


\begin{note}
Resource types contained in structs are only allocated registers when they are explicitly used.
This includes elements of arrays of resources as such array elements must be indexed with literals.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This includes elements of arrays of resources as such array elements must be indexed with literals.
This includes elements of arrays of resources, as such array elements must be indexed with literals.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't think this comma is needed. "As" serves the same purpose as "since", which I will replace it with for similar reasons as above.

This says that if it is a subordinate clause following the main close, no comma is needed. It is needed when it is a subordinate clause that precedes the main clause e.g. "Since such array elements must be indexed with literals, this includes elements of arrays of resources."

\begin{HLSL}
template <typename T = float4>
class Buffer {
Buffer();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use references elsewhere and when we do add references to the language I think it'll mean that this documentation just becomes correct.

I think that the copy constructors should take const references though.

Copy link
Member Author

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked with grammarly and copilot to verify my thinking about commas.

\begin{HLSL}
template <typename T = float4>
class Buffer {
Buffer();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

\end{itemize}

When aggregate resource types have register annotations,
they occupy the first register they specify as well as however many additional sequential registers
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think a comma is required here. "as well as" serves the same function as "and". In retrospect, I'll change it to "and" for simplicity. I think that makes it clearer that the comma isn't needed since it's just a single conjunction.


\begin{note}
Resource types contained in structs are only allocated registers when they are explicitly used.
This includes elements of arrays of resources as such array elements must be indexed with literals.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't think this comma is needed. "As" serves the same purpose as "since", which I will replace it with for similar reasons as above.

This says that if it is a subordinate clause following the main close, no comma is needed. It is needed when it is a subordinate clause that precedes the main clause e.g. "Since such array elements must be indexed with literals, this includes elements of arrays of resources."

RWBuffer<float> herbuf : register(u0, space1);
\end{HLSL}

A aggregate resource type can be:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@damyanp damyanp requested a review from llvm-beanz November 25, 2024 23:32
RWBuffer operator=(RWBuffer buf);

// element access
T &operator[](int n);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be T &operator[](size_t n);?

Along the same lines, should the type of index argument of Buffer::Load(...) methods above be size_t instead of int?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be T &operator[](size_t n);?

Along the same lines, should the type of index argument of Buffer::Load(...) methods above be size_t instead of int?

Never mind. It would contradict the public API

public:
Buffer();
Buffer(const Buffer &buf);
Buffer operator=(Buffer buf);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Buffer operator=(Buffer buf);
Buffer &operator=(const Buffer &buf);

public:
RWBuffer();
RWBuffer(RWBuffer buf);
RWBuffer operator=(RWBuffer buf);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
RWBuffer operator=(RWBuffer buf);
RWBuffer &operator=(const RWBuffer &buf);

but must be resolvable to a unique global buffer declaration.

\begin{note}
Local buffers must be resolvable to a unique global declaration, but not necessarily a unique individual buffer.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this wording slightly confusing. What is a "unique individual buffer" vs a "unique global declaration"?

I believe this and the next sentence have to do with arrays of resources, but that isn't clear to me from the wording here.

RWBuffer<int> lrwbuf = grwbuf;
}
\end{HLSL}
Buffer operands to the assignment operator must have the same element type.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps more simply:

Buffer types cannot be casted implicitly or explicitly.

The overload resolution of assignment operators isn't impacted.

public:
ByteAddressBuffer();
ByteAddressBuffer(const ByteAddressBuffer &buf);
ByteAddressBuffer operator=(ByteAddressBuffer buf);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ByteAddressBuffer operator=(ByteAddressBuffer buf);
ByteAddressBuffer &operator=(ByteAddressBuffer &buf);

public:
RWByteAddressBuffer();
RWByteAddressBuffer(const RWByteAddressBuffer &buf);
RWByteAddressBuffer operator=(RWByteAddressBuffer buf);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
RWByteAddressBuffer operator=(RWByteAddressBuffer buf);
RWByteAddressBuffer &operator=(RWByteAddressBuffer &buf);

Comment on lines +305 to +306
The alignment requirements of \texttt{offset} for this operation is the size in bytes of the largest
scalar type contained in the given tyep \texttt{T}.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The alignment requirements of \texttt{offset} for this operation is the size in bytes of the largest
scalar type contained in the given tyep \texttt{T}.
The alignment requirements of \texttt{offset} for this operation is the alignment requirement of an object of type \texttt{T} in the device memory space (\ref{Intro.Memory.Spaces.Device}).

I don't think we should be defining how the alignment requirement of a type is calculated here, instead we should define that elsewhere in the spec. You could add a placeholder reference for something like Intro.Memory.Alignment as well to make sure we have a citation.

Comment on lines +473 to +474
The buffer contents is treated as raw data and the casting to the given types
is done bit for bit.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take or leave this one, its very nitty.

Suggested change
The buffer contents is treated as raw data and the casting to the given types
is done bit for bit.
The buffer contents is treated as raw data. When accessed the bytes are interpreted as the target type with no conversions or interpolations applied.

uint DecrementCounter();
\end{HLSL}

Increment or decrements the hidden counter associated with the RWStructuredBuffer.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the return value?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Meeting Agenda item for the design meeting
Projects
Status: No status
4 participants