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

False zero alignment error for BDA GPU-AV #9531

Closed
spencer-lunarg opened this issue Feb 25, 2025 · 9 comments · Fixed by #9575
Closed

False zero alignment error for BDA GPU-AV #9531

spencer-lunarg opened this issue Feb 25, 2025 · 9 comments · Fixed by #9575
Assignees
Labels
GPU-AV GPU Assisted Validation

Comments

@spencer-lunarg
Copy link
Contributor

layout(buffer_reference) buffer DrawIndirectBuffer {
    uint drawCount;
    DrawIndirect commands[];
};

layout(buffer_reference) buffer PerDrawBuffer {
    PerDrawInfo info[];
};

struct FrustumCullingInfo {
    vec4 planes[6];
    uint64_t address;
};

layout(set = 0, binding = 0) restrict readonly buffer FrustumCulling {
    uint count;
    FrustumCullingInfo info[];
} frustumCulling;

void main() {
    FrustumCullingInfo frustumCullingInfo = frustumCulling.info[frustumIndex];

    uint drawIndex = atomicAdd(DrawIndirectBuffer(frustumCullingInfo.address).drawCount, 1);

    DrawIndirectBuffer(frustumCullingInfo.address).commands[drawIndex] = inDrawIndirect.commands[objectIndex];
    PerDrawBuffer(frustumCullingInfo.address + DRAW_INDIRECT_MAX_ENTITIES_SIZE).info[drawIndex] = inPerDraw.info[objectIndex];
}

generates

VUID-RuntimeSpirv-PhysicalStorageBuffer64-06315(ERROR / SPEC): vkCmdDispatch(): Unaligned pointer access: The OpStore at buffer device address 0x15208004 is not aligned to the instruction Aligned operand of 0.

which is bogus

@spencer-lunarg spencer-lunarg self-assigned this Feb 25, 2025
@spencer-lunarg spencer-lunarg added the GPU-AV GPU Assisted Validation label Feb 25, 2025
@ntsh-oni
Copy link
Contributor

ntsh-oni commented Feb 25, 2025

Full shader, for information:

#version 460
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#extension GL_EXT_buffer_reference2 : require

#define DRAW_INDIRECT_MAX_ENTITIES_SIZE 81936

layout(local_size_x = 8, local_size_y = 8) in;

struct FrustumCullingInfo {
	vec4 planes[6];
	uint64_t address;
};

struct ObjectInfo {
	vec3 position;
	mat4 rotation;
	vec3 scale;
	vec3 aabbMin;
	vec3 aabbMax;
};

layout(set = 0, binding = 0) restrict readonly buffer FrustumCulling {
	uint count;
	FrustumCullingInfo info[];
} frustumCulling;

layout(set = 0, binding = 1) restrict readonly buffer Objects {
	ObjectInfo info[];
} objects;

struct DrawIndirect {
	uint indexCount;
	uint instanceCount;
	uint firstIndex;
	int vertexOffset;
	uint firstInstance;
};

layout(set = 0, binding = 2) restrict readonly buffer InDrawIndirect {
	uint drawCount;
	DrawIndirect commands[];
} inDrawIndirect;

struct PerDrawInfo {
	uint objectID;
};

layout(set = 0, binding = 3) restrict readonly buffer InPerDraw {
	PerDrawInfo info[];
} inPerDraw;

layout(buffer_reference) buffer DrawIndirectBuffer {
	uint drawCount;
	DrawIndirect commands[];
};

layout(buffer_reference) buffer PerDrawBuffer {
	PerDrawInfo info[];
};

bool intersect(FrustumCullingInfo frustumCullingInfo, vec3 aabbMin, vec3 aabbMax) {
	const vec3 mmm = vec3(aabbMin.x, aabbMin.y, aabbMin.z);
	const vec3 Mmm = vec3(aabbMax.x, aabbMin.y, aabbMin.z);
	const vec3 mMm = vec3(aabbMin.x, aabbMax.y, aabbMin.z);
	const vec3 MMm = vec3(aabbMax.x, aabbMax.y, aabbMin.z);
	const vec3 mmM = vec3(aabbMin.x, aabbMin.y, aabbMax.z);
	const vec3 MmM = vec3(aabbMax.x, aabbMin.y, aabbMax.z);
	const vec3 mMM = vec3(aabbMin.x, aabbMax.y, aabbMax.z);
		const vec3 MMM = vec3(aabbMax.x, aabbMax.y, aabbMax.z);
	for (uint i = 0; i < 6; i++) {
		if (((dot(frustumCullingInfo.planes[i].xyz, mmm) + frustumCullingInfo.planes[i].w) <= 0.0f)
			&& ((dot(frustumCullingInfo.planes[i].xyz, Mmm) + frustumCullingInfo.planes[i].w) <= 0.0f)
			&& ((dot(frustumCullingInfo.planes[i].xyz, mMm) + frustumCullingInfo.planes[i].w) <= 0.0f)
			&& ((dot(frustumCullingInfo.planes[i].xyz, MMm) + frustumCullingInfo.planes[i].w) <= 0.0f)
			&& ((dot(frustumCullingInfo.planes[i].xyz, mmM) + frustumCullingInfo.planes[i].w) <= 0.0f)
			&& ((dot(frustumCullingInfo.planes[i].xyz, MmM) + frustumCullingInfo.planes[i].w) <= 0.0f)
			&& ((dot(frustumCullingInfo.planes[i].xyz, mMM) + frustumCullingInfo.planes[i].w) <= 0.0f)
			&& ((dot(frustumCullingInfo.planes[i].xyz, MMM) + frustumCullingInfo.planes[i].w) <= 0.0f)) {
			return false;
		}
	}

	return true;
}

