D758 - A primitive shader's global loads are bound per draw from their lanes' addresses

Status: decided Date: 2026-10-08

A primitive shader's global_load_dword* with no scalar base is traced as a draw buffer (D733). Every such load in a program reads one buffer, placed after the program's other buffers. Its source is the program through the last load, as for a computed descriptor (D753). For each draw that prefix runs on the host lane by lane, vector instructions included, through the translator's own semantics. The run starts as the module does: the user data, every execution-mask bit of the wave set, and every vector register zero but the ids the module seeds in a vertex lane, which are unknown. It follows each branch whose condition is known.

The draw binds the range from the lowest address an active lane forms to the end of the widest read from the highest. A lane is active when its execution-mask bit is known set at the load and it is one of the draw's vertices. The module reads the range relative to its guest base, which the draw's words carry beside the range's place (D747): one word per slot, the address's low half, because a flat address is translated from its low half. A load whose lanes' addresses or mask the host cannot know is refused by name, as is a draw of more vertices than one wave holds.

Amended by D970: the refusal of a branch on a mask the host cannot know belongs to the host's run alone. A compute dispatch refused so is prepared device-addressed where the device maps guest memory (D964). Its module carries the branch on the device, per wave, as it carries every branch, and nothing of it runs on the host.

The run is kept cheap without changing what it finds. It runs only the vector instructions whose results can reach a load's address, a backward slice to a fixed point. When no instruction it runs reads one lane from another, it runs only the draw's vertex lanes. A lane read, a permute, a data-parallel or local-data-share access, or a read of a vector-written mask other than a lane's own bit all count as reading another lane. The decoded program and its slice are found once per program. A run's answer is kept by program, user data and vertex count while every word it read still reads the same.

Why: the open-toolchain GL context's GLSL path (oops-sdk glsl_vs.c, vs_load_attributes) fetches each vertex attribute with global_load_dword* from base + stride * index. Its base and stride are words it loads from an attribute table, and the index is s12 plus the lane. The window (D711) sits wherever the shader's constant base is, and a vertex buffer is wherever the context allocated it. TSHP00001's first vertex buffer is 4 MiB past its window, and a later one 2.8 GiB past it. Every position read zero, and no triangle of either Zelda port reached a pixel. A global load has no descriptor, so nothing but the addresses the lanes form bounds it. Each of TSHP00001's thousands of draws a second brings its own base vertex, so the run is per draw and must be fast.

Rejected: