CBF byte-offset decoder: plain stores instead of SSE streaming stores

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
This commit is contained in:
2026-10-13 07:54:56 +02:00
co-authored by Claude Opus 5.5
parent 645d1cc1bb
commit 463cd8eec3
+1 -28
View File
@@ -6,11 +6,6 @@
#include <cstring>
#include <string>
#if defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64)
# include <emmintrin.h>
# define MINICBF_STREAM_STORE 1
#endif
#include "../common/JFJochException.h"
namespace {
@@ -19,26 +14,6 @@ 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; }
// Nothing on this side reads the decoded image back: it goes to the GPU by DMA, or a CPU engine
// walks it once and drops it. An ordinary store therefore pays twice over - it reads every cache
// line before overwriting it, and it evicts 72 MB of live cache to make room - so the pixels go
// straight past the cache. Measured on an 18 Mpx frame: 27 ms of ordinary stores against 11 ms of
// these. The bytes written are the same either way; the fence is what makes them visible to the
// copy that follows.
void StorePixel(int32_t *out, int32_t value) {
#ifdef MINICBF_STREAM_STORE
_mm_stream_si32(out, value);
#else
*out = value;
#endif
}
void StoreFence() {
#ifdef MINICBF_STREAM_STORE
_mm_sfence();
#endif
}
} // namespace
// The x-CBF_BYTE_OFFSET scheme: a running value, each pixel stored as a delta in the smallest
@@ -75,12 +50,10 @@ void DecodeCBFByteOffset(const uint8_t *data, size_t size, int32_t *out, size_t
}
value += delta;
StorePixel(out + written, static_cast<int32_t>(value));
out[written] = static_cast<int32_t>(value);
written++;
}
StoreFence();
if (written != n_pixels)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"miniCBF byte-offset stream ended after " + std::to_string(written)