j2k-metal 0.10.0

Metal decoder and encode-stage adapter for j2k
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
// SPDX-License-Identifier: MIT OR Apache-2.0

#[cfg(target_os = "macos")]
#[cfg(test)]
use super::test_counters;
use super::{
    accumulate_classic_tier1_scan_estimates, checked_buffer_slice, classic_tier1_pass_class_counts,
    compare_classic_tier1_symbol_plan_and_pass_plan_counters,
    compare_classic_tier1_symbol_plan_and_split_token_emit_counters,
    compare_classic_tier1_symbol_plan_and_token_emit_counters,
    completed_command_buffers_gpu_duration_and_elapsed_window, duration_share, encode_status_error,
    hybrid_stage_signpost, metal_profile_stages_enabled, packet_encode_status_error,
    profile_classic_tier1_token_pack, record_classic_tier1_density_counters,
    record_classic_tier1_pass_plan_counters, record_classic_tier1_symbol_plan_counters,
    record_classic_tier1_token_emit_counters, record_completed_resident_encode_gpu_stages,
    recycle_private_buffers, recycle_shared_buffers,
    validate_classic_tier1_split_token_emit_counters, wait_for_completion_metal, CommandBufferRef,
    Error, Instant, J2kClassicEncodeStatus, J2kCodestreamAssemblyStatus, J2kHtEncodeStatus,
    J2kPacketEncodeStatus, J2kPendingResidentLosslessCodestreamBatch, J2kResidentEncodeStageStats,
    J2kResidentLosslessCodestream, J2kResidentLosslessCodestreamBatchResult,
    J2kResidentTier1StatusKind, J2kResidentTier1StatusReadback, J2K_ENCODE_STATUS_OK,
    PACKET_PAYLOAD_COPY_STRIPES_PER_JOB, SIGNPOST_ENCODE_HYBRID_COMMAND_WAIT,
    SIGNPOST_ENCODE_HYBRID_RESULT_HARVEST,
};

