From 894ef156e14e028c6c7ef5ea3acf85696d4efebe Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 29 May 2020 20:06:16 -0700 Subject: [PATCH 1/4] Change to new merge strategy in binning WIP We get "device lost" on NV :/ --- piet-gpu-hal/src/vulkan.rs | 2 +- piet-gpu/bin/cli.rs | 8 +++--- piet-gpu/shader/binning.comp | 48 +++++------------------------------ piet-gpu/shader/binning.spv | Bin 19600 -> 16024 bytes piet-gpu/shader/coarse.spv | Bin 49152 -> 49240 bytes piet-gpu/src/lib.rs | 10 +++++--- 6 files changed, 18 insertions(+), 50 deletions(-) diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index 2fac015..402b13d 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -1016,7 +1016,7 @@ unsafe fn choose_compute_device( devices: &[vk::PhysicalDevice], surface: Option<&VkSurface>, ) -> Option<(vk::PhysicalDevice, u32)> { - for pdevice in devices { + for pdevice in &devices[1..] { let props = instance.get_physical_device_queue_family_properties(*pdevice); for (ix, info) in props.iter().enumerate() { // Check for surface presentation support diff --git a/piet-gpu/bin/cli.rs b/piet-gpu/bin/cli.rs index fe8c4ac..cc4cb44 100644 --- a/piet-gpu/bin/cli.rs +++ b/piet-gpu/bin/cli.rs @@ -181,12 +181,10 @@ fn main() -> Result<(), Error> { println!("Coarse kernel time: {:.3}ms", (ts[2] - ts[1]) * 1e3); println!("Render kernel time: {:.3}ms", (ts[3] - ts[2]) * 1e3); - /* let mut data: Vec = Default::default(); - device.read_buffer(&renderer.ptcl_buf, &mut data).unwrap(); - //piet_gpu::dump_k1_data(&data); - trace_ptcl(&data); - */ + device.read_buffer(&renderer.bin_buf, &mut data).unwrap(); + piet_gpu::dump_k1_data(&data); + //trace_ptcl(&data); let mut img_data: Vec = Default::default(); // Note: because png can use a `&[u8]` slice, we could avoid an extra copy diff --git a/piet-gpu/shader/binning.comp b/piet-gpu/shader/binning.comp index 713a654..d193dd2 100644 --- a/piet-gpu/shader/binning.comp +++ b/piet-gpu/shader/binning.comp @@ -45,8 +45,6 @@ shared uint bitmaps[N_SLICE][N_TILE]; shared uint count[N_SLICE][N_TILE]; shared uint sh_my_tile; shared uint sh_chunk_start[N_TILE]; -shared uint sh_chunk_end[N_TILE]; -shared uint sh_chunk_jump[N_TILE]; shared float sh_right_edge[N_TILE]; @@ -57,8 +55,6 @@ uint state_right_edge_index(uint partition_ix) { } void main() { - BinChunkRef chunk_ref = BinChunkRef((gl_LocalInvocationID.x * N_WG + gl_WorkGroupID.x) * BIN_INITIAL_ALLOC); - uint wr_limit = chunk_ref.offset + BIN_INITIAL_ALLOC; uint chunk_n = 0; uint my_n_elements = n_elements; while (true) { @@ -169,41 +165,15 @@ void main() { count[i][gl_LocalInvocationID.x] = element_count; } // element_count is number of elements covering bin for this invocation. + uint chunk_start = 0; if (element_count != 0) { - uint chunk_end; - uint chunk_new_start; - // Refactor to reduce code duplication? - if (chunk_n > 0) { - uint next_chunk = chunk_ref.offset + BinChunk_size + chunk_n * BinInstance_size; - if (next_chunk + BinChunk_size + min(24, element_count * BinInstance_size) > wr_limit) { - uint alloc_amount = max(BIN_ALLOC, BinChunk_size + element_count * BinInstance_size); - // could try to reduce fragmentation if BIN_ALLOC is only a bit above needed - next_chunk = atomicAdd(alloc, alloc_amount); - wr_limit = next_chunk + alloc_amount; - } - BinChunk_write(chunk_ref, BinChunk(chunk_n, BinChunkRef(next_chunk))); - chunk_ref = BinChunkRef(next_chunk); - } - BinInstanceRef instance_ref = BinInstanceRef(chunk_ref.offset + BinChunk_size); - if (instance_ref.offset + element_count * BinInstance_size > wr_limit) { - chunk_end = wr_limit; - chunk_n = (wr_limit - instance_ref.offset) / BinInstance_size; - uint alloc_amount = max(BIN_ALLOC, BinChunk_size + (element_count - chunk_n) * BinInstance_size); - chunk_new_start = atomicAdd(alloc, alloc_amount); - wr_limit = chunk_new_start + alloc_amount; - BinChunk_write(chunk_ref, BinChunk(chunk_n, BinChunkRef(chunk_new_start))); - chunk_ref = BinChunkRef(chunk_new_start); - chunk_new_start += BinChunk_size; - chunk_n = element_count - chunk_n; - } else { - chunk_end = ~0; - chunk_new_start = ~0; - chunk_n = element_count; - } - sh_chunk_start[gl_LocalInvocationID.x] = instance_ref.offset; - sh_chunk_end[gl_LocalInvocationID.x] = chunk_end; - sh_chunk_jump[gl_LocalInvocationID.x] = chunk_new_start - chunk_end; + // TODO: aggregate atomic adds (subgroup is probably fastest) + chunk_start = atomicAdd(alloc, element_count * BinInstance_size); + sh_chunk_start[gl_LocalInvocationID.x] = chunk_start; } + uint out_ix = (my_tile * N_TILE + gl_LocalInvocationID.x) * 2; + bins[out_ix] = element_count; + bins[out_ix + 1] = chunk_start; barrier(); // Use similar strategy as Laine & Karras paper; loop over bbox of bins @@ -219,9 +189,6 @@ void main() { idx += count[my_slice - 1][bin_ix]; } uint out_offset = sh_chunk_start[bin_ix] + idx * BinInstance_size; - if (out_offset >= sh_chunk_end[bin_ix]) { - out_offset += sh_chunk_jump[bin_ix]; - } BinInstance_write(BinInstanceRef(out_offset), BinInstance(element_ix, my_right_edge)); } x++; @@ -231,5 +198,4 @@ void main() { } } } - BinChunk_write(chunk_ref, BinChunk(chunk_n, BinChunkRef(0))); } diff --git a/piet-gpu/shader/binning.spv b/piet-gpu/shader/binning.spv index e932e4d3b944d2352e9ea514e2b4b4250c3e9a46..9f22a33b7a8812ba864f15fbee6d4b490ce04a31 100644 GIT binary patch literal 16024 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 WpK!IODe3bw;29KczE5)Br~d_$M=(MF diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index d951b247c1f2e6116832ab6fbd677a0e3ef937c0..b58a3274efdbbcf459803bf752365656e4568355 100644 GIT binary patch literal 49240 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 diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 65bbe5c..5f0f6be 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -160,7 +160,7 @@ impl Renderer { let state_buf = device.create_buffer(1 * 1024 * 1024, dev)?; let anno_buf = device.create_buffer(64 * 1024 * 1024, dev)?; - let bin_buf = device.create_buffer(64 * 1024 * 1024, dev)?; + let bin_buf = device.create_buffer(64 * 1024 * 1024, host)?; let ptcl_buf = device.create_buffer(48 * 1024 * 1024, dev)?; let image_dev = device.create_image2d(WIDTH as u32, HEIGHT as u32, dev)?; @@ -176,12 +176,12 @@ impl Renderer { let bin_alloc_buf_dev = device.create_buffer(12, dev)?; // TODO: constants - let bin_alloc_start = 256 * 64 * N_WG; + let bin_alloc_start = ((n_elements + 255) & !255) * 8; device .write_buffer(&bin_alloc_buf_host, &[ n_elements as u32, 0, - bin_alloc_start, + bin_alloc_start as u32, ]) ?; let bin_code = include_bytes!("../shader/binning.spv"); @@ -268,18 +268,22 @@ impl Renderer { ); cmd_buf.write_timestamp(&query_pool, 2); cmd_buf.memory_barrier(); + /* cmd_buf.dispatch( &self.coarse_pipeline, &self.coarse_ds, (WIDTH as u32 / 256, HEIGHT as u32 / 256, 1), ); + */ cmd_buf.write_timestamp(&query_pool, 3); cmd_buf.memory_barrier(); + /* cmd_buf.dispatch( &self.k4_pipeline, &self.k4_ds, ((WIDTH / TILE_W) as u32, (HEIGHT / TILE_H) as u32, 1), ); + */ cmd_buf.write_timestamp(&query_pool, 4); cmd_buf.memory_barrier(); cmd_buf.image_barrier(&self.image_dev, ImageLayout::General, ImageLayout::BlitSrc); From 121f29fef68fec89079132411586a0bbfe3ae00a Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 30 May 2020 08:35:26 -0700 Subject: [PATCH 2/4] Merge one segment at a time No parallelism yet, but seems to improve performance. --- piet-gpu-hal/src/vulkan.rs | 2 +- piet-gpu/bin/cli.rs | 4 +- piet-gpu/shader/binning.comp | 256 +++++++++++++++++------------------ piet-gpu/shader/binning.spv | Bin 16024 -> 15652 bytes piet-gpu/shader/coarse.comp | 73 ++-------- piet-gpu/shader/coarse.spv | Bin 49240 -> 46048 bytes piet-gpu/src/lib.rs | 13 +- 7 files changed, 144 insertions(+), 204 deletions(-) diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index 402b13d..2fac015 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -1016,7 +1016,7 @@ unsafe fn choose_compute_device( devices: &[vk::PhysicalDevice], surface: Option<&VkSurface>, ) -> Option<(vk::PhysicalDevice, u32)> { - for pdevice in &devices[1..] { + for pdevice in devices { let props = instance.get_physical_device_queue_family_properties(*pdevice); for (ix, info) in props.iter().enumerate() { // Check for surface presentation support diff --git a/piet-gpu/bin/cli.rs b/piet-gpu/bin/cli.rs index cc4cb44..5d7c09e 100644 --- a/piet-gpu/bin/cli.rs +++ b/piet-gpu/bin/cli.rs @@ -181,10 +181,12 @@ fn main() -> Result<(), Error> { println!("Coarse kernel time: {:.3}ms", (ts[2] - ts[1]) * 1e3); println!("Render kernel time: {:.3}ms", (ts[3] - ts[2]) * 1e3); + /* let mut data: Vec = Default::default(); - device.read_buffer(&renderer.bin_buf, &mut data).unwrap(); + device.read_buffer(&renderer.ptcl_buf, &mut data).unwrap(); piet_gpu::dump_k1_data(&data); //trace_ptcl(&data); + */ let mut img_data: Vec = Default::default(); // Note: because png can use a `&[u8]` slice, we could avoid an extra copy diff --git a/piet-gpu/shader/binning.comp b/piet-gpu/shader/binning.comp index d193dd2..d35c2d9 100644 --- a/piet-gpu/shader/binning.comp +++ b/piet-gpu/shader/binning.comp @@ -43,7 +43,6 @@ layout(set = 0, binding = 3) buffer BinsBuf { // Note: cudaraster has N_TILE + 1 to cut down on bank conflicts. shared uint bitmaps[N_SLICE][N_TILE]; shared uint count[N_SLICE][N_TILE]; -shared uint sh_my_tile; shared uint sh_chunk_start[N_TILE]; shared float sh_right_edge[N_TILE]; @@ -57,145 +56,138 @@ uint state_right_edge_index(uint partition_ix) { void main() { uint chunk_n = 0; uint my_n_elements = n_elements; - while (true) { - if (gl_LocalInvocationID.x == 0) { - sh_my_tile = atomicAdd(tile_ix, 1); + uint my_partition = gl_WorkGroupID.x; + + for (uint i = 0; i < N_SLICE; i++) { + bitmaps[i][gl_LocalInvocationID.x] = 0; + } + barrier(); + + // Read inputs and determine coverage of bins + uint element_ix = my_partition * N_TILE + gl_LocalInvocationID.x; + AnnotatedRef ref = AnnotatedRef(element_ix * Annotated_size); + uint tag = Annotated_Nop; + if (element_ix < my_n_elements) { + tag = Annotated_tag(ref); + } + int x0 = 0, y0 = 0, x1 = 0, y1 = 0; + float my_right_edge = INFINITY; + bool crosses_edge = false; + switch (tag) { + case Annotated_FillLine: + case Annotated_StrokeLine: + AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); + x0 = int(floor((min(line.p0.x, line.p1.x) - line.stroke.x) * SX)); + y0 = int(floor((min(line.p0.y, line.p1.y) - line.stroke.y) * SY)); + x1 = int(ceil((max(line.p0.x, line.p1.x) + line.stroke.x) * SX)); + y1 = int(ceil((max(line.p0.y, line.p1.y) + line.stroke.y) * SY)); + crosses_edge = tag == Annotated_FillLine && ceil(line.p0.y * TSY) != ceil(line.p1.y * TSY); + break; + case Annotated_Fill: + case Annotated_Stroke: + // Note: we take advantage of the fact that fills and strokes + // have compatible layout. + AnnoFill fill = Annotated_Fill_read(ref); + x0 = int(floor(fill.bbox.x * SX)); + y0 = int(floor(fill.bbox.y * SY)); + x1 = int(ceil(fill.bbox.z * SX)); + y1 = int(ceil(fill.bbox.w * SY)); + // It probably makes more sense to track x1, to avoid having to redo + // the rounding to tile coords. + my_right_edge = fill.bbox.z; + break; + } + + // If the last element in this partition is a fill edge, then we need to do a + // look-forward to find the right edge of its corresponding fill. That data is + // recorded in aggregates computed in the element processing pass. + if (gl_LocalInvocationID.x == N_TILE - 1 && tag == Annotated_FillLine) { + uint aggregate_ix = (my_partition + 1) * ELEMENT_BINNING_RATIO; + // This is sequential but the expectation is that the amount of + // look-forward is small (performance may degrade in the case + // of massively complex paths). + do { + my_right_edge = uintBitsToFloat(state[state_right_edge_index(aggregate_ix)]); + aggregate_ix++; + } while (isinf(my_right_edge)); + } + + // Now propagate right_edge backward, from fill to segment. + for (uint i = 0; i < LG_N_TILE; i++) { + // Note: we could try to cut down on write bandwidth here if the value hasn't + // changed, but not sure it's worth the complexity to track. + sh_right_edge[gl_LocalInvocationID.x] = my_right_edge; + barrier(); + if (gl_LocalInvocationID.x + (1 << i) < N_TILE && isinf(my_right_edge)) { + my_right_edge = sh_right_edge[gl_LocalInvocationID.x + (1 << i)]; } barrier(); - uint my_tile = sh_my_tile; - if (my_tile * N_TILE >= my_n_elements) { - break; - } + } + if (crosses_edge) { + x1 = int(ceil(my_right_edge * SX)); + } - for (uint i = 0; i < N_SLICE; i++) { - bitmaps[i][gl_LocalInvocationID.x] = 0; + // At this point, we run an iterator over the coverage area, + // trying to keep divergence low. + // Right now, it's just a bbox, but we'll get finer with + // segments. + x0 = clamp(x0, 0, N_TILE_X); + x1 = clamp(x1, x0, N_TILE_X); + y0 = clamp(y0, 0, N_TILE_Y); + y1 = clamp(y1, y0, N_TILE_Y); + if (x0 == x1) y1 = y0; + int x = x0, y = y0; + uint my_slice = gl_LocalInvocationID.x / 32; + uint my_mask = 1 << (gl_LocalInvocationID.x & 31); + while (y < y1) { + atomicOr(bitmaps[my_slice][y * N_TILE_X + x], my_mask); + x++; + if (x == x1) { + x = x0; + y++; } - barrier(); + } - // Read inputs and determine coverage of bins - uint element_ix = my_tile * N_TILE + gl_LocalInvocationID.x; - AnnotatedRef ref = AnnotatedRef(element_ix * Annotated_size); - uint tag = Annotated_Nop; - if (element_ix < my_n_elements) { - tag = Annotated_tag(ref); - } - int x0 = 0, y0 = 0, x1 = 0, y1 = 0; - float my_right_edge = INFINITY; - bool crosses_edge = false; - switch (tag) { - case Annotated_FillLine: - case Annotated_StrokeLine: - AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); - x0 = int(floor((min(line.p0.x, line.p1.x) - line.stroke.x) * SX)); - y0 = int(floor((min(line.p0.y, line.p1.y) - line.stroke.y) * SY)); - x1 = int(ceil((max(line.p0.x, line.p1.x) + line.stroke.x) * SX)); - y1 = int(ceil((max(line.p0.y, line.p1.y) + line.stroke.y) * SY)); - crosses_edge = tag == Annotated_FillLine && ceil(line.p0.y * TSY) != ceil(line.p1.y * TSY); - break; - case Annotated_Fill: - case Annotated_Stroke: - // Note: we take advantage of the fact that fills and strokes - // have compatible layout. - AnnoFill fill = Annotated_Fill_read(ref); - x0 = int(floor(fill.bbox.x * SX)); - y0 = int(floor(fill.bbox.y * SY)); - x1 = int(ceil(fill.bbox.z * SX)); - y1 = int(ceil(fill.bbox.w * SY)); - // It probably makes more sense to track x1, to avoid having to redo - // the rounding to tile coords. - my_right_edge = fill.bbox.z; - break; - } + barrier(); + // Allocate output segments. + uint element_count = 0; + for (uint i = 0; i < N_SLICE; i++) { + element_count += bitCount(bitmaps[i][gl_LocalInvocationID.x]); + count[i][gl_LocalInvocationID.x] = element_count; + } + // element_count is number of elements covering bin for this invocation. + uint chunk_start = 0; + if (element_count != 0) { + // TODO: aggregate atomic adds (subgroup is probably fastest) + chunk_start = atomicAdd(alloc, element_count * BinInstance_size); + sh_chunk_start[gl_LocalInvocationID.x] = chunk_start; + } + // Note: it might be more efficient for reading to do this in the + // other order (each bin is a contiguous sequence of partitions) + uint out_ix = (my_partition * N_TILE + gl_LocalInvocationID.x) * 2; + bins[out_ix] = element_count; + bins[out_ix + 1] = chunk_start; - // If the last element in this partition is a fill edge, then we need to do a - // look-forward to find the right edge of its corresponding fill. That data is - // recorded in aggregates computed in the element processing pass. - if (gl_LocalInvocationID.x == N_TILE - 1 && tag == Annotated_FillLine) { - uint aggregate_ix = (my_tile + 1) * ELEMENT_BINNING_RATIO; - // This is sequential but the expectation is that the amount of - // look-forward is small (performance may degrade in the case - // of massively complex paths). - do { - my_right_edge = uintBitsToFloat(state[state_right_edge_index(aggregate_ix)]); - aggregate_ix++; - } while (isinf(my_right_edge)); - } - - // Now propagate right_edge backward, from fill to segment. - for (uint i = 0; i < LG_N_TILE; i++) { - // Note: we could try to cut down on write bandwidth here if the value hasn't - // changed, but not sure it's worth the complexity to track. - sh_right_edge[gl_LocalInvocationID.x] = my_right_edge; - barrier(); - if (gl_LocalInvocationID.x + (1 << i) < N_TILE && isinf(my_right_edge)) { - my_right_edge = sh_right_edge[gl_LocalInvocationID.x + (1 << i)]; + barrier(); + // Use similar strategy as Laine & Karras paper; loop over bbox of bins + // touched by this element + x = x0; + y = y0; + while (y < y1) { + uint bin_ix = y * N_TILE_X + x; + uint out_mask = bitmaps[my_slice][bin_ix]; + if ((out_mask & my_mask) != 0) { + uint idx = bitCount(out_mask & (my_mask - 1)); + if (my_slice > 0) { + idx += count[my_slice - 1][bin_ix]; } - barrier(); + uint out_offset = sh_chunk_start[bin_ix] + idx * BinInstance_size; + BinInstance_write(BinInstanceRef(out_offset), BinInstance(element_ix, my_right_edge)); } - if (crosses_edge) { - x1 = int(ceil(my_right_edge * SX)); - } - - // At this point, we run an iterator over the coverage area, - // trying to keep divergence low. - // Right now, it's just a bbox, but we'll get finer with - // segments. - x0 = clamp(x0, 0, N_TILE_X); - x1 = clamp(x1, x0, N_TILE_X); - y0 = clamp(y0, 0, N_TILE_Y); - y1 = clamp(y1, y0, N_TILE_Y); - if (x0 == x1) y1 = y0; - int x = x0, y = y0; - uint my_slice = gl_LocalInvocationID.x / 32; - uint my_mask = 1 << (gl_LocalInvocationID.x & 31); - while (y < y1) { - atomicOr(bitmaps[my_slice][y * N_TILE_X + x], my_mask); - x++; - if (x == x1) { - x = x0; - y++; - } - } - - barrier(); - // Allocate output segments. - uint element_count = 0; - for (uint i = 0; i < N_SLICE; i++) { - element_count += bitCount(bitmaps[i][gl_LocalInvocationID.x]); - count[i][gl_LocalInvocationID.x] = element_count; - } - // element_count is number of elements covering bin for this invocation. - uint chunk_start = 0; - if (element_count != 0) { - // TODO: aggregate atomic adds (subgroup is probably fastest) - chunk_start = atomicAdd(alloc, element_count * BinInstance_size); - sh_chunk_start[gl_LocalInvocationID.x] = chunk_start; - } - uint out_ix = (my_tile * N_TILE + gl_LocalInvocationID.x) * 2; - bins[out_ix] = element_count; - bins[out_ix + 1] = chunk_start; - - barrier(); - // Use similar strategy as Laine & Karras paper; loop over bbox of bins - // touched by this element - x = x0; - y = y0; - while (y < y1) { - uint bin_ix = y * N_TILE_X + x; - uint out_mask = bitmaps[my_slice][bin_ix]; - if ((out_mask & my_mask) != 0) { - uint idx = bitCount(out_mask & (my_mask - 1)); - if (my_slice > 0) { - idx += count[my_slice - 1][bin_ix]; - } - uint out_offset = sh_chunk_start[bin_ix] + idx * BinInstance_size; - BinInstance_write(BinInstanceRef(out_offset), BinInstance(element_ix, my_right_edge)); - } - x++; - if (x == x1) { - x = x0; - y++; - } + x++; + if (x == x1) { + x = x0; + y++; } } } diff --git a/piet-gpu/shader/binning.spv b/piet-gpu/shader/binning.spv index 9f22a33b7a8812ba864f15fbee6d4b490ce04a31..6ea087746cc4641eb1746f46597823f20f338685 100644 GIT binary patch literal 15652 zcmai)2b^D3wS_O4LINQK5^6#UHIx9MBT|MI&Gk z*szypeb4%ADE407vqVu8dqG7k@B8k(D>?k}_j{K)?6uZDXP)i%|1 z{(Hu>s(yB=rlC~T_Em3fm#4`fw}Es=DfW*4eSzw(7xlQ`QZPjOn?W*M~`j?-3?(!99^bf9I-#_=MbYyI}e`sW4 zcyMauiec+bFY1kq4UTRYDl7C*qs*a)`V6e<8yg#6IW;l9c6bF5R}QZ^e|R-Anf26u z@%ZZ1lfzS0t!xi}NSnHTH}lav>zM^dCU-pRmo@R^j%%{+&v>($tA7)(e`0uGXbIIe z3{EY5NN;4gbi=Y`C(ypD+JW{Hq})?SYhs-_GCJxo9K&qK|bxTr+joW@2Q`j13KMT(Y5Q+gq{qtMvmDQzKI&<70K^P0XXv z9f#+VZmNlaE9<+XhjE<<-?HwfZfN&NqvNUuvM0c<`^kzt#yS&AEW54wiiVqN&ChT6 zk>M9L+;nRHr42v2;awF|+K#uYx*D9EuWRbHId@k#H+)OKw={f9zqdAgOTV`@yzRHE zdO5tA*Y4^AVCHOK9o8{@>_NP%`XoGgd=|{YO*&2PDY?%oG_CV01rv9=1c5^j3^i)4Y?;9N*A1vly&8MtvpX%6zrpvtuqZ(6Xmzfw^7k*mJ>K=f11j9lnuOw#^>kO)cJ2oz+&K zr(WaUYCf28Z9Ncm4!zYv^udYo$;si#_M|pr*$>@!S(9sbwLg4o|J~JU`0DnacI;~& z(^7M`P63?Ywj;UMZD=e^Zi z!IPJFj*B%#w^L*N1iY!nJ=IUa%){j9$l#W--P>sE1}4{1zqi_+4U%;k9N#d;E4Gd^ z6FqCa7kI0$r`k_m?_WkSF;&Mo42|4M8NItY3VnP-b6?6=z&RK7EV(bvZ~b*bZQoBo z8yVV&x2GC!{af$n?&>LMTj!{|x~kyI>Eq$V>7{g2&LW0)nUC)SpXJPxT33y`>$_`j z9Xz%_8N0Y<4Zjmy#>@FG>gWAe5hL#wsvSo2m(Kbyg2 zKXUuAjpOhf`@OSg%O7a@yq3R!4$E<6ZzeDMQ%isD)3QJLVq#(H{+>?9_O}OR4q2GT zVp`i?ybC$m-y(|70z7{IHJV?KRn66Q#Ww@Hh_V~)w!_Mevw%6YAGMUl)R_raH;%Dq zV-tHPuyNIlw=>pw&h-NRKL=}Fbz{xNs@cw1yJHi}@fl0ay3VgYb@>8p=0UzU+*taJ zwLdno4gecV%{-R0zGm#*)q$;FeKF%c2TZGHqdraoiJH&fKypFhP~-?^~< z&#>E2)U7YSr`7cTyv4Rj4u1eor_3el9}E3Hu)*fj?$1EmsLB6=RkN*e|B7|~)$Lb) zf2$=A?-g^i{y$q^na4Do(<#Yod$8ZI*53{6+__fzox{D*s_NQn^e<@r=6?{gp<7p8RW$FOcy^58-SB;ib07YL4t{qB|78dFn=b9W+x(sjH@@F=;rizm+;#W6 zE`GV+b|v@wuH=5>g?r}w&I@;+_#VF7_Z+| z;RnL~u9Ba`?s2d5)upGt*MAJ&Oz}N(BKyhn{u7G2_1#PIK6adU(=RCZ)O>6Gdt2T5 z?lrmCeP&C|LOh3QD{+8mS|94pZ+T`(jurc06-`*F0qNsVN{f!v%UsH@_ zTXEX{4czqK@s&imzlif#2d2DOaAeC|=FZB)vThBe&SJXQMP2Wsz2iq+L^Hc3dF^2xc zI23G*xwKtX_`yY&bvlTI$TbNtlZx@2q%*XrXabO?sNqrYl)VxE)8Oz1se>ZQB zN7t9Up8!_7gpzZ3DVU!+Z~ckc4>o4!9AAc}FEIzeYGuq-aDM8T`rqG=$b$|NP-y~R{{q2F3r@tw1`ty4u_vQw4ed+HCuv*#Qm2iIQwbY;fHiGrppXXSf z{x*TrpMMUJ{+^7kFa13QtXB4S6`Y^CKmF|4OcUEzT2JyS9jcw^A@n0<9sgGm|DNNpND-u#Yg|GtzVlyUjjCU zv0jXo=bP)L;3H_O?%baSei`^h6u&|AC(g^k`mUm1-}kQot7R?ZsryQ>eP*1m0;_o* zGbS~2Hh;&YwY{-l4R(EB3HJ_p4Oq?j6+3>%Zab}UGT&PJxEma)azdv61G?!C98sb`Gu06Rw8yc7E_%3CSc zGk>{tI)AT7AMeK3*~fpNsb>uD0Xv3I(TCq+?*+RC>aL^jtoMP{vsUj18%I53{{UFs z-&x%6{|WYSJ@kE$qUJn^Gsgb{m+SZ;xSDgG`r5oJJ`6UVb7@^;+22R8>CZYJp{UuP zICJtbaOa$S98EoQ^55WcPCfy5PSi6ep9HICPCf-Tj(XPX(_q(2U&i|xuzJpf+_5HC zZRdLGcP}~?ZSuSmY@W&CvtYHHA$@ALe=XMb?nT>sW7t8*qoe4`;@yTsjE%hAA`-ox|^}``0fTL&QHMdoVlNYJI~xbXzDj}?|8@j0<89P zit&GnRZEOtf;(gU3QhgaHpXwjYQLuBKKm`$^Pn$h_jh1*`?(h@cg(-XIzL+90e{5) ziQ=RGzSghJxc>}xyy1TVJCE-sC(qbl!PZfCE#!Zo7~8(Ywsj8f2RrV>`Wx8TzV|%? z4}jI&BdPOuuxsHRV4Z(}t*7q$+CSs^C)hvZGQR%w_b;&H|2^N~_D?!>UB5N@DEiaS zHu%bZroq*6*XUDA{jRotcsIPb#HLH~x8VANh*?vtF_7b^sek>mJ$>JDcL8f2Y>3 zHE-vAXRtByE}a8b%Xfr)7R6Y`7N_l8aMOSDXP&#jJI~3kXzJMyyMf&gw$+zdyMy(8 zk-XeXdw|t)ZuSJLrT#py^N{z?e6X7JGDm8uzW`k3x)9!(>moGuv{?*p=DOL-d&B+v z6=PY~e$=ez{5sdpkv1{*0o!l#+!w5teW6dSTtDa9*#5b_Ynxd6!_DWd?fE_ctY#he z@qu6;_p!bu6g6`ad!P9YeGqsv)<0WI?1Rya?Rj@!90FEzAKcrX(WP+P=8Re=dFso3 zc{sRpZkM5{r@te>&G>rid*Vp=VHE2bQ*IsSC1cR0{n6mN$u0RF16R8bEqNRZ@66*k zH1({<@nGAkC)UHj>iHeVzb{cs-zR|8!XFNH?(#dziD3Vp*Y~q^9gmvz(&i+vF_Op0 zU^VA9bxwgdbJYCq(+5x7x;}B$tk-!@7{haPD!%g0lE-%%xO{KQo$u4J?isE3$eGyX z6d(O(wSH}4oeeJEMUQ}&@1jS-t)uS#l%GK{wta~c>rvqH-E$6Ht$g>K3oqXZ=fSO~ zo;%~wV0Gtz1y*h!?(dc0yzk@}z^#*e>M>yNDeLJ=yT^j{8S{LsJiZITYT*}weaGb+ z;c;;5sOJn{3|7w>z69*!9O-*JMa?-9C-$Y_vaf!)eO=$4-^<`??x*xW0JojK+_S5| z>Y1}au$trZ@BQTIa|rC5y{)}}hT&?-eGS;h-1V)dsF}MsaV`fNC%KNm)ylp9M0mL# zYvJC#*439-qhNjE>%iunb2SE5vtGue<~~kt+O%H}Zu)KRr6<9?m(){d0<0cB3AWGN zA5&m8@6P100d6~e<}r>{ON=YPYW`i={qtp4NK`Izcz{F3;FCaJ9U<^r@x(wQc?I>)_>g z*Y$AgsQbRU5$ofA(RTwy&HW-yoSVSq9VUQCE8gY_BLwUEcR5?sc83|#F3O5#2ioVfba_Cl~eWV~2-as@_n17s)nM1scZ7G( z8j4!{mxEoC_(#BM-c8$KpGdKdy8Co3c9i1Yb^q9>+oTXE$u_oU6gx7W}#nesc%ErGwwv!EY=0 z%fK&hdG45}!p+0A%iLT8R?i)CEm$q%Hb=G8zaHFZ&7E`uT&=ugZiHvA>QCF7!1`Q6 z$10ESY2Y&M)8T669rFx$;_6S^XM*(^*Ey5N_bhN3_t|i@@{V~9JaP4>?Q_BUjO*OX z<9i;sjQf1J+69!H*%yElSAW{R5UkI*uAw}>7lF&TFNUj?cg#!RiK{%rz2 z{~N$+=W!x-#=enapT@PVesjMA`zDIH=RS~I-`JkNH&gU`HpMxcz2Ny2pFJs_%{{R5 zD4xx|u$iB?wR(A0-j1f8v+@qGnr9_z{!Vb#Mt{cpF0ejx5+^6`l0_7s1(f8p5NuA1 zvECQcu^*s#UnIx(fUQ^N_+Gerz5(6`R&)ROjcWV%Q`B8|W6JYyi9QIPMNv0bd2)4b z_oevkO-Zi%fX#J3thsvMeT-7(`XRXW%3MDTS5K}V0jnj~+2D^-)XmkH^89`M$HBW& z)Xi0%T&IDTQhW}gnCk)9gIjzc_7IABABxSL{7G<`_ov{tDf9j`Ts`~XGhj9Mfq5E3 zEo=XIuv*6X1+ZFQU7GK|FM`dd?B`2x_3W)LgYRnV7{k8Qte3vN0xtXdDqQU>iu>kk z*soLUYaPXQGqB&FsCyngC*N$f^!+V(`ZlJ0t68u7=C&ii55WfbT7NNjTb bcB|+2ukXUuzC+1eeGhyNMW1Udca8rKw{Co` literal 16024 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 0 ? - BinInstance_read(BinInstanceRef(start_chunk + BinChunk_size)).element_ix : ~0; - } if (th_ix < N_SLICE) { sh_bd_sign[th_ix] = 0; } @@ -138,47 +122,11 @@ void main() { sh_is_segment[th_ix] = 0; } - while (wr_ix - rd_ix <= N_TILE) { - // Choose segment with least element. - uint my_min; - if (th_ix < N_WG) { - if (th_ix == 0) { - sh_selected_n = 0; - sh_min_buf = ~0; - } - } - barrier(); - // Tempting to do this with subgroups, but atomic should be good enough. - if (th_ix < N_WG) { - my_min = sh_first_el[th_ix]; - atomicMin(sh_min_buf, my_min); - } - barrier(); - if (th_ix < N_WG) { - if (my_min == sh_min_buf && my_min != ~0) { - sh_elements_ref = sh_chunk[th_ix] + BinChunk_size; - uint selected_n = sh_chunk_n[th_ix]; - sh_selected_n = selected_n; - uint next_chunk = sh_chunk_next[th_ix]; - if (next_chunk == 0) { - sh_first_el[th_ix] = ~0; - } else { - sh_chunk[th_ix] = next_chunk; - BinChunk chunk = BinChunk_read(BinChunkRef(next_chunk)); - sh_chunk_n[th_ix] = chunk.n; - sh_chunk_next[th_ix] = chunk.next.offset; - sh_first_el[th_ix] = BinInstance_read( - BinInstanceRef(next_chunk + BinChunk_size)).element_ix; - } - } - } - barrier(); - uint chunk_n = sh_selected_n; - if (chunk_n == 0) { - // All chunks consumed - break; - } - BinInstanceRef inst_ref = BinInstanceRef(sh_elements_ref); + while (wr_ix - rd_ix <= N_TILE && partition_ix * N_TILE < my_n_elements) { + uint in_ix = (partition_ix * N_TILE + bin_ix) * 2; + uint chunk_n = bins[in_ix]; + uint elements_ref = bins[in_ix + 1]; + BinInstanceRef inst_ref = BinInstanceRef(elements_ref); if (th_ix < chunk_n) { BinInstance inst = BinInstance_read(BinInstance_index(inst_ref, th_ix)); uint wr_el_ix = (wr_ix + th_ix) % N_RINGBUF; @@ -186,6 +134,7 @@ void main() { sh_right_edge[wr_el_ix] = inst.right_edge; } wr_ix += chunk_n; + partition_ix++; } barrier(); diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index b58a3274efdbbcf459803bf752365656e4568355..a3dd59ec043b0771053ede1211b7504eb3bf7e93 100644 GIT binary patch literal 46048 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 literal 49240 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 vp9EG Renderer { let state_buf = device.create_buffer(1 * 1024 * 1024, dev)?; let anno_buf = device.create_buffer(64 * 1024 * 1024, dev)?; - let bin_buf = device.create_buffer(64 * 1024 * 1024, host)?; + let bin_buf = device.create_buffer(64 * 1024 * 1024, dev)?; let ptcl_buf = device.create_buffer(48 * 1024 * 1024, dev)?; let image_dev = device.create_image2d(WIDTH as u32, HEIGHT as u32, dev)?; @@ -192,12 +192,13 @@ impl Renderer { &[], )?; - let coarse_alloc_buf_host = device.create_buffer(4, host)?; - let coarse_alloc_buf_dev = device.create_buffer(4, dev)?; + let coarse_alloc_buf_host = device.create_buffer(8, host)?; + let coarse_alloc_buf_dev = device.create_buffer(8, dev)?; let coarse_alloc_start = WIDTH_IN_TILES * HEIGHT_IN_TILES * PTCL_INITIAL_ALLOC; device .write_buffer(&coarse_alloc_buf_host, &[ + n_elements as u32, coarse_alloc_start as u32, ]) ?; @@ -264,26 +265,22 @@ impl Renderer { cmd_buf.dispatch( &self.bin_pipeline, &self.bin_ds, - (N_WG, 1, 1), + (((self.n_elements + 255) / 256) as u32, 1, 1), ); cmd_buf.write_timestamp(&query_pool, 2); cmd_buf.memory_barrier(); - /* cmd_buf.dispatch( &self.coarse_pipeline, &self.coarse_ds, (WIDTH as u32 / 256, HEIGHT as u32 / 256, 1), ); - */ cmd_buf.write_timestamp(&query_pool, 3); cmd_buf.memory_barrier(); - /* cmd_buf.dispatch( &self.k4_pipeline, &self.k4_ds, ((WIDTH / TILE_W) as u32, (HEIGHT / TILE_H) as u32, 1), ); - */ cmd_buf.write_timestamp(&query_pool, 4); cmd_buf.memory_barrier(); cmd_buf.image_barrier(&self.image_dev, ImageLayout::General, ImageLayout::BlitSrc); From 192ddc5eabea7742c8e2b5da8e1ef5fe408c8878 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 30 May 2020 15:37:34 -0700 Subject: [PATCH 3/4] Parallel merge The fancy stuff :) --- piet-gpu/shader/coarse.comp | 82 ++++++++++++++++++++++++++++-------- piet-gpu/shader/coarse.spv | Bin 46048 -> 49012 bytes 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 082d902..78c758b 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -30,9 +30,16 @@ layout(set = 0, binding = 3) buffer PtclBuf { #define N_RINGBUF 512 +#define LG_N_PART_READ 8 +#define N_PART_READ (1 << LG_N_PART_READ) + shared uint sh_elements[N_RINGBUF]; shared float sh_right_edge[N_RINGBUF]; +// Number of elements in the partition; prefix sum. +shared uint sh_part_count[N_PART_READ]; +shared uint sh_part_elements[N_PART_READ]; + shared uint sh_bitmaps[N_SLICE][N_TILE]; shared uint sh_backdrop[N_SLICE][N_TILE]; shared uint sh_bd_sign[N_SLICE]; @@ -89,7 +96,7 @@ void main() { // invocations within the workgroup. We'll use variables to abstract. uint bin_ix = N_TILE_X * gl_WorkGroupID.y + gl_WorkGroupID.x; uint partition_ix = 0; - uint my_n_elements = n_elements; + uint n_partitions = (n_elements + N_TILE - 1) / N_TILE; // Top left coordinates of this bin. vec2 xy0 = vec2(N_TILE_X * TILE_WIDTH_PX * gl_WorkGroupID.x, N_TILE_Y * TILE_HEIGHT_PX * gl_WorkGroupID.y); uint th_ix = gl_LocalInvocationID.x; @@ -107,8 +114,14 @@ void main() { SegmentRef last_chunk_segs = SegmentRef(0); alloc_chunk_remaining = 0; - uint wr_ix = 0; + // I'm sure we can figure out how to do this with at least one fewer register... + // Items up to rd_ix have been read from sh_elements uint rd_ix = 0; + // Items up to wr_ix have been written into sh_elements + uint wr_ix = 0; + // Items between part_start_ix and ready_ix are ready to be transferred from sh_part_elements + uint part_start_ix = 0; + uint ready_ix = 0; if (th_ix < N_SLICE) { sh_bd_sign[th_ix] = 0; } @@ -122,21 +135,58 @@ void main() { sh_is_segment[th_ix] = 0; } - while (wr_ix - rd_ix <= N_TILE && partition_ix * N_TILE < my_n_elements) { - uint in_ix = (partition_ix * N_TILE + bin_ix) * 2; - uint chunk_n = bins[in_ix]; - uint elements_ref = bins[in_ix + 1]; - BinInstanceRef inst_ref = BinInstanceRef(elements_ref); - if (th_ix < chunk_n) { - BinInstance inst = BinInstance_read(BinInstance_index(inst_ref, th_ix)); - uint wr_el_ix = (wr_ix + th_ix) % N_RINGBUF; + // parallel read of input partitions + do { + if (ready_ix == wr_ix && partition_ix < n_partitions) { + part_start_ix = ready_ix; + uint count = 0; + if (th_ix < N_PART_READ && partition_ix + th_ix < n_partitions) { + uint in_ix = ((partition_ix + th_ix) * N_TILE + bin_ix) * 2; + count = bins[in_ix]; + sh_part_elements[th_ix] = bins[in_ix + 1]; + } + // prefix sum of counts + for (uint i = 0; i < LG_N_PART_READ; i++) { + if (th_ix < N_PART_READ) { + sh_part_count[th_ix] = count; + } + barrier(); + if (th_ix < N_PART_READ) { + if (th_ix >= (1 << i)) { + count += sh_part_count[th_ix - (1 << i)]; + } + } + barrier(); + } + if (th_ix < N_PART_READ) { + sh_part_count[th_ix] = part_start_ix + count; + } + barrier(); + ready_ix = sh_part_count[N_PART_READ - 1]; + partition_ix += N_PART_READ; + } + // use binary search to find element to read + uint ix = rd_ix + th_ix; + if (ix >= wr_ix && ix < ready_ix) { + uint part_ix = 0; + for (uint i = 0; i < LG_N_PART_READ; i++) { + uint probe = part_ix + ((N_PART_READ / 2) >> i); + if (ix >= sh_part_count[probe - 1]) { + part_ix = probe; + } + } + ix -= part_ix > 0 ? sh_part_count[part_ix - 1] : part_start_ix; + BinInstanceRef inst_ref = BinInstanceRef(sh_part_elements[part_ix]); + BinInstance inst = BinInstance_read(BinInstance_index(inst_ref, ix)); + uint wr_el_ix = (rd_ix + th_ix) % N_RINGBUF; sh_elements[wr_el_ix] = inst.element_ix; sh_right_edge[wr_el_ix] = inst.right_edge; } - wr_ix += chunk_n; - partition_ix++; - } - barrier(); + barrier(); + + wr_ix = min(rd_ix + N_TILE, ready_ix); + } while (wr_ix - rd_ix < N_TILE && (wr_ix < ready_ix || partition_ix < n_partitions)); + // We've done the merge and filled the buffer. @@ -475,9 +525,7 @@ void main() { barrier(); rd_ix += N_TILE; - // The second disjunct is there as a strange workaround on Nvidia. If it is - // removed, then the kernel fails with ERROR_DEVICE_LOST. - if (rd_ix >= wr_ix || bin_ix == ~0) break; + if (rd_ix >= ready_ix && partition_ix >= n_partitions) break; } Cmd_End_write(cmd_ref); } diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index a3dd59ec043b0771053ede1211b7504eb3bf7e93..252ff10d8b2b61be2b6d1649e52ed678ea539a04 100644 GIT binary patch literal 49012 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 laAV}(t-b}WmY6>V+eSSxe*#u_UL4D literal 46048 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 From 2c185c3718d8b830cfbd54d8e21673d2c99b796f Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 30 May 2020 21:12:55 -0700 Subject: [PATCH 4/4] Simplify ringbuf We don't really need a ring buffer, as we only read what we're actually going to process. --- piet-gpu/shader/coarse.comp | 21 ++++++++------------- piet-gpu/shader/coarse.spv | Bin 49012 -> 48612 bytes 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 78c758b..3656f77 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -28,13 +28,11 @@ layout(set = 0, binding = 3) buffer PtclBuf { #include "bins.h" #include "ptcl.h" -#define N_RINGBUF 512 - #define LG_N_PART_READ 8 #define N_PART_READ (1 << LG_N_PART_READ) -shared uint sh_elements[N_RINGBUF]; -shared float sh_right_edge[N_RINGBUF]; +shared uint sh_elements[N_TILE]; +shared float sh_right_edge[N_TILE]; // Number of elements in the partition; prefix sum. shared uint sh_part_count[N_PART_READ]; @@ -178,16 +176,14 @@ void main() { ix -= part_ix > 0 ? sh_part_count[part_ix - 1] : part_start_ix; BinInstanceRef inst_ref = BinInstanceRef(sh_part_elements[part_ix]); BinInstance inst = BinInstance_read(BinInstance_index(inst_ref, ix)); - uint wr_el_ix = (rd_ix + th_ix) % N_RINGBUF; - sh_elements[wr_el_ix] = inst.element_ix; - sh_right_edge[wr_el_ix] = inst.right_edge; + sh_elements[th_ix] = inst.element_ix; + sh_right_edge[th_ix] = inst.right_edge; } barrier(); wr_ix = min(rd_ix + N_TILE, ready_ix); } while (wr_ix - rd_ix < N_TILE && (wr_ix < ready_ix || partition_ix < n_partitions)); - // We've done the merge and filled the buffer. // Read one element, compute coverage. @@ -195,9 +191,8 @@ void main() { AnnotatedRef ref; float right_edge = 0.0; if (th_ix + rd_ix < wr_ix) { - uint rd_el_ix = (rd_ix + th_ix) % N_RINGBUF; - uint element_ix = sh_elements[rd_el_ix]; - right_edge = sh_right_edge[rd_el_ix]; + uint element_ix = sh_elements[th_ix]; + right_edge = sh_right_edge[th_ix]; ref = AnnotatedRef(element_ix * Annotated_size); tag = Annotated_tag(ref); } @@ -355,7 +350,7 @@ void main() { } } uint out_offset = seg_alloc + Segment_size * ix + SegChunk_size; - uint rd_el_ix = (rd_ix + slice_ix * 32 + bit_ix) % N_RINGBUF; + uint rd_el_ix = slice_ix * 32 + bit_ix; uint element_ix = sh_elements[rd_el_ix]; ref = AnnotatedRef(element_ix * Annotated_size); AnnoFillLineSeg line = Annotated_FillLine_read(ref); @@ -407,7 +402,7 @@ void main() { } } uint element_ref_ix = slice_ix * 32 + findLSB(nonseg_bitmap); - uint element_ix = sh_elements[(rd_ix + element_ref_ix) % N_RINGBUF]; + uint element_ix = sh_elements[element_ref_ix]; // Bits up to and including the lsb uint bd_mask = (nonseg_bitmap - 1) ^ nonseg_bitmap; diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 252ff10d8b2b61be2b6d1649e52ed678ea539a04..5a43f4abf13e1d65d900a91bcbeda31a384f3e65 100644 GIT binary patch literal 48612 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%0Ar-qVlu2fV%bEZGul9*$Lib1=`XsgtKZTT#@^ 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 P%WYu$QFp9z$NK*Ok!Hg$ literal 49012 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 laAV}(t-b}WmY6>V+eSSxe*#u_UL4D