// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include "ImagePreprocessor.h" #include "BSLZ4DecoderGPU.h" #include "../indexing/CUDAMemHelpers.h" #include "../indexing/CudaSharedTables.h" class ImagePreprocessorGPU : public ImagePreprocessor { std::shared_ptr stream; const bool copy_image_to_host; int threads; int blocks; // Geometry-only, so one copy per GPU shared with every other engine on it (CudaSharedTables.h). std::shared_ptr> gpu_mask; CudaDevicePtr gpu_decompressed_image; CudaDevicePtr gpu_stats; std::vector cpu_stats; CudaRegisteredVector cpu_stats_reg; CudaRegisteredVector input_reg; // page-locks the caller's decompression buffer std::vector cpu_image; // Built on first use: a decoder that can serve this engine's images, sized to the frame. std::unique_ptr bslz4_decoder; template ImageStatistics Analyze(ImagePreprocessorBuffer &processed_image, const uint8_t *input, T err_value, T sat_value); // Preprocess an image already sitting in gpu_decompressed_image, shared by both entry points. template ImageStatistics AnalyzeOnDevice(ImagePreprocessorBuffer &processed_image, T err_value, T sat_value); public: // copy_image_to_host copies the preprocessed image back after every frame. It is only needed when // something on the CPU reads it - the GPU engines all work off the device buffer - and at 4 bytes // per pixel it is the single largest transfer in the pipeline, so the caller says whether it wants it. ImagePreprocessorGPU(const DiffractionExperiment &experiment, const PixelMask &mask, std::shared_ptr stream, bool copy_image_to_host = true); ImageStatistics Analyze(ImagePreprocessorBuffer &processed_image, const uint8_t *decompressed_image, CompressedImageMode image_mode) override; bool AnalyzeCompressed(ImagePreprocessorBuffer &processed_image, const CompressedImage &image, ImageStatistics &stats) override; void PinInputBuffer(std::vector &buffer, size_t size) override; };