12#include "libavutil/log.h"
13#define FFNV_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_ERROR, msg, __VA_ARGS__)
14#define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_DEBUG, msg, __VA_ARGS__)
15#include <ffnvcodec/dynlink_loader.h>
18#define LOC QString("NVDECInterop: ")
21#define CUDA_CHECK(CUDA_FUNCS, CUDA_CALL) \
23 CUresult res = (CUDA_FUNCS)->CUDA_CALL; \
24 if (res != CUDA_SUCCESS) { \
26 (CUDA_FUNCS)->cuGetErrorString(res, &desc); \
27 LOG(VB_GENERAL, LOG_ERR, LOC + QString("CUDA error %1 (%2)").arg(res).arg(desc)); \
54 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Deleting CUDA resources");
57 std::vector<MythVideoTextureOpenGL*> textures = it.value();
58 for (
auto & texture : textures)
60 auto *data =
reinterpret_cast<QPair<CUarray,CUgraphicsResource>*
>(texture->m_data);
61 if (data && data->second)
64 texture->m_data =
nullptr;
69 CUcontext dummy =
nullptr;
95 if (std::any_of(nvdec->second.cbegin(), nvdec->second.cend(), matchType))
114std::vector<MythVideoTextureOpenGL*>
120 std::vector<MythVideoTextureOpenGL*> result;
125 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Mismatched OpenGL contexts");
128 QSize surfacesize(
Frame->m_width,
Frame->m_height);
133 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"Video texture size changed! %1x%2->%3x%4")
159 auto cudabuffer =
reinterpret_cast<CUdeviceptr
>(
Frame->m_buffer);
164 CUcontext dummy =
nullptr;
173 std::vector<QSize> sizes;
174 sizes.emplace_back(
Frame->m_width,
Frame->m_height);
175 sizes.emplace_back(
Frame->m_width,
Frame->m_height >> 1);
176 std::vector<MythVideoTextureOpenGL*> textures =
178 if (textures.empty())
185 for (
uint plane = 0; plane < textures.size(); ++plane)
192 QOpenGLTexture::PixelFormat format = QOpenGLTexture::Red;
193 QOpenGLTexture::PixelType pixtype = p010 ? QOpenGLTexture::UInt16 : QOpenGLTexture::UInt8;
194 QOpenGLTexture::TextureFormat internal = p010 ? QOpenGLTexture::R16_UNorm : QOpenGLTexture::R8_UNorm;
195 int width = tex->
m_size.width();
199 internal = p010 ? QOpenGLTexture::RG16_UNorm : QOpenGLTexture::RG8_UNorm;
200 format = QOpenGLTexture::RG;
205 0, format, pixtype,
nullptr);
207 CUarray array =
nullptr;
208 CUgraphicsResource graphicsResource =
nullptr;
210 QOpenGLTexture::Target2D, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD))
211 if (graphicsResource)
216 tex->
m_data =
reinterpret_cast<unsigned char*
>(
new QPair<CUarray,CUgraphicsResource>(array, graphicsResource));
231 for (
auto & texture : textures)
233 auto *data =
reinterpret_cast<QPair<CUarray,CUgraphicsResource>*
>(texture->m_data);
234 if (data && data->second)
237 texture->m_data =
nullptr;
238 if (texture->m_textureId)
256 for (
uint i = 0; i < result.size(); ++i)
258 auto *data =
reinterpret_cast<QPair<CUarray,CUgraphicsResource>*
>(result[i]->m_data);
260 memset(&cpy, 0,
sizeof(cpy));
261 cpy.srcMemoryType = CU_MEMORYTYPE_DEVICE;
262 cpy.srcDevice = cudabuffer +
static_cast<CUdeviceptr
>(
Frame->m_offsets[i]);
263 cpy.srcPitch =
static_cast<size_t>(
Frame->m_pitches[i]);
264 cpy.dstMemoryType = CU_MEMORYTYPE_ARRAY;
265 cpy.dstArray = data->first;
266 cpy.WidthInBytes =
static_cast<size_t>(result[i]->m_size.width()) * (p010 ? 2 : 1);
267 cpy.Height =
static_cast<size_t>(result[i]->m_size.height());
276 bool needreferences =
false;
301 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Reference frame error");
326 CUcontext& CudaContext,
bool& Retry)
336 if (cuda_load_functions(&CudaFuncs,
nullptr) != 0)
338 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
"Failed to load functions");
343 CUdevice cudevice = 0;
344 CUcontext dummy =
nullptr;
345 CUresult res = CudaFuncs->cuInit(0);
346 if (res != CUDA_SUCCESS)
348 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to initialise CUDA API");
352 unsigned int devicecount = 0;
353 res = CudaFuncs->cuGLGetDevices(&devicecount, &cudevice, 1, CU_GL_DEVICE_LIST_ALL);
354 if (res != CUDA_SUCCESS)
356 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to get CUDA device");
362 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No CUDA devices");
366 res = CudaFuncs->cuCtxCreate(&CudaContext, CU_CTX_SCHED_BLOCKING_SYNC, cudevice);
367 if (res != CUDA_SUCCESS)
369 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to create CUDA context (Err: %1)")
375 CudaFuncs->cuCtxPopCurrent(&dummy);
376 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Created CUDA context");
381 CUcontext& CudaContext)
385 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Must create CUDA context from main thread");
391 while (retries++ < 5)
398 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Will retry in 50ms");
399 std::this_thread::sleep_for(50ms);
405 CUcontext& CudaContext)
414 CUDA_CHECK(CudaFuncs, cuCtxDestroy(CudaContext))
415 cuda_free_functions(&CudaFuncs);
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
uint64_t m_discontinuityCounter
std::map< VideoFrameType, InteropTypes > InteropMap
std::vector< MythVideoTextureOpenGL * > Acquire(MythRenderOpenGL *Context, MythVideoColourSpace *ColourSpace, MythVideoFrame *Frame, FrameScanType Scan) override
Map CUDA video memory to OpenGL textures.
CUcontext GetCUDAContext()
static bool CreateCUDAPriv(MythRenderOpenGL *GLContext, CudaFunctions *&CudaFuncs, CUcontext &CudaContext, bool &Retry)
bool InitialiseCuda()
Initialise a CUDA context.
CudaFunctions * m_cudaFuncs
MythNVDECInterop(MythPlayerUI *Player, MythRenderOpenGL *Context)
static bool CreateCUDAContext(MythRenderOpenGL *GLContext, CudaFunctions *&CudaFuncs, CUcontext &CudaContext)
~MythNVDECInterop() override
void RotateReferenceFrames(CUdeviceptr Buffer)
static MythNVDECInterop * CreateNVDEC(MythPlayerUI *Player, MythRenderOpenGL *Context)
static void GetNVDECTypes(MythRenderOpenGL *Render, MythInteropGPU::InteropMap &Types)
void DeleteTextures() override
QVector< CUdeviceptr > m_referenceFrames
static void CleanupContext(MythRenderOpenGL *GLContext, CudaFunctions *&CudaFuncs, CUcontext &CudaContext)
virtual void DeleteTextures()
MythRenderOpenGL * m_openglContext
QHash< unsigned long long, std::vector< MythVideoTextureOpenGL * > > m_openglTextures
MythVideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
void SetSupportedAttributes(PictureAttributeSupported Supported)
Enable the given set of picture attributes.
bool UpdateColourSpace(const MythVideoFrame *Frame)
Set the current colourspace to use.
static int ColorDepth(int Format)
static std::vector< MythVideoTextureOpenGL * > CreateTextures(MythRenderOpenGL *Context, VideoFrameType Type, VideoFrameType Format, std::vector< QSize > Sizes, GLenum Target=QOpenGLTexture::Target2D)
Create a set of textures suitable for the given Type and Format.
static void DeleteTexture(MythRenderOpenGL *Context, MythVideoTextureOpenGL *Texture)
static const struct wl_interface * types[]
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
#define CUDA_CHECK(CUDA_FUNCS, CUDA_CALL)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
bool is_interlaced(FrameScanType Scan)
#define ALL_PICTURE_ATTRIBUTES