The host decoder wrote each pixel with _mm_stream_si32 and ended with _mm_sfence, to keep the decoded frame out of the cache on its way to the GPU by DMA. The GPU now decodes CBF itself, so the host decoder only serves the CPU engines and the tests, and the project rule is no SIMD intrinsics. Plain stores; the values written are the same. CBFDecoderGPU_MatchesHost, CBFDecoderGPU_ShortStreamIsRefused, ImagePreprocessorGPU_StoredEncodingsMatchCPU and the CBF reader tests pass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EizBKhTqrAYago9KJG3dA3
63 lines
2.2 KiB
C++
63 lines
2.2 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "CBFByteOffset.h"
|
|
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
#include "../common/JFJochException.h"
|
|
|
|
namespace {
|
|
|
|
int16_t ReadI16(const uint8_t *p) { int16_t v; std::memcpy(&v, p, 2); return v; }
|
|
int32_t ReadI32(const uint8_t *p) { int32_t v; std::memcpy(&v, p, 4); return v; }
|
|
int64_t ReadI64(const uint8_t *p) { int64_t v; std::memcpy(&v, p, 8); return v; }
|
|
|
|
} // namespace
|
|
|
|
// The x-CBF_BYTE_OFFSET scheme: a running value, each pixel stored as a delta in the smallest
|
|
// container that holds it, escaping to the next size with that container's most negative value.
|
|
// Following Bernstein & Hammersley (2006) Int. Tables Cryst. G, 37-43
|
|
void DecodeCBFByteOffset(const uint8_t *data, size_t size, int32_t *out, size_t n_pixels) {
|
|
int64_t value = 0;
|
|
size_t pos = 0;
|
|
size_t written = 0;
|
|
|
|
while (written < n_pixels) {
|
|
if (pos >= size)
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"miniCBF byte-offset stream ended after " + std::to_string(written)
|
|
+ " of " + std::to_string(n_pixels) + " pixels");
|
|
|
|
int64_t delta = static_cast<int8_t>(data[pos]);
|
|
pos += 1;
|
|
|
|
if (delta == -128) {
|
|
if (pos + 2 > size) break;
|
|
delta = ReadI16(data + pos);
|
|
pos += 2;
|
|
if (delta == -32768) {
|
|
if (pos + 4 > size) break;
|
|
delta = ReadI32(data + pos);
|
|
pos += 4;
|
|
if (delta == INT32_MIN) {
|
|
if (pos + 8 > size) break;
|
|
delta = ReadI64(data + pos);
|
|
pos += 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
value += delta;
|
|
out[written] = static_cast<int32_t>(value);
|
|
written++;
|
|
}
|
|
|
|
if (written != n_pixels)
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"miniCBF byte-offset stream ended after " + std::to_string(written)
|
|
+ " of " + std::to_string(n_pixels) + " pixels");
|
|
}
|
|
|