#[cfg(target_os = "macos")]
#[expect(
    clippy::too_many_lines,
    reason = "output validation is an exhaustive status-kind mapping"
)]
pub(in crate::engine) fn record_resident_tier1_output_usage(
    stage_stats: &mut J2kResidentEncodeStageStats,
    readback: &J2kResidentTier1StatusReadback,
    classic_gpu_token_pack_used: bool,
) -> Result<(), Error> {
    match readback.kind {
        J2kResidentTier1StatusKind::Classic => {
            let classic_jobs =
                readback
                    .classic_jobs
                    .as_ref()
                    .ok_or_else(|| Error::MetalKernel {
                        message:
                            "J2K Metal classic Tier-1 profile readback is missing job metadata"
                                .to_string(),
                    })?;
            let statuses = checked_buffer_slice::<J2kClassicEncodeStatus>(
                &readback.buffer,
                readback.count,
                "resident classic Tier-1 statuses",
            )?;
            if classic_jobs.len() != statuses.len() {
                return Err(Error::MetalKernel {
                    message: "J2K Metal classic Tier-1 profile readback job/status count mismatch"
                        .to_string(),
                });
            }
            for (status, job) in statuses.iter().zip(classic_jobs) {
                if status.code != J2K_ENCODE_STATUS_OK {
                    return Err(encode_status_error(
                        "classic Tier-1",
                        status.code,
                        status.detail,
                    ));
                }
                let data_len =
                    usize::try_from(status.data_len).map_err(|_| Error::MetalKernel {
                        message: "J2K Metal classic Tier-1 output length exceeds usize".to_string(),
                    })?;
                stage_stats.tier1_output_used_bytes_total = stage_stats
                    .tier1_output_used_bytes_total
                    .saturating_add(data_len);
                stage_stats.max_tier1_output_used_bytes =
                    stage_stats.max_tier1_output_used_bytes.max(data_len);
                if classic_gpu_token_pack_used {
                    stage_stats.tier1_token_pack_output_bytes_total = stage_stats
                        .tier1_token_pack_output_bytes_total
                        .saturating_add(data_len);
                    stage_stats.max_tier1_token_pack_output_bytes_per_block = stage_stats
                        .max_tier1_token_pack_output_bytes_per_block
                        .max(data_len);
                }
                let coding_passes =
                    usize::try_from(status.number_of_coding_passes).map_err(|_| {
                        Error::MetalKernel {
                            message: "J2K Metal classic Tier-1 coding-pass count exceeds usize"
                                .to_string(),
                        }
                    })?;
                stage_stats.tier1_coding_pass_count_total = stage_stats
                    .tier1_coding_pass_count_total
                    .saturating_add(coding_passes);
                stage_stats.max_tier1_coding_passes_per_block = stage_stats
                    .max_tier1_coding_passes_per_block
                    .max(coding_passes);
                let pass_counts =
                    classic_tier1_pass_class_counts(coding_passes, readback.classic_style_flags);
                let coeff_count = usize::try_from(job.width)
                    .and_then(|width| {
                        usize::try_from(job.height).map(|height| width.saturating_mul(height))
                    })
                    .map_err(|_| Error::MetalKernel {
                        message: "J2K Metal classic Tier-1 code-block dimensions exceed usize"
                            .to_string(),
                    })?;
                accumulate_classic_tier1_scan_estimates(stage_stats, pass_counts, coeff_count);
                stage_stats.tier1_arithmetic_pass_count_total = stage_stats
                    .tier1_arithmetic_pass_count_total
                    .saturating_add(pass_counts.arithmetic);
                stage_stats.tier1_raw_pass_count_total = stage_stats
                    .tier1_raw_pass_count_total
                    .saturating_add(pass_counts.raw);
                stage_stats.tier1_cleanup_pass_count_total = stage_stats
                    .tier1_cleanup_pass_count_total
                    .saturating_add(pass_counts.cleanup);
                stage_stats.tier1_sigprop_pass_count_total = stage_stats
                    .tier1_sigprop_pass_count_total
                    .saturating_add(pass_counts.sigprop);
                stage_stats.tier1_magref_pass_count_total = stage_stats
                    .tier1_magref_pass_count_total
                    .saturating_add(pass_counts.magref);
                stage_stats.tier1_arithmetic_cleanup_pass_count_total = stage_stats
                    .tier1_arithmetic_cleanup_pass_count_total
                    .saturating_add(pass_counts.arithmetic_cleanup);
                stage_stats.tier1_arithmetic_sigprop_pass_count_total = stage_stats
                    .tier1_arithmetic_sigprop_pass_count_total
                    .saturating_add(pass_counts.arithmetic_sigprop);
                stage_stats.tier1_arithmetic_magref_pass_count_total = stage_stats
                    .tier1_arithmetic_magref_pass_count_total
                    .saturating_add(pass_counts.arithmetic_magref);
                stage_stats.tier1_raw_sigprop_pass_count_total = stage_stats
                    .tier1_raw_sigprop_pass_count_total
                    .saturating_add(pass_counts.raw_sigprop);
                stage_stats.tier1_raw_magref_pass_count_total = stage_stats
                    .tier1_raw_magref_pass_count_total
                    .saturating_add(pass_counts.raw_magref);
                if coding_passes == 0 {
                    stage_stats.tier1_zero_block_count_total =
                        stage_stats.tier1_zero_block_count_total.saturating_add(1);
                } else {
                    stage_stats.tier1_nonzero_block_count_total = stage_stats
                        .tier1_nonzero_block_count_total
                        .saturating_add(1);
                }
                let missing_bitplanes =
                    usize::try_from(status.missing_bit_planes).map_err(|_| Error::MetalKernel {
                        message: "J2K Metal classic Tier-1 missing-bitplane count exceeds usize"
                            .to_string(),
                    })?;
                stage_stats.tier1_missing_bitplane_count_total = stage_stats
                    .tier1_missing_bitplane_count_total
                    .saturating_add(missing_bitplanes);
                stage_stats.max_tier1_missing_bitplanes_per_block = stage_stats
                    .max_tier1_missing_bitplanes_per_block
                    .max(missing_bitplanes);
                let segment_count =
                    usize::try_from(status.segment_count).map_err(|_| Error::MetalKernel {
                        message: "J2K Metal classic Tier-1 segment count exceeds usize".to_string(),
                    })?;
                stage_stats.tier1_segment_count_total = stage_stats
                    .tier1_segment_count_total
                    .saturating_add(segment_count);
                stage_stats.max_tier1_segments_per_block =
                    stage_stats.max_tier1_segments_per_block.max(segment_count);
            }
        }
        J2kResidentTier1StatusKind::HighThroughput => {
            let statuses = checked_buffer_slice::<J2kHtEncodeStatus>(
                &readback.buffer,
                readback.count,
                "resident HT Tier-1 statuses",
            )?;
            for status in statuses {
                if status.code != J2K_ENCODE_STATUS_OK {
                    return Err(encode_status_error(
                        "HTJ2K Tier-1",
                        status.code,
                        status.detail,
                    ));
                }
                let data_len =
                    usize::try_from(status.data_len).map_err(|_| Error::MetalKernel {
                        message: "HTJ2K Metal Tier-1 output length exceeds usize".to_string(),
                    })?;
                stage_stats.tier1_output_used_bytes_total = stage_stats
                    .tier1_output_used_bytes_total
                    .saturating_add(data_len);
                stage_stats.max_tier1_output_used_bytes =
                    stage_stats.max_tier1_output_used_bytes.max(data_len);
                let coding_passes =
                    usize::try_from(status.num_coding_passes).map_err(|_| Error::MetalKernel {
                        message: "HTJ2K Metal Tier-1 coding-pass count exceeds usize".to_string(),
                    })?;
                stage_stats.tier1_coding_pass_count_total = stage_stats
                    .tier1_coding_pass_count_total
                    .saturating_add(coding_passes);
                stage_stats.max_tier1_coding_passes_per_block = stage_stats
                    .max_tier1_coding_passes_per_block
                    .max(coding_passes);
                if coding_passes == 0 {
                    stage_stats.tier1_zero_block_count_total =
                        stage_stats.tier1_zero_block_count_total.saturating_add(1);
                } else {
                    stage_stats.tier1_nonzero_block_count_total = stage_stats
                        .tier1_nonzero_block_count_total
                        .saturating_add(1);
                }
                let missing_bitplanes =
                    usize::try_from(status.num_zero_bitplanes).map_err(|_| Error::MetalKernel {
                        message: "HTJ2K Metal Tier-1 missing-bitplane count exceeds usize"
                            .to_string(),
                    })?;
                stage_stats.tier1_missing_bitplane_count_total = stage_stats
                    .tier1_missing_bitplane_count_total
                    .saturating_add(missing_bitplanes);
                stage_stats.max_tier1_missing_bitplanes_per_block = stage_stats
                    .max_tier1_missing_bitplanes_per_block
                    .max(missing_bitplanes);
            }
        }
    }
    Ok(())
}

