marCCD frames are widened on the device
The marCCD reader read each frame's 16-bit scanlines into scratch and widened them to int32 on the worker thread (marccd::ReadInto, ~20 % of the image-loop worker CPU on 4nwv), and the 4-byte image was uploaded. ReadRawImage now reads the scanlines straight into the image's buffer and hands them over as a new read-only CompressionAlgorithm::UINT16_WIDENED (mode Int32): two bytes a pixel cross PCIe, from page-locked memory, and the preprocessing kernel widens them itself. It is not CompressedImageMode::Uint16, which calls 65535 an error pixel; a marCCD's 65535 is its saturation marker. So the kernel compares each pixel with int32's error marker and the int32 saturation cap - the comparisons are made on the pixel's value, in int64, rather than in the storage type - and decides every pixel exactly as for the int32 image the host would have widened it to. The host widening (JFJochDecompressPtr) is the CPU path. Test: ImagePreprocessorGPU_StoredEncodingsMatchCPU, with a frame carrying 65535 at a saturation of 65535, against the CPU preprocessor on the host-widened image. 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:
@@ -17,9 +17,9 @@
|
||||
#include "../image_analysis/image_preprocessing/ImagePreprocessorGPU.h"
|
||||
#include "../image_analysis/image_preprocessing/ImagePreprocessorBufferGPU.h"
|
||||
|
||||
// The miniCBF frames reach the GPU as their files store them, and the device has to turn them into
|
||||
// exactly the int32 image the host decoder would have: the same pixels, the same refusal of a stream
|
||||
// that ends early.
|
||||
// The miniCBF and marCCD frames reach the GPU as their files store them, and the device has to turn
|
||||
// them into exactly the int32 image the host decoder would have: the same pixels, the same refusal of
|
||||
// a stream that ends early.
|
||||
namespace {
|
||||
|
||||
// x-CBF_BYTE_OFFSET with the smallest container for each delta; force64 puts a delta in the 15-byte
|
||||
@@ -132,8 +132,9 @@ TEST_CASE("CBFDecoderGPU_ShortStreamIsRefused", "[ImagePreprocessorGPU]") {
|
||||
}
|
||||
}
|
||||
|
||||
// Through the preprocessor, as the image loop calls it: the stored encoding against the CPU
|
||||
// preprocessor fed what the host decodes it to.
|
||||
// Through the preprocessor, as the image loop calls it: the stored encodings against the CPU
|
||||
// preprocessor fed what the host decodes them to. The marCCD frame carries 65535, its saturation
|
||||
// marker, which a Uint16 image would call an error pixel - widened to int32 it is saturated.
|
||||
TEST_CASE("ImagePreprocessorGPU_StoredEncodingsMatchCPU", "[ImagePreprocessorGPU]") {
|
||||
if (get_gpu_count() == 0)
|
||||
SKIP("No CUDA GPU present");
|
||||
@@ -151,10 +152,15 @@ TEST_CASE("ImagePreprocessorGPU_StoredEncodingsMatchCPU", "[ImagePreprocessorGPU
|
||||
std::mt19937 rng(17);
|
||||
const auto pixels = MakePixels(npixels, 9);
|
||||
const auto cbf = EncodeByteOffset(pixels, rng);
|
||||
std::vector<uint16_t> marccd(npixels);
|
||||
for (size_t i = 0; i < npixels; i++)
|
||||
marccd[i] = (i % 1500 == 0) ? 65535 : static_cast<uint16_t>(rng() % 70000);
|
||||
|
||||
const std::vector<CompressedImage> images = {
|
||||
CompressedImage(cbf.data(), cbf.size(), x.GetXPixelsNum(), x.GetYPixelsNum(), CompressedImageMode::Int32,
|
||||
CompressionAlgorithm::CBF_BYTE_OFFSET)
|
||||
CompressionAlgorithm::CBF_BYTE_OFFSET),
|
||||
CompressedImage(marccd.data(), marccd.size() * sizeof(uint16_t), x.GetXPixelsNum(), x.GetYPixelsNum(),
|
||||
CompressedImageMode::Int32, CompressionAlgorithm::UINT16_WIDENED)
|
||||
};
|
||||
auto stream = std::make_shared<CudaStream>();
|
||||
ImagePreprocessorGPU gpu_pre(x, mask, stream, /*copy_image_to_host=*/true);
|
||||
|
||||
Reference in New Issue
Block a user