2 #include "libmythbase/mythconfig.h"
13 #include "libavutil/log.h"
14 #define FFNV_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_ERROR, msg, __VA_ARGS__)
15 #define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_DEBUG, msg, __VA_ARGS__)
16 #include <ffnvcodec/dynlink_loader.h>
19 #define LOC QString("NVDECInterop: ")
22 #define CUDA_CHECK(CUDA_FUNCS, CUDA_CALL) \
24 CUresult res = (CUDA_FUNCS)->CUDA_CALL; \
25 if (res != CUDA_SUCCESS) { \
27 (CUDA_FUNCS)->cuGetErrorString(res, &desc); \
28 LOG(VB_GENERAL, LOG_ERR, LOC + QString("CUDA error %1 (%2)").arg(res).arg(desc)); \
55 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Deleting CUDA resources");
58 std::vector<MythVideoTextureOpenGL*> textures = it.value();
59 for (
auto & texture : textures)
61 auto *data =
reinterpret_cast<QPair<CUarray,CUgraphicsResource>*
>(texture->m_data);
62 if (data && data->second)
65 texture->m_data =
nullptr;
70 CUcontext dummy =
nullptr;
96 if (std::any_of(nvdec->second.cbegin(), nvdec->second.cend(), matchType))
115 std::vector<MythVideoTextureOpenGL*>
121 std::vector<MythVideoTextureOpenGL*> result;
126 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Mismatched OpenGL contexts");
129 QSize surfacesize(
Frame->m_width,
Frame->m_height);
134 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"Video texture size changed! %1x%2->%3x%4")
160 auto cudabuffer =
reinterpret_cast<CUdeviceptr
>(
Frame->m_buffer);
165 CUcontext dummy =
nullptr;
174 std::vector<QSize> sizes;
175 sizes.emplace_back(
Frame->m_width,
Frame->m_height);
176 sizes.emplace_back(
Frame->m_width,
Frame->m_height >> 1);
177 std::vector<MythVideoTextureOpenGL*> textures =
179 if (textures.empty())
186 for (
uint plane = 0; plane < textures.size(); ++plane)
193 QOpenGLTexture::PixelFormat format = QOpenGLTexture::Red;
194 QOpenGLTexture::PixelType pixtype = p010 ? QOpenGLTexture::UInt16 : QOpenGLTexture::UInt8;
195 QOpenGLTexture::TextureFormat
internal = p010 ? QOpenGLTexture::R16_UNorm : QOpenGLTexture::R8_UNorm;
196 int width = tex->
m_size.width();
200 internal = p010 ? QOpenGLTexture::RG16_UNorm : QOpenGLTexture::RG8_UNorm;
201 format = QOpenGLTexture::RG;
206 0, format, pixtype,
nullptr);
208 CUarray array =
nullptr;
209 CUgraphicsResource graphicsResource =
nullptr;
211 QOpenGLTexture::Target2D, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD))
212 if (graphicsResource)
217 tex->
m_data =
reinterpret_cast<unsigned char*
>(
new QPair<CUarray,CUgraphicsResource>(array, graphicsResource));
232 for (
auto & texture : textures)
234 auto *data =
reinterpret_cast<QPair<CUarray,CUgraphicsResource>*
>(texture->m_data);
235 if (data && data->second)
238 texture->m_data =
nullptr;
239 if (texture->m_textureId)
257 for (
uint i = 0; i < result.size(); ++i)
259 auto *data =
reinterpret_cast<QPair<CUarray,CUgraphicsResource>*
>(result[i]->m_data);
261 memset(&cpy, 0,
sizeof(cpy));
262 cpy.srcMemoryType = CU_MEMORYTYPE_DEVICE;
263 cpy.srcDevice = cudabuffer +
static_cast<CUdeviceptr
>(
Frame->m_offsets[i]);
264 cpy.srcPitch =
static_cast<size_t>(
Frame->m_pitches[i]);
265 cpy.dstMemoryType = CU_MEMORYTYPE_ARRAY;
266 cpy.dstArray = data->first;
267 cpy.WidthInBytes =
static_cast<size_t>(result[i]->m_size.width()) * (p010 ? 2 : 1);
268 cpy.Height =
static_cast<size_t>(result[i]->m_size.height());
277 bool needreferences =
false;
302 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Reference frame error");
327 CUcontext& CudaContext,
bool& Retry)
337 if (cuda_load_functions(&CudaFuncs,
nullptr) != 0)
339 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
"Failed to load functions");
344 CUdevice cudevice = 0;
345 CUcontext dummy =
nullptr;
346 CUresult res = CudaFuncs->cuInit(0);
347 if (res != CUDA_SUCCESS)
349 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to initialise CUDA API");
353 unsigned int devicecount = 0;
354 res = CudaFuncs->cuGLGetDevices(&devicecount, &cudevice, 1, CU_GL_DEVICE_LIST_ALL);
355 if (res != CUDA_SUCCESS)
357 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to get CUDA device");
363 LOG(VB_GENERAL, LOG_ERR,
LOC +
"No CUDA devices");
367 res = CudaFuncs->cuCtxCreate(&CudaContext, CU_CTX_SCHED_BLOCKING_SYNC, cudevice);
368 if (res != CUDA_SUCCESS)
370 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to create CUDA context (Err: %1)")
376 CudaFuncs->cuCtxPopCurrent(&dummy);
377 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Created CUDA context");
382 CUcontext& CudaContext)
386 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Must create CUDA context from main thread");
392 while (retries++ < 5)
399 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Will retry in 50ms");
400 std::this_thread::sleep_for(50ms);
406 CUcontext& CudaContext)
415 CUDA_CHECK(CudaFuncs, cuCtxDestroy(CudaContext))
416 cuda_free_functions(&CudaFuncs);