The fragment shader CBV address was computed as gpuAddress + vsh->m_size,
but D3D12 requires constant buffer view addresses to be 256-byte aligned
(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT). When the vertex shader
constant buffer exceeds 256 bytes without being a multiple of 256, the
fragment shader reads from a misaligned address, producing corrupt uniform
values.
This causes rendering artifacts or completely black output for any shader
program where the VS constant buffer size is not a multiple of 256 bytes,
since the fragment shader receives incorrect uniform data (e.g. a non-zero
alpha reference threshold that discards all pixels).
The fix aligns the VS constant buffer size to 256 bytes before placing the
FS constants, and uses the aligned offset when computing the FS CBV address
in both the main render loop and the blitter path.
* DX12: fix invalid state when creating a BLIT_DST texture without mem block
* Only set state when it's not external texture.
---------
Co-authored-by: Branimir Karadžić <branimirkaradzic@gmail.com>
The _external parameter is written to the command buffer as uint64_t (8 bytes)
but read back as uintptr_t (4 bytes on 32-bit). This causes a 4-byte
deserialization misalignment on x86, corrupting all subsequent command
buffer reads and leading to EXCEPTION_ACCESS_VIOLATION (0xC0000005) during
D3D11 initialization.
Co-authored-by: Matteo Valdina <mavaldin@microsoft.com>
* vulkan: Do not hard-depend on Vulkan 1.2 and Vulkan 1.1.
* fix(ub): vector iterators are not the same as taking address of position.
* fix(ub): Mask bit iterator had implicit promotion bug.
* fix(ub): Vulkan backend shouldn't copy fragment shader source if there is none.
Replace stl::list (tinystl::vector with O(n) push_front) with a sorted
stl::vector free list that maintains address-order invariant.
Key improvements:
- free(): uses bx::upperBound for O(log n) sorted insertion + immediate
adjacent-block coalescing instead of O(n) push_front with deferred merge
- compact(): O(1) check (m_used empty?) instead of O(n log n) sort +
O(n) linear merge pass on every call
- alloc(): first-fit scan over cache-friendly contiguous memory instead
of pointer-chasing through fragmented list
- add(): sorted insert with coalescing via bx::upperBound, same as free()
Uses bx::upperBound from the bx foundation library for binary search,
no std:: usage. Added operator> to Free struct for bx::compareAscending
compatibility.
The public API and behavioral semantics are unchanged. All existing
callers (dynamic index/vertex buffer allocators, uniform cache store
allocator) continue to work identically.