Add NvJpegPool (4 encoders) and JPEG passthrough in BmpToJpeg

- NvJpegPool: singleton pool of 4 NvJpegCompressor instances with
  lock-free slot acquisition (~160MB VRAM). Threads that can't grab
  a slot fall back to TurboJPEG with zero wait.
- JPEG passthrough: BmpToJpeg now checks if input is already JPEG
  (FF D8 FF magic) and copies directly without re-encoding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 08:33:17 +10:00
parent 53a82da74a
commit 6c72751a14
2 changed files with 81 additions and 9 deletions

View File

@@ -5,6 +5,9 @@
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include <array>
#include <atomic>
#include <memory>
#include <opencv2/opencv.hpp>
// Forward declaration for NI Vision IMAQ Image (avoids nivision.h dependency for consumers)
@@ -63,6 +66,26 @@ namespace ANSCENTER
unsigned char* _gpuBuffer = nullptr; // reusable device memory
size_t _gpuBufferSize = 0;
};
// Fixed-size pool of NvJpegCompressors (~40MB VRAM each).
// Threads that can't acquire an encoder fall back to TurboJPEG.
class NvJpegPool {
public:
static constexpr int kPoolSize = 4;
static NvJpegPool& Instance();
// Try to compress with nvJPEG. Returns empty string if no encoder
// available or on non-NVIDIA hardware — caller should fall back.
[[nodiscard]] std::string tryCompress(const cv::Mat& image, int quality);
[[nodiscard]] bool isAvailable() const noexcept { return _available; }
private:
NvJpegPool();
~NvJpegPool() = default;
NvJpegPool(const NvJpegPool&) = delete;
NvJpegPool& operator=(const NvJpegPool&) = delete;
bool _available = false;
std::array<std::unique_ptr<NvJpegCompressor>, kPoolSize> _encoders;
std::array<std::atomic<bool>, kPoolSize> _inUse; // lock-free slot flags
};
/// <summary>
/// // ANSOPENCV class provides various image processing functionalities using OpenCV and ANS Center SDK.
/// </summary>