Commit: 47aebd9ae07408e46643aca308f2a074f03d57f3
Parent: a092e5ef5bfa9cddb5ad89b07bc9051d32bc1564
Author: Randy Palamar
Date: Tue, 25 Aug 2026 06:33:23 -0700
core/das: massage das to get 16 byte loads out of pointer; remove descriptor zoo
With a little bit of massaging we can get the compiler to emit 16
byte load instructions with a pointer instead of twice as many 8
byte loads. This provides an alternative fix to the old
performance issue which worked around by using and SSBO. Loading
from a pointer is much simpler and allows us to delete all the
descriptor set garbage. Also nvidia cards seem to perform slightly
better with pointers instead of SSBOs but I haven't tested this
extensively.
This performs quite a bit worse on my Qualcomm GPU but is still
workable. The extra complexity needed to use SSBOs is not really
worth it just to support Qualcomm's poorly designed GPU. If I need
more performance there it would be better to try using vendor
specific extensions which should actually accelerate things.
Diffstat:
8 files changed, 111 insertions(+), 310 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -226,15 +226,6 @@ beamformer_init(BeamformerInput *input)
// NOTE(rnp): if this becomes an issue we may be able to get by in some other way
fatal(str8("Failed to allocate space for beamformed data\n"));
}
-
- BeamformerShaderResourceInfo shader_resource_infos[] = {
- {
- .kind = BeamformerShaderResourceKind_Buffer,
- .handle = cs->backlog.buffer->handle,
- .slot = BeamformerShaderBufferSlot_BeamformedData,
- },
- };
- vk_bind_shader_resources(shader_resource_infos, countof(shader_resource_infos));
}
Arena *scratch = arena_create();
diff --git a/beamformer.meta b/beamformer.meta
@@ -7,17 +7,6 @@
@Constant(16) MaxParameterBlocks
@Constant(3) MaxRawDataFramesInFlight
-@Enumeration ShaderResourceKind
-{
- Buffer
-}
-
-@Enumeration ShaderBufferSlot
-{
- BeamformedData
- PingPong
-}
-
@Enumeration DecodeMode
{
None
@@ -319,10 +308,6 @@
`read_only global str8 beamformer_interpolation_mode_strings[] = {`
@Expand(InterpolationMode) ` str8_comp("$(name)"),`
`};`
- ``
- `read_only global str8 beamformer_shader_resource_kind_strings[] = {`
- @Expand(ShaderResourceKind) ` str8_comp("$(name)"),`
- `};`
}
@ShaderGroup Compute
@@ -361,9 +346,6 @@
@Shader(filter.glsl) Filter
{
- @Enumeration ShaderBufferSlot
- @Enumeration ShaderResourceKind
-
@ShaderAlias Demodulate
@Flags
@@ -391,8 +373,8 @@
@PushConstants
{
- [input_data U64]
- [output_element_offset U32]
+ [input_buffer U64]
+ [output_buffer U64]
}
}
@@ -403,8 +385,6 @@
@Enumeration AcquisitionKind
@Enumeration InterpolationMode
@Enumeration RCAOrientation
- @Enumeration ShaderBufferSlot
- @Enumeration ShaderResourceKind
@Flags
{
@@ -413,6 +393,7 @@
@Bake
{
+ [RFData U64]
[FocalVectors U64]
[Hadamard U64]
[IncoherentFrame U64]
@@ -452,7 +433,6 @@
[voxel_transform M4]
[xdc_element_pitch V2]
[output_frame U64]
- [rf_element_offset U32]
[channel_offset S32]
[readi_group U32]
}
diff --git a/beamformer_core.c b/beamformer_core.c
@@ -583,6 +583,23 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A
cp->rf_size = input_sample_count * pb->parameters.acquisition_count * chunk_channel_count
* beamformer_data_kind_byte_size[das_data_kind];
+ i64 buffer_size = PING_PONG_BUFFER_SLOTS * round_up_to(cp->rf_size, 64);
+ if (beamformer_context->compute_context.ping_pong_buffer.size < buffer_size) {
+ b32 cuda = cuda_supported();
+ GPUBufferAllocateInfo allocate_info = {
+ .size = buffer_size,
+ .export = cuda ? &beamformer_context->compute_context.ping_pong_export_handle : 0,
+ .label = str8("PingPongBuffer"),
+ };
+ gpu_buffer_allocate(&beamformer_context->compute_context.ping_pong_buffer, allocate_info);
+
+ // TODO(rnp): figure out how to share with CUDA
+ // IMPORTANT: on linux the handle is returned to os and should be cleared after import
+ // see usage of glImportMemoryFdEXT and surrounding code in ui.c for examples
+ if (cuda) {
+ }
+ }
+
read_only local_persist BeamformerDataKind data_kind_to_element_kind[] = {
[BeamformerDataKind_Int16] = BeamformerDataKind_Float16,
[BeamformerDataKind_Float16] = BeamformerDataKind_Float16,
@@ -887,6 +904,9 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A
db->OutputSizeZ = cp->output_points.z;
db->TransmitReceiveOrientation = pb->parameters.transmit_receive_orientation;
+ u64 pp_size = beamformer_context->compute_context.ping_pong_buffer.size / PING_PONG_BUFFER_SLOTS;
+ db->RFData = beamformer_context->compute_context.ping_pong_buffer.gpu_pointer + (PING_PONG_BUFFER_SLOTS - 1) * pp_size;
+
// NOTE(rnp): old gcc will miscompile an assignment
memory_copy(cp->xdc_transform.E, pb->parameters.xdc_transform.E, sizeof(cp->xdc_transform));
@@ -1224,32 +1244,6 @@ beamformer_commit_parameter_block(BeamformerCtx *ctx, BeamformerComputePlan *cp,
cp->acquisition_count = pb->parameters.acquisition_count;
cp->acquisition_kind = pb->parameters.acquisition_kind;
cp->contrast_mode = pb->parameters.contrast_mode;
-
- i64 buffer_size = PING_PONG_BUFFER_SLOTS * round_up_to(cp->rf_size, 64);
- if (ctx->compute_context.ping_pong_buffer.size < buffer_size) {
- b32 cuda = cuda_supported();
- GPUBufferAllocateInfo allocate_info = {
- .size = buffer_size,
- .export = cuda ? &ctx->compute_context.ping_pong_export_handle : 0,
- .label = str8("PingPongBuffer"),
- };
- gpu_buffer_allocate(&ctx->compute_context.ping_pong_buffer, allocate_info);
-
- BeamformerShaderResourceInfo shader_resource_infos[] = {
- {
- .kind = BeamformerShaderResourceKind_Buffer,
- .handle = ctx->compute_context.ping_pong_buffer.handle,
- .slot = BeamformerShaderBufferSlot_PingPong,
- },
- };
- vk_bind_shader_resources(shader_resource_infos, countof(shader_resource_infos));
-
- // TODO(rnp): figure out how to share with CUDA
- // IMPORTANT: on linux the handle is returned to os and should be cleared after import
- // see usage of glImportMemoryFdEXT and surrounding code in ui.c for examples
- if (cuda) {
- }
- }
}break;
}
}
@@ -1299,16 +1293,12 @@ do_compute_shader(BeamformerCtx *ctx, GPUCommandList cmd, BeamformerComputePlan
case BeamformerShaderKind_Filter:
case BeamformerShaderKind_Demodulate:
{
- BeamformerDataKind output_data_kind = cp->shader_descriptors[shader_slot].output_data_kind;
-
- u64 element_size = beamformer_data_kind_byte_size[output_data_kind];
BeamformerFilterPushConstants pc = {
- .input_data = shader_slot == 0 ? rf_pointer : pp_input_pointer,
- .output_element_offset = output_index * pp_size / element_size,
+ .input_buffer = shader_slot == 0 ? rf_pointer : pp_input_pointer,
};
- if ((shader_slot + 1) == das_index)
- pc.output_element_offset = das_output_index * pp_size / element_size;
+ if ((shader_slot + 1) == das_index) pc.output_buffer = pp_das_pointer;
+ else pc.output_buffer = pp_output_pointer;
if (shader_slot != 0 || (shader_slot + 1) == das_index)
gpu_command_pipeline_barrier(cmd);
@@ -1320,11 +1310,8 @@ do_compute_shader(BeamformerCtx *ctx, GPUCommandList cmd, BeamformerComputePlan
}break;
case BeamformerShaderKind_DAS:{
- u64 element_size = beamformer_data_kind_byte_size[cp->shader_descriptors[shader_slot].input_data_kind];
-
BeamformerDASPushConstants pc = {
.xdc_element_pitch = cp->xdc_element_pitch,
- .rf_element_offset = das_output_index * pp_size / element_size,
.output_frame = frame->gpu_pointer,
.channel_offset = channel_offset,
.readi_group = cp->readi_group,
diff --git a/beamformer_internal.h b/beamformer_internal.h
@@ -130,12 +130,6 @@ typedef struct {
u32 normals_offset;
} RenderModel;
-typedef struct {
- BeamformerShaderResourceKind kind;
- GPUHandle handle;
- u32 slot;
-} BeamformerShaderResourceInfo;
-
#include "threads.c"
#include "util_os_ui.c"
@@ -159,8 +153,6 @@ DEBUG_IMPORT void vk_render_model_allocate(GPUBuffer *, void *indices, u64 index
DEBUG_IMPORT void vk_render_model_range_upload(GPUBuffer *, void *data, u64 offset, u64 size, b32 non_temporal);
DEBUG_IMPORT void vk_render_model_release(GPUBuffer *);
-DEBUG_IMPORT void vk_bind_shader_resources(BeamformerShaderResourceInfo *infos, u64 info_count);
-
/* NOTE: Pipelines do not have bindings. Data should be passed using push constants.
* In particular the push constants should contain pointers to gpu memory using the
* BufferDeviceAddress extension. */
diff --git a/generated/beamformer.c b/generated/beamformer.c
@@ -13,17 +13,6 @@
#define BeamformerMaxRawDataFramesInFlight (3)
typedef enum {
- BeamformerShaderResourceKind_Buffer = 0,
- BeamformerShaderResourceKind_Count,
-} BeamformerShaderResourceKind;
-
-typedef enum {
- BeamformerShaderBufferSlot_BeamformedData = 0,
- BeamformerShaderBufferSlot_PingPong = 1,
- BeamformerShaderBufferSlot_Count,
-} BeamformerShaderBufferSlot;
-
-typedef enum {
BeamformerDecodeMode_None = 0,
BeamformerDecodeMode_Hadamard = 1,
BeamformerDecodeMode_Count,
@@ -197,6 +186,7 @@ typedef struct {
} BeamformerFilterBakeParameters;
typedef struct {
+ u64 RFData;
u64 FocalVectors;
u64 Hadamard;
u64 IncoherentFrame;
@@ -249,8 +239,8 @@ typedef struct {
} BeamformerDecodePushConstants;
typedef struct {
- u64 input_data;
- u32 output_element_offset;
+ u64 input_buffer;
+ u64 output_buffer;
} BeamformerFilterPushConstants;
typedef struct {
@@ -258,7 +248,6 @@ typedef struct {
m4 voxel_transform;
v2 xdc_element_pitch;
u64 output_frame;
- u32 rf_element_offset;
i32 channel_offset;
u32 readi_group;
} BeamformerDASPushConstants;
@@ -577,10 +566,6 @@ read_only global str8 beamformer_interpolation_mode_strings[] = {
str8_comp("Cubic"),
};
-read_only global str8 beamformer_shader_resource_kind_strings[] = {
- str8_comp("Buffer"),
-};
-
typedef enum {
BeamformerStructKind_DecodeBakeParameters = 0,
BeamformerStructKind_FilterBakeParameters = 1,
@@ -625,27 +610,28 @@ read_only global MetaStructMember *meta_struct_members_by_id[] = {
{17, 16, 1, 0},
{17, 24, 1, 0},
{17, 32, 1, 0},
- {18, 40, 1, 0},
- {14, 44, 1, 0},
- {10, 48, 1, 0},
- {10, 52, 1, 0},
+ {17, 40, 1, 0},
+ {18, 48, 1, 0},
+ {14, 52, 1, 0},
{10, 56, 1, 0},
{10, 60, 1, 0},
- {8, 64, 1, 0},
- {8, 68, 1, 0},
+ {10, 64, 1, 0},
+ {10, 68, 1, 0},
{8, 72, 1, 0},
{8, 76, 1, 0},
- {18, 80, 1, 0},
+ {8, 80, 1, 0},
{8, 84, 1, 0},
- {14, 88, 1, 0},
- {18, 92, 1, 0},
+ {18, 88, 1, 0},
+ {8, 92, 1, 0},
{14, 96, 1, 0},
- {8, 100, 1, 0},
- {8, 104, 1, 0},
- {18, 108, 1, 0},
- {18, 112, 1, 0},
+ {18, 100, 1, 0},
+ {14, 104, 1, 0},
+ {8, 108, 1, 0},
+ {8, 112, 1, 0},
{18, 116, 1, 0},
{18, 120, 1, 0},
+ {18, 124, 1, 0},
+ {18, 128, 1, 0},
},
(MetaStructMember []){
{17, 0, 1, 0},
@@ -695,6 +681,7 @@ read_only global str8 *meta_struct_member_names_by_id[] = {
str8_comp("OutputTransmitStride"),
},
(str8 []){
+ str8_comp("RFData"),
str8_comp("FocalVectors"),
str8_comp("Hadamard"),
str8_comp("IncoherentFrame"),
@@ -743,7 +730,7 @@ read_only global str8 *meta_struct_member_names_by_id[] = {
read_only global MetaStructInfo meta_struct_info_by_id[] = {
{str8_comp("DecodeBakeParameters"), 11, 48, 0},
{str8_comp("FilterBakeParameters"), 13, 56, 0},
- {str8_comp("DASBakeParameters"), 26, 124, 0},
+ {str8_comp("DASBakeParameters"), 27, 132, 0},
{str8_comp("CoherencyWeightingBakeParameters"), 3, 16, 0},
{str8_comp("ReshapeBakeParameters"), 9, 36, 0},
};
@@ -829,20 +816,13 @@ read_only global str8 beamformer_shader_global_header_strings[] = {
"};\n"
"\n"),
str8_comp(""
- "#define ShaderBufferSlot_BeamformedData 0\n"
- "#define ShaderBufferSlot_PingPong 1\n"
- "\n"),
- str8_comp(""
- "#define ShaderResourceKind_Buffer 0\n"
- "\n"),
- str8_comp(""
"#define ComplexFilter ((CompileFlags & (1 << 0)) != 0)\n"
"#define Demodulate ((CompileFlags & (1 << 1)) != 0)\n"
"\n"),
str8_comp(""
"layout(push_constant, std430) uniform PushConstants {\n"
- " uint64_t input_data;\n"
- " uint32_t output_element_offset;\n"
+ " uint64_t input_buffer;\n"
+ " uint64_t output_buffer;\n"
"};\n"
"\n"),
str8_comp("#define MaxChannelCount (256)\n\n"),
@@ -880,7 +860,6 @@ read_only global str8 beamformer_shader_global_header_strings[] = {
" f32mat4 voxel_transform;\n"
" f32vec2 xdc_element_pitch;\n"
" uint64_t output_frame;\n"
- " uint32_t rf_element_offset;\n"
" int32_t channel_offset;\n"
" uint32_t readi_group;\n"
"};\n"
@@ -952,19 +931,19 @@ read_only global b8 beamformer_shader_primitive_is_vertex[] = {
read_only global i32 *beamformer_shader_header_vectors[] = {
(i32 []){0, 1, 2},
- (i32 []){3, 4, 5, 6},
- (i32 []){7, 8, 9, 10, 3, 4, 11, 12},
- (i32 []){13},
- (i32 []){14, 15},
+ (i32 []){3, 4},
+ (i32 []){5, 6, 7, 8, 9, 10},
+ (i32 []){11},
+ (i32 []){12, 13},
0,
- (i32 []){16},
- (i32 []){17},
+ (i32 []){14},
+ (i32 []){15},
};
read_only global i32 beamformer_shader_header_vector_lengths[] = {
3,
- 4,
- 8,
+ 2,
+ 6,
1,
2,
0,
diff --git a/shaders/das.glsl b/shaders/das.glsl
@@ -31,13 +31,8 @@
#define RESULT_STORE(a) (a)
#endif
-layout(set = ShaderResourceKind_Buffer, binding = ShaderBufferSlot_PingPong) readonly buffer RF {
- InputDataType rf[];
-};
-
-layout(std430, buffer_reference) buffer Output {
- OutputDataType x[];
-};
+layout(std430, buffer_reference) buffer Input { InputDataType x[]; };
+layout(std430, buffer_reference) buffer Output { OutputDataType x[]; };
layout(std430, buffer_reference) buffer IncoherentOutput {
f32 x[];
@@ -48,6 +43,7 @@ layout(std430, buffer_reference) buffer F32 { f32 x[]; };
layout(std430, buffer_reference) buffer S16 { s16 x[]; };
layout(std430, buffer_reference) buffer U8 { u8 x[]; };
layout(std430, buffer_reference) buffer V2 { vec2 x[]; };
+layout(std430, buffer_reference) buffer V4 { vec4 x[]; };
#define RX_ORIENTATION(tx_rx) bitfieldExtract((tx_rx), 0, 4)
#define TX_ORIENTATION(tx_rx) bitfieldExtract((tx_rx), 4, 4)
@@ -68,7 +64,7 @@ vec2 rotate_iq(const vec2 iq, const float time)
#endif
/* NOTE: See: https://cubic.org/docs/hermite.htm */
-SAMPLE_TYPE cubic(const int offset, const float t)
+SAMPLE_TYPE cubic(const u64 rf_pointer, const f32 t)
{
const mat4 h = mat4(
2, -3, 0, 1,
@@ -77,12 +73,17 @@ SAMPLE_TYPE cubic(const int offset, const float t)
1, -1, 0, 0
);
- SAMPLE_TYPE samples[4] = {
- rf[offset + 0],
- rf[offset + 1],
- rf[offset + 2],
- rf[offset + 3],
- };
+ #if InputDataKind == DataKind_Float32
+ vec4 samples = V4(rf_pointer).x[0];
+ #else
+ SAMPLE_TYPE samples[4];
+ vec4 load1 = V4(rf_pointer).x[0];
+ vec4 load2 = V4(rf_pointer).x[1];
+ samples[0] = load1.xy;
+ samples[1] = load1.zw;
+ samples[2] = load2.xy;
+ samples[3] = load2.zw;
+ #endif
vec4 S = vec4(t * t * t, t * t, t, 1);
SAMPLE_TYPE P1 = samples[1];
@@ -100,26 +101,31 @@ SAMPLE_TYPE cubic(const int offset, const float t)
return result;
}
-SAMPLE_TYPE sample_rf(const int rf_offset, const float index)
+SAMPLE_TYPE sample_rf(const u64 rf_pointer, const f32 index)
{
SAMPLE_TYPE result = SAMPLE_TYPE(0);
switch (InterpolationMode) {
case InterpolationMode_Nearest:{
if (index >= 0.f && index < (f32(SampleCount) - 0.5f))
- result = rotate_iq(rf[rf_offset + int(round(index))], index / SamplingFrequency);
+ result = rotate_iq(Input(rf_pointer + InputDataKindByteSize * u32(round(index))).x[0], index / SamplingFrequency);
}break;
case InterpolationMode_Linear:{
if (index >= 0.f && index < f32(SampleCount - 1)) {
- s32 n = rf_offset + int(index);
- f32 t = fract(index);
- result = (1 - t) * rf[n] + t * rf[n + 1];
+ #if InputDataKind == DataKind_Float32
+ vec2 rf = V2(rf_pointer + InputDataKindByteSize * u32(index)).x[0];
+ #else
+ vec4 load = V4(rf_pointer + InputDataKindByteSize * u32(index)).x[0];
+ vec2 rf[2] = {load.xy, load.zw};
+ #endif
+ f32 t = fract(index);
+ result = (1 - t) * rf[0] + t * rf[1];
result = rotate_iq(result, index / SamplingFrequency);
}
}break;
case InterpolationMode_Cubic:{
if (index >= 1.f && index < f32(SampleCount - 2))
- result = rotate_iq(cubic(rf_offset + int(index), fract(index)), index / SamplingFrequency);
+ result = rotate_iq(cubic(rf_pointer + InputDataKindByteSize * u32(index), fract(index)), index / SamplingFrequency);
}break;
}
return result;
@@ -211,8 +217,9 @@ RESULT_TYPE RCA(const vec3 world_point)
vec2 xdc_world_point = rca_plane_projection((xdc_transform * vec4(world_point, 1)).xyz, rx_rows);
float transmit_distance = rca_transmit_distance(world_point, focal_vector, tx_rx_orientation);
- int rf_offset = int(rf_element_offset) + acquisition * SampleCount;
- rf_offset -= int(InterpolationMode == InterpolationMode_Cubic);
+ u64 rf_pointer = RFData + InputDataKindByteSize * acquisition * SampleCount;
+ rf_pointer -= InputDataKindByteSize * u32(InterpolationMode == InterpolationMode_Cubic);
+
for (f32 chunk_channel = 0.f; chunk_channel < f32(ChunkChannelCount); chunk_channel += 1.f) {
f32 rx_channel = f32(channel_offset) + chunk_channel;
vec3 rx_center = vec3(rx_channel * xdc_element_pitch, 0);
@@ -220,11 +227,11 @@ RESULT_TYPE RCA(const vec3 world_point)
f32 a_arg = abs(FNumber * receive_vector.x / abs(xdc_world_point.y));
if (a_arg < 0.5f) {
- float sidx = sample_index(transmit_distance + length(receive_vector));
- SAMPLE_TYPE value = apodize(a_arg) * sample_rf(rf_offset, sidx);
+ f32 index = sample_index(transmit_distance + length(receive_vector));
+ SAMPLE_TYPE value = apodize(a_arg) * sample_rf(rf_pointer, index);
result += RESULT_STORE(value);
}
- rf_offset += SampleCount * AcquisitionCount;
+ rf_pointer += InputDataKindByteSize * SampleCount * AcquisitionCount;
}
}
return result;
@@ -246,8 +253,8 @@ RESULT_TYPE HERCULES(const vec3 world_point)
RESULT_TYPE result = RESULT_TYPE(0);
for (f32 chunk_channel = 0.f; chunk_channel < f32(ChunkChannelCount); chunk_channel += 1.f) {
f32 rx_channel = f32(channel_offset) + chunk_channel;
- s32 rf_offset = s32(rf_element_offset) + s32(chunk_channel) * SampleCount * AcquisitionCount + s32(Sparse) * SampleCount;
- rf_offset -= s32(InterpolationMode == InterpolationMode_Cubic);
+ u64 rf_pointer = RFData + InputDataKindByteSize * (u32(chunk_channel) * SampleCount * AcquisitionCount + u32(Sparse) * SampleCount);
+ rf_pointer -= InputDataKindByteSize * u32(InterpolationMode == InterpolationMode_Cubic);
// NOTE(rnp): this wouldn't be so messy if we just forced an orientation like with FORCES
vec2 element_receive_delta_squared = xy_world_point;
@@ -273,11 +280,11 @@ RESULT_TYPE HERCULES(const vec3 world_point)
apodization *= apodize(f_number_over_z * sqrt(element_delta_squared));
float index = transmit_index + sqrt(z_delta_squared + element_delta_squared) * SamplingFrequency / SpeedOfSound;
- SAMPLE_TYPE value = apodization * sample_rf(rf_offset, index);
+ SAMPLE_TYPE value = apodization * sample_rf(rf_pointer, index);
result += RESULT_STORE(value);
}
- rf_offset += SampleCount;
+ rf_pointer += InputDataKindByteSize * SampleCount;
}
}
return result;
@@ -297,8 +304,8 @@ RESULT_TYPE FORCES(const vec3 xdc_world_point)
float a_arg = abs(FNumber * receive_x_delta / xdc_world_point.z);
if (a_arg < 0.5f) {
- s32 rf_offset = s32(rf_element_offset) + s32(chunk_channel) * SampleCount * AcquisitionCount + s32(Sparse) * SampleCount;
- rf_offset -= s32(InterpolationMode == InterpolationMode_Cubic);
+ u64 rf_pointer = RFData + InputDataKindByteSize * (u32(chunk_channel) * SampleCount * AcquisitionCount + u32(Sparse) * SampleCount);
+ rf_pointer -= InputDataKindByteSize * u32(InterpolationMode == InterpolationMode_Cubic);
f32 receive_index = sample_index(sqrt(receive_x_delta * receive_x_delta + z_delta_squared));
f32 apodization = apodize(a_arg);
@@ -307,9 +314,9 @@ RESULT_TYPE FORCES(const vec3 xdc_world_point)
f32 transmit_x_delta = xdc_world_point.x - xdc_element_pitch.x * tx_channel;
f32 transmit_index = sqrt(transmit_yz_squared + transmit_x_delta * transmit_x_delta) * SamplingFrequency / SpeedOfSound;
- SAMPLE_TYPE value = apodization * sample_rf(rf_offset, receive_index + transmit_index);
- result += RESULT_STORE(value);
- rf_offset += SampleCount;
+ SAMPLE_TYPE value = apodization * sample_rf(rf_pointer, receive_index + transmit_index);
+ result += RESULT_STORE(value);
+ rf_pointer += InputDataKindByteSize * SampleCount;
}
}
}
@@ -333,8 +340,8 @@ RESULT_TYPE READI_FORCES(const vec3 xdc_world_point)
f32 a_arg = abs(FNumber * receive_x_delta / xdc_world_point.z);
if (a_arg < 0.5f) {
- s32 channel_rf_offset = s32(rf_element_offset) + s32(chunk_channel) * SampleCount * AcquisitionCount;
- channel_rf_offset -= s32(InterpolationMode == InterpolationMode_Cubic);
+ u64 channel_rf_pointer = RFData + InputDataKindByteSize * u32(chunk_channel) * SampleCount * AcquisitionCount;
+ channel_rf_pointer -= InputDataKindByteSize * u32(InterpolationMode == InterpolationMode_Cubic);
f32 receive_index = sample_index(sqrt(receive_x_delta * receive_x_delta + z_delta_squared));
f32 apodization = apodize(a_arg);
@@ -344,16 +351,16 @@ RESULT_TYPE READI_FORCES(const vec3 xdc_world_point)
// acquisition, the second element in each group is beamformed using the second acquisition, etc.
for (s32 tx_group = 0; tx_group < s32(ReadiGroupCount); tx_group++) {
f32 group_apodization = apodization * F16(Hadamard).x[hadamard_offset + tx_group];
- s32 rf_offset = channel_rf_offset;
+ u64 rf_pointer = channel_rf_pointer;
for (f32 tx_event = 0; tx_event < f32(AcquisitionCount); tx_event += 1.f) {
f32 tx_element = f32(tx_group) * f32(AcquisitionCount) + tx_event;
f32 transmit_x_delta = xdc_world_point.x - xdc_element_pitch.x * tx_element;
f32 transmit_index = sqrt(transmit_yz_squared + transmit_x_delta * transmit_x_delta) * SamplingFrequency / SpeedOfSound;
- SAMPLE_TYPE value = group_apodization * sample_rf(rf_offset, receive_index + transmit_index);
- result += RESULT_STORE(value);
- rf_offset += SampleCount;
+ SAMPLE_TYPE value = group_apodization * sample_rf(rf_pointer, receive_index + transmit_index);
+ result += RESULT_STORE(value);
+ rf_pointer += InputDataKindByteSize * SampleCount;
}
}
}
diff --git a/shaders/filter.glsl b/shaders/filter.glsl
@@ -35,13 +35,8 @@
#define apply_filter(iq, h) ((iq) * (h))
#endif
-layout(std430, buffer_reference, buffer_reference_align = 64) restrict readonly buffer Input {
- InputDataType x[];
-};
-
-layout(set = ShaderResourceKind_Buffer, binding = ShaderBufferSlot_PingPong) buffer Output {
- OutputDataType output_data[];
-};
+layout(std430, buffer_reference) restrict readonly buffer Input { InputDataType x[]; };
+layout(std430, buffer_reference) restrict writeonly buffer Output { OutputDataType x[]; };
layout(std430, buffer_reference, buffer_reference_align = 64) restrict readonly buffer Filter {
FILTER_TYPE values[FilterLength];
@@ -87,7 +82,7 @@ void main()
in_offset /= 2;
// NOTE(rnp): broken out to avoid overflow from the subtraction
- u64 input_address = input_data + in_offset;
+ u64 input_address = input_buffer + in_offset;
input_address += InputDataKindByteSize * (DecimationRate * gl_WorkGroupID.x * gl_WorkGroupSize.x);
input_address -= InputDataKindByteSize * (FilterLength - 1);
@@ -120,16 +115,15 @@ void main()
u32 out_offset = OutputChannelStride * channel +
OutputTransmitStride * transmit +
- OutputSampleStride * out_sample +
- output_element_offset;
+ OutputSampleStride * out_sample;
if (BatchSampleCount != 0) {
// NOTE(rnp): deinterleave
- output_data[out_offset] = OutputDataType(result.x);
+ Output(output_buffer).x[out_offset] = OutputDataType(result.x);
out_offset += BatchSampleCount;
- output_data[out_offset] = OutputDataType(result.y);
+ Output(output_buffer).x[out_offset] = OutputDataType(result.y);
} else {
- output_data[out_offset] = OutputDataType(result);
+ Output(output_buffer).x[out_offset] = OutputDataType(result);
}
}
}
diff --git a/vulkan.c b/vulkan.c
@@ -2,7 +2,6 @@
// TODO(rnp)
// [ ]: what is needed for HDR? I think it makes sense to just default to it nowadays
// [ ]: once opengl is removed switch images to SRGB and/or 16 bit Float
-// [ ]: VK_KHR_robustness2 probably shouldn't be required but it also might not matter
#include "beamformer_internal.h"
#include "vulkan.h"
@@ -127,12 +126,6 @@ typedef struct {
VkDevice device;
VkPhysicalDevice physical_device;
- VkDescriptorPool descriptor_pool;
- VkDescriptorSetLayout descriptor_set_layouts[BeamformerShaderResourceKind_Count];
- VkDescriptorSet descriptor_sets[BeamformerShaderResourceKind_Count];
- // NOTE(rnp): must store these if we want to allow partial updates easily
- VkDescriptorBufferInfo descriptor_buffer_infos[BeamformerShaderBufferSlot_Count];
-
// NOTE(rnp): fallback for when a shader fails to compile
VulkanPipeline default_compute_pipeline;
VulkanPipeline default_graphics_pipeline;
@@ -186,7 +179,6 @@ read_only global const char *vk_required_instance_extensions[] = {
X("VK_KHR_8bit_storage") \
X("VK_KHR_external_memory") \
X("VK_KHR_external_semaphore") \
- X("VK_KHR_robustness2") \
X("VK_KHR_storage_buffer_storage_class") \
X("VK_KHR_timeline_semaphore") \
VK_OS_REQUIRED_DEVICE_EXTENSIONS_LIST
@@ -212,6 +204,8 @@ read_only global str8 vk_optional_device_extensions[] = {VK_OPTIONAL_DEVICE_EXTE
#define VK_REQUIRED_PHYSICAL_12_FEATURES \
X(bufferDeviceAddress) \
X(shaderFloat16) \
+ X(shaderInt8) \
+ X(storageBuffer8BitAccess) \
X(timelineSemaphore) \
X(vulkanMemoryModel) \
@@ -621,8 +615,6 @@ vk_compute_pipeline_from_info(Arena *arena, VulkanPipelineCreateInfo *info, u32
VkPipelineLayoutCreateInfo pipeline_layout_create_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
- .setLayoutCount = countof(vulkan_context->descriptor_set_layouts),
- .pSetLayouts = vulkan_context->descriptor_set_layouts,
.pushConstantRangeCount = push_constants_size ? 1 : 0,
.pPushConstantRanges = push_constants_size ? &push_constant_range : 0,
};
@@ -687,8 +679,6 @@ vk_graphics_pipeline_from_infos(Arena *arena, VulkanPipelineCreateInfo *infos, u
VkPipelineLayoutCreateInfo pipeline_layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
- .setLayoutCount = countof(vulkan_context->descriptor_set_layouts),
- .pSetLayouts = vulkan_context->descriptor_set_layouts,
.pushConstantRangeCount = push_constants_size ? 1 : 0,
.pPushConstantRanges = push_constants_size ? &pcr : 0,
};
@@ -1682,13 +1672,6 @@ vk_load_queues(Arena *arena, Stream *err)
device_create_info.pNext = &coop_mat_features;
}
- VkPhysicalDeviceRobustness2FeaturesKHR robust2 = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR,
- .pNext = (void *)device_create_info.pNext,
- .nullDescriptor = 1,
- };
- device_create_info.pNext = &robust2;
-
VkPhysicalDeviceVulkan13Features v13f = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
.pNext = (void *)device_create_info.pNext,
@@ -1804,85 +1787,6 @@ vk_load_graphics(void)
}
}
-function void
-vk_load_descriptor_block(void)
-{
- // NOTE(rnp):
- // * One Descriptor Pool
- // * One Descriptor Set Per Resource Kind
- // * Shaders know the ResourceKind enumeration
- // * Shaders know the per set binding points
-
- VulkanContext *vk = vulkan_context;
-
- // NOTE(rnp): Pool
- VkDescriptorPoolSize pool_sizes[] = {
- {
- .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
- .descriptorCount = BeamformerShaderBufferSlot_Count,
- },
- };
- static_assert(countof(pool_sizes) == BeamformerShaderResourceKind_Count, "");
-
- VkDescriptorPoolCreateInfo pool_create_info = {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
- .maxSets = BeamformerShaderResourceKind_Count,
- .poolSizeCount = countof(pool_sizes),
- .pPoolSizes = pool_sizes,
- };
-
- vkCreateDescriptorPool(vk->device, &pool_create_info, 0, &vk->descriptor_pool);
-
- // NOTE(rnp): Set Layouts
- VkDescriptorSetLayoutCreateInfo layout_create_info = {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
- };
-
- {
- VkDescriptorSetLayoutBinding layout_bindings[BeamformerShaderBufferSlot_Count];
- for EachEnumValue(BeamformerShaderBufferSlot, it) {
- layout_bindings[it] = (VkDescriptorSetLayoutBinding){
- .binding = it,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_ALL,
- };
- }
- layout_create_info.bindingCount = countof(layout_bindings),
- layout_create_info.pBindings = layout_bindings,
- vkCreateDescriptorSetLayout(vk->device, &layout_create_info, 0,
- vk->descriptor_set_layouts + BeamformerShaderResourceKind_Buffer);
- }
-
- // NOTE(rnp): Sets
- VkDescriptorSetAllocateInfo set_allocate_info = {
- .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
- .descriptorPool = vk->descriptor_pool,
- .descriptorSetCount = countof(vk->descriptor_sets),
- .pSetLayouts = vk->descriptor_set_layouts,
- };
- static_assert(countof(vk->descriptor_set_layouts) == countof(vk->descriptor_sets), "");
- vkAllocateDescriptorSets(vk->device, &set_allocate_info, vk->descriptor_sets);
-
- vk_label_object(DESCRIPTOR_POOL, vk->descriptor_pool, str8("Beamformer Resources"), str8("Pool"));
-
- Temp scratch;
- DeferLoop(take_lock(&vk->arena_lock, -1), release_lock(&vk->arena_lock))
- DeferLoop(scratch = temp_begin(vk->arena), temp_end(scratch))
- {
- for EachElement(vk->descriptor_sets, it) {
- Stream sb = arena_stream(vk->arena);
- stream_append_str8s(&sb, str8("Beamformer "), beamformer_shader_resource_kind_strings[it], str8("s"));
- vk_label_object(DESCRIPTOR_SET, vk->descriptor_sets[it], stream_to_str8(&sb), str8("Set"));
- vk_label_object(DESCRIPTOR_SET_LAYOUT, vk->descriptor_set_layouts[it], stream_to_str8(&sb), str8("Set Layout"));
- }
- }
-
- // NOTE(rnp): junk API requirement that doesn't allow 0 initialization
- for EachElement(vk->descriptor_buffer_infos, it)
- vk->descriptor_buffer_infos[it].range = VK_WHOLE_SIZE;
-}
-
///////////////////////
// NOTE(rnp): User API
@@ -1906,7 +1810,6 @@ vk_load(OSLibrary vulkan_library_handle, Stream *err)
vk_load_physical_device(vk->arena, err);
vk_load_queues(vk->arena, err);
vk_load_graphics();
- vk_load_descriptor_block();
read_only local_persist str8 default_compute_shader = str8(""
"#version 430 core\n"
@@ -2435,36 +2338,6 @@ vk_pipeline_release(VulkanHandle h)
}
}
-DEBUG_IMPORT void
-vk_bind_shader_resources(BeamformerShaderResourceInfo *infos, u64 info_count)
-{
- VulkanContext *vk = vulkan_context;
-
- VkWriteDescriptorSet write_sets[BeamformerShaderResourceKind_Count] = {0};
-
- for EachIndex(info_count, it) {
- switch (infos[it].kind) {
- case BeamformerShaderResourceKind_Buffer:{
- VulkanBuffer *vb = vk_entity_data(infos[it].handle.value, VulkanEntityKind_Buffer);
- vk->descriptor_buffer_infos[infos[it].slot].buffer = vb->buffer;
- vk->descriptor_buffer_infos[infos[it].slot].offset = 0;
- vk->descriptor_buffer_infos[infos[it].slot].range = vb->memory_size;
- }break;
-
- InvalidDefaultCase;
- }
- }
-
- write_sets[BeamformerShaderResourceKind_Buffer].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_sets[BeamformerShaderResourceKind_Buffer].dstSet = vk->descriptor_sets[BeamformerShaderResourceKind_Buffer];
- write_sets[BeamformerShaderResourceKind_Buffer].dstBinding = 0;
- write_sets[BeamformerShaderResourceKind_Buffer].descriptorCount = countof(vk->descriptor_buffer_infos);
- write_sets[BeamformerShaderResourceKind_Buffer].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- write_sets[BeamformerShaderResourceKind_Buffer].pBufferInfo = vk->descriptor_buffer_infos;
-
- vkUpdateDescriptorSets(vk->device, countof(write_sets), write_sets, 0, 0);
-}
-
DEBUG_IMPORT GPUCommandList
gpu_command_list_begin(GPUTimeline timeline)
{
@@ -2530,8 +2403,6 @@ gpu_command_bind_pipeline(GPUCommandList command, VulkanHandle pipeline)
VkCommandBuffer cmd = vk_command_buffer(command);
vkCmdBindPipeline(cmd, bind_point, vp->pipeline);
- vkCmdBindDescriptorSets(cmd, bind_point, vp->layout, 0, countof(vk->descriptor_sets),
- vk->descriptor_sets, 0, 0);
vcp->bound_pipeline = vp;
}
}