1 /* 2 // Sample demonstrating interoperability of OpenCV UMat with Direct X surface 3 // At first, the data obtained from video file or camera and 4 // placed onto Direct X surface, 5 // following mapping of this Direct X surface to OpenCV UMat and call cv::Blur 6 // function. The result is mapped back to Direct X surface and rendered through 7 // Direct X API. 8 */ 9 #define WIN32_LEAN_AND_MEAN 10 #include <windows.h> 11 #include <d3d10.h> 12 13 #include "opencv2/core.hpp" 14 #include "opencv2/core/directx.hpp" 15 #include "opencv2/core/ocl.hpp" 16 #include "opencv2/imgproc.hpp" 17 #include "opencv2/videoio.hpp" 18 19 #include "d3dsample.hpp" 20 21 #pragma comment (lib, "d3d10.lib") 22 23 24 using namespace std; 25 using namespace cv; 26 27 class D3D10WinApp : public D3DSample 28 { 29 public: 30 D3D10WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : 31 D3DSample(width, height, window_name, cap) {} 32 33 ~D3D10WinApp() {} 34 35 36 int create(void) 37 { 38 // base initialization 39 D3DSample::create(); 40 41 // initialize DirectX 42 HRESULT r; 43 44 DXGI_SWAP_CHAIN_DESC scd; 45 46 ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); 47 48 scd.BufferCount = 1; // one back buffer 49 scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color 50 scd.BufferDesc.Width = m_width; // set the back buffer width 51 scd.BufferDesc.Height = m_height; // set the back buffer height 52 scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used 53 scd.OutputWindow = m_hWnd; // the window to be used 54 scd.SampleDesc.Count = 1; // how many multisamples 55 scd.Windowed = TRUE; // windowed/full-screen mode 56 scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 57 scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching 58 59 r = ::D3D10CreateDeviceAndSwapChain( 60 NULL, 61 D3D10_DRIVER_TYPE_HARDWARE, 62 NULL, 63 0, 64 D3D10_SDK_VERSION, 65 &scd, 66 &m_pD3D10SwapChain, 67 &m_pD3D10Dev); 68 if (FAILED(r)) 69 { 70 return -1; 71 } 72 73 r = m_pD3D10SwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&m_pBackBuffer); 74 if (FAILED(r)) 75 { 76 return -1; 77 } 78 79 r = m_pD3D10Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget); 80 if (FAILED(r)) 81 { 82 return -1; 83 } 84 85 m_pD3D10Dev->OMSetRenderTargets(1, &m_pRenderTarget, NULL); 86 87 D3D10_VIEWPORT viewport; 88 ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT)); 89 90 viewport.Width = m_width; 91 viewport.Height = m_height; 92 viewport.MinDepth = 0.0f; 93 viewport.MaxDepth = 0.0f; 94 95 m_pD3D10Dev->RSSetViewports(1, &viewport); 96 97 D3D10_TEXTURE2D_DESC desc = { 0 }; 98 99 desc.Width = m_width; 100 desc.Height = m_height; 101 desc.MipLevels = 1; 102 desc.ArraySize = 1; 103 desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 104 desc.SampleDesc.Count = 1; 105 desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; 106 desc.Usage = D3D10_USAGE_DYNAMIC; 107 desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; 108 109 r = m_pD3D10Dev->CreateTexture2D(&desc, NULL, &m_pSurface); 110 if (FAILED(r)) 111 { 112 std::cerr << "Can't create texture with input image" << std::endl; 113 return -1; 114 } 115 116 // initialize OpenCL context of OpenCV lib from DirectX 117 if (cv::ocl::haveOpenCL()) 118 { 119 m_oclCtx = cv::directx::ocl::initializeContextFromD3D10Device(m_pD3D10Dev); 120 } 121 122 m_oclDevName = cv::ocl::useOpenCL() ? 123 cv::ocl::Context::getDefault().device(0).name() : 124 "No OpenCL device"; 125 126 return 0; 127 } // create() 128 129 130 // get media data on DX surface for further processing 131 int get_surface(ID3D10Texture2D** ppSurface) 132 { 133 HRESULT r; 134 135 if (!m_cap.read(m_frame_bgr)) 136 return -1; 137 138 cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA); 139 140 UINT subResource = ::D3D10CalcSubresource(0, 0, 1); 141 142 D3D10_MAPPED_TEXTURE2D mappedTex; 143 r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); 144 if (FAILED(r)) 145 { 146 return r; 147 } 148 149 cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); 150 // copy video frame data to surface 151 m_frame_rgba.copyTo(m); 152 153 m_pSurface->Unmap(subResource); 154 155 *ppSurface = m_pSurface; 156 157 return 0; 158 } // get_surface() 159 160 161 // process and render media data 162 int render() 163 { 164 try 165 { 166 if (m_shutdown) 167 return 0; 168 169 HRESULT r; 170 ID3D10Texture2D* pSurface; 171 172 r = get_surface(&pSurface); 173 if (FAILED(r)) 174 { 175 return -1; 176 } 177 178 switch (m_mode) 179 { 180 case MODE_NOP: 181 // no processing 182 break; 183 184 case MODE_CPU: 185 { 186 // process video frame on CPU 187 UINT subResource = ::D3D10CalcSubresource(0, 0, 1); 188 189 D3D10_MAPPED_TEXTURE2D mappedTex; 190 r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); 191 if (FAILED(r)) 192 { 193 return r; 194 } 195 196 cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); 197 198 if (!m_disableProcessing) 199 { 200 // blur D3D10 surface with OpenCV on CPU 201 cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); 202 } 203 204 m_pSurface->Unmap(subResource); 205 206 break; 207 } 208 209 case MODE_GPU: 210 { 211 // process video frame on GPU 212 cv::UMat u; 213 214 cv::directx::convertFromD3D10Texture2D(pSurface, u); 215 216 if (!m_disableProcessing) 217 { 218 // blur D3D9 surface with OpenCV on GPU with OpenCL 219 cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); 220 } 221 222 cv::directx::convertToD3D10Texture2D(u, pSurface); 223 224 break; 225 } 226 227 } // switch 228 229 print_info(pSurface, m_mode, getFps(), m_oclDevName); 230 231 // traditional DX render pipeline: 232 // BitBlt surface to backBuffer and flip backBuffer to frontBuffer 233 m_pD3D10Dev->CopyResource(m_pBackBuffer, pSurface); 234 235 // present the back buffer contents to the display 236 // switch the back buffer and the front buffer 237 r = m_pD3D10SwapChain->Present(0, 0); 238 if (FAILED(r)) 239 { 240 return -1; 241 } 242 } // try 243 244 catch (cv::Exception& e) 245 { 246 std::cerr << "Exception: " << e.what() << std::endl; 247 return 10; 248 } 249 250 return 0; 251 } // render() 252 253 254 void print_info(ID3D10Texture2D* pSurface, int mode, float fps, cv::String oclDevName) 255 { 256 HRESULT r; 257 258 UINT subResource = ::D3D10CalcSubresource(0, 0, 1); 259 260 D3D10_MAPPED_TEXTURE2D mappedTex; 261 r = pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); 262 if (FAILED(r)) 263 { 264 return; 265 } 266 267 cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); 268 269 cv::String strMode = cv::format("%s", m_modeStr[mode].c_str()); 270 cv::String strFPS = cv::format("%2.1f", fps); 271 cv::String strDevName = cv::format("%s", oclDevName.c_str()); 272 273 cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0)); 274 cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0)); 275 cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0)); 276 277 m_pSurface->Unmap(subResource); 278 279 return; 280 } // print_info() 281 282 283 int cleanup(void) 284 { 285 SAFE_RELEASE(m_pSurface); 286 SAFE_RELEASE(m_pBackBuffer); 287 SAFE_RELEASE(m_pD3D10SwapChain); 288 SAFE_RELEASE(m_pRenderTarget); 289 SAFE_RELEASE(m_pD3D10Dev); 290 D3DSample::cleanup(); 291 return 0; 292 } // cleanup() 293 294 private: 295 ID3D10Device* m_pD3D10Dev; 296 IDXGISwapChain* m_pD3D10SwapChain; 297 ID3D10Texture2D* m_pBackBuffer; 298 ID3D10Texture2D* m_pSurface; 299 ID3D10RenderTargetView* m_pRenderTarget; 300 cv::ocl::Context m_oclCtx; 301 cv::String m_oclPlatformName; 302 cv::String m_oclDevName; 303 }; 304 305 306 // main func 307 int main(int argc, char** argv) 308 { 309 std::string title = "D3D10 interop sample"; 310 return d3d_app<D3D10WinApp>(argc, argv, title); 311 } 312