/* RAII обёртки над CUDA Driver/Runtime ресурсами (Phase 11b). * * Передача handle'ов между объектами по-прежнему zero-copy (CUdeviceptr — * это unsigned long long; обмен идентичен plain C-коду). Эти обёртки только * автоматизируют lifetime — без них приходилось бы вручную помнить про * cuMemFree и закрывать stream'ы в путях ошибок. * * NB: классы non-copyable (чтобы не вызвать двойной cuMemFree), но movable. * * Лицензия: LGPL-2.1+ */ #ifndef CUFRAMES_COMPOSER_CPP_CUDA_RAII_HPP #define CUFRAMES_COMPOSER_CPP_CUDA_RAII_HPP #include #include #include namespace cfc { /* VMM-allocated NV12 буфер для output / staging. Используется и compose, * и NVENC (через тот же CUdeviceptr — zero-copy). */ class CudaBuffer { public: CudaBuffer() = default; /* Аллокация в ctor; бросать исключения не хочется — проверяем ok(). */ explicit CudaBuffer(std::size_t bytes) { if (cuMemAlloc(&ptr_, bytes) == CUDA_SUCCESS) { size_ = bytes; } } ~CudaBuffer() { reset(); } CudaBuffer(const CudaBuffer&) = delete; CudaBuffer& operator=(const CudaBuffer&) = delete; CudaBuffer(CudaBuffer&& other) noexcept : ptr_(other.ptr_), size_(other.size_) { other.ptr_ = 0; other.size_ = 0; } CudaBuffer& operator=(CudaBuffer&& other) noexcept { if (this != &other) { reset(); ptr_ = other.ptr_; size_ = other.size_; other.ptr_ = 0; other.size_ = 0; } return *this; } void reset() noexcept { if (ptr_) { cuMemFree(ptr_); ptr_ = 0; size_ = 0; } } CUdeviceptr ptr() const noexcept { return ptr_; } std::size_t size() const noexcept { return size_; } bool ok() const noexcept { return ptr_ != 0; } private: CUdeviceptr ptr_ = 0; std::size_t size_ = 0; }; /* CUDA stream — owner. Композитор использует default stream (Phase 2/3), * но обёртка готова к stream-pipelining (Phase 12+). */ class CudaStream { public: CudaStream() = default; /* Создать non-default stream. */ static CudaStream create() { CudaStream s; cudaStreamCreate(&s.stream_); s.owned_ = (s.stream_ != nullptr); return s; } /* Обёртка над уже существующим stream'ом (не владеет). */ static CudaStream wrap(cudaStream_t s) noexcept { CudaStream w; w.stream_ = s; w.owned_ = false; return w; } ~CudaStream() { reset(); } CudaStream(const CudaStream&) = delete; CudaStream& operator=(const CudaStream&) = delete; CudaStream(CudaStream&& other) noexcept : stream_(other.stream_), owned_(other.owned_) { other.stream_ = nullptr; other.owned_ = false; } CudaStream& operator=(CudaStream&& other) noexcept { if (this != &other) { reset(); stream_ = other.stream_; owned_ = other.owned_; other.stream_ = nullptr; other.owned_ = false; } return *this; } void reset() noexcept { if (owned_ && stream_) { cudaStreamDestroy(stream_); } stream_ = nullptr; owned_ = false; } cudaStream_t handle() const noexcept { return stream_; } CUstream cu_handle() const noexcept { return reinterpret_cast(stream_); } private: cudaStream_t stream_ = nullptr; bool owned_ = false; }; } // namespace cfc #endif /* CUFRAMES_COMPOSER_CPP_CUDA_RAII_HPP */