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

Validation error when creating texture of size 64x32 #323

Closed
cloudhead opened this issue Aug 31, 2019 · 12 comments
Closed

Validation error when creating texture of size 64x32 #323

cloudhead opened this issue Aug 31, 2019 · 12 comments
Labels
external: upstream Issues happening in lower level APIs or platforms

Comments

@cloudhead
Copy link
Contributor

I have code that sometimes when creating a texture triggers this validation error and results in the rendered image to be corrupted:

VALIDATION [VUID-vkBindImageMemory-memoryOffset-01048 (0)] : vkBindImageMemory(): memoryOffset is 0x23e00 but must be an integer multiple of the VkMemoryRequirements::alignment value 0x1000, returned from a call to vkGetImageMemoryRequirements with image. The Vulkan spec states: memoryOffset must be an integer multiple of the alignment member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memoryOffset-01048)

Looking at the wgpu code, it looks like it already handles alignment:

let memory = self
.mem_allocator
.lock()
.allocate(
&self.raw,
requirements.type_mask as u32,
rendy_memory::Data,
requirements.size,
requirements.alignment,
)
.unwrap();
unsafe {
self.raw
.bind_image_memory(memory.memory(), memory.range().start, &mut image)
.unwrap()
};

So I'm wondering why this causes problems. If creating a 64x64 texture, there is no error. But a 64x32 texture results in the above error and corruption.

@kvark
Copy link
Member

kvark commented Sep 1, 2019

Looks like a bug in rendy? @omni-viral

@zakarumych
Copy link

I guess dynamic allocator is used.
This function
https://docs.rs/rendy-memory/0.4.0/src/rendy_memory/allocator/dynamic.rs.html#509
ensures alignment.
@cloudhead can you validated that wgpu specifies 0x1000?

@cloudhead
Copy link
Contributor Author

I think the Heaps allocator is used. When I tried reproducing this again, it took me a while to get the validation error to show up again, but the image was still corrupted. I finally got it to show up again, and using trace logging, it seems like the right alignment is passed into rendy:

[2019-09-01T19:57:52Z TRACE rendy_memory::heaps] Allocate memory block: type '1', usage 'Data', size: '12308', align: '4096'
[2019-09-01T19:57:52Z TRACE rendy_memory::allocator::dynamic] Allocate dynamic block: size: 12308, align: 4096, aligned size: 16384, type: 1
[2019-09-01T19:57:52Z TRACE rendy_memory::allocator::dynamic] Allocate block of size 16384
[2019-09-01T19:57:52Z TRACE rendy_memory::allocator::dynamic] Allocate 4 consecutive blocks for size 4352 from the entry
[2019-09-01T19:57:52Z TRACE rendy_memory::allocator::dynamic] Allocate 4 consecutive blocks of size 4352 from chunk 0
[2019-09-01T19:57:52Z ERROR gfx_backend_vulkan]
VALIDATION [VUID-vkBindImageMemory-memoryOffset-01048 (0)] : vkBindImageMemory(): memoryOffset is 0x43300 but must be an integer multiple of the VkMemoryRequirements::alignment value 0x1000, returned from a call to vkGetImageMemoryRequirements with image. The Vulkan spec states: memoryOffset must be an integer multiple of the alignment member of the VkMemoryRequirements structure returned from a call to vkGetImageMemoryRequirements with image (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkBindImageMemory-memoryOffset-01048)
object info: (type: IMAGE, hndl: 1832)

@cloudhead
Copy link
Contributor Author

The same trace which does not show any corruption nor gives any error reads:

[2019-09-01T20:02:01Z TRACE rendy_memory::heaps] Allocate memory block: type '1', usage 'Data', size: '12308', align: '4096'
[2019-09-01T20:02:01Z TRACE rendy_memory::allocator::dynamic] Allocate dynamic block: size: 12308, align: 4096, aligned size: 16384, type: 1
[2019-09-01T20:02:01Z TRACE rendy_memory::allocator::dynamic] Allocate block of size 16384
[2019-09-01T20:02:01Z TRACE rendy_memory::allocator::dynamic] Allocate 1 consecutive blocks for size 16384 from the entry
[2019-09-01T20:02:01Z TRACE rendy_memory::allocator::dynamic] Allocate 1 consecutive blocks of size 16384 from chunk 0

The only difference seems to be that it allocates 1 large block, vs 4 small ones.

@zakarumych
Copy link

@cloudhead Heaps delegates memory allocation. To DynamicAllocator this time.
I see where the problem comes from.

@cloudhead
Copy link
Contributor Author

@omni-viral anything I can do to help?

@zakarumych
Copy link

Here's what I think is causing the problem.
In DynamicAllocator blocks are size-aligned, so bumping size up to aligned value and allocating block of that size will always return properly aligned blocks.
But there is an exception.
When no chunks of specified size are created allocator checks chunks of smaller to see if there are consecutive free blocks that have enough total size and allocate them together.
But smaller blocks have smaller alignment. Which results in inappropriatly aligned allocation when, for example (aligned_size / N) % align != 0 with N = 2,3,4. i.e. for size less than or equal to alignment.

@zakarumych
Copy link

To fix this problem the code that searches smaller chunks should take alignment into account to find out properly aligned range inside the free blocks sequence.

@cloudhead
Copy link
Contributor Author

Ah yes, that makes sense. Aren't large blocks also checked for alignment anyway? Since a 4096 byte block could also be mis-aligned? Or are blocks always aligned to their size?

@zakarumych
Copy link

In the DynamicAllocator specifically any chunk of blocks of size N is aligned to N and thus all blocks from it are aligned to N

@kvark kvark added the external: upstream Issues happening in lower level APIs or platforms label Sep 3, 2019
@cloudhead
Copy link
Contributor Author

@omni-viral - see amethyst/rendy#200 - that was indeed the problem.

@cloudhead
Copy link
Contributor Author

The fix has now been merged and published in rendy-memory, so this is now fixed.

kvark pushed a commit to kvark/wgpu that referenced this issue Jun 3, 2021
323: Rename SwapChain::get_next_texture to SwapChain::get_next_frame, and return errors to the user. r=kvark a=AlphaModder

Depends on gfx-rs#668.

This creates a new type `SwapChainResult` just for the method. 
It also alters the signature of `Context::swap_chain_get_next_texture` to return 
```rust
(Option<Self::TextureViewId>, wgt::SwapChainStatus, Self::SwapChainOutputDetail)
```
which is a little ugly but I couldn't think of anything better. 

Co-authored-by: AlphaModder <quasiflux@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external: upstream Issues happening in lower level APIs or platforms
Projects
None yet
Development

No branches or pull requests

3 participants