This commit is contained in:
Amir Hassan 2025-06-02 17:55:52 +08:00 committed by GitHub
commit aec6c706a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 203 additions and 159 deletions

View File

@ -0,0 +1,36 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_CORE_VA_INTEL_INTEROP_HPP
#define OPENCV_CORE_VA_INTEL_INTEROP_HPP
#ifndef __cplusplus
# error va_intel_interop.hpp header must be compiled as C++
#endif
#if defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL)
# include <CL/cl.h>
# ifdef HAVE_VA_INTEL_OLD_HEADER
# include <CL/va_ext.h>
# else
# include <CL/cl_va_api_media_sharing_intel.h>
# endif
# include "opencv2/core.hpp"
# include "opencv2/core/ocl.hpp"
namespace cv { namespace va_intel {
class VAAPIInterop : public cv::ocl::Context::UserContext
{
public:
VAAPIInterop(cl_platform_id platform);
virtual ~VAAPIInterop() {};
clCreateFromVA_APIMediaSurfaceINTEL_fn clCreateFromVA_APIMediaSurfaceINTEL;
clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn clEnqueueAcquireVA_APIMediaSurfacesINTEL;
clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn clEnqueueReleaseVA_APIMediaSurfacesINTEL;
};
}} // namespace cv::va_intel
#endif /* defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL) */
#endif /* OPENCV_CORE_VA_INTEL_INTEROP_HPP */

View File

@ -12,7 +12,6 @@
# error va_intel.hpp header must be compiled as C++
#endif
#include "opencv2/core.hpp"
#include "ocl.hpp"
#if defined(HAVE_VA)
@ -45,10 +44,9 @@ using namespace cv::ocl;
// TODO static functions in the Context class
/** @brief Creates OpenCL context from VA.
@param display - VADisplay for which CL interop should be established.
@param tryInterop - try to set up for interoperability, if true; set up for use slow copy if false.
@return Returns reference to OpenCL Context
*/
CV_EXPORTS Context& initializeContextFromVA(VADisplay display, bool tryInterop = true);
CV_EXPORTS Context& initializeContextFromVA(VADisplay display);
} // namespace cv::va_intel::ocl

View File

@ -19,22 +19,16 @@ using namespace cv;
////////////////////////////////////////////////////////////////////////
// CL-VA Interoperability
#ifdef HAVE_OPENCL
# include "opencv2/core/opencl/runtime/opencl_core.hpp"
# include "opencv2/core.hpp"
# include "opencv2/core/ocl.hpp"
# include "opencl_kernels_core.hpp"
# ifdef HAVE_VA_INTEL
# include "opencv2/core/detail/va_intel_interop.hpp"
# endif
#endif // HAVE_OPENCL
#ifdef HAVE_VA_INTEL
#ifdef HAVE_VA_INTEL_OLD_HEADER
# include <CL/va_ext.h>
#else
# include <CL/cl_va_api_media_sharing_intel.h>
#endif
#endif
#ifdef HAVE_VA
#ifndef OPENCV_LIBVA_LINK
#include "va_wrapper.impl.hpp"
@ -46,47 +40,16 @@ static void init_libva() { /* nothing */ }
using namespace cv::detail;
#endif
namespace cv { namespace va_intel {
namespace cv { namespace va_intel { namespace ocl {
#ifdef HAVE_VA_INTEL
class VAAPIInterop : public ocl::Context::UserContext
Context& initializeContextFromVA(VADisplay display)
{
public:
VAAPIInterop(cl_platform_id platform) {
clCreateFromVA_APIMediaSurfaceINTEL = (clCreateFromVA_APIMediaSurfaceINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clCreateFromVA_APIMediaSurfaceINTEL");
clEnqueueAcquireVA_APIMediaSurfacesINTEL = (clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueAcquireVA_APIMediaSurfacesINTEL");
clEnqueueReleaseVA_APIMediaSurfacesINTEL = (clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueReleaseVA_APIMediaSurfacesINTEL");
if (!clCreateFromVA_APIMediaSurfaceINTEL ||
!clEnqueueAcquireVA_APIMediaSurfacesINTEL ||
!clEnqueueReleaseVA_APIMediaSurfacesINTEL) {
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get extension function for VA-API interop");
}
}
virtual ~VAAPIInterop() {
}
clCreateFromVA_APIMediaSurfaceINTEL_fn clCreateFromVA_APIMediaSurfaceINTEL;
clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn clEnqueueAcquireVA_APIMediaSurfacesINTEL;
clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn clEnqueueReleaseVA_APIMediaSurfacesINTEL;
};
#endif // HAVE_VA_INTEL
namespace ocl {
Context& initializeContextFromVA(VADisplay display, bool tryInterop)
{
CV_UNUSED(display); CV_UNUSED(tryInterop);
CV_UNUSED(display);
#if !defined(HAVE_VA)
NO_VA_SUPPORT_ERROR;
#else // !HAVE_VA
# ifdef HAVE_VA_INTEL
if (tryInterop)
{
cl_uint numPlatforms;
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
if (status != CL_SUCCESS)
@ -174,13 +137,12 @@ Context& initializeContextFromVA(VADisplay display, bool tryInterop)
}
clExecCtx.bind();
return const_cast<Context&>(clExecCtx.getContext());
}
} else {
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for VA-interop");
}
# endif // HAVE_VA_INTEL
{
Context& ctx = Context::getDefault(true);
return ctx;
}
#endif // !HAVE_VA
}
@ -536,18 +498,16 @@ void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface,
#ifdef HAVE_VA_INTEL
ocl::OpenCLExecutionContext& ocl_context = ocl::OpenCLExecutionContext::getCurrent();
VAAPIInterop* interop = ocl_context.getContext().getUserContext<VAAPIInterop>().get();
CV_LOG_IF_DEBUG(NULL, !interop,
"OpenCL/VA_INTEL: Can't interop with current OpenCL context - missing VAAPIInterop API. "
"OpenCL context should be created through initializeContextFromVA()");
void* context_display = ocl_context.getContext().getOpenCLContextProperty(CL_CONTEXT_VA_API_DISPLAY_INTEL);
CV_LOG_IF_INFO(NULL, interop && !context_display,
"OpenCL/VA_INTEL: Can't interop with current OpenCL context - missing VA display, context re-creation is required");
bool isValidContextDisplay = (display == context_display);
CV_LOG_IF_INFO(NULL, interop && context_display && !isValidContextDisplay,
"OpenCL/VA_INTEL: Can't interop with current OpenCL context - VA display mismatch: " << context_display << "(context) vs " << (void*)display << "(surface)");
if (isValidContextDisplay && interop)
{
VAAPIInterop* interop = ocl_context.getContext().getUserContext<VAAPIInterop>().get();
if(!context_display || context_display != display)
CV_Error_(cv::Error::StsBadArg, ("Can't interop with current OpenCL context - VA display mismatch: %p (context) vs %p (surface).\ndid you call initializeContextFromVA before using VideoCapture/VideoWriter?", context_display, (void*)display));
if(!display)
CV_Error(cv::Error::StsBadArg,
"Invalid VADisplay passed to convertFromVASurface");
if(interop) {
UMat u = src.getUMat();
// TODO Add support for roi
@ -589,10 +549,14 @@ void convertToVASurface(VADisplay display, InputArray src, VASurfaceID surface,
status = clReleaseMemObject(clImageUV);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (UV plane)");
}
else
return;
} else
# endif // HAVE_VA_INTEL
{
CV_LOG_DEBUG(NULL,
"OpenCL/VA_INTEL: Can't interop with current OpenCL context - missing VAAPIInterop API. "
"OpenCL context should be created through initializeContextFromVA()");
init_libva();
Mat m = src.getMat();
@ -682,9 +646,16 @@ void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, Out
#ifdef HAVE_VA_INTEL
ocl::OpenCLExecutionContext& ocl_context = ocl::OpenCLExecutionContext::getCurrent();
void* context_display = ocl_context.getContext().getOpenCLContextProperty(CL_CONTEXT_VA_API_DISPLAY_INTEL);
VAAPIInterop* interop = ocl_context.getContext().getUserContext<VAAPIInterop>().get();
if (display == ocl_context.getContext().getOpenCLContextProperty(CL_CONTEXT_VA_API_DISPLAY_INTEL) && interop)
{
if(!context_display || context_display != display)
CV_Error_(cv::Error::StsBadArg, ("Can't interop with current OpenCL context - VA display mismatch: %p (context) vs %p (surface).\ndid you call initializeContextFromVA before using VideoCapture/VideoWriter?", context_display, (void*)display));
if(!display)
CV_Error(cv::Error::StsBadArg,
"Invalid VADisplay passed to convertFromVASurface");
if(interop) {
UMat u = dst.getUMat();
// TODO Add support for roi
@ -726,10 +697,14 @@ void convertFromVASurface(VADisplay display, VASurfaceID surface, Size size, Out
status = clReleaseMemObject(clImageUV);
if (status != CL_SUCCESS)
CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed (UV plane)");
}
else
return;
} else
# endif // HAVE_VA_INTEL
{
CV_LOG_DEBUG(NULL,
"OpenCL/VA_INTEL: Can't interop with current OpenCL context - missing VAAPIInterop API. "
"OpenCL context should be created through initializeContextFromVA()");
init_libva();
Mat m = dst.getMat();

View File

@ -0,0 +1,27 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "precomp.hpp"
#if defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL)
# include "opencv2/core/opencl/runtime/opencl_core.hpp"
# include "opencv2/core/detail/va_intel_interop.hpp"
namespace cv { namespace va_intel {
VAAPIInterop::VAAPIInterop(cl_platform_id platform) {
clCreateFromVA_APIMediaSurfaceINTEL = (clCreateFromVA_APIMediaSurfaceINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clCreateFromVA_APIMediaSurfaceINTEL");
clEnqueueAcquireVA_APIMediaSurfacesINTEL = (clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueAcquireVA_APIMediaSurfacesINTEL");
clEnqueueReleaseVA_APIMediaSurfacesINTEL = (clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn)
clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueReleaseVA_APIMediaSurfacesINTEL");
if (!clCreateFromVA_APIMediaSurfaceINTEL ||
!clEnqueueAcquireVA_APIMediaSurfacesINTEL ||
!clEnqueueReleaseVA_APIMediaSurfacesINTEL) {
CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get extension function for VA-API interop");
}
}
}} // namespace cv::va_intel
#endif /* defined(HAVE_VA_INTEL) && defined(HAVE_OPENCL) */

View File

@ -32,6 +32,7 @@
#include <va/va_backend.h>
#ifdef HAVE_VA_INTEL
#include "opencv2/core/va_intel.hpp"
#include "opencv2/core/detail/va_intel_interop.hpp"
#ifndef CL_TARGET_OPENCL_VERSION
#define CL_TARGET_OPENCL_VERSION 120
#endif
@ -455,6 +456,8 @@ AVHWDeviceType hw_check_opencl_context(AVHWDeviceContext* ctx) {
VADisplay vadisplay_ctx = hw_get_va_display(ctx);
if (vadisplay_ocl && vadisplay_ocl == vadisplay_ctx)
return AV_HWDEVICE_TYPE_VAAPI;
else
CV_Error_(cv::Error::StsBadArg, ("Can't interop with current OpenCL context - VA display mismatch: %p (hwcontext) vs %p (ocl_context).\ndid you call initializeContextFromVA before using VideoCapture/VideoWriter?", vadisplay_ctx, vadisplay_ocl));
#endif
#ifdef HAVE_D3D11
ID3D11Device* d3d11device_ocl = (ID3D11Device*)ocl_context.getContext().getOpenCLContextProperty(CL_CONTEXT_D3D11_DEVICE_KHR);
@ -472,11 +475,18 @@ void hw_init_opencl(AVBufferRef* ctx) {
AVHWDeviceContext* hw_device_ctx = (AVHWDeviceContext*)ctx->data;
if (!hw_device_ctx)
return;
ocl::OpenCLExecutionContext& ocl_context = ocl::OpenCLExecutionContext::getCurrent();
#ifdef HAVE_VA_INTEL
cv::va_intel::VAAPIInterop* interop = ocl_context.getContext().getUserContext<cv::va_intel::VAAPIInterop>().get();
//only initialize the context automatically if it isn't already
if(!interop) {
VADisplay va_display = hw_get_va_display(hw_device_ctx);
if (va_display) {
va_intel::ocl::initializeContextFromVA(va_display);
}
} else {
CV_LOG_DEBUG(NULL, "OpenCL/VA_INTEL: CL/VA interop already initialized. ")
}
#endif
#ifdef HAVE_D3D11
AVD3D11VADeviceContext* d3d11_device_ctx = hw_get_d3d11_device_ctx(hw_device_ctx);
@ -486,8 +496,7 @@ void hw_init_opencl(AVBufferRef* ctx) {
#endif
if (hw_check_opencl_context(hw_device_ctx) != AV_HWDEVICE_TYPE_NONE) {
// Attach AVHWDeviceContext to OpenCL context
ocl::Context &ocl_context = ocl::OpenCLExecutionContext::getCurrent().getContext();
ocl_context.setUserContext(std::make_shared<OpenCL_FFMPEG_Context>(ctx));
ocl_context.getContext().setUserContext(std::make_shared<OpenCL_FFMPEG_Context>(ctx));
}
}

View File

@ -200,10 +200,10 @@ static float run(const char* infile, const char* outfile1, const char* outfile2,
VASurfaceID surface;
VAStatus status;
Timer t;
if(doInterop) {
// initialize CL context for CL/VA interop
cv::va_intel::ocl::initializeContextFromVA(va::display, doInterop);
cv::va_intel::ocl::initializeContextFromVA(va::display);
}
// load input image
cv::UMat u1 = readImage(infile);
cv::Size size2 = u1.size();
@ -215,7 +215,6 @@ static float run(const char* infile, const char* outfile1, const char* outfile2,
cv::va_intel::convertFromVASurface(va::display, surface, size2, u1);
cv::UMat u2;
cv::blur(u1, u2, cv::Size(7, 7), cv::Point(-3, -3));
// measure performance on some image processing
writeImage(u1, outfile1, doInterop);
t.start();