From d21065e5590958d3e890a2367337b9ffaec19abf Mon Sep 17 00:00:00 2001 From: sin471 Date: Sat, 28 Feb 2026 15:33:16 +0900 Subject: [PATCH 1/6] Fix coredump on Meteor lake --- src/driver/spinnakerdriver.cpp | 64 +++++++++++++++++++++++++--------- src/driver/spinnakerdriver.h | 3 +- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/driver/spinnakerdriver.cpp b/src/driver/spinnakerdriver.cpp index 5d17dc0..50c0cf2 100644 --- a/src/driver/spinnakerdriver.cpp +++ b/src/driver/spinnakerdriver.cpp @@ -16,9 +16,19 @@ #ifdef SPINNAKER #include "spinnakerdriver.h" +#include +#include #define CATCH_SPINNAKER(f) try { f; } catch (Spinnaker::Exception &e) { std::cerr << "[Spinnaker] Could not set parameter: " << e.GetFullErrorMessage() << std::endl; } +constexpr int kMinBufferCount = 3; // Minimum buffer count required for NewestOnly mode +constexpr size_t kUsb3PacketSize = 1024; // USB3 packet size alignment requirement +constexpr size_t kPageSize = 4096; // Page size alignment requirement for Meteor Lake + +static size_t alignUp(size_t size, size_t alignment) { + return ((size + alignment - 1) / alignment) * alignment; +} + class SpinnakerImage : public RawImage { public: @@ -114,22 +124,39 @@ SpinnakerDriver::SpinnakerDriver(const CameraConfig& config) { } pCam->TLStream.StreamBufferHandlingMode.SetValue(Spinnaker::StreamBufferHandlingMode_NewestOnly); - pCam->TLStream.StreamBufferCountManual.SetValue(pCam->TLStream.StreamBufferCountManual.GetMin()); + + // NewestOnly mode requires at least kMinBufferCount buffers + int requiredBuffers = std::max(kMinBufferCount, (int)pCam->TLStream.StreamBufferCountManual.GetMin()); + pCam->TLStream.StreamBufferCountManual.SetValue(requiredBuffers); // Provide image buffers to achieve faster mapping with OpenCL - int width = pCam->WidthMax.GetValue(); - int height = pCam->HeightMax.GetValue(); - for(int i = 0; i < pCam->TLStream.StreamBufferCountManual.GetMin(); i++) { - std::shared_ptr buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, "spinnaker"); - buffers[buffer] = std::make_unique>(buffer->write()); - } + int width = (int)pCam->Width.GetValue(); + int height = (int)pCam->Height.GetValue(); + size_t rawSize = (size_t)width * height; + + // USB3 packet size alignment is required for zero copy + // https://www.intel.com/content/dam/develop/external/us/en/documents/opencl-zero-copy-in-opencl-1-2.pdf + finalBufferSize_ = alignUp(alignUp(rawSize, kUsb3PacketSize), kPageSize); std::vector bufferPtrs; - for (auto& item: buffers) - bufferPtrs.push_back(**item.second); + for(int i = 0; i < requiredBuffers; i++) { + void* alignedPtr = nullptr; + if (posix_memalign(&alignedPtr, kPageSize, finalBufferSize_) != 0) { + throw std::runtime_error("[Spinnaker] posix_memalign failed"); + } + + std::shared_ptr buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, (unsigned char*)alignedPtr); + + // Create OpenCL mapping + buffers[buffer] = std::make_unique>(buffer->write()); + + bufferPtrs.push_back(alignedPtr); + } + + // Register user-owned buffers with the camera pCam->SetBufferOwnership(Spinnaker::SPINNAKER_BUFFER_OWNERSHIP_USER); - pCam->SetUserBuffers(bufferPtrs.data(), buffers.size(), width*height); + pCam->SetUserBuffers(bufferPtrs.data(), bufferPtrs.size(), finalBufferSize_); //pCam->Timestamp.SetValue(); if (IsWritable(pCam->GevSCPSPacketSize)) { @@ -153,21 +180,26 @@ double SpinnakerDriver::expectedFrametime() { SpinnakerDriver::~SpinnakerDriver() { pCam->EndAcquisition(); + pCam->DeInit(); } std::shared_ptr SpinnakerDriver::borrow(const Spinnaker::ImagePtr& pImage) { void* data = pImage->GetData(); for (auto& item : buffers) { - if(item.second != nullptr && **item.second == data) { - item.second = nullptr; - return item.first; + if(item.second != nullptr) { + void* bStart = static_cast(**item.second); + + void* bEnd = static_cast(bStart) + finalBufferSize_; + + if (data >= bStart && data < bEnd) { + item.second = nullptr; // Mark buffer as in use + return item.first; + } } } std::cerr << "[Spinnaker] Did not get image with given buffer, creating new buffer; expect OpenCL performance degradation" << std::endl; - std::shared_ptr image = std::make_shared(&PixelFormat::RGGB8, (int)pImage->GetWidth() / 2, (int)pImage->GetHeight() / 2, (unsigned char*)pImage->GetData()); - buffers[image] = nullptr; - return image; + return std::make_shared(&PixelFormat::RGGB8, (int)pImage->GetWidth() / 2, (int)pImage->GetHeight() / 2, (unsigned char*)data); } void SpinnakerDriver::restore(const RawImage& image) { diff --git a/src/driver/spinnakerdriver.h b/src/driver/spinnakerdriver.h index af0d52b..276abb2 100644 --- a/src/driver/spinnakerdriver.h +++ b/src/driver/spinnakerdriver.h @@ -38,6 +38,7 @@ class SpinnakerDriver : public CameraDriver { Spinnaker::CameraPtr pCam; std::map, std::unique_ptr>> buffers; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) + size_t finalBufferSize_ = 0; // Allocated buffer size per frame, used for buffer matching in borrow() }; -#endif \ No newline at end of file +#endif From db8ba78b6682f534096df94e0ed9d9622f22f004 Mon Sep 17 00:00:00 2001 From: Tachiken <114806142+sin471@users.noreply.github.com> Date: Sat, 28 Feb 2026 16:20:02 +0900 Subject: [PATCH 2/6] Remove 4KB alignment --- src/driver/spinnakerdriver.cpp | 57 ++++++++++++++++++---------------- src/driver/spinnakerdriver.h | 12 +++++-- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/driver/spinnakerdriver.cpp b/src/driver/spinnakerdriver.cpp index 50c0cf2..64a03a4 100644 --- a/src/driver/spinnakerdriver.cpp +++ b/src/driver/spinnakerdriver.cpp @@ -18,18 +18,18 @@ #include "spinnakerdriver.h" #include #include +#include +#include #define CATCH_SPINNAKER(f) try { f; } catch (Spinnaker::Exception &e) { std::cerr << "[Spinnaker] Could not set parameter: " << e.GetFullErrorMessage() << std::endl; } constexpr int kMinBufferCount = 3; // Minimum buffer count required for NewestOnly mode constexpr size_t kUsb3PacketSize = 1024; // USB3 packet size alignment requirement -constexpr size_t kPageSize = 4096; // Page size alignment requirement for Meteor Lake static size_t alignUp(size_t size, size_t alignment) { return ((size + alignment - 1) / alignment) * alignment; } - class SpinnakerImage : public RawImage { public: SpinnakerImage(SpinnakerDriver& source, const Spinnaker::ImagePtr& pImage): RawImage(*source.borrow(pImage)), source(source), pImage(pImage) { @@ -134,22 +134,22 @@ SpinnakerDriver::SpinnakerDriver(const CameraConfig& config) { int height = (int)pCam->Height.GetValue(); size_t rawSize = (size_t)width * height; - // USB3 packet size alignment is required for zero copy - // https://www.intel.com/content/dam/develop/external/us/en/documents/opencl-zero-copy-in-opencl-1-2.pdf - finalBufferSize_ = alignUp(alignUp(rawSize, kUsb3PacketSize), kPageSize); + // Buffer size must be a multiple of USB3 packet size for stability + finalBufferSize_ = alignUp(rawSize, kUsb3PacketSize); std::vector bufferPtrs; for(int i = 0; i < requiredBuffers; i++) { void* alignedPtr = nullptr; - if (posix_memalign(&alignedPtr, kPageSize, finalBufferSize_) != 0) { + // Use alignment to satisfy Spinnaker SDK constraints + if (posix_memalign(&alignedPtr, kUsb3PacketSize, finalBufferSize_) != 0) { throw std::runtime_error("[Spinnaker] posix_memalign failed"); } - std::shared_ptr buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, (unsigned char*)alignedPtr); + auto buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, (unsigned char*)alignedPtr); - // Create OpenCL mapping - buffers[buffer] = std::make_unique>(buffer->write()); + // Map raw pointer to BufferContext to track ownership and OpenCL mappings + bufferPool[alignedPtr] = {buffer, std::make_unique>(buffer->write())}; bufferPtrs.push_back(alignedPtr); } @@ -157,7 +157,6 @@ SpinnakerDriver::SpinnakerDriver(const CameraConfig& config) { // Register user-owned buffers with the camera pCam->SetBufferOwnership(Spinnaker::SPINNAKER_BUFFER_OWNERSHIP_USER); pCam->SetUserBuffers(bufferPtrs.data(), bufferPtrs.size(), finalBufferSize_); - //pCam->Timestamp.SetValue(); if (IsWritable(pCam->GevSCPSPacketSize)) { CATCH_SPINNAKER(pCam->GevSCPSPacketSize.SetValue(9000)); @@ -179,23 +178,28 @@ double SpinnakerDriver::expectedFrametime() { } SpinnakerDriver::~SpinnakerDriver() { - pCam->EndAcquisition(); - pCam->DeInit(); + if (pCam) { + pCam->EndAcquisition(); + pCam->DeInit(); + } + + // Explicitly free memory allocated by posix_memalign to prevent leaks + for (auto& item : bufferPool) { + if (item.first != nullptr) { + free(item.first); + } + } + bufferPool.clear(); } std::shared_ptr SpinnakerDriver::borrow(const Spinnaker::ImagePtr& pImage) { void* data = pImage->GetData(); - for (auto& item : buffers) { - if(item.second != nullptr) { - void* bStart = static_cast(**item.second); - - void* bEnd = static_cast(bStart) + finalBufferSize_; - - if (data >= bStart && data < bEnd) { - item.second = nullptr; // Mark buffer as in use - return item.first; - } - } + + // Match by raw pointer to ensure we use the pre-allocated OpenCL-mapped buffer + auto it = bufferPool.find(data); + if (it != bufferPool.end() && it->second.clMap != nullptr) { + it->second.clMap = nullptr; // Mark buffer as in use + return it->second.image; } std::cerr << "[Spinnaker] Did not get image with given buffer, creating new buffer; expect OpenCL performance degradation" << std::endl; @@ -203,9 +207,10 @@ std::shared_ptr SpinnakerDriver::borrow(const Spinnaker::ImagePtr& pIm } void SpinnakerDriver::restore(const RawImage& image) { - for (auto& item : buffers) { - if(item.first->buffer == image.buffer) { - item.second = std::make_unique>(item.first->write()); + for (auto& item : bufferPool) { + if(item.second.image->buffer == image.buffer) { + // Restore mapping for future use + item.second.clMap = std::make_unique>(item.second.image->write()); return; } } diff --git a/src/driver/spinnakerdriver.h b/src/driver/spinnakerdriver.h index 276abb2..d883d07 100644 --- a/src/driver/spinnakerdriver.h +++ b/src/driver/spinnakerdriver.h @@ -19,6 +19,11 @@ #include "cameradriver.h" #include "Spinnaker.h" +struct BufferContext { + std::shared_ptr image; + std::unique_ptr> clMap; +}; + class SpinnakerDriver : public CameraDriver { public: explicit SpinnakerDriver(const CameraConfig& config); @@ -37,8 +42,9 @@ class SpinnakerDriver : public CameraDriver { Spinnaker::SystemPtr pSystem; Spinnaker::CameraPtr pCam; - std::map, std::unique_ptr>> buffers; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) - size_t finalBufferSize_ = 0; // Allocated buffer size per frame, used for buffer matching in borrow() + std::map bufferPool; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) + size_t finalBufferSize_ = 0; // Allocated buffer size per frame, used for buffer matching in borrow() + }; -#endif +#endif \ No newline at end of file From 48171d020b67e2dafac2261239797afdb83172d2 Mon Sep 17 00:00:00 2001 From: sin471 Date: Sat, 28 Feb 2026 17:58:00 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=E3=81=A8=E3=82=8A=E3=81=82=E3=81=88?= =?UTF-8?q?=E3=81=9A=E6=98=A0=E5=83=8F=E3=82=82=E5=8B=95=E3=81=84=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/driver/spinnakerdriver.cpp | 44 ++++++++++++++++------------------ src/driver/spinnakerdriver.h | 31 ++++++++++++------------ 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/src/driver/spinnakerdriver.cpp b/src/driver/spinnakerdriver.cpp index 64a03a4..ff30cf2 100644 --- a/src/driver/spinnakerdriver.cpp +++ b/src/driver/spinnakerdriver.cpp @@ -25,6 +25,7 @@ constexpr int kMinBufferCount = 3; // Minimum buffer count required for NewestOnly mode constexpr size_t kUsb3PacketSize = 1024; // USB3 packet size alignment requirement +constexpr size_t kPageSize = 4096; // Page size alignment requirement for Meteor Lake static size_t alignUp(size_t size, size_t alignment) { return ((size + alignment - 1) / alignment) * alignment; @@ -134,22 +135,23 @@ SpinnakerDriver::SpinnakerDriver(const CameraConfig& config) { int height = (int)pCam->Height.GetValue(); size_t rawSize = (size_t)width * height; - // Buffer size must be a multiple of USB3 packet size for stability - finalBufferSize_ = alignUp(rawSize, kUsb3PacketSize); + // Align to both USB3 packet and Page size for Meteor Lake stability/decoding + finalBufferSize_ = alignUp(alignUp(rawSize, kUsb3PacketSize), kPageSize); std::vector bufferPtrs; - for(int i = 0; i < requiredBuffers; i++) { void* alignedPtr = nullptr; - // Use alignment to satisfy Spinnaker SDK constraints - if (posix_memalign(&alignedPtr, kUsb3PacketSize, finalBufferSize_) != 0) { + if (posix_memalign(&alignedPtr, kPageSize, finalBufferSize_) != 0) { throw std::runtime_error("[Spinnaker] posix_memalign failed"); } + // Track pointer for explicit free() in destructor + m_allocatedPtrs.push_back(alignedPtr); + auto buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, (unsigned char*)alignedPtr); - // Map raw pointer to BufferContext to track ownership and OpenCL mappings - bufferPool[alignedPtr] = {buffer, std::make_unique>(buffer->write())}; + // Create OpenCL mapping + buffers[buffer] = std::make_unique>(buffer->write()); bufferPtrs.push_back(alignedPtr); } @@ -183,37 +185,31 @@ SpinnakerDriver::~SpinnakerDriver() { pCam->DeInit(); } - // Explicitly free memory allocated by posix_memalign to prevent leaks - for (auto& item : bufferPool) { - if (item.first != nullptr) { - free(item.first); - } + // Explicitly free memory to prevent leaks + for (void* ptr : m_allocatedPtrs) { + if (ptr) free(ptr); } - bufferPool.clear(); + m_allocatedPtrs.clear(); } - std::shared_ptr SpinnakerDriver::borrow(const Spinnaker::ImagePtr& pImage) { void* data = pImage->GetData(); - // Match by raw pointer to ensure we use the pre-allocated OpenCL-mapped buffer - auto it = bufferPool.find(data); - if (it != bufferPool.end() && it->second.clMap != nullptr) { - it->second.clMap = nullptr; // Mark buffer as in use + auto it = m_fastBufferPool.find(data); + if (it != m_fastBufferPool.end() && it->second.clMap != nullptr) { + it->second.clMap = nullptr; // 使用中にマーク return it->second.image; } - std::cerr << "[Spinnaker] Did not get image with given buffer, creating new buffer; expect OpenCL performance degradation" << std::endl; return std::make_shared(&PixelFormat::RGGB8, (int)pImage->GetWidth() / 2, (int)pImage->GetHeight() / 2, (unsigned char*)data); } void SpinnakerDriver::restore(const RawImage& image) { - for (auto& item : bufferPool) { - if(item.second.image->buffer == image.buffer) { - // Restore mapping for future use - item.second.clMap = std::make_unique>(item.second.image->write()); + for (auto& item : buffers) { + if(item.first->buffer == image.buffer) { + item.second = std::make_unique>(item.first->write()); return; } } } -#endif +#endif \ No newline at end of file diff --git a/src/driver/spinnakerdriver.h b/src/driver/spinnakerdriver.h index d883d07..2966353 100644 --- a/src/driver/spinnakerdriver.h +++ b/src/driver/spinnakerdriver.h @@ -19,32 +19,33 @@ #include "cameradriver.h" #include "Spinnaker.h" +// 生のポインタアドレス -> {RawImage, CLMap} の対応表 struct BufferContext { std::shared_ptr image; std::unique_ptr> clMap; }; - class SpinnakerDriver : public CameraDriver { -public: - explicit SpinnakerDriver(const CameraConfig& config); - ~SpinnakerDriver() override; + public: + explicit SpinnakerDriver(const CameraConfig& config); + ~SpinnakerDriver() override; - std::shared_ptr readImage() override; + std::shared_ptr readImage() override; - const PixelFormat format() override; + const PixelFormat format() override; - double expectedFrametime() override; + double expectedFrametime() override; - std::shared_ptr borrow(const Spinnaker::ImagePtr& pImage); - void restore(const RawImage& image); + std::shared_ptr borrow(const Spinnaker::ImagePtr& pImage); + void restore(const RawImage& image); -private: - Spinnaker::SystemPtr pSystem; - Spinnaker::CameraPtr pCam; + private: + Spinnaker::SystemPtr pSystem; + Spinnaker::CameraPtr pCam; - std::map bufferPool; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) + std::map, std::unique_ptr>> buffers; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) size_t finalBufferSize_ = 0; // Allocated buffer size per frame, used for buffer matching in borrow() - + std::vector m_allocatedPtrs; + std::map m_fastBufferPool; }; -#endif \ No newline at end of file +#endif From 50d3d0b625e880d02000b1db1aaa22a73caad441 Mon Sep 17 00:00:00 2001 From: sin471 Date: Sat, 28 Feb 2026 20:36:36 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=E3=83=AD=E3=83=9C=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=81=A8=E3=83=9C=E3=83=BC=E3=83=AB=E3=82=92=E6=A4=9C=E5=87=BA?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=8B=E3=81=A3=E3=81=9F=E3=81=AE?= =?UTF-8?q?=E3=81=A7=E6=88=BB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/driver/spinnakerdriver.cpp | 80 +++++++++++++++++----------------- src/driver/spinnakerdriver.h | 31 +++++++------ src/main.cpp | 1 + 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/driver/spinnakerdriver.cpp b/src/driver/spinnakerdriver.cpp index ff30cf2..324605c 100644 --- a/src/driver/spinnakerdriver.cpp +++ b/src/driver/spinnakerdriver.cpp @@ -1,12 +1,9 @@ /* Copyright 2024 Felix Weinmann - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,18 +15,9 @@ #include "spinnakerdriver.h" #include #include -#include -#include #define CATCH_SPINNAKER(f) try { f; } catch (Spinnaker::Exception &e) { std::cerr << "[Spinnaker] Could not set parameter: " << e.GetFullErrorMessage() << std::endl; } -constexpr int kMinBufferCount = 3; // Minimum buffer count required for NewestOnly mode -constexpr size_t kUsb3PacketSize = 1024; // USB3 packet size alignment requirement -constexpr size_t kPageSize = 4096; // Page size alignment requirement for Meteor Lake - -static size_t alignUp(size_t size, size_t alignment) { - return ((size + alignment - 1) / alignment) * alignment; -} class SpinnakerImage : public RawImage { public: @@ -124,41 +112,50 @@ SpinnakerDriver::SpinnakerDriver(const CameraConfig& config) { CATCH_SPINNAKER(pCam->BalanceRatio.SetValue(config.whiteBalanceRed)) } + // 4. 【重要】ストリーム設定とバッファ計算 pCam->TLStream.StreamBufferHandlingMode.SetValue(Spinnaker::StreamBufferHandlingMode_NewestOnly); - // NewestOnly mode requires at least kMinBufferCount buffers - int requiredBuffers = std::max(kMinBufferCount, (int)pCam->TLStream.StreamBufferCountManual.GetMin()); + // ドキュメント指定: NewestOnly の場合は最低 3 枚必要 + int requiredBuffers = std::max(3, (int)pCam->TLStream.StreamBufferCountManual.GetMin()); pCam->TLStream.StreamBufferCountManual.SetValue(requiredBuffers); // Provide image buffers to achieve faster mapping with OpenCL - int width = (int)pCam->Width.GetValue(); + int width = (int)pCam->Width.GetValue(); int height = (int)pCam->Height.GetValue(); size_t rawSize = (size_t)width * height; - // Align to both USB3 packet and Page size for Meteor Lake stability/decoding - finalBufferSize_ = alignUp(alignUp(rawSize, kUsb3PacketSize), kPageSize); + // ドキュメント指定: USB3パケットサイズ(1024)の倍数に切り上げ + size_t usb3AlignedSize = ((rawSize + 1024 - 1) / 1024) * 1024; + // Meteor Lake 要求: 4KB(4096)境界にさらに切り上げ + size_t finalBufferSize = (usb3AlignedSize + 4095) & ~4095; + if(config.autoGain()) { + CATCH_SPINNAKER(pCam->GainAuto.SetValue(Spinnaker::GainAuto_Continuous)) + } else { + CATCH_SPINNAKER(pCam->GainAuto.SetValue(Spinnaker::GainAuto_Off)) + CATCH_SPINNAKER(pCam->Gain.SetValue(config.gain)) + } std::vector bufferPtrs; + for(int i = 0; i < requiredBuffers; i++) { void* alignedPtr = nullptr; - if (posix_memalign(&alignedPtr, kPageSize, finalBufferSize_) != 0) { + if (posix_memalign(&alignedPtr, 4096, finalBufferSize) != 0) { throw std::runtime_error("[Spinnaker] posix_memalign failed"); } - // Track pointer for explicit free() in destructor - m_allocatedPtrs.push_back(alignedPtr); - - auto buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, (unsigned char*)alignedPtr); + std::shared_ptr buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, (unsigned char*)alignedPtr); - // Create OpenCL mapping + // OpenCLマッピングを作成 buffers[buffer] = std::make_unique>(buffer->write()); + // カメラに渡すリストに追加 bufferPtrs.push_back(alignedPtr); } - // Register user-owned buffers with the camera + // ユーザーバッファの登録 pCam->SetBufferOwnership(Spinnaker::SPINNAKER_BUFFER_OWNERSHIP_USER); - pCam->SetUserBuffers(bufferPtrs.data(), bufferPtrs.size(), finalBufferSize_); + pCam->SetUserBuffers(bufferPtrs.data(), bufferPtrs.size(), finalBufferSize); + //pCam->Timestamp.SetValue(); if (IsWritable(pCam->GevSCPSPacketSize)) { CATCH_SPINNAKER(pCam->GevSCPSPacketSize.SetValue(9000)); @@ -180,26 +177,29 @@ double SpinnakerDriver::expectedFrametime() { } SpinnakerDriver::~SpinnakerDriver() { - if (pCam) { - pCam->EndAcquisition(); - pCam->DeInit(); - } - - // Explicitly free memory to prevent leaks - for (void* ptr : m_allocatedPtrs) { - if (ptr) free(ptr); - } - m_allocatedPtrs.clear(); + pCam->EndAcquisition(); + pCam->DeInit(); } + std::shared_ptr SpinnakerDriver::borrow(const Spinnaker::ImagePtr& pImage) { void* data = pImage->GetData(); - - auto it = m_fastBufferPool.find(data); - if (it != m_fastBufferPool.end() && it->second.clMap != nullptr) { - it->second.clMap = nullptr; // 使用中にマーク - return it->second.image; + for (auto& item : buffers) { + if(item.second != nullptr) { + // item.first->write() を呼ぶと CLMap オブジェクトが返るため、 + // そのオブジェクトが保持しているポインタを ** で取り出す + void* bStart = static_cast(**item.second); + + // 4KB(1ページ)の範囲内であれば同一バッファとみなす + void* bEnd = static_cast(bStart) + 4096; + + if (data >= bStart && data < bEnd) { + item.second = nullptr; // 貸出中マーク + return item.first; + } + } } + // 一致しなかった場合のフォールバック return std::make_shared(&PixelFormat::RGGB8, (int)pImage->GetWidth() / 2, (int)pImage->GetHeight() / 2, (unsigned char*)data); } diff --git a/src/driver/spinnakerdriver.h b/src/driver/spinnakerdriver.h index 2966353..a92f543 100644 --- a/src/driver/spinnakerdriver.h +++ b/src/driver/spinnakerdriver.h @@ -19,33 +19,32 @@ #include "cameradriver.h" #include "Spinnaker.h" -// 生のポインタアドレス -> {RawImage, CLMap} の対応表 struct BufferContext { std::shared_ptr image; std::unique_ptr> clMap; }; + class SpinnakerDriver : public CameraDriver { - public: - explicit SpinnakerDriver(const CameraConfig& config); - ~SpinnakerDriver() override; +public: + explicit SpinnakerDriver(const CameraConfig& config); + ~SpinnakerDriver() override; - std::shared_ptr readImage() override; + std::shared_ptr readImage() override; - const PixelFormat format() override; + const PixelFormat format() override; - double expectedFrametime() override; + double expectedFrametime() override; - std::shared_ptr borrow(const Spinnaker::ImagePtr& pImage); - void restore(const RawImage& image); + std::shared_ptr borrow(const Spinnaker::ImagePtr& pImage); + void restore(const RawImage& image); - private: - Spinnaker::SystemPtr pSystem; - Spinnaker::CameraPtr pCam; +private: + Spinnaker::SystemPtr pSystem; + Spinnaker::CameraPtr pCam; - std::map, std::unique_ptr>> buffers; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) + std::map,std::unique_ptr>> buffers; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) size_t finalBufferSize_ = 0; // Allocated buffer size per frame, used for buffer matching in borrow() - std::vector m_allocatedPtrs; - std::map m_fastBufferPool; + }; -#endif +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 5523b9c..e4de0a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -421,6 +421,7 @@ int main(int argc, char* argv[]) { #else detection->set_t_sent(r.camera->getTime()); #endif + std::cout << wrapper.DebugString() << std::endl; r.socket->send(wrapper); r.socket->updateTime(); r.openCl->clearEvents(); From 9ee6355713e522103a76eda66579b611bd39bee6 Mon Sep 17 00:00:00 2001 From: sin471 Date: Sat, 28 Feb 2026 20:51:35 +0900 Subject: [PATCH 5/6] =?UTF-8?q?4KB=E3=82=A2=E3=83=A9=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=83=A1=E3=83=B3=E3=83=88=E3=81=AA=E3=81=97=E3=81=A7=E6=A4=9C?= =?UTF-8?q?=E5=87=BA=E3=81=A7=E3=81=8D=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/driver/spinnakerdriver.cpp | 80 +++++++++++++++++----------------- src/driver/spinnakerdriver.h | 31 ++++++------- 2 files changed, 56 insertions(+), 55 deletions(-) diff --git a/src/driver/spinnakerdriver.cpp b/src/driver/spinnakerdriver.cpp index 324605c..38a182b 100644 --- a/src/driver/spinnakerdriver.cpp +++ b/src/driver/spinnakerdriver.cpp @@ -1,9 +1,12 @@ /* Copyright 2024 Felix Weinmann + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,9 +18,18 @@ #include "spinnakerdriver.h" #include #include +#include +#include #define CATCH_SPINNAKER(f) try { f; } catch (Spinnaker::Exception &e) { std::cerr << "[Spinnaker] Could not set parameter: " << e.GetFullErrorMessage() << std::endl; } +constexpr int kMinBufferCount = 3; // Minimum buffer count required for NewestOnly mode +constexpr size_t kUsb3PacketSize = 1024; // USB3 packet size alignment requirement +// constexpr size_t kPageSize = 4096; // Page size alignment requirement for Meteor Lake + +static size_t alignUp(size_t size, size_t alignment) { + return ((size + alignment - 1) / alignment) * alignment; +} class SpinnakerImage : public RawImage { public: @@ -112,50 +124,41 @@ SpinnakerDriver::SpinnakerDriver(const CameraConfig& config) { CATCH_SPINNAKER(pCam->BalanceRatio.SetValue(config.whiteBalanceRed)) } - // 4. 【重要】ストリーム設定とバッファ計算 pCam->TLStream.StreamBufferHandlingMode.SetValue(Spinnaker::StreamBufferHandlingMode_NewestOnly); - // ドキュメント指定: NewestOnly の場合は最低 3 枚必要 - int requiredBuffers = std::max(3, (int)pCam->TLStream.StreamBufferCountManual.GetMin()); + // NewestOnly mode requires at least kMinBufferCount buffers + int requiredBuffers = std::max(kMinBufferCount, (int)pCam->TLStream.StreamBufferCountManual.GetMin()); pCam->TLStream.StreamBufferCountManual.SetValue(requiredBuffers); // Provide image buffers to achieve faster mapping with OpenCL - int width = (int)pCam->Width.GetValue(); + int width = (int)pCam->Width.GetValue(); int height = (int)pCam->Height.GetValue(); size_t rawSize = (size_t)width * height; - // ドキュメント指定: USB3パケットサイズ(1024)の倍数に切り上げ - size_t usb3AlignedSize = ((rawSize + 1024 - 1) / 1024) * 1024; - // Meteor Lake 要求: 4KB(4096)境界にさらに切り上げ - size_t finalBufferSize = (usb3AlignedSize + 4095) & ~4095; + // Align to both USB3 packet and Page size for Meteor Lake stability/decoding + finalBufferSize_ = alignUp(rawSize, kUsb3PacketSize); - if(config.autoGain()) { - CATCH_SPINNAKER(pCam->GainAuto.SetValue(Spinnaker::GainAuto_Continuous)) - } else { - CATCH_SPINNAKER(pCam->GainAuto.SetValue(Spinnaker::GainAuto_Off)) - CATCH_SPINNAKER(pCam->Gain.SetValue(config.gain)) - } std::vector bufferPtrs; - for(int i = 0; i < requiredBuffers; i++) { void* alignedPtr = nullptr; - if (posix_memalign(&alignedPtr, 4096, finalBufferSize) != 0) { + if (posix_memalign(&alignedPtr, kUsb3PacketSize, finalBufferSize_) != 0) { throw std::runtime_error("[Spinnaker] posix_memalign failed"); } - std::shared_ptr buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, (unsigned char*)alignedPtr); + // Track pointer for explicit free() in destructor + m_allocatedPtrs.push_back(alignedPtr); + + auto buffer = std::make_shared(&PixelFormat::RGGB8, width/2, height/2, (unsigned char*)alignedPtr); - // OpenCLマッピングを作成 + // Create OpenCL mapping buffers[buffer] = std::make_unique>(buffer->write()); - // カメラに渡すリストに追加 bufferPtrs.push_back(alignedPtr); } - // ユーザーバッファの登録 + // Register user-owned buffers with the camera pCam->SetBufferOwnership(Spinnaker::SPINNAKER_BUFFER_OWNERSHIP_USER); - pCam->SetUserBuffers(bufferPtrs.data(), bufferPtrs.size(), finalBufferSize); - //pCam->Timestamp.SetValue(); + pCam->SetUserBuffers(bufferPtrs.data(), bufferPtrs.size(), finalBufferSize_); if (IsWritable(pCam->GevSCPSPacketSize)) { CATCH_SPINNAKER(pCam->GevSCPSPacketSize.SetValue(9000)); @@ -177,29 +180,26 @@ double SpinnakerDriver::expectedFrametime() { } SpinnakerDriver::~SpinnakerDriver() { - pCam->EndAcquisition(); - pCam->DeInit(); -} + if (pCam) { + pCam->EndAcquisition(); + pCam->DeInit(); + } + // Explicitly free memory to prevent leaks + for (void* ptr : m_allocatedPtrs) { + if (ptr) free(ptr); + } + m_allocatedPtrs.clear(); +} std::shared_ptr SpinnakerDriver::borrow(const Spinnaker::ImagePtr& pImage) { void* data = pImage->GetData(); - for (auto& item : buffers) { - if(item.second != nullptr) { - // item.first->write() を呼ぶと CLMap オブジェクトが返るため、 - // そのオブジェクトが保持しているポインタを ** で取り出す - void* bStart = static_cast(**item.second); - - // 4KB(1ページ)の範囲内であれば同一バッファとみなす - void* bEnd = static_cast(bStart) + 4096; - - if (data >= bStart && data < bEnd) { - item.second = nullptr; // 貸出中マーク - return item.first; - } - } + + auto it = m_fastBufferPool.find(data); + if (it != m_fastBufferPool.end() && it->second.clMap != nullptr) { + it->second.clMap = nullptr; // 使用中にマーク + return it->second.image; } - // 一致しなかった場合のフォールバック return std::make_shared(&PixelFormat::RGGB8, (int)pImage->GetWidth() / 2, (int)pImage->GetHeight() / 2, (unsigned char*)data); } diff --git a/src/driver/spinnakerdriver.h b/src/driver/spinnakerdriver.h index a92f543..2966353 100644 --- a/src/driver/spinnakerdriver.h +++ b/src/driver/spinnakerdriver.h @@ -19,32 +19,33 @@ #include "cameradriver.h" #include "Spinnaker.h" +// 生のポインタアドレス -> {RawImage, CLMap} の対応表 struct BufferContext { std::shared_ptr image; std::unique_ptr> clMap; }; - class SpinnakerDriver : public CameraDriver { -public: - explicit SpinnakerDriver(const CameraConfig& config); - ~SpinnakerDriver() override; + public: + explicit SpinnakerDriver(const CameraConfig& config); + ~SpinnakerDriver() override; - std::shared_ptr readImage() override; + std::shared_ptr readImage() override; - const PixelFormat format() override; + const PixelFormat format() override; - double expectedFrametime() override; + double expectedFrametime() override; - std::shared_ptr borrow(const Spinnaker::ImagePtr& pImage); - void restore(const RawImage& image); + std::shared_ptr borrow(const Spinnaker::ImagePtr& pImage); + void restore(const RawImage& image); -private: - Spinnaker::SystemPtr pSystem; - Spinnaker::CameraPtr pCam; + private: + Spinnaker::SystemPtr pSystem; + Spinnaker::CameraPtr pCam; - std::map,std::unique_ptr>> buffers; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) + std::map, std::unique_ptr>> buffers; // Use own image buffers for page size alignment (OpenCL pinned memory and zero copy) size_t finalBufferSize_ = 0; // Allocated buffer size per frame, used for buffer matching in borrow() - + std::vector m_allocatedPtrs; + std::map m_fastBufferPool; }; -#endif \ No newline at end of file +#endif From 475f51f230fb089b1c954616bd50476d866bc699 Mon Sep 17 00:00:00 2001 From: sin471 Date: Sat, 28 Feb 2026 22:35:11 +0900 Subject: [PATCH 6/6] Translate to English --- src/driver/spinnakerdriver.cpp | 4 ++-- src/driver/spinnakerdriver.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/driver/spinnakerdriver.cpp b/src/driver/spinnakerdriver.cpp index 38a182b..c58f413 100644 --- a/src/driver/spinnakerdriver.cpp +++ b/src/driver/spinnakerdriver.cpp @@ -196,7 +196,7 @@ std::shared_ptr SpinnakerDriver::borrow(const Spinnaker::ImagePtr& pIm auto it = m_fastBufferPool.find(data); if (it != m_fastBufferPool.end() && it->second.clMap != nullptr) { - it->second.clMap = nullptr; // 使用中にマーク + it->second.clMap = nullptr; // mark as in use return it->second.image; } @@ -212,4 +212,4 @@ void SpinnakerDriver::restore(const RawImage& image) { } } -#endif \ No newline at end of file +#endif diff --git a/src/driver/spinnakerdriver.h b/src/driver/spinnakerdriver.h index 2966353..bdaa22a 100644 --- a/src/driver/spinnakerdriver.h +++ b/src/driver/spinnakerdriver.h @@ -19,7 +19,7 @@ #include "cameradriver.h" #include "Spinnaker.h" -// 生のポインタアドレス -> {RawImage, CLMap} の対応表 +// Map raw pointer addresses to corresponding {RawImage, CLMap} context struct BufferContext { std::shared_ptr image; std::unique_ptr> clMap;