From 77b5c391e99d596c74bd71cd9a62972ce4ef3d6b Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 28 Nov 2019 17:12:47 +0000 Subject: [PATCH] Check that we handle padding and alignment around structs * On all APIs structs are aligned up to 16-byte alignment, and on D3D as with arrays then elements coming after the struct can be packed into the padding after the last struct element. --- util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp | 16 ++++++- util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp | 16 ++++++- util/test/demos/gl/gl_cbuffer_zoo.cpp | 20 +++++++-- util/test/demos/vk/vk_cbuffer_zoo.cpp | 30 +++++++++++-- util/test/tests/D3D11/D3D11_CBuffer_Zoo.py | 26 ++++++++++- util/test/tests/D3D12/D3D12_CBuffer_Zoo.py | 26 ++++++++++- util/test/tests/GL/GL_CBuffer_Zoo.py | 27 ++++++++++-- util/test/tests/Vulkan/VK_CBuffer_Zoo.py | 48 ++++++++++++++++++--- 8 files changed, 187 insertions(+), 22 deletions(-) diff --git a/util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp b/util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp index a34df4ec2..8cab2c648 100644 --- a/util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp +++ b/util/test/demos/d3d11/d3d11_cbuffer_zoo.cpp @@ -36,6 +36,8 @@ struct float3_1 { float3 a; float b; }; struct nested { float3_1 a; float4 b[4]; float3_1 c[4]; }; +struct float2_struct { float x; float y; }; + struct nested_with_padding { float a; // 0, <1, 2, 3> @@ -239,7 +241,19 @@ cbuffer consts : register(b0) nested_with_padding ak[2]; // 440 - 467, 468 - 495 - float4 test; // {496, 497, 498, 499} + float4 dummy13; // forces no trailing overlap with ak + + float al; // {500}, <501, 502, 503> + + // struct is always float4 aligned, can't be packed with al + float2_struct am; // {504, 505}, <506, 507> + + // struct allows trailing things into padding + float an; // {506} + + float4 gldummy4; // account for an not overlapping in GL/VK + + float4 test; // {512, 513, 514, 515} }; float4 main() : SV_Target0 diff --git a/util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp b/util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp index 36cb8405c..cec132713 100644 --- a/util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp +++ b/util/test/demos/d3d12/d3d12_cbuffer_zoo.cpp @@ -36,6 +36,8 @@ struct float3_1 { float3 a; float b; }; struct nested { float3_1 a; float4 b[4]; float3_1 c[4]; }; +struct float2_struct { float x; float y; }; + struct nested_with_padding { float a; // 0, <1, 2, 3> @@ -239,7 +241,19 @@ cbuffer consts : register(b0) nested_with_padding ak[2]; // 440 - 467, 468 - 495 - float4 test; // {496, 497, 498, 499} + float4 dummy13; // forces no trailing overlap with ak + + float al; // {500}, <501, 502, 503> + + // struct is always float4 aligned, can't be packed with al + float2_struct am; // {504, 505}, <506, 507> + + // struct allows trailing things into padding + float an; // {506} + + float4 gldummy4; // account for an not overlapping in GL/VK + + float4 test; // {512, 513, 514, 515} }; // this comes from root signature constants diff --git a/util/test/demos/gl/gl_cbuffer_zoo.cpp b/util/test/demos/gl/gl_cbuffer_zoo.cpp index 94792d5d0..6dd48d96d 100644 --- a/util/test/demos/gl/gl_cbuffer_zoo.cpp +++ b/util/test/demos/gl/gl_cbuffer_zoo.cpp @@ -71,6 +71,8 @@ struct vec3_1 { vec3 a; float b; }; struct nested { vec3_1 a; vec4 b[4]; vec3_1 c[4]; }; +struct float2_struct { float x; float y; }; + struct nested_with_padding { float a; // 0, <1, 2, 3> @@ -270,14 +272,24 @@ layout(binding = 0, std140) uniform constsbuf nested_with_padding ak[2]; // 440 - 467, 468 - 495 - vec4 test; // {496, 497, 498, 499} + vec4 dummy12; // forces no trailing overlap with ak + + float al; // {500}, <501, 502, 503> + + // struct is always float4 aligned, can't be packed with al + float2_struct am; // {504, 505}, <506, 507> + + // struct doesn't allow trailing things into padding + float an; // {506} + + vec4 test; // {512, 513, 514, 515} // because GL has worse handling of multidimensional arrays than other APIs, we add an extra test // here with more than 2 dimensions - vec4 multiarray2[4][3][2]; // [0][0][0] = {500, 501, 502, 503} - // [0][0][1] = {504, 505, 506, 507} - // [0][1][0] = {508, ..., ..., ...} + vec4 multiarray2[4][3][2]; // [0][0][0] = {516, 517, 518, ...} + // [0][0][1] = {..., ..., ..., ...} + // [0][1][0] = {..., ..., ..., ...} // [0][1][1] = {..., ..., ..., ...} // [0][2][0] = {..., ..., ..., ...} // [0][2][1] = {..., ..., ..., ...} diff --git a/util/test/demos/vk/vk_cbuffer_zoo.cpp b/util/test/demos/vk/vk_cbuffer_zoo.cpp index 373521766..78927103a 100644 --- a/util/test/demos/vk/vk_cbuffer_zoo.cpp +++ b/util/test/demos/vk/vk_cbuffer_zoo.cpp @@ -70,6 +70,8 @@ struct vec3_1 { vec3 a; float b; }; struct nested { vec3_1 a; vec4 b[4]; vec3_1 c[4]; }; +struct float2_struct { float x; float y; }; + struct nested_with_padding { float a; // 0, <1, 2, 3> @@ -269,7 +271,17 @@ layout(set = 0, binding = 0, std140) uniform constsbuf nested_with_padding ak[2]; // 440 - 467, 468 - 495 - vec4 test; // {496, 497, 498, 499} + vec4 dummy12; // forces no trailing overlap with ak + + float al; // {500}, <501, 502, 503> + + // struct is always float4 aligned, can't be packed with al + float2_struct am; // {504, 505}, <506, 507> + + // struct doesn't allow trailing things into padding + float an; // {508} + + vec4 test; // {512, 513, 514, 515} }; layout (constant_id = 0) const int A = 10; @@ -289,6 +301,8 @@ struct float3_1 { float3 a; float b; }; struct nested { float3_1 a; float4 b[4]; float3_1 c[4]; }; +struct float2_struct { float x; float y; }; + struct nested_with_padding { float a; // 0, <1, 2, 3> @@ -496,9 +510,19 @@ layout(set = 0, binding = 0) cbuffer consts // <435, 439> // } - nested_with_padding ak[2]; // 440 - 467, 468 - 495 + nested_with_padding ak[2]; // 440 - 467, 468 - 494 + + float4 dummy14; // forces no trailing overlap with ak - float4 test; // {496, 497, 498, 499} + float al; // {500}, <501, 502, 503> + + // struct is always float4 aligned, can't be packed with al + float2_struct am; // {504, 505}, <506, 507> + + // struct doesn't allow trailing things into padding + float an; // {508} + + float4 test; // {512, 513, 514, 515} }; float4 main() : SV_Target0 diff --git a/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py b/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py index f855e0542..b4b7fca6d 100644 --- a/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py +++ b/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py @@ -335,13 +335,35 @@ class D3D11_CBuffer_Zoo(rdtest.TestCase): }), }) + # float2 dummy13; + var_check.check('dummy13') + + # float al; + var_check.check('al').rows(1).cols(1).value([500.0]) + + # struct float2_struct + # { + # float x, y; + # }; + # float2_struct am; + var_check.check('am').rows(0).cols(0).members({ + 'x': lambda y: y.rows(1).cols(1).value([504.0]), + 'y': lambda y: y.rows(1).cols(1).value([505.0]), + }) + + # float an; + var_check.check('an').rows(1).cols(1).value([506.0]) + + # float4 gldummy4; + var_check.check('gldummy4') + # float4 test; - var_check.check('test').rows(1).cols(4).value([496.0, 497.0, 498.0, 499.0]) + var_check.check('test').rows(1).cols(4).value([512.0, 513.0, 514.0, 515.0]) var_check.done() rdtest.log.success("CBuffer variables are as expected") - self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [496.1, 497.0, 498.0, 499.0]) + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [512.1, 513.0, 514.0, 515.0]) rdtest.log.success("Picked value is as expected") diff --git a/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py b/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py index 33dc6a9fe..41df840d0 100644 --- a/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py +++ b/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py @@ -357,14 +357,36 @@ class D3D12_CBuffer_Zoo(rdtest.TestCase): }), }) + # float2 dummy13; + var_check.check('dummy13') + + # float al; + var_check.check('al').rows(1).cols(1).value([500.0]) + + # struct float2_struct + # { + # float x, y; + # }; + # float2_struct am; + var_check.check('am').rows(0).cols(0).members({ + 'x': lambda y: y.rows(1).cols(1).value([504.0]), + 'y': lambda y: y.rows(1).cols(1).value([505.0]), + }) + + # float an; + var_check.check('an').rows(1).cols(1).value([506.0]) + + # float4 gldummy4; + var_check.check('gldummy4') + # float4 test; - var_check.check('test').rows(1).cols(4).value([496.0, 497.0, 498.0, 499.0]) + var_check.check('test').rows(1).cols(4).value([512.0, 513.0, 514.0, 515.0]) var_check.done() rdtest.log.success("CBuffer variables are as expected") - self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [496.1, 497.0, 498.0, 499.0]) + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [512.1, 513.0, 514.0, 515.0]) rdtest.log.success("Picked value is as expected") diff --git a/util/test/tests/GL/GL_CBuffer_Zoo.py b/util/test/tests/GL/GL_CBuffer_Zoo.py index 5f7e9b700..056f8aa96 100644 --- a/util/test/tests/GL/GL_CBuffer_Zoo.py +++ b/util/test/tests/GL/GL_CBuffer_Zoo.py @@ -320,11 +320,30 @@ class GL_CBuffer_Zoo(rdtest.TestCase): }), }) - # vec4 test; - var_check.check('test').rows(1).cols(4).value([496.0, 497.0, 498.0, 499.0]) + # float2 dummy12; + var_check.check('dummy12') + + # float al; + var_check.check('al').rows(1).cols(1).value([500.0]) + + # struct float2_struct + # { + # float x, y; + # }; + # float2_struct am; + var_check.check('am').rows(0).cols(0).members({ + 'x': lambda y: y.rows(1).cols(1).value([504.0]), + 'y': lambda y: y.rows(1).cols(1).value([505.0]), + }) + + # float an; + var_check.check('an').rows(1).cols(1).value([508.0]) + + # float4 test; + var_check.check('test').rows(1).cols(4).value([512.0, 513.0, 514.0, 515.0]) # to save duplicating if this array changes, we calculate out from the start, as the array is tightly packed - base = 500.0 + base = 516.0 exp_vals = lambda wi,yi,xi: [base + wi * 24.0 + yi * 8.0 + xi * 4.0 + c * 1.0 for c in range(0,4)] @@ -392,7 +411,7 @@ class GL_CBuffer_Zoo(rdtest.TestCase): rdtest.log.success("CBuffer variables are as expected") - self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [496.1, 497.0, 498.0, 499.0]) + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [512.1, 513.0, 514.0, 515.0]) rdtest.log.success("Picked value is as expected") diff --git a/util/test/tests/Vulkan/VK_CBuffer_Zoo.py b/util/test/tests/Vulkan/VK_CBuffer_Zoo.py index dc8957faa..ff5735b95 100644 --- a/util/test/tests/Vulkan/VK_CBuffer_Zoo.py +++ b/util/test/tests/Vulkan/VK_CBuffer_Zoo.py @@ -327,14 +327,33 @@ class VK_CBuffer_Zoo(rdtest.TestCase): }), }) - # vec4 test; - var_check.check('test').rows(1).cols(4).value([496.0, 497.0, 498.0, 499.0]) + # vec4 dummy12; + var_check.check('dummy12') + + # float al; + var_check.check('al').rows(1).cols(1).value([500.0]) + + # struct float2_struct + # { + # float x, y; + # }; + # float2_struct am; + var_check.check('am').rows(0).cols(0).members({ + 'x': lambda y: y.rows(1).cols(1).value([504.0]), + 'y': lambda y: y.rows(1).cols(1).value([505.0]), + }) + + # float an; + var_check.check('an').rows(1).cols(1).value([508.0]) + + # float4 test; + var_check.check('test').rows(1).cols(4).value([512.0, 513.0, 514.0, 515.0]) var_check.done() rdtest.log.success("GLSL CBuffer variables are as expected") - self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [496.1, 497.0, 498.0, 499.0]) + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [512.1, 513.0, 514.0, 515.0]) rdtest.log.success("GLSL picked value is as expected") @@ -704,13 +723,32 @@ class VK_CBuffer_Zoo(rdtest.TestCase): }), }) + # float4 dummy14; + var_check.check('dummy14') + + # float al; + var_check.check('al').rows(1).cols(1).value([500.0]) + + # struct float2_struct + # { + # float x, y; + # }; + # float2_struct am; + var_check.check('am').rows(0).cols(0).members({ + 'x': lambda y: y.rows(1).cols(1).value([504.0]), + 'y': lambda y: y.rows(1).cols(1).value([505.0]), + }) + + # float an; + var_check.check('an').rows(1).cols(1).value([508.0]) + # float4 test; - var_check.check('test').rows(1).cols(4).value([496.0, 497.0, 498.0, 499.0]) + var_check.check('test').rows(1).cols(4).value([512.0, 513.0, 514.0, 515.0]) var_check.done() rdtest.log.success("HLSL CBuffer variables are as expected") - self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [496.1, 497.0, 498.0, 499.0]) + self.check_pixel_value(pipe.GetOutputTargets()[0].resourceId, 0.5, 0.5, [512.1, 513.0, 514.0, 515.0]) rdtest.log.success("HLSL picked value is as expected")