#[cfg(target_os = "macos")]
pub(in crate::engine) fn wait_resident_codestream_command_buffer(
    command_buffer: &CommandBufferRef,
) -> Result<(), Error> {
    #[cfg(test)]
    test_counters::record_resident_codestream_command_buffer_wait();
    let _signpost = hybrid_stage_signpost(SIGNPOST_ENCODE_HYBRID_COMMAND_WAIT);
    wait_for_completion_metal(command_buffer)
}

#[cfg(target_os = "macos")]
#[expect(
    clippy::too_many_lines,
    reason = "result harvesting keeps buffer validation and timing ownership atomic"
)]
pub(in crate::engine) fn finish_completed_resident_lossless_codestream_batch(
    pending: J2kPendingResidentLosslessCodestreamBatch,
) -> Result<J2kResidentLosslessCodestreamBatchResult, Error> {
    let _signpost = hybrid_stage_signpost(SIGNPOST_ENCODE_HYBRID_RESULT_HARVEST);
    let profile_stages = metal_profile_stages_enabled();
    let result_harvest_started = profile_stages.then(Instant::now);
    let gpu_timings = completed_command_buffers_gpu_duration_and_elapsed_window(
        &pending.retained_command_buffers,
        &pending.command_buffer,
    );
    let gpu_duration = gpu_timings.map(|timings| timings.0);
    let gpu_elapsed_wall_duration = gpu_timings.map(|timings| timings.1);
    let mut stage_stats = pending.stage_stats;
    if let Some(duration) = gpu_elapsed_wall_duration {
        stage_stats.gpu_elapsed_wall_duration = duration;
    }
    if profile_stages {
        record_completed_resident_encode_gpu_stages(
            &mut stage_stats,
            &pending.gpu_stage_command_buffers,
        );
    }
    if let Some(readback) = pending.tier1_status_readback.as_ref() {
        record_resident_tier1_output_usage(
            &mut stage_stats,
            readback,
            pending.classic_gpu_token_pack_used,
        )?;
    }
    if let Some(readback) = pending.classic_tier1_density_readback.as_ref() {
        record_classic_tier1_density_counters(&mut stage_stats, readback)?;
    }
    if let Some(readback) = pending.classic_tier1_symbol_plan_readback.as_ref() {
        record_classic_tier1_symbol_plan_counters(&mut stage_stats, readback)?;
    }
    if let (Some(symbol_plan), Some(pass_plan)) = (
        pending.classic_tier1_symbol_plan_readback.as_ref(),
        pending.classic_tier1_pass_plan_readback.as_ref(),
    ) {
        compare_classic_tier1_symbol_plan_and_pass_plan_counters(symbol_plan, pass_plan)?;
    }
    if let Some(readback) = pending.classic_tier1_pass_plan_readback.as_ref() {
        record_classic_tier1_pass_plan_counters(&mut stage_stats, readback)?;
    }
    if let (Some(symbol_plan), Some(token_emit)) = (
        pending.classic_tier1_symbol_plan_readback.as_ref(),
        pending.classic_tier1_token_emit_readback.as_ref(),
    ) {
        compare_classic_tier1_symbol_plan_and_token_emit_counters(symbol_plan, token_emit)?;
    }
    if let Some(readback) = pending.classic_tier1_token_emit_readback.as_ref() {
        record_classic_tier1_token_emit_counters(&mut stage_stats, readback)?;
        profile_classic_tier1_token_pack(&mut stage_stats, readback)?;
    }
    if let Some(readback) = pending.classic_tier1_split_token_emit_readback.as_ref() {
        validate_classic_tier1_split_token_emit_counters(readback)?;
    }
    if let (Some(symbol_plan), Some(split_emit)) = (
        pending.classic_tier1_symbol_plan_readback.as_ref(),
        pending.classic_tier1_split_token_emit_readback.as_ref(),
    ) {
        compare_classic_tier1_symbol_plan_and_split_token_emit_counters(symbol_plan, split_emit)?;
    }
    let runtime = pending.runtime.clone();
    let recyclable_private_buffers = pending.recyclable_private_buffers;
    let private_recycle_started = profile_stages.then(Instant::now);
    recycle_private_buffers(&runtime, recyclable_private_buffers)?;
    if let Some(started) = private_recycle_started {
        stage_stats.result_private_recycle_duration = started.elapsed();
    }
    let gpu_duration_share =
        gpu_duration.map(|duration| duration_share(duration, pending.capacities.len()));
    let status_copy_started = profile_stages.then(Instant::now);
    let statuses = checked_buffer_slice::<J2kCodestreamAssemblyStatus>(
        &pending.status_buffer,
        pending.capacities.len(),
        "resident codestream assembly statuses",
    )?;
    let packet_statuses = checked_buffer_slice::<J2kPacketEncodeStatus>(
        &pending.packet_status_buffer,
        pending.capacities.len(),
        "resident packet encode statuses",
    )?;
    if let Some(started) = status_copy_started {
        stage_stats.result_status_copy_duration = started.elapsed();
    }
    let recyclable_shared_buffers = pending.recyclable_shared_buffers;
    let shared_recycle_started = profile_stages.then(Instant::now);
    recycle_shared_buffers(&runtime, recyclable_shared_buffers)?;
    if let Some(started) = shared_recycle_started {
        stage_stats.result_shared_recycle_duration = started.elapsed();
    }
    let codestream_collect_started = profile_stages.then(Instant::now);
    let mut budget = crate::batch_allocation::BatchMetadataBudget::new(
        "J2K Metal resident codestream result collection",
    );
    let mut codestreams = budget.try_vec(
        pending.capacities.len(),
        "J2K Metal resident codestream results",
    )?;
    for (index, status) in statuses.into_iter().enumerate() {
        let packet_status = packet_statuses
            .get(index)
            .ok_or_else(|| Error::MetalKernel {
                message: "J2K Metal packetization status missing for resident batch tile"
                    .to_string(),
            })?;
        if packet_status.code != J2K_ENCODE_STATUS_OK {
            return Err(packet_encode_status_error(*packet_status));
        }
        if status.code != J2K_ENCODE_STATUS_OK {
            return Err(encode_status_error(
                pending.status_stage,
                status.code,
                status.detail,
            ));
        }
        let data_len = usize::try_from(status.data_len).map_err(|_| Error::MetalKernel {
            message: pending.length_error.to_string(),
        })?;
        let capacity = pending.capacities[index];
        if data_len > capacity {
            return Err(Error::MetalKernel {
                message: pending.capacity_error.to_string(),
            });
        }
        let packet_output_used =
            usize::try_from(packet_status.data_len).map_err(|_| Error::MetalKernel {
                message: "J2K Metal packet output length exceeds usize".to_string(),
            })?;
        let packet_payload_copy_jobs =
            usize::try_from(packet_status.detail).map_err(|_| Error::MetalKernel {
                message: "J2K Metal packet payload-copy count exceeds usize".to_string(),
            })?;
        let packet_payload_copy_bytes =
            usize::try_from(packet_status.payload_copy_bytes).map_err(|_| Error::MetalKernel {
                message: "J2K Metal packet payload-copy byte count exceeds usize".to_string(),
            })?;
        let packet_payload_copy_small_jobs = usize::try_from(packet_status.payload_copy_small_jobs)
            .map_err(|_| Error::MetalKernel {
                message: "J2K Metal small packet payload-copy count exceeds usize".to_string(),
            })?;
        let packet_payload_copy_medium_jobs =
            usize::try_from(packet_status.payload_copy_medium_jobs).map_err(|_| {
                Error::MetalKernel {
                    message: "J2K Metal medium packet payload-copy count exceeds usize".to_string(),
                }
            })?;
        let packet_payload_copy_large_jobs = usize::try_from(packet_status.payload_copy_large_jobs)
            .map_err(|_| Error::MetalKernel {
                message: "J2K Metal large packet payload-copy count exceeds usize".to_string(),
            })?;
        let packet_payload_copy_active_stripes =
            packet_payload_copy_jobs.saturating_mul(PACKET_PAYLOAD_COPY_STRIPES_PER_JOB as usize);
        stage_stats.packet_output_used_bytes_total = stage_stats
            .packet_output_used_bytes_total
            .saturating_add(packet_output_used);
        stage_stats.max_packet_output_used_bytes = stage_stats
            .max_packet_output_used_bytes
            .max(packet_output_used);
        stage_stats.packet_payload_copy_job_count_total = stage_stats
            .packet_payload_copy_job_count_total
            .saturating_add(packet_payload_copy_jobs);
        stage_stats.max_packet_payload_copy_jobs_used_per_tile = stage_stats
            .max_packet_payload_copy_jobs_used_per_tile
            .max(packet_payload_copy_jobs);
        stage_stats.packet_payload_copy_bytes_total = stage_stats
            .packet_payload_copy_bytes_total
            .saturating_add(packet_payload_copy_bytes);
        stage_stats.max_packet_payload_copy_bytes_per_tile = stage_stats
            .max_packet_payload_copy_bytes_per_tile
            .max(packet_payload_copy_bytes);
        stage_stats.packet_payload_copy_small_job_count_total = stage_stats
            .packet_payload_copy_small_job_count_total
            .saturating_add(packet_payload_copy_small_jobs);
        stage_stats.packet_payload_copy_medium_job_count_total = stage_stats
            .packet_payload_copy_medium_job_count_total
            .saturating_add(packet_payload_copy_medium_jobs);
        stage_stats.packet_payload_copy_large_job_count_total = stage_stats
            .packet_payload_copy_large_job_count_total
            .saturating_add(packet_payload_copy_large_jobs);
        stage_stats.packet_payload_copy_active_stripe_count_total = stage_stats
            .packet_payload_copy_active_stripe_count_total
            .saturating_add(packet_payload_copy_active_stripes);
        if pending.codestream_payload_copy_dispatched {
            stage_stats.codestream_payload_copy_bytes_total = stage_stats
                .codestream_payload_copy_bytes_total
                .saturating_add(packet_output_used);
        }
        codestreams.push(J2kResidentLosslessCodestream {
            buffer: pending.buffer.clone(),
            byte_offset: pending.byte_offsets[index],
            byte_len: data_len,
            capacity,
            gpu_duration: gpu_duration_share,
        });
    }
    if let Some(started) = codestream_collect_started {
        stage_stats.result_codestream_collect_duration = started.elapsed();
    }
    if let Some(started) = result_harvest_started {
        stage_stats.result_harvest_duration = started.elapsed();
    }
    Ok(J2kResidentLosslessCodestreamBatchResult {
        codestreams,
        stage_stats,
    })
}