void main() {
	uint objectIndex = gl_GlobalInvocationID.x;
	if (objectIndex >= inDrawIndirect.drawCount) {
		return;
	}

	uint frustumIndex = gl_GlobalInvocationID.y;
	if (frustumIndex >= frustumCulling.count) {
		return;
	}

	FrustumCullingInfo frustumCullingInfo = frustumCulling.info[frustumIndex];

	vec3 aabbMin = objects.info[objectIndex].aabbMin;
	vec3 aabbMax = objects.info[objectIndex].aabbMax;

	vec3 newAABBMin = objects.info[objectIndex].position;
	vec3 newAABBMax = objects.info[objectIndex].position;

	float a;
	float b;

	for (uint i = 0; i < 3; i++) {
		for (uint j = 0; j < 3; j++) {
			a = objects.info[objectIndex].rotation[j][i] * aabbMin[j] * abs(objects.info[objectIndex].scale[j]);
			b = objects.info[objectIndex].rotation[j][i] * aabbMax[j] * abs(objects.info[objectIndex].scale[j]);

			newAABBMin[i] += (a < b) ? a : b;
			newAABBMax[i] += (a < b) ? b : a;
		}
	}

	aabbMin = newAABBMin;
	aabbMax = newAABBMax;

	if (intersect(frustumCullingInfo, aabbMin, aabbMax)) {
		uint drawIndex = atomicAdd(DrawIndirectBuffer(frustumCullingInfo.address).drawCount, 1);

		DrawIndirectBuffer(frustumCullingInfo.address).commands[drawIndex] = inDrawIndirect.commands[objectIndex];
		PerDrawBuffer(frustumCullingInfo.address + DRAW_INDIRECT_MAX_ENTITIES_SIZE).info[drawIndex] = inPerDraw.info[objectIndex];
	}
}

@ntsh-oni
Copy link
Contributor

And full validation message:

Validation Error: [ VUID-RuntimeSpirv-PhysicalStorageBuffer64-06315 ] Object 0: handle = 0x28b3d2a5000, type = VK_OBJECT_TYPE_QUEUE; Object 1: handle = 0x28b71123070, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x74774701 | vkCmdDispatch(): Unaligned pointer access: The OpStore at buffer device address 0x1521c010 is not aligned to the instruction Aligned operand of 0.
Stage = Compute.  Global invocation ID (x, y, z) = (8, 0, 0)
Command buffer (0x28b71123070)
        Compute Dispatch Index 0
Pipeline (944a2c0000000039)
Shader Module (9638f80000000036) (internal ID 1)
SPIR-V Instruction Index = 730
Shader validation error occurred at line 126
No Text operand found in DebugSource
The Vulkan spec states: If the PhysicalStorageBuffer64 addressing model is enabled the pointer value of a memory access instruction must be at least as aligned as specified by the Aligned memory access operand (https://vulkan.lunarg.com/doc/view/1.4.304.1/windows/antora/spec/latest/appendices/spirvenv.html#VUID-RuntimeSpirv-PhysicalStorageBuffer64-06315)

I don't know if it's related but the Global Invocation ID is always 8 (which is the local_size_x) for this message.

@spencer-lunarg
Copy link
Contributor Author

Taking a look at this right now, one thing strange about the message is

Shader validation error occurred at line 126

where there is clearly no line 126 in the source

  • Is this for sure the right compute shader source?
  • How did you compile it to SPIR-V?

@spencer-lunarg
Copy link
Contributor Author

Awww, wow, found the issue https://godbolt.org/z/c447Koa45

There is a OpStore %419 %418 Aligned 0 and that is why it was aligned to zero... need to figure out if this is a glslang bug, lacking of spirv-val or just an edge case we need to gaurd

@ntsh-oni
Copy link
Contributor

ntsh-oni commented Mar 4, 2025

Taking a look at this right now, one thing strange about the message is

Shader validation error occurred at line 126

where there is clearly no line 126 in the source

* Is this for sure the right compute shader source?

* How did you compile it to SPIR-V?

It is the right one, line 126 is either
DrawIndirectBuffer(frustumCullingInfo.address).commands[drawIndex] = inDrawIndirect.commands[objectIndex];
or
PerDrawBuffer(frustumCullingInfo.address + DRAW_INDIRECT_MAX_ENTITIES_SIZE).info[drawIndex] = inPerDraw.info[objectIndex];

Compiled using glslang.

@spencer-lunarg
Copy link
Contributor Author

So got confirmation that glslang is producing invalid SPIR-V (https://godbolt.org/z/r35M64enW)

It can't do Aligned 0, but we are missing validation in spirv-val

  1. Will raise glslang issue
  2. Will get spec text to add a VU to catch this
  3. Will get spirv-val code in (so it would have caught at pipeline creation)
  4. Will make the GPU-AV code robust and look for 0 and ignore

@spencer-lunarg
Copy link
Contributor Author

@ntsh-oni heads up, GPU-AV now won't report a false positive, but glslang has a bug (KhronosGroup/glslang#3893) and a future SDK (the one after 1.4.309) will report it as invalid SPIR-V

@ntsh-oni
Copy link
Contributor

ntsh-oni commented Mar 5, 2025

Alright! So, the original glsl code has an alignment issue then?

@spencer-lunarg
Copy link
Contributor Author

yes, you can see a trimmed down version here https://godbolt.org/z/r35M64enW that OpStore %34 %32 Aligned 0 is not valid, Aligned needs to be a power of 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
GPU-AV GPU Assisted Validation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants