From 11b9d5bf4d68a9e00680f376662743236f3828c5 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 2 Dec 2013 01:50:24 +0400 Subject: [PATCH] core: added DirectX interop implementation (OpenCL) with samples --- modules/core/include/opencv2/core.hpp | 1 - modules/core/include/opencv2/core/base.hpp | 21 +- modules/core/include/opencv2/core/directx.hpp | 95 ++ modules/core/include/opencv2/core/ocl.hpp | 27 +- modules/core/src/directx.cpp | 1134 +++++++++++++++++ modules/core/src/directx.inc.hpp | 55 + modules/core/src/ocl.cpp | 79 +- modules/core/src/precomp.hpp | 3 + samples/CMakeLists.txt | 8 + samples/directx/CMakeLists.txt | 45 + samples/directx/d3d10_interop.cpp | 138 ++ samples/directx/d3d11_interop.cpp | 143 +++ samples/directx/d3d9_interop.cpp | 149 +++ samples/directx/d3d9ex_interop.cpp | 158 +++ samples/directx/d3d_base.inl.hpp | 457 +++++++ 15 files changed, 2474 insertions(+), 39 deletions(-) create mode 100644 modules/core/include/opencv2/core/directx.hpp create mode 100644 modules/core/src/directx.cpp create mode 100644 modules/core/src/directx.inc.hpp create mode 100644 samples/directx/CMakeLists.txt create mode 100644 samples/directx/d3d10_interop.cpp create mode 100644 samples/directx/d3d11_interop.cpp create mode 100644 samples/directx/d3d9_interop.cpp create mode 100644 samples/directx/d3d9ex_interop.cpp create mode 100644 samples/directx/d3d_base.inl.hpp diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp index 87263fa7d..5e72764cb 100644 --- a/modules/core/include/opencv2/core.hpp +++ b/modules/core/include/opencv2/core.hpp @@ -1262,5 +1262,4 @@ template<> struct ParamType #include "opencv2/core/operations.hpp" #include "opencv2/core/cvstd.inl.hpp" - #endif /*__OPENCV_CORE_HPP__*/ diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp index 18a996bbe..6e783005f 100644 --- a/modules/core/include/opencv2/core/base.hpp +++ b/modules/core/include/opencv2/core/base.hpp @@ -223,19 +223,26 @@ enum { CV_EXPORTS void error(int _code, const String& _err, const char* _func, const char* _file, int _line); #ifdef __GNUC__ -# if defined __clang__ || defined __APPLE__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Winvalid-noreturn" -# endif +# if defined __clang__ || defined __APPLE__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Winvalid-noreturn" +# endif #endif CV_INLINE CV_NORETURN void errorNoReturn(int _code, const String& _err, const char* _func, const char* _file, int _line) { error(_code, _err, _func, _file, _line); +#ifdef __GNUC__ +# if !defined __clang__ && !defined __APPLE__ + // this suppresses this warning: "noreturn" function does return [enabled by default] + __builtin_trap(); + // or use infinite loop: for (;;) {} +# endif +#endif } #ifdef __GNUC__ -# if defined __clang__ || defined __APPLE__ -# pragma GCC diagnostic pop -# endif +# if defined __clang__ || defined __APPLE__ +# pragma GCC diagnostic pop +# endif #endif diff --git a/modules/core/include/opencv2/core/directx.hpp b/modules/core/include/opencv2/core/directx.hpp new file mode 100644 index 000000000..2a8991ad5 --- /dev/null +++ b/modules/core/include/opencv2/core/directx.hpp @@ -0,0 +1,95 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors as is and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the copyright holders or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_CORE_DIRECTX_HPP__ +#define __OPENCV_CORE_DIRECTX_HPP__ + +#include "mat.hpp" +#include "ocl.hpp" + +#if !defined(__d3d11_h__) +struct ID3D11Device; +struct ID3D11Texture2D; +#endif + +#if !defined(__d3d10_h__) +struct ID3D10Device; +struct ID3D10Texture2D; +#endif + +#if !defined(_D3D9_H_) +struct IDirect3DDevice9; +struct IDirect3DDevice9Ex; +struct IDirect3DSurface9; +#endif + +namespace cv { namespace directx { + +namespace ocl { +using namespace cv::ocl; + +// TODO static functions in the Context class +CV_EXPORTS Context2& initializeContextFromD3D11Device(ID3D11Device* pD3D11Device); +CV_EXPORTS Context2& initializeContextFromD3D10Device(ID3D10Device* pD3D10Device); +CV_EXPORTS Context2& initializeContextFromDirect3DDevice9Ex(IDirect3DDevice9Ex* pDirect3DDevice9Ex); +CV_EXPORTS Context2& initializeContextFromDirect3DDevice9(IDirect3DDevice9* pDirect3DDevice9); + +} // namespace cv::directx::ocl + +CV_EXPORTS void convertToD3D11Texture2D(InputArray src, ID3D11Texture2D* pD3D11Texture2D); +CV_EXPORTS void convertFromD3D11Texture2D(ID3D11Texture2D* pD3D11Texture2D, OutputArray dst); + +CV_EXPORTS void convertToD3D10Texture2D(InputArray src, ID3D10Texture2D* pD3D10Texture2D); +CV_EXPORTS void convertFromD3D10Texture2D(ID3D10Texture2D* pD3D10Texture2D, OutputArray dst); + +CV_EXPORTS void convertToDirect3DSurface9(InputArray src, IDirect3DSurface9* pDirect3DSurface9, void* surfaceSharedHandle = NULL); +CV_EXPORTS void convertFromDirect3DSurface9(IDirect3DSurface9* pDirect3DSurface9, OutputArray dst, void* surfaceSharedHandle = NULL); + +// Get OpenCV type from DirectX type, return -1 if there is no equivalent +CV_EXPORTS int getTypeFromDXGI_FORMAT(const int iDXGI_FORMAT); // enum DXGI_FORMAT for D3D10/D3D11 + +// Get OpenCV type from DirectX type, return -1 if there is no equivalent +CV_EXPORTS int getTypeFromD3DFORMAT(const int iD3DFORMAT); // enum D3DTYPE for D3D9 + + +} } // namespace cv::directx + +#endif // __OPENCV_CORE_DIRECTX_HPP__ diff --git a/modules/core/include/opencv2/core/ocl.hpp b/modules/core/include/opencv2/core/ocl.hpp index f2535940f..a9fdf1e7f 100644 --- a/modules/core/include/opencv2/core/ocl.hpp +++ b/modules/core/include/opencv2/core/ocl.hpp @@ -214,10 +214,33 @@ public: Program getProg(const ProgramSource2& prog, const String& buildopt, String& errmsg); - static Context2& getDefault(); + static Context2& getDefault(bool initialize = true); void* ptr() const; -protected: + struct Impl; + inline struct Impl* _getImpl() const { return p; }; +protected: + Impl* p; +}; + + +// TODO Move to internal header +void initializeContextFromHandle(Context2& ctx, void* platform, void* context, void* device); + +class CV_EXPORTS Platform +{ +public: + Platform(); + ~Platform(); + Platform(const Platform& p); + Platform& operator = (const Platform& p); + + void* ptr() const; + static Platform& getDefault(); + + struct Impl; + inline struct Impl* _getImpl() const { return p; }; +protected: Impl* p; }; diff --git a/modules/core/src/directx.cpp b/modules/core/src/directx.cpp new file mode 100644 index 000000000..071df0352 --- /dev/null +++ b/modules/core/src/directx.cpp @@ -0,0 +1,1134 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors as is and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the copyright holders or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +#include "opencv2/core.hpp" +#include "opencv2/core/ocl.hpp" +#include "opencv2/core/directx.hpp" + +#ifdef HAVE_DIRECTX +#include +# include "directx.inc.hpp" +#else // HAVE_DIRECTX +#define NO_DIRECTX_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without DirectX support") +#endif + +#ifndef HAVE_OPENCL +# define NO_OPENCL_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without OpenCL support") +#endif // HAVE_OPENCL + +namespace cv { namespace directx { + +int getTypeFromDXGI_FORMAT(const int iDXGI_FORMAT) +{ + (void)iDXGI_FORMAT; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#else + const int errorType = -1; + switch ((enum DXGI_FORMAT)iDXGI_FORMAT) + { + //case DXGI_FORMAT_UNKNOWN: + //case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: return CV_32FC4; + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: return CV_32SC4; + //case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: return CV_32FC3; + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: return CV_32SC3; + //case DXGI_FORMAT_R16G16B16A16_TYPELESS: + //case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: return CV_16UC4; + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: return CV_16SC4; + //case DXGI_FORMAT_R32G32_TYPELESS: + //case DXGI_FORMAT_R32G32_FLOAT: + //case DXGI_FORMAT_R32G32_UINT: + //case DXGI_FORMAT_R32G32_SINT: + //case DXGI_FORMAT_R32G8X24_TYPELESS: + //case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + //case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + //case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + //case DXGI_FORMAT_R10G10B10A2_TYPELESS: + //case DXGI_FORMAT_R10G10B10A2_UNORM: + //case DXGI_FORMAT_R10G10B10A2_UINT: + //case DXGI_FORMAT_R11G11B10_FLOAT: + //case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: return CV_8UC4; + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: return CV_8SC4; + //case DXGI_FORMAT_R16G16_TYPELESS: + //case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: return CV_16UC2; + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: return CV_16SC2; + //case DXGI_FORMAT_R32_TYPELESS: + //case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: return CV_32FC1; + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: return CV_32SC1; + //case DXGI_FORMAT_R24G8_TYPELESS: + //case DXGI_FORMAT_D24_UNORM_S8_UINT: + //case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + //case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + //case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: return CV_8UC2; + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: return CV_8SC2; + //case DXGI_FORMAT_R16_TYPELESS: + //case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: return CV_16UC1; + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: return CV_16SC1; + //case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: return CV_8UC1; + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: return CV_8SC1; + case DXGI_FORMAT_A8_UNORM: return CV_8UC1; + //case DXGI_FORMAT_R1_UNORM: + //case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + //case DXGI_FORMAT_R8G8_B8G8_UNORM: + //case DXGI_FORMAT_G8R8_G8B8_UNORM: + //case DXGI_FORMAT_BC1_TYPELESS: + //case DXGI_FORMAT_BC1_UNORM: + //case DXGI_FORMAT_BC1_UNORM_SRGB: + //case DXGI_FORMAT_BC2_TYPELESS: + //case DXGI_FORMAT_BC2_UNORM: + //case DXGI_FORMAT_BC2_UNORM_SRGB: + //case DXGI_FORMAT_BC3_TYPELESS: + //case DXGI_FORMAT_BC3_UNORM: + //case DXGI_FORMAT_BC3_UNORM_SRGB: + //case DXGI_FORMAT_BC4_TYPELESS: + //case DXGI_FORMAT_BC4_UNORM: + //case DXGI_FORMAT_BC4_SNORM: + //case DXGI_FORMAT_BC5_TYPELESS: + //case DXGI_FORMAT_BC5_UNORM: + //case DXGI_FORMAT_BC5_SNORM: + //case DXGI_FORMAT_B5G6R5_UNORM: + //case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: return CV_8UC4; + //case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + //case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return CV_8UC4; + //case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return CV_8UC4; + //case DXGI_FORMAT_BC6H_TYPELESS: + //case DXGI_FORMAT_BC6H_UF16: + //case DXGI_FORMAT_BC6H_SF16: + //case DXGI_FORMAT_BC7_TYPELESS: + //case DXGI_FORMAT_BC7_UNORM: + //case DXGI_FORMAT_BC7_UNORM_SRGB: + default: break; + } + return errorType; +#endif +} + +int getTypeFromD3DFORMAT(const int iD3DFORMAT) +{ + (void)iD3DFORMAT; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#else + const int errorType = -1; + switch ((enum _D3DFORMAT)iD3DFORMAT) + { + //case D3DFMT_UNKNOWN: + case D3DFMT_R8G8B8: return CV_8UC3; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: return CV_8UC4; + //case D3DFMT_R5G6B5: + //case D3DFMT_X1R5G5B5: + //case D3DFMT_A1R5G5B5: + //case D3DFMT_A4R4G4B4: + //case D3DFMT_R3G3B2: + case D3DFMT_A8: return CV_8UC1; + //case D3DFMT_A8R3G3B2: + //case D3DFMT_X4R4G4B4: + //case D3DFMT_A2B10G10R10: + case D3DFMT_A8B8G8R8: + case D3DFMT_X8B8G8R8: return CV_8UC4; + //case D3DFMT_G16R16: + //case D3DFMT_A2R10G10B10: + //case D3DFMT_A16B16G16R16: + + case D3DFMT_A8P8: return CV_8UC2; + case D3DFMT_P8: return CV_8UC1; + + case D3DFMT_L8: return CV_8UC1; + case D3DFMT_A8L8: return CV_8UC2; + //case D3DFMT_A4L4: + + case D3DFMT_V8U8: return CV_8UC2; + //case D3DFMT_L6V5U5: + case D3DFMT_X8L8V8U8: + case D3DFMT_Q8W8V8U8: return CV_8UC4; + case D3DFMT_V16U16: return CV_16UC4; // TODO 16SC4 ? + //case D3DFMT_A2W10V10U10: + + case D3DFMT_D16_LOCKABLE: return CV_16UC1; + case D3DFMT_D32: return CV_32SC1; + //case D3DFMT_D15S1: + //case D3DFMT_D24S8: + //case D3DFMT_D24X8: + //case D3DFMT_D24X4S4: + case D3DFMT_D16: return CV_16UC1; + + case D3DFMT_D32F_LOCKABLE: return CV_32FC1; + default: break; + } + return errorType; +#endif +} + +namespace ocl { + +#if defined(HAVE_DIRECTX) && defined(HAVE_OPENCL) +static bool g_isDirect3DDevice9Ex = false; // Direct3DDevice9Ex or Direct3DDevice9 was used +#endif + +Context2& initializeContextFromD3D11Device(ID3D11Device* pD3D11Device) +{ + (void)pD3D11Device; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL) + NO_OPENCL_SUPPORT_ERROR; +#else + cl_uint numPlatforms; + cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms"); + if (numPlatforms == 0) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms"); + + std::vector platforms(numPlatforms); + status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms"); + + // TODO Filter platforms by name from OPENCV_OPENCL_DEVICE + + int found = -1; + cl_device_id device = NULL; + cl_uint numDevices = 0; + cl_context context = NULL; + + // try with CL_PREFERRED_DEVICES_FOR_D3D11_KHR + for (int i = 0; i < (int)numPlatforms; i++) + { + clGetDeviceIDsFromD3D11KHR_fn clGetDeviceIDsFromD3D11KHR = (clGetDeviceIDsFromD3D11KHR_fn) + clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromD3D11KHR"); + if (!clGetDeviceIDsFromD3D11KHR) + continue; + + device = NULL; + numDevices = 0; + status = clGetDeviceIDsFromD3D11KHR(platforms[i], CL_D3D11_DEVICE_KHR, pD3D11Device, + CL_PREFERRED_DEVICES_FOR_D3D11_KHR, 1, &device, &numDevices); + if (status != CL_SUCCESS) + continue; + if (numDevices > 0) + { + cl_context_properties properties[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + CL_CONTEXT_D3D11_DEVICE_KHR, (cl_context_properties)(pD3D11Device), + CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, + NULL, NULL + }; + context = clCreateContext(properties, 1, &device, NULL, NULL, &status); + if (status != CL_SUCCESS) + { + clReleaseDevice(device); + } + else + { + found = i; + break; + } + } + } + if (found < 0) + { + // try with CL_ALL_DEVICES_FOR_D3D11_KHR + for (int i = 0; i < (int)numPlatforms; i++) + { + clGetDeviceIDsFromD3D11KHR_fn clGetDeviceIDsFromD3D11KHR = (clGetDeviceIDsFromD3D11KHR_fn) + clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromD3D11KHR"); + if (!clGetDeviceIDsFromD3D11KHR) + continue; + + device = NULL; + numDevices = 0; + status = clGetDeviceIDsFromD3D11KHR(platforms[i], CL_D3D11_DEVICE_KHR, pD3D11Device, + CL_ALL_DEVICES_FOR_D3D11_KHR, 1, &device, &numDevices); + if (status != CL_SUCCESS) + continue; + if (numDevices > 0) + { + cl_context_properties properties[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + CL_CONTEXT_D3D11_DEVICE_KHR, (cl_context_properties)(pD3D11Device), + CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, + NULL, NULL + }; + context = clCreateContext(properties, 1, &device, NULL, NULL, &status); + if (status != CL_SUCCESS) + { + clReleaseDevice(device); + } + else + { + found = i; + break; + } + } + } + if (found < 0) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for DirectX interop"); + } + + + Context2& ctx = Context2::getDefault(false); + initializeContextFromHandle(ctx, platforms[found], context, device); + return ctx; +#endif +} + +Context2& initializeContextFromD3D10Device(ID3D10Device* pD3D10Device) +{ + (void)pD3D10Device; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL) + NO_OPENCL_SUPPORT_ERROR; +#else + cl_uint numPlatforms; + cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms"); + if (numPlatforms == 0) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms"); + + std::vector platforms(numPlatforms); + status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms"); + + // TODO Filter platforms by name from OPENCV_OPENCL_DEVICE + + int found = -1; + cl_device_id device = NULL; + cl_uint numDevices = 0; + cl_context context = NULL; + + // try with CL_PREFERRED_DEVICES_FOR_D3D10_KHR + for (int i = 0; i < (int)numPlatforms; i++) + { + clGetDeviceIDsFromD3D10KHR_fn clGetDeviceIDsFromD3D10KHR = (clGetDeviceIDsFromD3D10KHR_fn) + clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromD3D10KHR"); + if (!clGetDeviceIDsFromD3D10KHR) + continue; + + device = NULL; + numDevices = 0; + status = clGetDeviceIDsFromD3D10KHR(platforms[i], CL_D3D10_DEVICE_KHR, pD3D10Device, + CL_PREFERRED_DEVICES_FOR_D3D10_KHR, 1, &device, &numDevices); + if (status != CL_SUCCESS) + continue; + if (numDevices > 0) + { + cl_context_properties properties[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + CL_CONTEXT_D3D10_DEVICE_KHR, (cl_context_properties)(pD3D10Device), + CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, + NULL, NULL + }; + context = clCreateContext(properties, 1, &device, NULL, NULL, &status); + if (status != CL_SUCCESS) + { + clReleaseDevice(device); + } + else + { + found = i; + break; + } + } + } + if (found < 0) + { + // try with CL_ALL_DEVICES_FOR_D3D10_KHR + for (int i = 0; i < (int)numPlatforms; i++) + { + clGetDeviceIDsFromD3D10KHR_fn clGetDeviceIDsFromD3D10KHR = (clGetDeviceIDsFromD3D10KHR_fn) + clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromD3D10KHR"); + if (!clGetDeviceIDsFromD3D10KHR) + continue; + + device = NULL; + numDevices = 0; + status = clGetDeviceIDsFromD3D10KHR(platforms[i], CL_D3D10_DEVICE_KHR, pD3D10Device, + CL_ALL_DEVICES_FOR_D3D10_KHR, 1, &device, &numDevices); + if (status != CL_SUCCESS) + continue; + if (numDevices > 0) + { + cl_context_properties properties[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + CL_CONTEXT_D3D10_DEVICE_KHR, (cl_context_properties)(pD3D10Device), + CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, + NULL, NULL + }; + context = clCreateContext(properties, 1, &device, NULL, NULL, &status); + if (status != CL_SUCCESS) + { + clReleaseDevice(device); + } + else + { + found = i; + break; + } + } + } + if (found < 0) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for DirectX interop"); + } + + + Context2& ctx = Context2::getDefault(false); + initializeContextFromHandle(ctx, platforms[found], context, device); + return ctx; +#endif +} + +Context2& initializeContextFromDirect3DDevice9Ex(IDirect3DDevice9Ex* pDirect3DDevice9Ex) +{ + (void)pDirect3DDevice9Ex; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL) + NO_OPENCL_SUPPORT_ERROR; +#else + cl_uint numPlatforms; + cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms"); + if (numPlatforms == 0) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms"); + + std::vector platforms(numPlatforms); + status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms"); + + // TODO Filter platforms by name from OPENCV_OPENCL_DEVICE + + int found = -1; + cl_device_id device = NULL; + cl_uint numDevices = 0; + cl_context context = NULL; + + // try with CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR + for (int i = 0; i < (int)numPlatforms; i++) + { + clGetDeviceIDsFromDX9MediaAdapterKHR_fn clGetDeviceIDsFromDX9MediaAdapterKHR = (clGetDeviceIDsFromDX9MediaAdapterKHR_fn) + clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromDX9MediaAdapterKHR"); + if (!clGetDeviceIDsFromDX9MediaAdapterKHR) + continue; + + device = NULL; + numDevices = 0; + cl_dx9_media_adapter_type_khr type = CL_ADAPTER_D3D9EX_KHR; + status = clGetDeviceIDsFromDX9MediaAdapterKHR(platforms[i], 1, &type, &pDirect3DDevice9Ex, + CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR, 1, &device, &numDevices); + if (status != CL_SUCCESS) + continue; + if (numDevices > 0) + { + cl_context_properties properties[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + CL_CONTEXT_ADAPTER_D3D9EX_KHR, (cl_context_properties)(pDirect3DDevice9Ex), + CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, + NULL, NULL + }; + context = clCreateContext(properties, 1, &device, NULL, NULL, &status); + if (status != CL_SUCCESS) + { + clReleaseDevice(device); + } + else + { + found = i; + break; + } + } + } + if (found < 0) + { + // try with CL_ALL_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR + for (int i = 0; i < (int)numPlatforms; i++) + { + clGetDeviceIDsFromDX9MediaAdapterKHR_fn clGetDeviceIDsFromDX9MediaAdapterKHR = (clGetDeviceIDsFromDX9MediaAdapterKHR_fn) + clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromDX9MediaAdapterKHR"); + if (!clGetDeviceIDsFromDX9MediaAdapterKHR) + continue; + + device = NULL; + numDevices = 0; + cl_dx9_media_adapter_type_khr type = CL_ADAPTER_D3D9EX_KHR; + status = clGetDeviceIDsFromDX9MediaAdapterKHR(platforms[i], 1, &type, &pDirect3DDevice9Ex, + CL_ALL_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR, 1, &device, &numDevices); + if (status != CL_SUCCESS) + continue; + if (numDevices > 0) + { + cl_context_properties properties[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + CL_CONTEXT_ADAPTER_D3D9EX_KHR, (cl_context_properties)(pDirect3DDevice9Ex), + CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, + NULL, NULL + }; + context = clCreateContext(properties, 1, &device, NULL, NULL, &status); + if (status != CL_SUCCESS) + { + clReleaseDevice(device); + } + else + { + found = i; + break; + } + } + } + if (found < 0) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for DirectX interop"); + } + + Context2& ctx = Context2::getDefault(false); + initializeContextFromHandle(ctx, platforms[found], context, device); + g_isDirect3DDevice9Ex = true; + return ctx; +#endif +} + +Context2& initializeContextFromDirect3DDevice9(IDirect3DDevice9* pDirect3DDevice9) +{ + (void)pDirect3DDevice9; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL) + NO_OPENCL_SUPPORT_ERROR; +#else + cl_uint numPlatforms; + cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms"); + if (numPlatforms == 0) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: No available platforms"); + + std::vector platforms(numPlatforms); + status = clGetPlatformIDs(numPlatforms, &platforms[0], NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't get number of platforms"); + + // TODO Filter platforms by name from OPENCV_OPENCL_DEVICE + + int found = -1; + cl_device_id device = NULL; + cl_uint numDevices = 0; + cl_context context = NULL; + + // try with CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR + for (int i = 0; i < (int)numPlatforms; i++) + { + clGetDeviceIDsFromDX9MediaAdapterKHR_fn clGetDeviceIDsFromDX9MediaAdapterKHR = (clGetDeviceIDsFromDX9MediaAdapterKHR_fn) + clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromDX9MediaAdapterKHR"); + if (!clGetDeviceIDsFromDX9MediaAdapterKHR) + continue; + + device = NULL; + numDevices = 0; + cl_dx9_media_adapter_type_khr type = CL_ADAPTER_D3D9_KHR; + status = clGetDeviceIDsFromDX9MediaAdapterKHR(platforms[i], 1, &type, &pDirect3DDevice9, + CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR, 1, &device, &numDevices); + if (status != CL_SUCCESS) + continue; + if (numDevices > 0) + { + cl_context_properties properties[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + CL_CONTEXT_ADAPTER_D3D9_KHR, (cl_context_properties)(pDirect3DDevice9), + CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, + NULL, NULL + }; + context = clCreateContext(properties, 1, &device, NULL, NULL, &status); + if (status != CL_SUCCESS) + { + clReleaseDevice(device); + } + else + { + found = i; + break; + } + } + } + if (found < 0) + { + // try with CL_ALL_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR + for (int i = 0; i < (int)numPlatforms; i++) + { + clGetDeviceIDsFromDX9MediaAdapterKHR_fn clGetDeviceIDsFromDX9MediaAdapterKHR = (clGetDeviceIDsFromDX9MediaAdapterKHR_fn) + clGetExtensionFunctionAddressForPlatform(platforms[i], "clGetDeviceIDsFromDX9MediaAdapterKHR"); + if (!clGetDeviceIDsFromDX9MediaAdapterKHR) + continue; + + device = NULL; + numDevices = 0; + cl_dx9_media_adapter_type_khr type = CL_ADAPTER_D3D9_KHR; + status = clGetDeviceIDsFromDX9MediaAdapterKHR(platforms[i], 1, &type, &pDirect3DDevice9, + CL_ALL_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR, 1, &device, &numDevices); + if (status != CL_SUCCESS) + continue; + if (numDevices > 0) + { + cl_context_properties properties[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platforms[i], + CL_CONTEXT_ADAPTER_D3D9_KHR, (cl_context_properties)(pDirect3DDevice9), + CL_CONTEXT_INTEROP_USER_SYNC, CL_FALSE, + NULL, NULL + }; + context = clCreateContext(properties, 1, &device, NULL, NULL, &status); + if (status != CL_SUCCESS) + { + clReleaseDevice(device); + } + else + { + found = i; + break; + } + } + } + if (found < 0) + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't create context for DirectX interop"); + } + + Context2& ctx = Context2::getDefault(false); + initializeContextFromHandle(ctx, platforms[found], context, device); + g_isDirect3DDevice9Ex = false; + return ctx; +#endif +} + +} // namespace cv::ocl + +#if defined(HAVE_DIRECTX) && defined(HAVE_OPENCL) +clCreateFromD3D11Texture2DKHR_fn clCreateFromD3D11Texture2DKHR = NULL; +clEnqueueAcquireD3D11ObjectsKHR_fn clEnqueueAcquireD3D11ObjectsKHR = NULL; +clEnqueueReleaseD3D11ObjectsKHR_fn clEnqueueReleaseD3D11ObjectsKHR = NULL; + +static void __OpenCLinitializeD3D11() +{ + using namespace cv::ocl; + static cl_platform_id initializedPlatform = NULL; + cl_platform_id platform = (cl_platform_id)Platform::getDefault().ptr(); + if (initializedPlatform != platform) + { + clCreateFromD3D11Texture2DKHR = (clCreateFromD3D11Texture2DKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clCreateFromD3D11Texture2DKHR"); + clEnqueueAcquireD3D11ObjectsKHR = (clEnqueueAcquireD3D11ObjectsKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueAcquireD3D11ObjectsKHR"); + clEnqueueReleaseD3D11ObjectsKHR = (clEnqueueReleaseD3D11ObjectsKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueReleaseD3D11ObjectsKHR"); + initializedPlatform = platform; + } + if (!clCreateFromD3D11Texture2DKHR || !clEnqueueAcquireD3D11ObjectsKHR || !clEnqueueReleaseD3D11ObjectsKHR) + { + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't find functions for D3D11"); + } +} +#endif // defined(HAVE_DIRECTX) && defined(HAVE_OPENCL) + +void convertToD3D11Texture2D(InputArray src, ID3D11Texture2D* pD3D11Texture2D) +{ + (void)src; (void)pD3D11Texture2D; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif defined(HAVE_OPENCL) + __OpenCLinitializeD3D11(); + + D3D11_TEXTURE2D_DESC desc = { 0 }; + pD3D11Texture2D->GetDesc(&desc); + + int srcType = src.type(); + int textureType = getTypeFromDXGI_FORMAT(desc.Format); + CV_Assert(textureType == srcType); + + Size srcSize = src.size(); + CV_Assert(srcSize.width == (int)desc.Width && srcSize.height == (int)desc.Height); + + using namespace cv::ocl; + Context2& ctx = Context2::getDefault(); + cl_context context = (cl_context)ctx.ptr(); + + UMat u = src.getUMat(); + + // TODO Add support for roi + CV_Assert(u.offset == 0); + CV_Assert(u.isContinuous()); + + cl_int status = 0; + cl_mem clImage = clCreateFromD3D11Texture2DKHR(context, CL_MEM_WRITE_ONLY, pD3D11Texture2D, 0, &status); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromD3D11Texture2DKHR failed"); + + cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ); + + cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr(); + status = clEnqueueAcquireD3D11ObjectsKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireD3D11ObjectsKHR failed"); + size_t offset = 0; // TODO + size_t dst_origin[3] = {0, 0, 0}; + size_t region[3] = {u.cols, u.rows, 1}; + status = clEnqueueCopyBufferToImage(q, clBuffer, clImage, offset, dst_origin, region, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueCopyBufferToImage failed"); + status = clEnqueueReleaseD3D11ObjectsKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseD3D11ObjectsKHR failed"); + + status = clFinish(q); // TODO Use events + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed"); + + status = clReleaseMemObject(clImage); // TODO RAII + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed"); +#else + // TODO memcpy + NO_OPENCL_SUPPORT_ERROR; +#endif +} +void convertFromD3D11Texture2D(ID3D11Texture2D* pD3D11Texture2D, OutputArray dst) +{ + (void)pD3D11Texture2D; (void)dst; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif defined(HAVE_OPENCL) + __OpenCLinitializeD3D11(); + + D3D11_TEXTURE2D_DESC desc = { 0 }; + pD3D11Texture2D->GetDesc(&desc); + + int textureType = getTypeFromDXGI_FORMAT(desc.Format); + CV_Assert(textureType >= 0); + + using namespace cv::ocl; + Context2& ctx = Context2::getDefault(); + cl_context context = (cl_context)ctx.ptr(); + + // TODO Need to specify ACCESS_WRITE here somehow to prevent useless data copying! + dst.create(Size(desc.Width, desc.Height), textureType); + UMat u = dst.getUMat(); + + // TODO Add support for roi + CV_Assert(u.offset == 0); + CV_Assert(u.isContinuous()); + + cl_int status = 0; + cl_mem clImage = clCreateFromD3D11Texture2DKHR(context, CL_MEM_READ_ONLY, pD3D11Texture2D, 0, &status); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromD3D11Texture2DKHR failed"); + + cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ); + + cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr(); + status = clEnqueueAcquireD3D11ObjectsKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireD3D11ObjectsKHR failed"); + size_t offset = 0; // TODO + size_t src_origin[3] = {0, 0, 0}; + size_t region[3] = {u.cols, u.rows, 1}; + status = clEnqueueCopyImageToBuffer(q, clImage, clBuffer, src_origin, region, offset, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueCopyImageToBuffer failed"); + status = clEnqueueReleaseD3D11ObjectsKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseD3D11ObjectsKHR failed"); + + status = clFinish(q); // TODO Use events + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed"); + + status = clReleaseMemObject(clImage); // TODO RAII + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed"); +#else + // TODO memcpy + NO_OPENCL_SUPPORT_ERROR; +#endif +} + +#if defined(HAVE_DIRECTX) && defined(HAVE_OPENCL) +clCreateFromD3D10Texture2DKHR_fn clCreateFromD3D10Texture2DKHR = NULL; +clEnqueueAcquireD3D10ObjectsKHR_fn clEnqueueAcquireD3D10ObjectsKHR = NULL; +clEnqueueReleaseD3D10ObjectsKHR_fn clEnqueueReleaseD3D10ObjectsKHR = NULL; + +static void __OpenCLinitializeD3D10() +{ + using namespace cv::ocl; + static cl_platform_id initializedPlatform = NULL; + cl_platform_id platform = (cl_platform_id)Platform::getDefault().ptr(); + if (initializedPlatform != platform) + { + clCreateFromD3D10Texture2DKHR = (clCreateFromD3D10Texture2DKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clCreateFromD3D10Texture2DKHR"); + clEnqueueAcquireD3D10ObjectsKHR = (clEnqueueAcquireD3D10ObjectsKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueAcquireD3D10ObjectsKHR"); + clEnqueueReleaseD3D10ObjectsKHR = (clEnqueueReleaseD3D10ObjectsKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueReleaseD3D10ObjectsKHR"); + initializedPlatform = platform; + } + if (!clCreateFromD3D10Texture2DKHR || !clEnqueueAcquireD3D10ObjectsKHR || !clEnqueueReleaseD3D10ObjectsKHR) + { + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't find functions for D3D10"); + } +} +#endif // defined(HAVE_DIRECTX) && defined(HAVE_OPENCL) + +void convertToD3D10Texture2D(InputArray src, ID3D10Texture2D* pD3D10Texture2D) +{ + (void)src; (void)pD3D10Texture2D; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif defined(HAVE_OPENCL) + __OpenCLinitializeD3D10(); + + D3D10_TEXTURE2D_DESC desc = { 0 }; + pD3D10Texture2D->GetDesc(&desc); + + int srcType = src.type(); + int textureType = getTypeFromDXGI_FORMAT(desc.Format); + CV_Assert(textureType == srcType); + + Size srcSize = src.size(); + CV_Assert(srcSize.width == (int)desc.Width && srcSize.height == (int)desc.Height); + + using namespace cv::ocl; + Context2& ctx = Context2::getDefault(); + cl_context context = (cl_context)ctx.ptr(); + + UMat u = src.getUMat(); + + // TODO Add support for roi + CV_Assert(u.offset == 0); + CV_Assert(u.isContinuous()); + + cl_int status = 0; + cl_mem clImage = clCreateFromD3D10Texture2DKHR(context, CL_MEM_WRITE_ONLY, pD3D10Texture2D, 0, &status); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromD3D10Texture2DKHR failed"); + + cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ); + + cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr(); + status = clEnqueueAcquireD3D10ObjectsKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireD3D10ObjectsKHR failed"); + size_t offset = 0; // TODO + size_t dst_origin[3] = {0, 0, 0}; + size_t region[3] = {u.cols, u.rows, 1}; + status = clEnqueueCopyBufferToImage(q, clBuffer, clImage, offset, dst_origin, region, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueCopyBufferToImage failed"); + status = clEnqueueReleaseD3D10ObjectsKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseD3D10ObjectsKHR failed"); + + status = clFinish(q); // TODO Use events + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed"); + + status = clReleaseMemObject(clImage); // TODO RAII + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed"); +#else + // TODO memcpy + NO_OPENCL_SUPPORT_ERROR; +#endif +} +void convertFromD3D10Texture2D(ID3D10Texture2D* pD3D10Texture2D, OutputArray dst) +{ + (void)pD3D10Texture2D; (void)dst; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif defined(HAVE_OPENCL) + __OpenCLinitializeD3D10(); + + D3D10_TEXTURE2D_DESC desc = { 0 }; + pD3D10Texture2D->GetDesc(&desc); + + int textureType = getTypeFromDXGI_FORMAT(desc.Format); + CV_Assert(textureType >= 0); + + using namespace cv::ocl; + Context2& ctx = Context2::getDefault(); + cl_context context = (cl_context)ctx.ptr(); + + // TODO Need to specify ACCESS_WRITE here somehow to prevent useless data copying! + dst.create(Size(desc.Width, desc.Height), textureType); + UMat u = dst.getUMat(); + + // TODO Add support for roi + CV_Assert(u.offset == 0); + CV_Assert(u.isContinuous()); + + cl_int status = 0; + cl_mem clImage = clCreateFromD3D10Texture2DKHR(context, CL_MEM_READ_ONLY, pD3D10Texture2D, 0, &status); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromD3D10Texture2DKHR failed"); + + cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ); + + cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr(); + status = clEnqueueAcquireD3D10ObjectsKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireD3D10ObjectsKHR failed"); + size_t offset = 0; // TODO + size_t src_origin[3] = {0, 0, 0}; + size_t region[3] = {u.cols, u.rows, 1}; + status = clEnqueueCopyImageToBuffer(q, clImage, clBuffer, src_origin, region, offset, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueCopyImageToBuffer failed"); + status = clEnqueueReleaseD3D10ObjectsKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseD3D10ObjectsKHR failed"); + + status = clFinish(q); // TODO Use events + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed"); + + status = clReleaseMemObject(clImage); // TODO RAII + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed"); +#else + // TODO memcpy + NO_OPENCL_SUPPORT_ERROR; +#endif +} + +#if defined(HAVE_DIRECTX) && defined(HAVE_OPENCL) +clCreateFromDX9MediaSurfaceKHR_fn clCreateFromDX9MediaSurfaceKHR = NULL; +clEnqueueAcquireDX9MediaSurfacesKHR_fn clEnqueueAcquireDX9MediaSurfacesKHR = NULL; +clEnqueueReleaseDX9MediaSurfacesKHR_fn clEnqueueReleaseDX9MediaSurfacesKHR = NULL; + +static void __OpenCLinitializeD3D9() +{ + using namespace cv::ocl; + static cl_platform_id initializedPlatform = NULL; + cl_platform_id platform = (cl_platform_id)Platform::getDefault().ptr(); + if (initializedPlatform != platform) + { + clCreateFromDX9MediaSurfaceKHR = (clCreateFromDX9MediaSurfaceKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clCreateFromDX9MediaSurfaceKHR"); + clEnqueueAcquireDX9MediaSurfacesKHR = (clEnqueueAcquireDX9MediaSurfacesKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueAcquireDX9MediaSurfacesKHR"); + clEnqueueReleaseDX9MediaSurfacesKHR = (clEnqueueReleaseDX9MediaSurfacesKHR_fn) + clGetExtensionFunctionAddressForPlatform(platform, "clEnqueueReleaseDX9MediaSurfacesKHR"); + initializedPlatform = platform; + } + if (!clCreateFromDX9MediaSurfaceKHR || !clEnqueueAcquireDX9MediaSurfacesKHR || !clEnqueueReleaseDX9MediaSurfacesKHR) + { + CV_Error(cv::Error::OpenCLInitError, "OpenCL: Can't find functions for D3D9"); + } +} +#endif // defined(HAVE_DIRECTX) && defined(HAVE_OPENCL) + +void convertToDirect3DSurface9(InputArray src, IDirect3DSurface9* pDirect3DSurface9, void* surfaceSharedHandle) +{ + (void)src; (void)pDirect3DSurface9; (void)surfaceSharedHandle; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif defined(HAVE_OPENCL) + __OpenCLinitializeD3D9(); + + D3DSURFACE_DESC desc; + if (FAILED(pDirect3DSurface9->GetDesc(&desc))) + { + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: Can't get D3D surface description"); + } + + int srcType = src.type(); + int surfaceType = getTypeFromD3DFORMAT(desc.Format); + CV_Assert(surfaceType == srcType); + + Size srcSize = src.size(); + CV_Assert(srcSize.width == (int)desc.Width && srcSize.height == (int)desc.Height); + + using namespace cv::ocl; + Context2& ctx = Context2::getDefault(); + cl_context context = (cl_context)ctx.ptr(); + + UMat u = src.getUMat(); + + // TODO Add support for roi + CV_Assert(u.offset == 0); + CV_Assert(u.isContinuous()); + + cl_int status = 0; + cl_dx9_surface_info_khr surfaceInfo = {pDirect3DSurface9, (HANDLE)surfaceSharedHandle}; + cl_mem clImage = clCreateFromDX9MediaSurfaceKHR(context, CL_MEM_WRITE_ONLY, + ocl::g_isDirect3DDevice9Ex ? CL_ADAPTER_D3D9EX_KHR : CL_ADAPTER_D3D9_KHR, + &surfaceInfo, 0, &status); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromDX9MediaSurfaceKHR failed"); + + cl_mem clBuffer = (cl_mem)u.handle(ACCESS_READ); + + cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr(); + status = clEnqueueAcquireDX9MediaSurfacesKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireDX9MediaSurfacesKHR failed"); + size_t offset = 0; // TODO + size_t dst_origin[3] = {0, 0, 0}; + size_t region[3] = {u.cols, u.rows, 1}; + status = clEnqueueCopyBufferToImage(q, clBuffer, clImage, offset, dst_origin, region, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueCopyBufferToImage failed"); + status = clEnqueueReleaseDX9MediaSurfacesKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseDX9MediaSurfacesKHR failed"); + + status = clFinish(q); // TODO Use events + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed"); + + status = clReleaseMemObject(clImage); // TODO RAII + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed"); +#else + // TODO pDirect3DSurface9->LockRect() + memcpy + Unlock() + NO_OPENCL_SUPPORT_ERROR; +#endif +} + +void convertFromDirect3DSurface9(IDirect3DSurface9* pDirect3DSurface9, OutputArray dst, void* surfaceSharedHandle) +{ + (void)pDirect3DSurface9; (void)dst; (void)surfaceSharedHandle; +#if !defined(HAVE_DIRECTX) + NO_DIRECTX_SUPPORT_ERROR; +#elif defined(HAVE_OPENCL) + __OpenCLinitializeD3D9(); + + D3DSURFACE_DESC desc; + if (FAILED(pDirect3DSurface9->GetDesc(&desc))) + { + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: Can't get D3D surface description"); + } + + int surfaceType = getTypeFromD3DFORMAT(desc.Format); + CV_Assert(surfaceType >= 0); + + using namespace cv::ocl; + Context2& ctx = Context2::getDefault(); + cl_context context = (cl_context)ctx.ptr(); + + // TODO Need to specify ACCESS_WRITE here somehow to prevent useless data copying! + dst.create(Size(desc.Width, desc.Height), surfaceType); + UMat u = dst.getUMat(); + + // TODO Add support for roi + CV_Assert(u.offset == 0); + CV_Assert(u.isContinuous()); + + cl_int status = 0; + cl_dx9_surface_info_khr surfaceInfo = {pDirect3DSurface9, (HANDLE)surfaceSharedHandle}; + cl_mem clImage = clCreateFromDX9MediaSurfaceKHR(context, CL_MEM_READ_ONLY, + ocl::g_isDirect3DDevice9Ex ? CL_ADAPTER_D3D9EX_KHR : CL_ADAPTER_D3D9_KHR, + &surfaceInfo, 0, &status); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clCreateFromDX9MediaSurfaceKHR failed"); + + cl_mem clBuffer = (cl_mem)u.handle(ACCESS_WRITE); + + cl_command_queue q = (cl_command_queue)Queue::getDefault().ptr(); + status = clEnqueueAcquireDX9MediaSurfacesKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueAcquireDX9MediaSurfacesKHR failed"); + size_t offset = 0; // TODO + size_t src_origin[3] = {0, 0, 0}; + size_t region[3] = {u.cols, u.rows, 1}; + status = clEnqueueCopyImageToBuffer(q, clImage, clBuffer, src_origin, region, offset, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueCopyImageToBuffer failed"); + status = clEnqueueReleaseDX9MediaSurfacesKHR(q, 1, &clImage, 0, NULL, NULL); + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clEnqueueReleaseDX9MediaSurfacesKHR failed"); + + status = clFinish(q); // TODO Use events + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clFinish failed"); + + status = clReleaseMemObject(clImage); // TODO RAII + if (status != CL_SUCCESS) + CV_Error(cv::Error::OpenCLApiCallError, "OpenCL: clReleaseMem failed"); +#else + // TODO pDirect3DSurface9->LockRect() + memcpy + Unlock() + NO_OPENCL_SUPPORT_ERROR; +#endif +} + +} } // namespace cv::directx diff --git a/modules/core/src/directx.inc.hpp b/modules/core/src/directx.inc.hpp new file mode 100644 index 000000000..a8e7a1714 --- /dev/null +++ b/modules/core/src/directx.inc.hpp @@ -0,0 +1,55 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors as is and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the copyright holders or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#if defined(HAVE_DIRECTX) +#include +#include +#include + +#ifdef HAVE_OPENCL +#include "opencv2/core/opencl/runtime/opencl_core.hpp" + +#include +#include +#include +#endif // HAVE_OPENCL + +#endif // HAVE_DIRECTX diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp index 6681e8181..f56482b92 100644 --- a/modules/core/src/ocl.cpp +++ b/modules/core/src/ocl.cpp @@ -1363,21 +1363,6 @@ void finish2() void release() { if( CV_XADD(&refcount, -1) == 1 ) delete this; } \ int refcount -class Platform -{ -public: - Platform(); - ~Platform(); - Platform(const Platform& p); - Platform& operator = (const Platform& p); - - void* ptr() const; - static Platform& getDefault(); -protected: - struct Impl; - Impl* p; -}; - struct Platform::Impl { Impl() @@ -1773,6 +1758,12 @@ const Device& Device::getDefault() struct Context2::Impl { + Impl() + { + refcount = 1; + handle = 0; + } + Impl(int dtype0) { refcount = 1; @@ -1855,7 +1846,6 @@ struct Context2::Impl cl_context handle; std::vector devices; - bool initialized; typedef ProgramSource2::hash_t hash_t; @@ -1937,22 +1927,29 @@ const Device& Context2::device(size_t idx) const return !p || idx >= p->devices.size() ? dummy : p->devices[idx]; } -Context2& Context2::getDefault() +Context2& Context2::getDefault(bool initialize) { static Context2 ctx; - if( !ctx.p && haveOpenCL() ) + if(!ctx.p && haveOpenCL()) { - // do not create new Context2 right away. - // First, try to retrieve existing context of the same type. - // In its turn, Platform::getContext() may call Context2::create() - // if there is no such context. - ctx.create(Device::TYPE_ACCELERATOR); - if(!ctx.p) - ctx.create(Device::TYPE_DGPU); - if(!ctx.p) - ctx.create(Device::TYPE_IGPU); - if(!ctx.p) - ctx.create(Device::TYPE_CPU); + if (initialize) + { + // do not create new Context2 right away. + // First, try to retrieve existing context of the same type. + // In its turn, Platform::getContext() may call Context2::create() + // if there is no such context. + ctx.create(Device::TYPE_ACCELERATOR); + if(!ctx.p) + ctx.create(Device::TYPE_DGPU); + if(!ctx.p) + ctx.create(Device::TYPE_IGPU); + if(!ctx.p) + ctx.create(Device::TYPE_CPU); + } + else + { + ctx.p = new Impl(); + } } return ctx; @@ -1964,6 +1961,30 @@ Program Context2::getProg(const ProgramSource2& prog, return p ? p->getProg(prog, buildopts, errmsg) : Program(); } +void initializeContextFromHandle(Context2& ctx, void* platform, void* _context, void* _device) +{ + cl_context context = (cl_context)_context; + cl_device_id device = (cl_device_id)_device; + + // cleanup old context + Context2::Impl* impl = ctx._getImpl(); + if (impl->handle) + { + cl_int status = clReleaseContext(impl->handle); + (void)status; + } + impl->devices.clear(); + + impl->handle = context; + impl->devices.resize(1); + impl->devices[0].set(device); + + Platform& p = Platform::getDefault(); + Platform::Impl* pImpl = p._getImpl(); + pImpl->handle = (cl_platform_id)platform; +} + + struct Queue::Impl { Impl(const Context2& c, const Device& d) diff --git a/modules/core/src/precomp.hpp b/modules/core/src/precomp.hpp index 47d6fdc76..a6a39fa3a 100644 --- a/modules/core/src/precomp.hpp +++ b/modules/core/src/precomp.hpp @@ -43,6 +43,9 @@ #ifndef __OPENCV_PRECOMP_H__ #define __OPENCV_PRECOMP_H__ +#include "opencv2/opencv_modules.hpp" +#include "cvconfig.h" + #include "opencv2/core/utility.hpp" #include "opencv2/core/core_c.h" #include "opencv2/core/cuda.hpp" diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 48a419d75..9dd3df0b6 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -15,6 +15,10 @@ add_subdirectory(cpp) add_subdirectory(gpu) add_subdirectory(ocl) +if(WIN32 AND HAVE_DIRECTX) + add_subdirectory(directx) +endif() + if(ANDROID AND BUILD_ANDROID_EXAMPLES) add_subdirectory(android) endif() @@ -62,6 +66,10 @@ add_subdirectory(cpp) add_subdirectory(ocl) # FIXIT: can't use cvconfig.h in samples: add_subdirectory(gpu) +if(WIN32) + add_subdirectory(directx) +endif() + # # END OF BUILD CASE 2: Build samples with library binaries # diff --git a/samples/directx/CMakeLists.txt b/samples/directx/CMakeLists.txt new file mode 100644 index 000000000..0bd7de941 --- /dev/null +++ b/samples/directx/CMakeLists.txt @@ -0,0 +1,45 @@ +SET(OPENCV_DIRECTX_SAMPLES_REQUIRED_DEPS opencv_core opencv_imgproc opencv_highgui) + +ocv_check_dependencies(${OPENCV_DIRECTX_SAMPLES_REQUIRED_DEPS}) + +if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) + set(project "directx") + string(TOUPPER "${project}" project_upper) + + project("${project}_samples") + + ocv_include_modules(${OPENCV_DIRECTX_SAMPLES_REQUIRED_DEPS}) + + # --------------------------------------------- + # Define executable targets + # --------------------------------------------- + MACRO(OPENCV_DEFINE_DIRECTX_EXAMPLE name srcs) + set(the_target "example_${project}_${name}") + add_executable(${the_target} ${srcs}) + + target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${OPENCV_DIRECTX_SAMPLES_REQUIRED_DEPS}) + + set_target_properties(${the_target} PROPERTIES + OUTPUT_NAME "${project}-example-${name}" + PROJECT_LABEL "(EXAMPLE_${project_upper}) ${name}") + + if(ENABLE_SOLUTION_FOLDERS) + set_target_properties(${the_target} PROPERTIES FOLDER "samples//${project}") + endif() + + if(WIN32) + if(MSVC AND NOT BUILD_SHARED_LIBS) + set_target_properties(${the_target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:atlthunk.lib /NODEFAULTLIB:atlsd.lib /DEBUG") + endif() + install(TARGETS ${the_target} RUNTIME DESTINATION "${OPENCV_SAMPLES_BIN_INSTALL_PATH}/${project}" COMPONENT main) + endif() + ENDMACRO() + + file(GLOB all_samples RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) + + foreach(sample_filename ${all_samples}) + get_filename_component(sample ${sample_filename} NAME_WE) + file(GLOB sample_srcs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${sample}.*) + OPENCV_DEFINE_DIRECTX_EXAMPLE(${sample} ${sample_srcs}) + endforeach() +endif() diff --git a/samples/directx/d3d10_interop.cpp b/samples/directx/d3d10_interop.cpp new file mode 100644 index 000000000..a9eccdfe2 --- /dev/null +++ b/samples/directx/d3d10_interop.cpp @@ -0,0 +1,138 @@ +#include +#include +#pragma comment (lib, "d3d10.lib") + +#define USE_D3D10 +#define WINDOW_NAME "OpenCV Direct3D 10 Sample" + +IDXGISwapChain *swapchain = NULL; +ID3D10Device *dev = NULL; +ID3D10Texture2D *pBackBufferTexture = NULL; +ID3D10Texture2D *pCPUWriteTexture = NULL; +ID3D10Texture2D *pInputTexture = NULL; +ID3D10RenderTargetView *backbuffer = NULL; + +#include "d3d_base.inl.hpp" + +bool initDirect3D() +{ + DXGI_SWAP_CHAIN_DESC scd; + + ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); + + scd.BufferCount = 1; // one back buffer + scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color + scd.BufferDesc.Width = WIDTH; // set the back buffer width + scd.BufferDesc.Height = HEIGHT; // set the back buffer height + scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used + scd.OutputWindow = hWnd; // the window to be used + scd.SampleDesc.Count = 1; // how many multisamples + scd.Windowed = TRUE; // windowed/full-screen mode + scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching + + if (FAILED(D3D10CreateDeviceAndSwapChain( + NULL, + D3D10_DRIVER_TYPE_HARDWARE, + NULL, + 0, + D3D10_SDK_VERSION, + &scd, + &swapchain, + &dev))) + { + return false; + } + + if (FAILED(swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBufferTexture))) + { + return false; + } + + if (FAILED(dev->CreateRenderTargetView(pBackBufferTexture, NULL, &backbuffer))) + { + return false; + } + + dev->OMSetRenderTargets(1, &backbuffer, NULL); + + D3D10_VIEWPORT viewport; + ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT)); + viewport.Width = WIDTH; + viewport.Height = HEIGHT; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 0.0f; + dev->RSSetViewports(1, &viewport); + + return true; +} + +bool initDirect3DTextures() +{ + { // Create texture for demo 0 + D3D10_TEXTURE2D_DESC desc = { 0 }; + desc.Width = WIDTH; + desc.Height = HEIGHT; + desc.MipLevels = desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + if (FAILED(dev->CreateTexture2D(&desc, NULL, &pCPUWriteTexture))) + { + std::cerr << "Can't create texture for CPU write sample" << std::endl; + return false; + } + } + + { // Create Read-only texture + cv::Mat inputMat = getInputTexture(); + + D3D10_TEXTURE2D_DESC desc = { 0 }; + desc.Width = inputMat.size().width; + desc.Height = inputMat.size().height; + desc.MipLevels = desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; + desc.Usage = D3D10_USAGE_IMMUTABLE; + desc.CPUAccessFlags = cv::ocl::useOpenCL() ? 0 : D3D10_CPU_ACCESS_READ; + + D3D10_SUBRESOURCE_DATA srInitData; + srInitData.pSysMem = inputMat.data; + srInitData.SysMemPitch = (UINT)inputMat.step[0]; + + if (FAILED(dev->CreateTexture2D(&desc, &srInitData, &pInputTexture))) + { + std::cerr << "Can't create texture with input image" << std::endl; + return false; + } + } + + return true; +} + +void cleanUp(void) +{ + if (swapchain) swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode + + SAFE_RELEASE(swapchain); + SAFE_RELEASE(pCPUWriteTexture); + SAFE_RELEASE(pInputTexture); + SAFE_RELEASE(pBackBufferTexture); + SAFE_RELEASE(backbuffer); + SAFE_RELEASE(dev); +} + + +void render(void) +{ + // check to make sure you have a valid Direct3D device + CV_Assert(dev); + + renderToD3DObject(); + + // switch the back buffer and the front buffer + swapchain->Present(0, 0); +} diff --git a/samples/directx/d3d11_interop.cpp b/samples/directx/d3d11_interop.cpp new file mode 100644 index 000000000..9db9c31fb --- /dev/null +++ b/samples/directx/d3d11_interop.cpp @@ -0,0 +1,143 @@ +#include +#include +#pragma comment (lib, "d3d11.lib") + +#define USE_D3D11 +#define WINDOW_NAME "OpenCV Direct3D 11 Sample" + +IDXGISwapChain *swapchain = NULL; +ID3D11Device *dev = NULL; +ID3D11DeviceContext *devcon = NULL; +ID3D11Texture2D *pBackBufferTexture = NULL; +ID3D11Texture2D *pCPUWriteTexture = NULL; +ID3D11Texture2D *pInputTexture = NULL; +ID3D11RenderTargetView *backbuffer = NULL; + +#include "d3d_base.inl.hpp" + +bool initDirect3D() +{ + DXGI_SWAP_CHAIN_DESC scd; + + ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); + + scd.BufferCount = 1; // one back buffer + scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color + scd.BufferDesc.Width = WIDTH; // set the back buffer width + scd.BufferDesc.Height = HEIGHT; // set the back buffer height + scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used + scd.OutputWindow = hWnd; // the window to be used + scd.SampleDesc.Count = 1; // how many multisamples + scd.Windowed = TRUE; // windowed/full-screen mode + scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching + + if (FAILED(D3D11CreateDeviceAndSwapChain( + NULL, + D3D_DRIVER_TYPE_HARDWARE, + NULL, + 0, + NULL, + 0, + D3D11_SDK_VERSION, + &scd, + &swapchain, + &dev, + NULL, + &devcon))) + { + return false; + } + + if (FAILED(swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBufferTexture))) + { + return false; + } + + if (FAILED(dev->CreateRenderTargetView(pBackBufferTexture, NULL, &backbuffer))) + { + return false; + } + + devcon->OMSetRenderTargets(1, &backbuffer, NULL); + + D3D11_VIEWPORT viewport = { 0 }; + viewport.Width = WIDTH; + viewport.Height = HEIGHT; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 0.0f; + devcon->RSSetViewports(1, &viewport); + + return true; +} + +bool initDirect3DTextures() +{ + { // Create texture for demo 0 + D3D11_TEXTURE2D_DESC desc = { 0 }; + desc.Width = WIDTH; + desc.Height = HEIGHT; + desc.MipLevels = desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if (FAILED(dev->CreateTexture2D(&desc, NULL, &pCPUWriteTexture))) + { + std::cerr << "Can't create texture for CPU write sample" << std::endl; + return false; + } + } + + { // Create Read-only texture + cv::Mat inputMat = getInputTexture(); + + D3D11_TEXTURE2D_DESC desc = { 0 }; + desc.Width = inputMat.size().width; + desc.Height = inputMat.size().height; + desc.MipLevels = desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.Usage = D3D11_USAGE_IMMUTABLE; + desc.CPUAccessFlags = cv::ocl::useOpenCL() ? 0 : D3D11_CPU_ACCESS_READ; + + D3D11_SUBRESOURCE_DATA srInitData; + srInitData.pSysMem = inputMat.data; + srInitData.SysMemPitch = (UINT)inputMat.step[0]; + + if (FAILED(dev->CreateTexture2D(&desc, &srInitData, &pInputTexture))) + { + std::cerr << "Can't create texture with input image" << std::endl; + return false; + } + } + + return true; +} + +void cleanUp(void) +{ + if (swapchain) swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode + + SAFE_RELEASE(swapchain); + SAFE_RELEASE(pCPUWriteTexture); + SAFE_RELEASE(pInputTexture); + SAFE_RELEASE(pBackBufferTexture); + SAFE_RELEASE(backbuffer); + SAFE_RELEASE(dev); + SAFE_RELEASE(devcon); +} + + +void render(void) +{ + // check to make sure you have a valid Direct3D device + CV_Assert(dev); + + renderToD3DObject(); + + // switch the back buffer and the front buffer + swapchain->Present(0, 0); +} diff --git a/samples/directx/d3d9_interop.cpp b/samples/directx/d3d9_interop.cpp new file mode 100644 index 000000000..fc9bdbdd3 --- /dev/null +++ b/samples/directx/d3d9_interop.cpp @@ -0,0 +1,149 @@ +#include +#include +#pragma comment (lib, "d3d9.lib") + +#define USE_D3D9 +#define WINDOW_NAME "OpenCV Direct3D 9 Sample" + +IDirect3D9 *pD3D = NULL; +IDirect3DDevice9 *dev = NULL; +IDirect3DSurface9 *pBackBuffer = NULL; +IDirect3DSurface9 *pCPUWriteSurface = NULL; // required name +IDirect3DSurface9 *pReadOnlySurface = NULL; // required name +HANDLE readOnlySurfaceShared = 0; // required name +IDirect3DSurface9 *pSurface = NULL; // required name +HANDLE surfaceShared = 0; // required name + +#include "d3d_base.inl.hpp" + +bool initDirect3D(void) +{ + if (NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION))) + { + return false; + } + + D3DPRESENT_PARAMETERS d3dpp; + ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS)); + + DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_NOWINDOWCHANGES + | D3DCREATE_MULTITHREADED; + + d3dpp.Windowed = true; + d3dpp.Flags = 0; + d3dpp.BackBufferCount = 0; + d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; + d3dpp.BackBufferHeight = HEIGHT; + d3dpp.BackBufferWidth = WIDTH; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = hWnd; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + + if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, flags, &d3dpp, &dev))) + { + return false; + } + + if (FAILED(dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) + { + return false; + } + + return true; +} + +bool initDirect3DTextures() +{ + // Note: sharing is not supported on some platforms + if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSurface, NULL/*&surfaceShared*/))) + { + std::cerr << "Can't create surface for result" << std::endl; + return false; + } + + // Note: sharing is not supported on some platforms + if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pReadOnlySurface, NULL/*&readOnlySurfaceShared*/))) + { + std::cerr << "Can't create read only surface" << std::endl; + return false; + } + else + { + IDirect3DSurface9* pTmpSurface; + if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pTmpSurface, NULL))) + { + std::cerr << "Can't create temp surface for CPU write" << std::endl; + return false; + } + + D3DLOCKED_RECT memDesc = {0, NULL}; + RECT rc = {0, 0, WIDTH, HEIGHT}; + if (SUCCEEDED(pTmpSurface->LockRect(&memDesc, &rc, 0))) + { + cv::Mat m(cv::Size(WIDTH, HEIGHT), CV_8UC4, memDesc.pBits, (int)memDesc.Pitch); + getInputTexture().copyTo(m); + pTmpSurface->UnlockRect(); + dev->StretchRect(pTmpSurface, NULL, pReadOnlySurface, NULL, D3DTEXF_NONE); + } + else + { + std::cerr << "Can't LockRect() on surface" << std::endl; + } + pTmpSurface->Release(); + } + + if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pCPUWriteSurface, NULL))) + { + std::cerr << "Can't create surface for CPU write" << std::endl; + return false; + } + + return true; +} + +void render(void) +{ + // check to make sure you have a valid Direct3D device + CV_Assert(dev); + + renderToD3DObject(); + + if (g_sampleType == 0) + { + // nothing + } + else if (g_sampleType == 1) + { + if (FAILED(dev->StretchRect(pCPUWriteSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) + { + std::cerr << "Can't StretchRect()" << std::endl; + } + } + else + { + if (FAILED(dev->StretchRect(pSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) + { + std::cerr << "Can't StretchRect()" << std::endl; + } + } + + if (SUCCEEDED(dev -> BeginScene())) + { + // end the scene + dev -> EndScene(); + } + + // present the back buffer contents to the display + dev->Present(NULL, NULL, NULL, NULL); +} + +void cleanUp (void) +{ + SAFE_RELEASE(pCPUWriteSurface); + SAFE_RELEASE(pReadOnlySurface); + SAFE_RELEASE(pSurface); + SAFE_RELEASE(pBackBuffer); + SAFE_RELEASE(dev); + SAFE_RELEASE(pD3D);} diff --git a/samples/directx/d3d9ex_interop.cpp b/samples/directx/d3d9ex_interop.cpp new file mode 100644 index 000000000..38d23007b --- /dev/null +++ b/samples/directx/d3d9ex_interop.cpp @@ -0,0 +1,158 @@ +#include +#include +#pragma comment (lib, "d3d9.lib") + +#define USE_D3DEX +#define WINDOW_NAME "OpenCV Direct3D 9 Ex Sample" + +IDirect3D9Ex *pD3D = NULL; +IDirect3DDevice9Ex *dev = NULL; +IDirect3DSurface9 *pBackBuffer = NULL; +IDirect3DSurface9 *pCPUWriteSurface = NULL; // required name +IDirect3DSurface9 *pReadOnlySurface = NULL; // required name +HANDLE readOnlySurfaceShared = 0; // required name +IDirect3DSurface9 *pSurface = NULL; // required name +HANDLE surfaceShared = 0; // required name + +#include "d3d_base.inl.hpp" + +bool initDirect3D(void) +{ + if (FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D))) + { + return false; + } + + D3DDISPLAYMODEEX ddm; + ZeroMemory(&ddm, sizeof(ddm)); + ddm.Size = sizeof(D3DDISPLAYMODEEX); + D3DDISPLAYROTATION rotation; + if (FAILED(pD3D->GetAdapterDisplayModeEx(D3DADAPTER_DEFAULT, &ddm, &rotation))) + { + return false; + } + + D3DPRESENT_PARAMETERS d3dpp; + ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS)); + + DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_NOWINDOWCHANGES + | D3DCREATE_MULTITHREADED; + + d3dpp.Windowed = true; + d3dpp.Flags = 0; + d3dpp.BackBufferCount = 0; + d3dpp.BackBufferFormat = ddm.Format; + d3dpp.BackBufferHeight = HEIGHT; + d3dpp.BackBufferWidth = WIDTH; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = hWnd; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + + if (FAILED(pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, flags, &d3dpp, NULL, &dev))) + { + return false; + } + + if (FAILED(dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) + { + return false; + } + + return true; +} + +bool initDirect3DTextures() +{ + if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSurface, &surfaceShared))) + { + std::cerr << "Can't create surface for result" << std::endl; + return false; + } + + if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pReadOnlySurface, &readOnlySurfaceShared))) + { + std::cerr << "Can't create read only surface" << std::endl; + return false; + } + else + { + IDirect3DSurface9* pTmpSurface; + if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pTmpSurface, NULL))) + { + std::cerr << "Can't create temp surface for CPU write" << std::endl; + return false; + } + + D3DLOCKED_RECT memDesc = {0, NULL}; + RECT rc = {0, 0, WIDTH, HEIGHT}; + if (SUCCEEDED(pTmpSurface->LockRect(&memDesc, &rc, 0))) + { + cv::Mat m(cv::Size(WIDTH, HEIGHT), CV_8UC4, memDesc.pBits, (int)memDesc.Pitch); + getInputTexture().copyTo(m); + pTmpSurface->UnlockRect(); + dev->StretchRect(pTmpSurface, NULL, pReadOnlySurface, NULL, D3DTEXF_NONE); + } + else + { + std::cerr << "Can't LockRect() on surface" << std::endl; + } + pTmpSurface->Release(); + } + + if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pCPUWriteSurface, NULL))) + { + std::cerr << "Can't create surface for CPU write" << std::endl; + return false; + } + + return true; +} + + +void render(void) +{ + // check to make sure you have a valid Direct3D device + CV_Assert(dev); + + renderToD3DObject(); + + if (g_sampleType == 0) + { + // nothing + } + else if (g_sampleType == 1) + { + if (FAILED(dev->StretchRect(pCPUWriteSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) + { + std::cerr << "Can't StretchRect()" << std::endl; + } + } + else + { + if (FAILED(dev->StretchRect(pSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) + { + std::cerr << "Can't StretchRect()" << std::endl; + } + } + + if (SUCCEEDED(dev -> BeginScene())) + { + // end the scene + dev -> EndScene(); + } + + // present the back buffer contents to the display + dev->Present(NULL, NULL, NULL, NULL); +} + +void cleanUp (void) +{ + SAFE_RELEASE(pCPUWriteSurface); + SAFE_RELEASE(pReadOnlySurface); + SAFE_RELEASE(pSurface); + SAFE_RELEASE(pBackBuffer); + SAFE_RELEASE(dev); + SAFE_RELEASE(pD3D); +} diff --git a/samples/directx/d3d_base.inl.hpp b/samples/directx/d3d_base.inl.hpp new file mode 100644 index 000000000..6b6de300d --- /dev/null +++ b/samples/directx/d3d_base.inl.hpp @@ -0,0 +1,457 @@ +// +// Don't use as a standalone file +// + +#include "opencv2/core.hpp" +#include "opencv2/core/utility.hpp" // cv::format +#include "opencv2/imgproc.hpp" // cvtColor +#include "opencv2/imgproc/types_c.h" // cvtColor +#include "opencv2/highgui.hpp" // imread +#include "opencv2/core/directx.hpp" + +#include +#include + +using namespace cv; +using namespace cv::directx; +static const int fontFace = cv::FONT_HERSHEY_DUPLEX; +#if !defined(USE_D3D9) && !defined(USE_D3DEX) +const cv::Scalar frameColor(255,128,0,255); +#else +const cv::Scalar frameColor(0,128,255,255); // BGRA for D3D9 +#endif + +#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; } + +const int WIDTH = 1024; +const int HEIGHT = 768; + +HINSTANCE hInstance; +HWND hWnd; + +// external declaration +bool initDirect3D(void); +bool initDirect3DTextures(void); +void render(void); +void cleanUp (void); + +#define USAGE_DESCRIPTION_0 "1 - CPU write via LockRect/Map" +#define USAGE_DESCRIPTION_1 "2* - Mat->D3D" +#define USAGE_DESCRIPTION_2 "3* - D3D->UMat / change UMat / UMat->D3D" +#define USAGE_DESCRIPTION_3 "0 - show input texture without any processing" +#define USAGE_DESCRIPTION_SPACE "SPACE - toggle frame processing (only data transfers)" + +static int g_sampleType = 0; +static int g_disableProcessing = false; + +// forward declaration +static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); + +static bool initWindow() +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(0, IDI_APPLICATION); + wcex.hCursor = LoadCursor(0, IDC_ARROW); + wcex.hbrBackground = 0; + wcex.lpszMenuName = 0L; + wcex.lpszClassName = "OpenCVDirectX"; + wcex.hIconSm = 0; + + RegisterClassEx(&wcex); + + RECT rc = {0, 0, WIDTH, HEIGHT}; + AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false); + hWnd = CreateWindow("OpenCVDirectX", WINDOW_NAME, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL); + + if (!hWnd) + return false; + + ShowWindow(hWnd, SW_SHOW); + UpdateWindow(hWnd); + + return true; +} + +static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + case WM_CHAR: + if (wParam >= '0' && wParam <= '3') + { + g_sampleType = (char)wParam - '0'; + return 0; + } + else if (wParam == ' ') + { + g_disableProcessing = !g_disableProcessing; + return 0; + } + else if (wParam == VK_ESCAPE) + { + DestroyWindow(hWnd); + return 0; + } + break; + } + return DefWindowProc(hWnd, message, wParam, lParam); +} + +static float getFps() +{ + static std::queue time_queue; + + int64 now = cv::getTickCount(), then = 0; + time_queue.push(now); + + if (time_queue.size() >= 2) + then = time_queue.front(); + + if (time_queue.size() >= 25) + time_queue.pop(); + + return time_queue.size() * (float)cv::getTickFrequency() / (now - then); +} + +static int bgColor[4] = {0, 0, 0, 0}; +static cv::Mat* inputMat = NULL; + +static void renderToD3DObject(void) +{ + static int frame = 0; + + const float fps = getFps(); + + String deviceName = cv::ocl::useOpenCL() ? cv::ocl::Context2::getDefault().device(0).name() : "No OpenCL device"; + + if ((frame % std::max(1, (int)(fps / 25))) == 0) + { + String msg = format("%s%s: %s, Sample %d, Frame %d, fps %g (%g ms)", + g_disableProcessing ? "(FRAME PROCESSING DISABLED) " : "", + WINDOW_NAME, deviceName.c_str(), g_sampleType, + frame, fps, (int(10 * 1000.0 / fps)) * 0.1); + SetWindowText(hWnd, msg.c_str()); + } + + // 0..255 + int c[4] = + { + std::abs((frame & 0x1ff) - 0x100), + std::abs(((frame * 2) & 0x1ff) - 0x100), + std::abs(((frame / 2) & 0x1ff) - 0x100), + 0 + }; + + int c1 = c[0] / 2 - 0x40 - bgColor[0]; + int c2 = c[1] / 2 - 0x40 - bgColor[1]; + int c3 = c[2] / 2 - 0x40 - bgColor[2]; + + switch (g_sampleType) + { + case 0: +#if defined(USE_D3D9) || defined (USE_D3DEX) + if (FAILED(dev->StretchRect(pReadOnlySurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) + { + std::cerr << "Can't StretchRect()" << std::endl; + } +#elif defined(USE_D3D10) + dev->CopyResource(pBackBufferTexture, pInputTexture); +#elif defined(USE_D3D11) + devcon->CopyResource(pBackBufferTexture, pInputTexture); +#else +#error "Invalid USE_D3D value" +#endif + break; + + case 1: + { + int BOXSIZE = 50; + int x = std::abs(((frame * 1) % (2 * (WIDTH - BOXSIZE))) - (WIDTH - BOXSIZE)); + int y = std::abs(((frame / 2) % (2 * (HEIGHT - BOXSIZE))) - (HEIGHT - BOXSIZE)); + cv::Rect boxRect(x, y, BOXSIZE, BOXSIZE); +#if defined(USE_D3D9) || defined (USE_D3DEX) + D3DLOCKED_RECT memDesc = {0, NULL}; + RECT rc = {0, 0, WIDTH, HEIGHT}; + if (SUCCEEDED(pCPUWriteSurface->LockRect(&memDesc, &rc, 0))) + { + if (!g_disableProcessing) + { + Mat m(Size(WIDTH, HEIGHT), CV_8UC4, memDesc.pBits, (int)memDesc.Pitch); + inputMat->copyTo(m); + m(boxRect).setTo(Scalar(c[0], c[1], c[2], 255)); + } + pCPUWriteSurface->UnlockRect(); + } + else + { + std::cerr << "Can't LockRect() on surface" << std::endl; + } +#elif defined(USE_D3D10) + D3D10_MAPPED_TEXTURE2D mappedTex; + if (SUCCEEDED(pCPUWriteTexture->Map( D3D10CalcSubresource(0, 0, 1), D3D10_MAP_WRITE_DISCARD, 0, &mappedTex))) + { + if (!g_disableProcessing) + { + Mat m(Size(WIDTH, HEIGHT), CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); + inputMat->copyTo(m); + m(boxRect).setTo(Scalar(c[0], c[1], c[2], 255)); + } + pCPUWriteTexture->Unmap(D3D10CalcSubresource(0, 0, 1)); + dev->CopyResource(pBackBufferTexture, pCPUWriteTexture); + } + else + { + std::cerr << "Can't Map() texture" << std::endl; + } +#elif defined(USE_D3D11) + D3D11_MAPPED_SUBRESOURCE mappedTex; + if (SUCCEEDED(devcon->Map(pCPUWriteTexture, D3D11CalcSubresource(0, 0, 1), D3D11_MAP_WRITE_DISCARD, 0, &mappedTex))) + { + if (!g_disableProcessing) + { + Mat m(Size(WIDTH, HEIGHT), CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); + inputMat->copyTo(m); + m(boxRect).setTo(Scalar(c[0], c[1], c[2], 255)); + } + devcon->Unmap(pCPUWriteTexture, D3D11CalcSubresource(0, 0, 1)); + devcon->CopyResource(pBackBufferTexture, pCPUWriteTexture); + } + else + { + std::cerr << "Can't Map() texture" << std::endl; + } +#else +#error "Invalid USE_D3D value" +#endif + break; + } + case 2: + { + static Mat m; + if (!g_disableProcessing) + { +#if 1 + cv::add(*inputMat, Scalar(c1, c2, c3, 255), m); +#else + inputMat->copyTo(m); +#endif + cv::putText(m, + cv::format("Frame %d, fps %g (%g ms)", + frame, fps, (int(10 * 1000.0 / fps)) * 0.1), + cv::Point(8, 80), fontFace, 1, frameColor, 2); + } + else + { + m.create(Size(WIDTH, HEIGHT), CV_8UC4); + } + try + { + #if defined(USE_D3D9) || defined (USE_D3DEX) + convertToDirect3DSurface9(m, pSurface, (void*)surfaceShared); + #elif defined(USE_D3D10) + convertToD3D10Texture2D(m, pBackBufferTexture); + #elif defined(USE_D3D11) + convertToD3D11Texture2D(m, pBackBufferTexture); + #else + #error "Invalid USE_D3D value" + #endif + } + catch (cv::Exception& e) + { + std::cerr << "Can't convert to D3D object: exception: " << e.what() << std::endl; + } + catch (...) + { + std::cerr << "Can't convert to D3D object" << std::endl; + } + break; + } + case 3: + { + static UMat tmp; + try + { +#if defined(USE_D3D9) || defined (USE_D3DEX) + convertFromDirect3DSurface9(pReadOnlySurface, tmp, (void*)readOnlySurfaceShared); +#elif defined(USE_D3D10) + convertFromD3D10Texture2D(pInputTexture, tmp); +#elif defined(USE_D3D11) + convertFromD3D11Texture2D(pInputTexture, tmp); +#else +#error "Invalid USE_D3D value" +#endif + } + catch (cv::Exception& e) + { + std::cerr << "Can't convert from D3D object: exception: " << e.what() << std::endl; + } + catch (...) + { + std::cerr << "Can't convert from D3D object" << std::endl; + } + static UMat res; + if (!g_disableProcessing) + { + cv::add(tmp, Scalar(c1, c2, c3, 255), res); + } + else + { + res = tmp; + } + try + { +#if defined(USE_D3D9) || defined (USE_D3DEX) + convertToDirect3DSurface9(res, pSurface, (void*)surfaceShared); +#elif defined(USE_D3D10) + convertToD3D10Texture2D(res, pBackBufferTexture); +#elif defined(USE_D3D11) + convertToD3D11Texture2D(res, pBackBufferTexture); +#else +#error "Invalid USE_D3D value" +#endif + } + catch (cv::Exception& e) + { + std::cerr << "Can't convert to D3D object: exception: " << e.what() << std::endl; + } + catch (...) + { + std::cerr << "Can't convert to D3D object" << std::endl; + } + break; + } + } + frame++; +} + + +static cv::Mat getInputTexture() +{ + cv::Mat inputMat = cv::imread("input.bmp", cv::IMREAD_COLOR); + + if (inputMat.depth() != CV_8U) + { + inputMat.convertTo(inputMat, CV_8U); + } + if (inputMat.type() == CV_8UC3) + { + cv::cvtColor(inputMat, inputMat, CV_RGB2BGRA); + } + if (inputMat.type() != CV_8UC4 || inputMat.size().area() == 0) + { + std::cerr << "Invalid input image format. Generate other" << std::endl; + inputMat.create(cv::Size(WIDTH, HEIGHT), CV_8UC4); + inputMat.setTo(cv::Scalar(0, 0, 255, 255)); + bgColor[0] = -128; bgColor[1] = -128; bgColor[2] = 127; bgColor[3] = -128; + } + if (inputMat.size().width != WIDTH || inputMat.size().height != HEIGHT) + { + cv::resize(inputMat, inputMat, cv::Size(WIDTH, HEIGHT)); + } + String deviceName = cv::ocl::useOpenCL() ? cv::ocl::Context2::getDefault().device(0).name() : "No OpenCL device"; + cv::Scalar color(64, 255, 64, 255); + cv::putText(inputMat, + cv::format("OpenCL Device name: %s", deviceName.c_str()), + cv::Point(8,32), fontFace, 1, color); + cv::putText(inputMat, WINDOW_NAME, cv::Point(50, HEIGHT - 32), fontFace, 1, color); + cv::putText(inputMat, USAGE_DESCRIPTION_0, cv::Point(30, 128), fontFace, 1, color); + cv::putText(inputMat, USAGE_DESCRIPTION_1, cv::Point(30, 192), fontFace, 1, color); + cv::putText(inputMat, USAGE_DESCRIPTION_2, cv::Point(30, 256), fontFace, 1, color); + cv::putText(inputMat, USAGE_DESCRIPTION_3, cv::Point(30, 320), fontFace, 1, color); + cv::putText(inputMat, USAGE_DESCRIPTION_SPACE, cv::Point(30, 448), fontFace, 1, color); + +#if defined(USE_D3D9) || defined (USE_D3DEX) + cv::cvtColor(inputMat, inputMat, CV_RGBA2BGRA); + std::swap(bgColor[0], bgColor[2]); +#endif + + // Make a global copy + ::inputMat = new cv::Mat(inputMat); + + return inputMat; +} + +static int mainLoop() +{ + hInstance = GetModuleHandle(NULL); + + if (!initWindow()) + CV_Error(cv::Error::StsError, "Can't create window"); + + if (!initDirect3D()) + CV_Error(cv::Error::StsError, "Can't create D3D object"); + + if (cv::ocl::haveOpenCL()) + { +#if defined(USE_D3D9) + cv::ocl::Context2& ctx = cv::directx::ocl::initializeContextFromDirect3DDevice9(dev); +#elif defined (USE_D3DEX) + cv::ocl::Context2& ctx = cv::directx::ocl::initializeContextFromDirect3DDevice9Ex(dev); +#elif defined(USE_D3D10) + cv::ocl::Context2& ctx = cv::directx::ocl::initializeContextFromD3D10Device(dev); +#elif defined(USE_D3D11) + cv::ocl::Context2& ctx = cv::directx::ocl::initializeContextFromD3D11Device(dev); +#else +#error "Invalid USE_D3D value" +#endif + std::cout << "Selected device: " << ctx.device(0).name().c_str() << std::endl; + g_sampleType = 2; + } + else + { + std::cerr << "OpenCL is not available. DirectX - OpenCL interop will not work" << std::endl; + } + + if (!initDirect3DTextures()) + CV_Error(cv::Error::StsError, "Can't create D3D texture object"); + + MSG msg; + ZeroMemory(&msg, sizeof(msg)); + + while (msg.message != WM_QUIT) + { + if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + render(); + } + } + + cleanUp(); + + return static_cast(msg.wParam); +} + +int main(int /*argc*/, char ** /*argv*/) +{ + try + { + return mainLoop(); + } + catch (cv::Exception& e) + { + std::cerr << "Exception: " << e.what() << std::endl; + return 10; + } + catch (...) + { + std::cerr << "FATAL ERROR: Unknown exception" << std::endl; + return 11; + } +}