removed original samples and replace them with new ones. modified new samples (reduce code duplication, add cmd line params and short description)
parent
3cb4954d70
commit
f0197006e0
11 changed files with 1281 additions and 2528 deletions
@ -1,138 +1,299 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <d3d10.h> |
||||
#pragma comment (lib, "d3d10.lib") |
||||
|
||||
#define USE_D3D10 |
||||
#define WINDOW_NAME "OpenCV Direct3D 10 Sample" |
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
|
||||
#include "d3dsample.hpp" |
||||
|
||||
IDXGISwapChain *swapchain = NULL; |
||||
ID3D10Device *dev = NULL; |
||||
ID3D10Texture2D *pBackBufferTexture = NULL; |
||||
ID3D10Texture2D *pCPUWriteTexture = NULL; |
||||
ID3D10Texture2D *pInputTexture = NULL; |
||||
ID3D10RenderTargetView *backbuffer = NULL; |
||||
#pragma comment (lib, "d3d10.lib") |
||||
|
||||
#include "d3d_base.inl.hpp" |
||||
|
||||
bool initDirect3D() |
||||
using namespace std; |
||||
using namespace cv; |
||||
|
||||
class D3D10WinApp : public D3DSample |
||||
{ |
||||
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; |
||||
} |
||||
public: |
||||
D3D10WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
D3DSample(width, height, window_name, cap) {} |
||||
|
||||
~D3D10WinApp() {} |
||||
|
||||
if (FAILED(swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBufferTexture))) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if (FAILED(dev->CreateRenderTargetView(pBackBufferTexture, NULL, &backbuffer))) |
||||
int create(void) |
||||
{ |
||||
return false; |
||||
} |
||||
// base initialization
|
||||
D3DSample::create(); |
||||
|
||||
dev->OMSetRenderTargets(1, &backbuffer, NULL); |
||||
// initialize DirectX
|
||||
HRESULT r; |
||||
|
||||
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); |
||||
DXGI_SWAP_CHAIN_DESC scd; |
||||
|
||||
return true; |
||||
} |
||||
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); |
||||
|
||||
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))) |
||||
scd.BufferCount = 1; // one back buffer
|
||||
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
|
||||
scd.BufferDesc.Width = m_width; // set the back buffer width
|
||||
scd.BufferDesc.Height = m_height; // set the back buffer height
|
||||
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
|
||||
scd.OutputWindow = m_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
|
||||
|
||||
r = ::D3D10CreateDeviceAndSwapChain( |
||||
NULL, |
||||
D3D10_DRIVER_TYPE_HARDWARE, |
||||
NULL, |
||||
0, |
||||
D3D10_SDK_VERSION, |
||||
&scd, |
||||
&m_pD3D10SwapChain, |
||||
&m_pD3D10Dev); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D10SwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&m_pBackBuffer); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D10Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create texture for CPU write sample" << std::endl; |
||||
return false; |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
{ // Create Read-only texture
|
||||
cv::Mat inputMat = getInputTexture(); |
||||
m_pD3D10Dev->OMSetRenderTargets(1, &m_pRenderTarget, NULL); |
||||
|
||||
D3D10_VIEWPORT viewport; |
||||
ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT)); |
||||
|
||||
viewport.Width = m_width; |
||||
viewport.Height = m_height; |
||||
viewport.MinDepth = 0.0f; |
||||
viewport.MaxDepth = 0.0f; |
||||
|
||||
m_pD3D10Dev->RSSetViewports(1, &viewport); |
||||
|
||||
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.ptr(); |
||||
srInitData.SysMemPitch = (UINT)inputMat.step[0]; |
||||
desc.Width = m_width; |
||||
desc.Height = m_height; |
||||
desc.MipLevels = 1; |
||||
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, &srInitData, &pInputTexture))) |
||||
r = m_pD3D10Dev->CreateTexture2D(&desc, NULL, &m_pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create texture with input image" << std::endl; |
||||
return false; |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
// initialize OpenCL context of OpenCV lib from DirectX
|
||||
if (cv::ocl::haveOpenCL()) |
||||
{ |
||||
m_oclCtx = cv::directx::ocl::initializeContextFromD3D10Device(m_pD3D10Dev); |
||||
} |
||||
|
||||
void cleanUp(void) |
||||
{ |
||||
if (swapchain) swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
|
||||
m_oclDevName = cv::ocl::useOpenCL() ? |
||||
cv::ocl::Context::getDefault().device(0).name() : |
||||
"No OpenCL device"; |
||||
|
||||
SAFE_RELEASE(swapchain); |
||||
SAFE_RELEASE(pCPUWriteTexture); |
||||
SAFE_RELEASE(pInputTexture); |
||||
SAFE_RELEASE(pBackBufferTexture); |
||||
SAFE_RELEASE(backbuffer); |
||||
SAFE_RELEASE(dev); |
||||
} |
||||
return 0; |
||||
} // create()
|
||||
|
||||
|
||||
void render(void) |
||||
{ |
||||
// check to make sure you have a valid Direct3D device
|
||||
CV_Assert(dev); |
||||
// get media data on DX surface for further processing
|
||||
int get_surface(ID3D10Texture2D** ppSurface) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
if (!m_cap.read(m_frame_bgr)) |
||||
return -1; |
||||
|
||||
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA); |
||||
|
||||
UINT subResource = ::D3D10CalcSubresource(0, 0, 1); |
||||
|
||||
D3D10_MAPPED_TEXTURE2D mappedTex; |
||||
r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
// copy video frame data to surface
|
||||
m_frame_rgba.copyTo(m); |
||||
|
||||
m_pSurface->Unmap(subResource); |
||||
|
||||
*ppSurface = m_pSurface; |
||||
|
||||
return 0; |
||||
} // get_surface()
|
||||
|
||||
|
||||
// process and render media data
|
||||
int render() |
||||
{ |
||||
try |
||||
{ |
||||
if (m_shutdown) |
||||
return 0; |
||||
|
||||
HRESULT r; |
||||
ID3D10Texture2D* pSurface; |
||||
|
||||
r = get_surface(&pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
switch (m_mode) |
||||
{ |
||||
case MODE_NOP: |
||||
// no processing
|
||||
break; |
||||
|
||||
case MODE_CPU: |
||||
{ |
||||
// process video frame on CPU
|
||||
UINT subResource = ::D3D10CalcSubresource(0, 0, 1); |
||||
|
||||
D3D10_MAPPED_TEXTURE2D mappedTex; |
||||
r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D10 surface with OpenCV on CPU
|
||||
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
m_pSurface->Unmap(subResource); |
||||
|
||||
break; |
||||
} |
||||
|
||||
case MODE_GPU: |
||||
{ |
||||
// process video frame on GPU
|
||||
cv::UMat u; |
||||
|
||||
cv::directx::convertFromD3D10Texture2D(pSurface, u); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on GPU with OpenCL
|
||||
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
cv::directx::convertToD3D10Texture2D(u, pSurface); |
||||
|
||||
break; |
||||
} |
||||
|
||||
} // switch
|
||||
|
||||
print_info(pSurface, m_mode, getFps(), m_oclDevName); |
||||
|
||||
// traditional DX render pipeline:
|
||||
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
|
||||
m_pD3D10Dev->CopyResource(m_pBackBuffer, pSurface); |
||||
|
||||
// present the back buffer contents to the display
|
||||
// switch the back buffer and the front buffer
|
||||
r = m_pD3D10SwapChain->Present(0, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
} // try
|
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
return 0; |
||||
} // render()
|
||||
|
||||
|
||||
void print_info(ID3D10Texture2D* pSurface, int mode, float fps, cv::String oclDevName) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
UINT subResource = ::D3D10CalcSubresource(0, 0, 1); |
||||
|
||||
D3D10_MAPPED_TEXTURE2D mappedTex; |
||||
r = pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
|
||||
cv::String strMode = cv::format("%s", m_modeStr[mode].c_str()); |
||||
cv::String strFPS = cv::format("%2.1f", fps); |
||||
cv::String strDevName = cv::format("%s", oclDevName.c_str()); |
||||
|
||||
cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
|
||||
m_pSurface->Unmap(subResource); |
||||
|
||||
return; |
||||
} // print_info()
|
||||
|
||||
|
||||
int cleanup(void) |
||||
{ |
||||
SAFE_RELEASE(m_pSurface); |
||||
SAFE_RELEASE(m_pBackBuffer); |
||||
SAFE_RELEASE(m_pD3D10SwapChain); |
||||
SAFE_RELEASE(m_pRenderTarget); |
||||
SAFE_RELEASE(m_pD3D10Dev); |
||||
D3DSample::cleanup(); |
||||
return 0; |
||||
} // cleanup()
|
||||
|
||||
private: |
||||
ID3D10Device* m_pD3D10Dev; |
||||
IDXGISwapChain* m_pD3D10SwapChain; |
||||
ID3D10Texture2D* m_pBackBuffer; |
||||
ID3D10Texture2D* m_pSurface; |
||||
ID3D10RenderTargetView* m_pRenderTarget; |
||||
cv::ocl::Context m_oclCtx; |
||||
cv::String m_oclPlatformName; |
||||
cv::String m_oclDevName; |
||||
}; |
||||
|
||||
renderToD3DObject(); |
||||
|
||||
// switch the back buffer and the front buffer
|
||||
swapchain->Present(0, 0); |
||||
} |
||||
// main func
|
||||
ENTRY_POINT(D3D10WinApp, "D3D10 interop sample"); |
||||
|
@ -1,397 +0,0 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <d3d10.h> |
||||
|
||||
#include <string> |
||||
#include <iostream> |
||||
#include <queue> |
||||
|
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
#include "winapp.hpp" |
||||
|
||||
#pragma comment (lib, "d3d10.lib") |
||||
|
||||
|
||||
class D3D10WinApp : public WinApp |
||||
{ |
||||
public: |
||||
D3D10WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
WinApp(width, height, window_name) |
||||
{ |
||||
m_shutdown = false; |
||||
m_mode = 0; |
||||
m_modeStr[0] = cv::String("No processing"); |
||||
m_modeStr[1] = cv::String("Processing on CPU"); |
||||
m_modeStr[2] = cv::String("Processing on GPU"); |
||||
m_disableProcessing = false; |
||||
m_cap = cap; |
||||
} |
||||
|
||||
~D3D10WinApp() {} |
||||
|
||||
int onClose(void) |
||||
{ |
||||
m_shutdown = true; |
||||
cleanup(); |
||||
::DestroyWindow(m_hWnd); |
||||
return 0; |
||||
} |
||||
|
||||
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
||||
{ |
||||
switch (message) |
||||
{ |
||||
case WM_CHAR: |
||||
if (wParam >= '0' && wParam <= '2') |
||||
{ |
||||
m_mode = (char)wParam - '0'; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_SPACE) |
||||
{ |
||||
m_disableProcessing = !m_disableProcessing; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_ESCAPE) |
||||
{ |
||||
return onClose(); |
||||
} |
||||
break; |
||||
|
||||
case WM_CLOSE: |
||||
return onClose(); |
||||
|
||||
case WM_DESTROY: |
||||
::PostQuitMessage(0); |
||||
return 0; |
||||
} |
||||
|
||||
return ::DefWindowProc(hWnd, message, wParam, lParam); |
||||
} |
||||
|
||||
static float getFps() |
||||
{ |
||||
static std::queue<int64> time_queue; |
||||
|
||||
int64 now = cv::getTickCount(); |
||||
int64 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); |
||||
} |
||||
|
||||
int init(void) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
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 = m_width; // set the back buffer width
|
||||
scd.BufferDesc.Height = m_height; // set the back buffer height
|
||||
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
|
||||
scd.OutputWindow = m_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
|
||||
|
||||
r = ::D3D10CreateDeviceAndSwapChain( |
||||
NULL, |
||||
D3D10_DRIVER_TYPE_HARDWARE, |
||||
NULL, |
||||
0, |
||||
D3D10_SDK_VERSION, |
||||
&scd, |
||||
&m_pD3D10SwapChain, |
||||
&m_pD3D10Dev); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D10SwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&m_pBackBuffer); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D10Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
m_pD3D10Dev->OMSetRenderTargets(1, &m_pRenderTarget, NULL); |
||||
|
||||
D3D10_VIEWPORT viewport; |
||||
ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT)); |
||||
|
||||
viewport.Width = m_width; |
||||
viewport.Height = m_height; |
||||
viewport.MinDepth = 0.0f; |
||||
viewport.MaxDepth = 0.0f; |
||||
|
||||
m_pD3D10Dev->RSSetViewports(1, &viewport); |
||||
|
||||
D3D10_TEXTURE2D_DESC desc = { 0 }; |
||||
|
||||
desc.Width = m_width; |
||||
desc.Height = m_height; |
||||
desc.MipLevels = 1; |
||||
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; |
||||
|
||||
r = m_pD3D10Dev->CreateTexture2D(&desc, NULL, &m_pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create texture with input image" << std::endl; |
||||
return -1; |
||||
} |
||||
|
||||
if (cv::ocl::haveOpenCL()) |
||||
{ |
||||
m_oclCtx = cv::directx::ocl::initializeContextFromD3D10Device(m_pD3D10Dev); |
||||
} |
||||
|
||||
m_oclDevName = cv::ocl::useOpenCL() ? |
||||
cv::ocl::Context::getDefault().device(0).name() : |
||||
"No OpenCL device"; |
||||
|
||||
return 0; |
||||
} // init()
|
||||
|
||||
|
||||
int get_surface(ID3D10Texture2D** ppSurface) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
if (!m_cap.read(m_frame_bgr)) |
||||
return -1; |
||||
|
||||
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA); |
||||
|
||||
UINT subResource = ::D3D10CalcSubresource(0, 0, 1); |
||||
|
||||
D3D10_MAPPED_TEXTURE2D mappedTex; |
||||
r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
// copy video frame data to surface
|
||||
m_frame_rgba.copyTo(m); |
||||
|
||||
m_pSurface->Unmap(subResource); |
||||
|
||||
*ppSurface = m_pSurface; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
void print_info(ID3D10Texture2D* pSurface, int mode, float fps, cv::String oclDevName) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
UINT subResource = ::D3D10CalcSubresource(0, 0, 1); |
||||
|
||||
D3D10_MAPPED_TEXTURE2D mappedTex; |
||||
r = pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
|
||||
cv::String strMode = cv::format("%s", m_modeStr[mode].c_str()); |
||||
cv::String strFPS = cv::format("%2.1f", fps); |
||||
cv::String strDevName = cv::format("%s", oclDevName.c_str()); |
||||
|
||||
cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
|
||||
m_pSurface->Unmap(subResource); |
||||
|
||||
return; |
||||
} |
||||
|
||||
|
||||
int render() |
||||
{ |
||||
try |
||||
{ |
||||
if (m_shutdown) |
||||
return 0; |
||||
|
||||
HRESULT r; |
||||
ID3D10Texture2D* pSurface; |
||||
|
||||
r = get_surface(&pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
switch (m_mode) |
||||
{ |
||||
case 0: |
||||
// no processing
|
||||
break; |
||||
|
||||
case 1: |
||||
{ |
||||
// process video frame on CPU
|
||||
UINT subResource = ::D3D10CalcSubresource(0, 0, 1); |
||||
|
||||
D3D10_MAPPED_TEXTURE2D mappedTex; |
||||
r = m_pSurface->Map(subResource, D3D10_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D10 surface with OpenCV on CPU
|
||||
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
m_pSurface->Unmap(subResource); |
||||
|
||||
break; |
||||
} |
||||
|
||||
case 2: |
||||
{ |
||||
// process video frame on GPU
|
||||
cv::UMat u; |
||||
|
||||
cv::directx::convertFromD3D10Texture2D(pSurface, u); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on GPU with OpenCL
|
||||
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
cv::directx::convertToD3D10Texture2D(u, pSurface); |
||||
|
||||
break; |
||||
} |
||||
|
||||
} // switch
|
||||
|
||||
print_info(pSurface, m_mode, getFps(), m_oclDevName); |
||||
|
||||
// traditional DX render pipeline:
|
||||
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
|
||||
m_pD3D10Dev->CopyResource(m_pBackBuffer, pSurface); |
||||
|
||||
// present the back buffer contents to the display
|
||||
// switch the back buffer and the front buffer
|
||||
r = m_pD3D10SwapChain->Present(0, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cleanup(void) |
||||
{ |
||||
SAFE_RELEASE(m_pSurface); |
||||
SAFE_RELEASE(m_pBackBuffer); |
||||
SAFE_RELEASE(m_pD3D10SwapChain); |
||||
SAFE_RELEASE(m_pRenderTarget); |
||||
SAFE_RELEASE(m_pD3D10Dev); |
||||
return 0; |
||||
} |
||||
|
||||
private: |
||||
bool m_shutdown; |
||||
int m_mode; |
||||
cv::String m_modeStr[3]; |
||||
int m_disableProcessing; |
||||
ID3D10Device* m_pD3D10Dev; |
||||
IDXGISwapChain* m_pD3D10SwapChain; |
||||
ID3D10Texture2D* m_pBackBuffer; |
||||
ID3D10Texture2D* m_pSurface; |
||||
ID3D10RenderTargetView* m_pRenderTarget; |
||||
cv::VideoCapture m_cap; |
||||
cv::Mat m_frame_bgr; |
||||
cv::Mat m_frame_rgba; |
||||
cv::ocl::Context m_oclCtx; |
||||
cv::String m_oclPlatformName; |
||||
cv::String m_oclDevName; |
||||
}; |
||||
|
||||
|
||||
using namespace cv; |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
cv::VideoCapture cap; |
||||
|
||||
if (argc > 1) |
||||
{ |
||||
cap.open(argv[1]); |
||||
} |
||||
else |
||||
cap.open(0); |
||||
|
||||
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH); |
||||
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT); |
||||
std::string wndname = "D3D10 Window"; |
||||
|
||||
D3D10WinApp app(width, height, wndname, cap); |
||||
|
||||
try |
||||
{ |
||||
app.Create(); |
||||
return app.run(); |
||||
} |
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
catch (...) |
||||
{ |
||||
std::cerr << "FATAL ERROR: Unknown exception" << std::endl; |
||||
return 11; |
||||
} |
||||
} |
@ -1,143 +1,305 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <d3d11.h> |
||||
#pragma comment (lib, "d3d11.lib") |
||||
|
||||
#define USE_D3D11 |
||||
#define WINDOW_NAME "OpenCV Direct3D 11 Sample" |
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
|
||||
#include "d3dsample.hpp" |
||||
|
||||
IDXGISwapChain *swapchain = NULL; |
||||
ID3D11Device *dev = NULL; |
||||
ID3D11DeviceContext *devcon = NULL; |
||||
ID3D11Texture2D *pBackBufferTexture = NULL; |
||||
ID3D11Texture2D *pCPUWriteTexture = NULL; |
||||
ID3D11Texture2D *pInputTexture = NULL; |
||||
ID3D11RenderTargetView *backbuffer = NULL; |
||||
#pragma comment (lib, "d3d11.lib") |
||||
|
||||
#include "d3d_base.inl.hpp" |
||||
|
||||
bool initDirect3D() |
||||
using namespace std; |
||||
using namespace cv; |
||||
|
||||
class D3D11WinApp : public D3DSample |
||||
{ |
||||
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; |
||||
} |
||||
public: |
||||
D3D11WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
D3DSample(width, height, window_name, cap) {} |
||||
|
||||
~D3D11WinApp() {} |
||||
|
||||
if (FAILED(swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBufferTexture))) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if (FAILED(dev->CreateRenderTargetView(pBackBufferTexture, NULL, &backbuffer))) |
||||
int create(void) |
||||
{ |
||||
return false; |
||||
} |
||||
// base initialization
|
||||
D3DSample::create(); |
||||
|
||||
devcon->OMSetRenderTargets(1, &backbuffer, NULL); |
||||
// initialize DirectX
|
||||
HRESULT r; |
||||
|
||||
D3D11_VIEWPORT viewport = { 0 }; |
||||
viewport.Width = WIDTH; |
||||
viewport.Height = HEIGHT; |
||||
viewport.MinDepth = 0.0f; |
||||
viewport.MaxDepth = 0.0f; |
||||
devcon->RSSetViewports(1, &viewport); |
||||
DXGI_SWAP_CHAIN_DESC scd; |
||||
|
||||
return true; |
||||
} |
||||
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); |
||||
|
||||
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))) |
||||
scd.BufferCount = 1; // one back buffer
|
||||
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
|
||||
scd.BufferDesc.Width = m_width; // set the back buffer width
|
||||
scd.BufferDesc.Height = m_height; // set the back buffer height
|
||||
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
|
||||
scd.OutputWindow = m_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
|
||||
|
||||
r = ::D3D11CreateDeviceAndSwapChain( |
||||
NULL, |
||||
D3D_DRIVER_TYPE_HARDWARE, |
||||
NULL, |
||||
0, |
||||
NULL, |
||||
0, |
||||
D3D11_SDK_VERSION, |
||||
&scd, |
||||
&m_pD3D11SwapChain, |
||||
&m_pD3D11Dev, |
||||
NULL, |
||||
&m_pD3D11Ctx); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D11SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&m_pBackBuffer); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D11Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create texture for CPU write sample" << std::endl; |
||||
return false; |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
{ // Create Read-only texture
|
||||
cv::Mat inputMat = getInputTexture(); |
||||
m_pD3D11Ctx->OMSetRenderTargets(1, &m_pRenderTarget, NULL); |
||||
|
||||
D3D11_VIEWPORT viewport; |
||||
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); |
||||
|
||||
viewport.Width = (float)m_width; |
||||
viewport.Height = (float)m_height; |
||||
viewport.MinDepth = 0.0f; |
||||
viewport.MaxDepth = 0.0f; |
||||
|
||||
m_pD3D11Ctx->RSSetViewports(1, &viewport); |
||||
|
||||
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.ptr(); |
||||
srInitData.SysMemPitch = (UINT)inputMat.step[0]; |
||||
desc.Width = m_width; |
||||
desc.Height = m_height; |
||||
desc.MipLevels = 1; |
||||
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, &srInitData, &pInputTexture))) |
||||
r = m_pD3D11Dev->CreateTexture2D(&desc, NULL, &m_pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create texture with input image" << std::endl; |
||||
return false; |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
// initialize OpenCL context of OpenCV lib from DirectX
|
||||
if (cv::ocl::haveOpenCL()) |
||||
{ |
||||
m_oclCtx = cv::directx::ocl::initializeContextFromD3D11Device(m_pD3D11Dev); |
||||
} |
||||
|
||||
void cleanUp(void) |
||||
{ |
||||
if (swapchain) swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
|
||||
m_oclDevName = cv::ocl::useOpenCL() ? |
||||
cv::ocl::Context::getDefault().device(0).name() : |
||||
"No OpenCL device"; |
||||
|
||||
SAFE_RELEASE(swapchain); |
||||
SAFE_RELEASE(pCPUWriteTexture); |
||||
SAFE_RELEASE(pInputTexture); |
||||
SAFE_RELEASE(pBackBufferTexture); |
||||
SAFE_RELEASE(backbuffer); |
||||
SAFE_RELEASE(dev); |
||||
SAFE_RELEASE(devcon); |
||||
} |
||||
return 0; |
||||
} // create()
|
||||
|
||||
|
||||
void render(void) |
||||
{ |
||||
// check to make sure you have a valid Direct3D device
|
||||
CV_Assert(dev); |
||||
// get media data on DX surface for further processing
|
||||
int get_surface(ID3D11Texture2D** ppSurface) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
if (!m_cap.read(m_frame_bgr)) |
||||
return -1; |
||||
|
||||
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA); |
||||
|
||||
UINT subResource = ::D3D11CalcSubresource(0, 0, 1); |
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedTex; |
||||
r = m_pD3D11Ctx->Map(m_pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
// copy video frame data to surface
|
||||
m_frame_rgba.copyTo(m); |
||||
|
||||
m_pD3D11Ctx->Unmap(m_pSurface, subResource); |
||||
|
||||
*ppSurface = m_pSurface; |
||||
|
||||
return 0; |
||||
} // get_surface()
|
||||
|
||||
|
||||
// process and render media data
|
||||
int render() |
||||
{ |
||||
try |
||||
{ |
||||
if (m_shutdown) |
||||
return 0; |
||||
|
||||
HRESULT r; |
||||
ID3D11Texture2D* pSurface; |
||||
|
||||
r = get_surface(&pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
switch (m_mode) |
||||
{ |
||||
case MODE_NOP: |
||||
// no processing
|
||||
break; |
||||
|
||||
case MODE_CPU: |
||||
{ |
||||
// process video frame on CPU
|
||||
UINT subResource = ::D3D11CalcSubresource(0, 0, 1); |
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedTex; |
||||
r = m_pD3D11Ctx->Map(m_pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D10 surface with OpenCV on CPU
|
||||
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
m_pD3D11Ctx->Unmap(m_pSurface, subResource); |
||||
|
||||
break; |
||||
} |
||||
|
||||
case MODE_GPU: |
||||
{ |
||||
// process video frame on GPU
|
||||
cv::UMat u; |
||||
|
||||
cv::directx::convertFromD3D11Texture2D(pSurface, u); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on GPU with OpenCL
|
||||
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
cv::directx::convertToD3D11Texture2D(u, pSurface); |
||||
|
||||
break; |
||||
} |
||||
|
||||
} // switch
|
||||
|
||||
print_info(pSurface, m_mode, getFps(), m_oclDevName); |
||||
|
||||
// traditional DX render pipeline:
|
||||
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
|
||||
m_pD3D11Ctx->CopyResource(m_pBackBuffer, pSurface); |
||||
|
||||
// present the back buffer contents to the display
|
||||
// switch the back buffer and the front buffer
|
||||
r = m_pD3D11SwapChain->Present(0, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
} // try
|
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
return 0; |
||||
} // render()
|
||||
|
||||
|
||||
void print_info(ID3D11Texture2D* pSurface, int mode, float fps, cv::String oclDevName) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
UINT subResource = ::D3D11CalcSubresource(0, 0, 1); |
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedTex; |
||||
r = m_pD3D11Ctx->Map(pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
|
||||
cv::String strMode = cv::format("%s", m_modeStr[mode].c_str()); |
||||
cv::String strFPS = cv::format("%2.1f", fps); |
||||
cv::String strDevName = cv::format("%s", oclDevName.c_str()); |
||||
|
||||
cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
|
||||
m_pD3D11Ctx->Unmap(pSurface, subResource); |
||||
|
||||
return; |
||||
} // printf_info()
|
||||
|
||||
|
||||
int cleanup(void) |
||||
{ |
||||
SAFE_RELEASE(m_pSurface); |
||||
SAFE_RELEASE(m_pBackBuffer); |
||||
SAFE_RELEASE(m_pD3D11SwapChain); |
||||
SAFE_RELEASE(m_pRenderTarget); |
||||
SAFE_RELEASE(m_pD3D11Dev); |
||||
SAFE_RELEASE(m_pD3D11Ctx); |
||||
D3DSample::cleanup(); |
||||
return 0; |
||||
} // cleanup()
|
||||
|
||||
private: |
||||
ID3D11Device* m_pD3D11Dev; |
||||
IDXGISwapChain* m_pD3D11SwapChain; |
||||
ID3D11DeviceContext* m_pD3D11Ctx; |
||||
ID3D11Texture2D* m_pBackBuffer; |
||||
ID3D11Texture2D* m_pSurface; |
||||
ID3D11RenderTargetView* m_pRenderTarget; |
||||
cv::ocl::Context m_oclCtx; |
||||
cv::String m_oclPlatformName; |
||||
cv::String m_oclDevName; |
||||
}; |
||||
|
||||
renderToD3DObject(); |
||||
|
||||
// switch the back buffer and the front buffer
|
||||
swapchain->Present(0, 0); |
||||
} |
||||
// main func
|
||||
ENTRY_POINT(D3D11WinApp, "D3D11 interop sample"); |
||||
|
@ -1,403 +0,0 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <d3d11.h> |
||||
|
||||
#include <string> |
||||
#include <iostream> |
||||
#include <queue> |
||||
|
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
#include "winapp.hpp" |
||||
|
||||
#pragma comment (lib, "d3d11.lib") |
||||
|
||||
|
||||
class D3D11WinApp : public WinApp |
||||
{ |
||||
public: |
||||
D3D11WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
WinApp(width, height, window_name) |
||||
{ |
||||
m_shutdown = false; |
||||
m_mode = 0; |
||||
m_modeStr[0] = cv::String("No processing"); |
||||
m_modeStr[1] = cv::String("Processing on CPU"); |
||||
m_modeStr[2] = cv::String("Processing on GPU"); |
||||
m_disableProcessing = false; |
||||
m_cap = cap; |
||||
} |
||||
|
||||
~D3D11WinApp() {} |
||||
|
||||
int onClose(void) |
||||
{ |
||||
m_shutdown = true; |
||||
cleanup(); |
||||
::DestroyWindow(m_hWnd); |
||||
return 0; |
||||
} |
||||
|
||||
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
||||
{ |
||||
switch (message) |
||||
{ |
||||
case WM_CHAR: |
||||
if (wParam >= '0' && wParam <= '2') |
||||
{ |
||||
m_mode = (char)wParam - '0'; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_SPACE) |
||||
{ |
||||
m_disableProcessing = !m_disableProcessing; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_ESCAPE) |
||||
{ |
||||
return onClose(); |
||||
} |
||||
break; |
||||
|
||||
case WM_CLOSE: |
||||
return onClose(); |
||||
|
||||
case WM_DESTROY: |
||||
::PostQuitMessage(0); |
||||
return 0; |
||||
} |
||||
|
||||
return ::DefWindowProc(hWnd, message, wParam, lParam); |
||||
} |
||||
|
||||
static float getFps() |
||||
{ |
||||
static std::queue<int64> time_queue; |
||||
|
||||
int64 now = cv::getTickCount(); |
||||
int64 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); |
||||
} |
||||
|
||||
int init(void) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
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 = m_width; // set the back buffer width
|
||||
scd.BufferDesc.Height = m_height; // set the back buffer height
|
||||
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
|
||||
scd.OutputWindow = m_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
|
||||
|
||||
r = ::D3D11CreateDeviceAndSwapChain( |
||||
NULL, |
||||
D3D_DRIVER_TYPE_HARDWARE, |
||||
NULL, |
||||
0, |
||||
NULL, |
||||
0, |
||||
D3D11_SDK_VERSION, |
||||
&scd, |
||||
&m_pD3D11SwapChain, |
||||
&m_pD3D11Dev, |
||||
NULL, |
||||
&m_pD3D11Ctx); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D11SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&m_pBackBuffer); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D11Dev->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTarget); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
m_pD3D11Ctx->OMSetRenderTargets(1, &m_pRenderTarget, NULL); |
||||
|
||||
D3D11_VIEWPORT viewport; |
||||
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); |
||||
|
||||
viewport.Width = (float)m_width; |
||||
viewport.Height = (float)m_height; |
||||
viewport.MinDepth = 0.0f; |
||||
viewport.MaxDepth = 0.0f; |
||||
|
||||
m_pD3D11Ctx->RSSetViewports(1, &viewport); |
||||
|
||||
D3D11_TEXTURE2D_DESC desc = { 0 }; |
||||
|
||||
desc.Width = m_width; |
||||
desc.Height = m_height; |
||||
desc.MipLevels = 1; |
||||
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; |
||||
|
||||
r = m_pD3D11Dev->CreateTexture2D(&desc, NULL, &m_pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create texture with input image" << std::endl; |
||||
return -1; |
||||
} |
||||
|
||||
if (cv::ocl::haveOpenCL()) |
||||
{ |
||||
m_oclCtx = cv::directx::ocl::initializeContextFromD3D11Device(m_pD3D11Dev); |
||||
} |
||||
|
||||
m_oclDevName = cv::ocl::useOpenCL() ? |
||||
cv::ocl::Context::getDefault().device(0).name() : |
||||
"No OpenCL device"; |
||||
|
||||
return 0; |
||||
} // init()
|
||||
|
||||
|
||||
int get_surface(ID3D11Texture2D** ppSurface) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
if (!m_cap.read(m_frame_bgr)) |
||||
return -1; |
||||
|
||||
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA); |
||||
|
||||
UINT subResource = ::D3D11CalcSubresource(0, 0, 1); |
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedTex; |
||||
r = m_pD3D11Ctx->Map(m_pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
// copy video frame data to surface
|
||||
m_frame_rgba.copyTo(m); |
||||
|
||||
m_pD3D11Ctx->Unmap(m_pSurface, subResource); |
||||
|
||||
*ppSurface = m_pSurface; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
void print_info(ID3D11Texture2D* pSurface, int mode, float fps, cv::String oclDevName) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
UINT subResource = ::D3D11CalcSubresource(0, 0, 1); |
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedTex; |
||||
r = m_pD3D11Ctx->Map(pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
|
||||
cv::String strMode = cv::format("%s", m_modeStr[mode].c_str()); |
||||
cv::String strFPS = cv::format("%2.1f", fps); |
||||
cv::String strDevName = cv::format("%s", oclDevName.c_str()); |
||||
|
||||
cv::putText(m, strMode, cv::Point(0, 16), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
cv::putText(m, strFPS, cv::Point(0, 32), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
cv::putText(m, strDevName, cv::Point(0, 48), 1, 0.8, cv::Scalar(0, 0, 0)); |
||||
|
||||
m_pD3D11Ctx->Unmap(pSurface, subResource); |
||||
|
||||
return; |
||||
} |
||||
|
||||
|
||||
int render() |
||||
{ |
||||
try |
||||
{ |
||||
if (m_shutdown) |
||||
return 0; |
||||
|
||||
HRESULT r; |
||||
ID3D11Texture2D* pSurface; |
||||
|
||||
r = get_surface(&pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
switch (m_mode) |
||||
{ |
||||
case 0: |
||||
// no processing
|
||||
break; |
||||
|
||||
case 1: |
||||
{ |
||||
// process video frame on CPU
|
||||
UINT subResource = ::D3D11CalcSubresource(0, 0, 1); |
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedTex; |
||||
r = m_pD3D11Ctx->Map(m_pSurface, subResource, D3D11_MAP_WRITE_DISCARD, 0, &mappedTex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, mappedTex.pData, (int)mappedTex.RowPitch); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D10 surface with OpenCV on CPU
|
||||
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
m_pD3D11Ctx->Unmap(m_pSurface, subResource); |
||||
|
||||
break; |
||||
} |
||||
|
||||
case 2: |
||||
{ |
||||
// process video frame on GPU
|
||||
cv::UMat u; |
||||
|
||||
cv::directx::convertFromD3D11Texture2D(pSurface, u); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on GPU with OpenCL
|
||||
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
cv::directx::convertToD3D11Texture2D(u, pSurface); |
||||
|
||||
break; |
||||
} |
||||
|
||||
} // switch
|
||||
|
||||
print_info(pSurface, m_mode, getFps(), m_oclDevName); |
||||
|
||||
// traditional DX render pipeline:
|
||||
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
|
||||
m_pD3D11Ctx->CopyResource(m_pBackBuffer, pSurface); |
||||
|
||||
// present the back buffer contents to the display
|
||||
// switch the back buffer and the front buffer
|
||||
r = m_pD3D11SwapChain->Present(0, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cleanup(void) |
||||
{ |
||||
SAFE_RELEASE(m_pSurface); |
||||
SAFE_RELEASE(m_pBackBuffer); |
||||
SAFE_RELEASE(m_pD3D11SwapChain); |
||||
SAFE_RELEASE(m_pRenderTarget); |
||||
SAFE_RELEASE(m_pD3D11Dev); |
||||
SAFE_RELEASE(m_pD3D11Ctx); |
||||
return 0; |
||||
} |
||||
|
||||
private: |
||||
bool m_shutdown; |
||||
int m_mode; |
||||
cv::String m_modeStr[3]; |
||||
int m_disableProcessing; |
||||
ID3D11Device* m_pD3D11Dev; |
||||
IDXGISwapChain* m_pD3D11SwapChain; |
||||
ID3D11DeviceContext* m_pD3D11Ctx; |
||||
ID3D11Texture2D* m_pBackBuffer; |
||||
ID3D11Texture2D* m_pSurface; |
||||
ID3D11RenderTargetView* m_pRenderTarget; |
||||
cv::VideoCapture m_cap; |
||||
cv::Mat m_frame_bgr; |
||||
cv::Mat m_frame_rgba; |
||||
cv::ocl::Context m_oclCtx; |
||||
cv::String m_oclPlatformName; |
||||
cv::String m_oclDevName; |
||||
}; |
||||
|
||||
|
||||
using namespace cv; |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
cv::VideoCapture cap; |
||||
|
||||
if (argc > 1) |
||||
{ |
||||
cap.open(argv[1]); |
||||
} |
||||
else |
||||
cap.open(0); |
||||
|
||||
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH); |
||||
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT); |
||||
std::string wndname = "D3D11 Window"; |
||||
|
||||
D3D11WinApp app(width, height, wndname, cap); |
||||
|
||||
try |
||||
{ |
||||
app.Create(); |
||||
return app.run(); |
||||
} |
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
catch (...) |
||||
{ |
||||
std::cerr << "FATAL ERROR: Unknown exception" << std::endl; |
||||
return 11; |
||||
} |
||||
} |
@ -1,149 +1,297 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <d3d9.h> |
||||
#pragma comment (lib, "d3d9.lib") |
||||
|
||||
#define USE_D3D9 |
||||
#define WINDOW_NAME "OpenCV Direct3D 9 Sample" |
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
|
||||
#include "d3dsample.hpp" |
||||
|
||||
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
|
||||
#pragma comment (lib, "d3d9.lib") |
||||
|
||||
#include "d3d_base.inl.hpp" |
||||
|
||||
bool initDirect3D(void) |
||||
using namespace std; |
||||
using namespace cv; |
||||
|
||||
class D3D9WinApp : public D3DSample |
||||
{ |
||||
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; |
||||
} |
||||
public: |
||||
D3D9WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
D3DSample(width, height, window_name, cap) {} |
||||
|
||||
~D3D9WinApp() {} |
||||
|
||||
if (FAILED(dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) |
||||
int create(void) |
||||
{ |
||||
return false; |
||||
} |
||||
// base initialization
|
||||
D3DSample::create(); |
||||
|
||||
return true; |
||||
} |
||||
// initialize DirectX
|
||||
HRESULT r; |
||||
|
||||
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; |
||||
} |
||||
m_pD3D9 = ::Direct3DCreate9(D3D_SDK_VERSION); |
||||
if (NULL == m_pD3D9) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
// 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))) |
||||
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | |
||||
D3DCREATE_PUREDEVICE | |
||||
D3DCREATE_NOWINDOWCHANGES | |
||||
D3DCREATE_MULTITHREADED | |
||||
D3DCREATE_FPU_PRESERVE; |
||||
|
||||
D3DPRESENT_PARAMETERS d3dpp; |
||||
::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); |
||||
|
||||
d3dpp.Windowed = true; |
||||
d3dpp.Flags = 0; |
||||
d3dpp.BackBufferCount = 0; |
||||
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; |
||||
d3dpp.BackBufferHeight = m_height; |
||||
d3dpp.BackBufferWidth = m_width; |
||||
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; |
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; |
||||
d3dpp.hDeviceWindow = m_hWnd; |
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; |
||||
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; |
||||
|
||||
r = m_pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, &m_pD3D9Dev); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create temp surface for CPU write" << std::endl; |
||||
return false; |
||||
return -1; |
||||
} |
||||
|
||||
D3DLOCKED_RECT memDesc = {0, NULL}; |
||||
RECT rc = {0, 0, WIDTH, HEIGHT}; |
||||
if (SUCCEEDED(pTmpSurface->LockRect(&memDesc, &rc, 0))) |
||||
r = m_pD3D9Dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer); |
||||
if (FAILED(r)) |
||||
{ |
||||
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); |
||||
return -1; |
||||
} |
||||
else |
||||
|
||||
r = m_pD3D9Dev->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't LockRect() on surface" << std::endl; |
||||
std::cerr << "Can't create surface for result" << std::endl; |
||||
return -1; |
||||
} |
||||
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; |
||||
} |
||||
// initialize OpenCL context of OpenCV lib from DirectX
|
||||
if (cv::ocl::haveOpenCL()) |
||||
{ |
||||
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9Dev); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
m_oclDevName = cv::ocl::useOpenCL() ? |
||||
cv::ocl::Context::getDefault().device(0).name() : |
||||
"No OpenCL device"; |
||||
|
||||
void render(void) |
||||
{ |
||||
// check to make sure you have a valid Direct3D device
|
||||
CV_Assert(dev); |
||||
return 0; |
||||
} // create()
|
||||
|
||||
renderToD3DObject(); |
||||
|
||||
if (g_sampleType == 0) |
||||
// get media data on DX surface for further processing
|
||||
int get_surface(LPDIRECT3DSURFACE9* ppSurface) |
||||
{ |
||||
// nothing
|
||||
} |
||||
else if (g_sampleType == 1) |
||||
HRESULT r; |
||||
|
||||
if (!m_cap.read(m_frame_bgr)) |
||||
return -1; |
||||
|
||||
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA); |
||||
|
||||
D3DLOCKED_RECT memDesc = { 0, NULL }; |
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
|
||||
r = m_pSurface->LockRect(&memDesc, &rc, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); |
||||
// copy video frame data to surface
|
||||
m_frame_rgba.copyTo(m); |
||||
|
||||
r = m_pSurface->UnlockRect(); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
*ppSurface = m_pSurface; |
||||
|
||||
return 0; |
||||
} // get_surface()
|
||||
|
||||
|
||||
// process and render media data
|
||||
int render() |
||||
{ |
||||
if (FAILED(dev->StretchRect(pCPUWriteSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) |
||||
try |
||||
{ |
||||
if (m_shutdown) |
||||
return 0; |
||||
|
||||
HRESULT r; |
||||
LPDIRECT3DSURFACE9 pSurface; |
||||
|
||||
r = get_surface(&pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
switch (m_mode) |
||||
{ |
||||
case MODE_NOP: |
||||
// no processing
|
||||
break; |
||||
|
||||
case MODE_CPU: |
||||
{ |
||||
// process video frame on CPU
|
||||
D3DLOCKED_RECT memDesc = { 0, NULL }; |
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
|
||||
r = pSurface->LockRect(&memDesc, &rc, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on CPU
|
||||
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
r = pSurface->UnlockRect(); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
case MODE_GPU: |
||||
{ |
||||
// process video frame on GPU
|
||||
cv::UMat u; |
||||
|
||||
cv::directx::convertFromDirect3DSurface9(pSurface, u); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on GPU with OpenCL
|
||||
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
cv::directx::convertToDirect3DSurface9(u, pSurface); |
||||
|
||||
break; |
||||
} |
||||
|
||||
} // switch
|
||||
|
||||
print_info(pSurface, m_mode, getFps(), m_oclDevName); |
||||
|
||||
// traditional DX render pipeline:
|
||||
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
|
||||
r = m_pD3D9Dev->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
// present the back buffer contents to the display
|
||||
r = m_pD3D9Dev->Present(NULL, NULL, NULL, NULL); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
} // try
|
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Can't StretchRect()" << std::endl; |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
} |
||||
else |
||||
|
||||
return 0; |
||||
} // render()
|
||||
|
||||
|
||||
void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName) |
||||
{ |
||||
if (FAILED(dev->StretchRect(pSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) |
||||
HDC hDC; |
||||
|
||||
HRESULT r = pSurface->GetDC(&hDC); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't StretchRect()" << std::endl; |
||||
return; |
||||
} |
||||
|
||||
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT); |
||||
|
||||
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont); |
||||
|
||||
if (hOldFont) |
||||
{ |
||||
TEXTMETRIC tm; |
||||
::GetTextMetrics(hDC, &tm); |
||||
|
||||
char buf[256]; |
||||
int y = 0; |
||||
|
||||
buf[0] = 0; |
||||
sprintf(buf, "Mode: %s", m_modeStr[mode].c_str()); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
y += tm.tmHeight; |
||||
buf[0] = 0; |
||||
sprintf(buf, "FPS: %2.1f", fps); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
y += tm.tmHeight; |
||||
buf[0] = 0; |
||||
sprintf(buf, "OpenCL device: %s", oclDevName.c_str()); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
::SelectObject(hDC, hOldFont); |
||||
} |
||||
} |
||||
|
||||
if (SUCCEEDED(dev -> BeginScene())) |
||||
r = pSurface->ReleaseDC(hDC); |
||||
|
||||
return; |
||||
} // print_info()
|
||||
|
||||
|
||||
int cleanup(void) |
||||
{ |
||||
// end the scene
|
||||
dev -> EndScene(); |
||||
} |
||||
SAFE_RELEASE(m_pSurface); |
||||
SAFE_RELEASE(m_pBackBuffer); |
||||
SAFE_RELEASE(m_pD3D9Dev); |
||||
SAFE_RELEASE(m_pD3D9); |
||||
D3DSample::cleanup(); |
||||
return 0; |
||||
} // cleanup()
|
||||
|
||||
// present the back buffer contents to the display
|
||||
dev->Present(NULL, NULL, NULL, NULL); |
||||
} |
||||
private: |
||||
LPDIRECT3D9 m_pD3D9; |
||||
LPDIRECT3DDEVICE9 m_pD3D9Dev; |
||||
LPDIRECT3DSURFACE9 m_pBackBuffer; |
||||
LPDIRECT3DSURFACE9 m_pSurface; |
||||
cv::ocl::Context m_oclCtx; |
||||
cv::String m_oclPlatformName; |
||||
cv::String m_oclDevName; |
||||
}; |
||||
|
||||
void cleanUp (void) |
||||
{ |
||||
SAFE_RELEASE(pCPUWriteSurface); |
||||
SAFE_RELEASE(pReadOnlySurface); |
||||
SAFE_RELEASE(pSurface); |
||||
SAFE_RELEASE(pBackBuffer); |
||||
SAFE_RELEASE(dev); |
||||
SAFE_RELEASE(pD3D);} |
||||
|
||||
// main func
|
||||
ENTRY_POINT(D3D9WinApp, "D3D9 interop sample"); |
||||
|
@ -1,396 +0,0 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <d3d9.h> |
||||
|
||||
#include <string> |
||||
#include <iostream> |
||||
#include <queue> |
||||
|
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
#include "winapp.hpp" |
||||
|
||||
#pragma comment (lib, "d3d9.lib") |
||||
|
||||
|
||||
class D3D9WinApp : public WinApp |
||||
{ |
||||
public: |
||||
D3D9WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
WinApp(width, height, window_name) |
||||
{ |
||||
m_shutdown = false; |
||||
m_mode = 0; |
||||
m_modeStr[0] = cv::String("No processing"); |
||||
m_modeStr[1] = cv::String("Processing on CPU"); |
||||
m_modeStr[2] = cv::String("Processing on GPU"); |
||||
m_disableProcessing = false; |
||||
m_cap = cap; |
||||
} |
||||
|
||||
~D3D9WinApp() {} |
||||
|
||||
int onClose(void) |
||||
{ |
||||
m_shutdown = true; |
||||
cleanup(); |
||||
::DestroyWindow(m_hWnd); |
||||
return 0; |
||||
} |
||||
|
||||
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
||||
{ |
||||
switch (message) |
||||
{ |
||||
case WM_CHAR: |
||||
if (wParam >= '0' && wParam <= '2') |
||||
{ |
||||
m_mode = (char)wParam - '0'; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_SPACE) |
||||
{ |
||||
m_disableProcessing = !m_disableProcessing; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_ESCAPE) |
||||
{ |
||||
return onClose(); |
||||
} |
||||
break; |
||||
|
||||
case WM_CLOSE: |
||||
return onClose(); |
||||
|
||||
case WM_DESTROY: |
||||
::PostQuitMessage(0); |
||||
return 0; |
||||
} |
||||
|
||||
return ::DefWindowProc(hWnd, message, wParam, lParam); |
||||
} |
||||
|
||||
static float getFps() |
||||
{ |
||||
static std::queue<int64> time_queue; |
||||
|
||||
int64 now = cv::getTickCount(); |
||||
int64 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); |
||||
} |
||||
|
||||
int init(void) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
m_pD3D9 = ::Direct3DCreate9(D3D_SDK_VERSION); |
||||
if (NULL == m_pD3D9) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | |
||||
D3DCREATE_PUREDEVICE | |
||||
D3DCREATE_NOWINDOWCHANGES | |
||||
D3DCREATE_MULTITHREADED | |
||||
D3DCREATE_FPU_PRESERVE; |
||||
|
||||
D3DPRESENT_PARAMETERS d3dpp; |
||||
::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); |
||||
|
||||
d3dpp.Windowed = true; |
||||
d3dpp.Flags = 0; |
||||
d3dpp.BackBufferCount = 0; |
||||
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; |
||||
d3dpp.BackBufferHeight = m_height; |
||||
d3dpp.BackBufferWidth = m_width; |
||||
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; |
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; |
||||
d3dpp.hDeviceWindow = m_hWnd; |
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; |
||||
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; |
||||
|
||||
r = m_pD3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, &m_pD3D9Dev); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D9Dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D9Dev->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create surface for result" << std::endl; |
||||
return -1; |
||||
} |
||||
|
||||
if (cv::ocl::haveOpenCL()) |
||||
{ |
||||
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9Dev); |
||||
} |
||||
|
||||
m_oclDevName = cv::ocl::useOpenCL() ? |
||||
cv::ocl::Context::getDefault().device(0).name() : |
||||
"No OpenCL device"; |
||||
|
||||
return 0; |
||||
} // init()
|
||||
|
||||
|
||||
int get_surface(LPDIRECT3DSURFACE9* ppSurface) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
if (!m_cap.read(m_frame_bgr)) |
||||
return -1; |
||||
|
||||
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA); |
||||
|
||||
D3DLOCKED_RECT memDesc = { 0, NULL }; |
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
|
||||
r = m_pSurface->LockRect(&memDesc, &rc, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); |
||||
// copy video frame data to surface
|
||||
m_frame_rgba.copyTo(m); |
||||
|
||||
r = m_pSurface->UnlockRect(); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
*ppSurface = m_pSurface; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName) |
||||
{ |
||||
HDC hDC; |
||||
|
||||
HRESULT r = pSurface->GetDC(&hDC); |
||||
if (FAILED(r)) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT); |
||||
|
||||
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont); |
||||
|
||||
if (hOldFont) |
||||
{ |
||||
TEXTMETRIC tm; |
||||
::GetTextMetrics(hDC, &tm); |
||||
|
||||
char buf[256]; |
||||
int y = 0; |
||||
|
||||
buf[0] = 0; |
||||
sprintf(buf, "Mode: %s", m_modeStr[mode].c_str()); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
y += tm.tmHeight; |
||||
buf[0] = 0; |
||||
sprintf(buf, "FPS: %2.1f", fps); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
y += tm.tmHeight; |
||||
buf[0] = 0; |
||||
sprintf(buf, "OpenCL device: %s", oclDevName.c_str()); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
::SelectObject(hDC, hOldFont); |
||||
} |
||||
|
||||
r = pSurface->ReleaseDC(hDC); |
||||
|
||||
return; |
||||
} |
||||
|
||||
|
||||
int render() |
||||
{ |
||||
try |
||||
{ |
||||
if (m_shutdown) |
||||
return 0; |
||||
|
||||
HRESULT r; |
||||
LPDIRECT3DSURFACE9 pSurface; |
||||
|
||||
r = get_surface(&pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
switch (m_mode) |
||||
{ |
||||
case 0: |
||||
// no processing
|
||||
break; |
||||
|
||||
case 1: |
||||
{ |
||||
// process video frame on CPU
|
||||
D3DLOCKED_RECT memDesc = { 0, NULL }; |
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
|
||||
r = pSurface->LockRect(&memDesc, &rc, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on CPU
|
||||
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
r = pSurface->UnlockRect(); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
case 2: |
||||
{ |
||||
// process video frame on GPU
|
||||
cv::UMat u; |
||||
|
||||
cv::directx::convertFromDirect3DSurface9(pSurface, u); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on GPU with OpenCL
|
||||
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
cv::directx::convertToDirect3DSurface9(u, pSurface); |
||||
|
||||
break; |
||||
} |
||||
|
||||
} // switch
|
||||
|
||||
print_info(pSurface, m_mode, getFps(), m_oclDevName); |
||||
|
||||
// traditional DX render pipeline:
|
||||
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
|
||||
r = m_pD3D9Dev->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
// present the back buffer contents to the display
|
||||
r = m_pD3D9Dev->Present(NULL, NULL, NULL, NULL); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cleanup(void) |
||||
{ |
||||
SAFE_RELEASE(m_pSurface); |
||||
SAFE_RELEASE(m_pBackBuffer); |
||||
SAFE_RELEASE(m_pD3D9Dev); |
||||
SAFE_RELEASE(m_pD3D9); |
||||
return 0; |
||||
} |
||||
|
||||
private: |
||||
bool m_shutdown; |
||||
int m_mode; |
||||
cv::String m_modeStr[3]; |
||||
int m_disableProcessing; |
||||
LPDIRECT3D9 m_pD3D9; |
||||
LPDIRECT3DDEVICE9 m_pD3D9Dev; |
||||
LPDIRECT3DSURFACE9 m_pBackBuffer; |
||||
LPDIRECT3DSURFACE9 m_pSurface; |
||||
cv::VideoCapture m_cap; |
||||
cv::Mat m_frame_bgr; |
||||
cv::Mat m_frame_rgba; |
||||
cv::ocl::Context m_oclCtx; |
||||
cv::String m_oclPlatformName; |
||||
cv::String m_oclDevName; |
||||
}; |
||||
|
||||
|
||||
using namespace cv; |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
cv::VideoCapture cap; |
||||
|
||||
if (argc > 1) |
||||
{ |
||||
cap.open(argv[1]); |
||||
} |
||||
else |
||||
cap.open(0); |
||||
|
||||
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH); |
||||
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT); |
||||
std::string wndname = "D3D9 Window"; |
||||
|
||||
D3D9WinApp app(width, height, wndname, cap); |
||||
|
||||
try |
||||
{ |
||||
app.Create(); |
||||
return app.run(); |
||||
} |
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
catch (...) |
||||
{ |
||||
std::cerr << "FATAL ERROR: Unknown exception" << std::endl; |
||||
return 11; |
||||
} |
||||
} |
@ -1,158 +1,298 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <d3d9.h> |
||||
#pragma comment (lib, "d3d9.lib") |
||||
|
||||
#define USE_D3DEX |
||||
#define WINDOW_NAME "OpenCV Direct3D 9 Ex Sample" |
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
|
||||
#include "d3dsample.hpp" |
||||
|
||||
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
|
||||
#pragma comment (lib, "d3d9.lib") |
||||
|
||||
#include "d3d_base.inl.hpp" |
||||
|
||||
bool initDirect3D(void) |
||||
using namespace std; |
||||
using namespace cv; |
||||
|
||||
class D3D9ExWinApp : public D3DSample |
||||
{ |
||||
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; |
||||
} |
||||
public: |
||||
D3D9ExWinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
D3DSample(width, height, window_name, cap) {} |
||||
|
||||
~D3D9ExWinApp() {} |
||||
|
||||
if (FAILED(dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))) |
||||
int create(void) |
||||
{ |
||||
return false; |
||||
} |
||||
// base initialization
|
||||
D3DSample::create(); |
||||
|
||||
return true; |
||||
} |
||||
// initialize DirectX
|
||||
HRESULT r; |
||||
|
||||
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; |
||||
} |
||||
r = ::Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9Ex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
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))) |
||||
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | |
||||
D3DCREATE_PUREDEVICE | |
||||
D3DCREATE_NOWINDOWCHANGES | |
||||
D3DCREATE_MULTITHREADED | |
||||
D3DCREATE_FPU_PRESERVE; |
||||
|
||||
D3DPRESENT_PARAMETERS d3dpp; |
||||
::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); |
||||
|
||||
d3dpp.Windowed = true; |
||||
d3dpp.Flags = 0; |
||||
d3dpp.BackBufferCount = 0; |
||||
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; |
||||
d3dpp.BackBufferHeight = m_height; |
||||
d3dpp.BackBufferWidth = m_width; |
||||
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; |
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; |
||||
d3dpp.hDeviceWindow = m_hWnd; |
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; |
||||
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; |
||||
|
||||
r = m_pD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, NULL, &m_pD3D9DevEx); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D9DevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create temp surface for CPU write" << std::endl; |
||||
return false; |
||||
return -1; |
||||
} |
||||
|
||||
D3DLOCKED_RECT memDesc = {0, NULL}; |
||||
RECT rc = {0, 0, WIDTH, HEIGHT}; |
||||
if (SUCCEEDED(pTmpSurface->LockRect(&memDesc, &rc, 0))) |
||||
r = m_pD3D9DevEx->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL); |
||||
if (FAILED(r)) |
||||
{ |
||||
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); |
||||
std::cerr << "Can't create surface for result" << std::endl; |
||||
return -1; |
||||
} |
||||
else |
||||
|
||||
// initialize OpenCL context of OpenCV lib from DirectX
|
||||
if (cv::ocl::haveOpenCL()) |
||||
{ |
||||
std::cerr << "Can't LockRect() on surface" << std::endl; |
||||
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9DevEx); |
||||
} |
||||
pTmpSurface->Release(); |
||||
} |
||||
|
||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pCPUWriteSurface, NULL))) |
||||
m_oclDevName = cv::ocl::useOpenCL() ? |
||||
cv::ocl::Context::getDefault().device(0).name() : |
||||
"No OpenCL device"; |
||||
|
||||
return 0; |
||||
} // create()
|
||||
|
||||
|
||||
// get media data on DX surface for further processing
|
||||
int get_surface(LPDIRECT3DSURFACE9* ppSurface) |
||||
{ |
||||
std::cerr << "Can't create surface for CPU write" << std::endl; |
||||
return false; |
||||
} |
||||
HRESULT r; |
||||
|
||||
return true; |
||||
} |
||||
if (!m_cap.read(m_frame_bgr)) |
||||
return -1; |
||||
|
||||
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA); |
||||
|
||||
void render(void) |
||||
{ |
||||
// check to make sure you have a valid Direct3D device
|
||||
CV_Assert(dev); |
||||
D3DLOCKED_RECT memDesc = { 0, NULL }; |
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
|
||||
renderToD3DObject(); |
||||
r = m_pSurface->LockRect(&memDesc, &rc, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
if (g_sampleType == 0) |
||||
{ |
||||
// nothing
|
||||
} |
||||
else if (g_sampleType == 1) |
||||
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); |
||||
// copy video frame data to surface
|
||||
m_frame_rgba.copyTo(m); |
||||
|
||||
r = m_pSurface->UnlockRect(); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
*ppSurface = m_pSurface; |
||||
|
||||
return 0; |
||||
} // get_surface()
|
||||
|
||||
|
||||
// process and render media data
|
||||
int render() |
||||
{ |
||||
if (FAILED(dev->StretchRect(pCPUWriteSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) |
||||
try |
||||
{ |
||||
std::cerr << "Can't StretchRect()" << std::endl; |
||||
if (m_shutdown) |
||||
return 0; |
||||
|
||||
HRESULT r; |
||||
LPDIRECT3DSURFACE9 pSurface; |
||||
|
||||
r = get_surface(&pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
switch (m_mode) |
||||
{ |
||||
case MODE_NOP: |
||||
// no processing
|
||||
break; |
||||
|
||||
case MODE_CPU: |
||||
{ |
||||
// process video frame on CPU
|
||||
D3DLOCKED_RECT memDesc = { 0, NULL }; |
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
|
||||
r = pSurface->LockRect(&memDesc, &rc, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on CPU
|
||||
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
r = pSurface->UnlockRect(); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
case MODE_GPU: |
||||
{ |
||||
// process video frame on GPU
|
||||
cv::UMat u; |
||||
|
||||
cv::directx::convertFromDirect3DSurface9(pSurface, u); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on GPU with OpenCL
|
||||
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
cv::directx::convertToDirect3DSurface9(u, pSurface); |
||||
|
||||
break; |
||||
} |
||||
|
||||
} // switch
|
||||
|
||||
print_info(pSurface, m_mode, getFps(), m_oclDevName); |
||||
|
||||
// traditional DX render pipeline:
|
||||
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
|
||||
r = m_pD3D9DevEx->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
// present the back buffer contents to the display
|
||||
r = m_pD3D9DevEx->Present(NULL, NULL, NULL, NULL); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
} // try
|
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
} |
||||
else |
||||
|
||||
return 0; |
||||
} // render()
|
||||
|
||||
|
||||
void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName) |
||||
{ |
||||
if (FAILED(dev->StretchRect(pSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE))) |
||||
HDC hDC; |
||||
|
||||
HRESULT r = pSurface->GetDC(&hDC); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't StretchRect()" << std::endl; |
||||
return; |
||||
} |
||||
|
||||
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT); |
||||
|
||||
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont); |
||||
|
||||
if (hOldFont) |
||||
{ |
||||
TEXTMETRIC tm; |
||||
::GetTextMetrics(hDC, &tm); |
||||
|
||||
char buf[256]; |
||||
int y = 0; |
||||
|
||||
buf[0] = 0; |
||||
sprintf(buf, "Mode: %s", m_modeStr[mode].c_str()); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
y += tm.tmHeight; |
||||
buf[0] = 0; |
||||
sprintf(buf, "FPS: %2.1f", fps); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
y += tm.tmHeight; |
||||
buf[0] = 0; |
||||
sprintf(buf, "OpenCL device: %s", oclDevName.c_str()); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
::SelectObject(hDC, hOldFont); |
||||
} |
||||
} |
||||
|
||||
if (SUCCEEDED(dev -> BeginScene())) |
||||
r = pSurface->ReleaseDC(hDC); |
||||
|
||||
return; |
||||
} // print_info()
|
||||
|
||||
|
||||
int cleanup(void) |
||||
{ |
||||
// end the scene
|
||||
dev -> EndScene(); |
||||
} |
||||
SAFE_RELEASE(m_pSurface); |
||||
SAFE_RELEASE(m_pBackBuffer); |
||||
SAFE_RELEASE(m_pD3D9DevEx); |
||||
SAFE_RELEASE(m_pD3D9Ex); |
||||
D3DSample::cleanup(); |
||||
return 0; |
||||
} // cleanup()
|
||||
|
||||
// present the back buffer contents to the display
|
||||
dev->Present(NULL, NULL, NULL, NULL); |
||||
} |
||||
private: |
||||
LPDIRECT3D9EX m_pD3D9Ex; |
||||
LPDIRECT3DDEVICE9EX m_pD3D9DevEx; |
||||
LPDIRECT3DSURFACE9 m_pBackBuffer; |
||||
LPDIRECT3DSURFACE9 m_pSurface; |
||||
cv::ocl::Context m_oclCtx; |
||||
cv::String m_oclPlatformName; |
||||
cv::String m_oclDevName; |
||||
}; |
||||
|
||||
void cleanUp (void) |
||||
{ |
||||
SAFE_RELEASE(pCPUWriteSurface); |
||||
SAFE_RELEASE(pReadOnlySurface); |
||||
SAFE_RELEASE(pSurface); |
||||
SAFE_RELEASE(pBackBuffer); |
||||
SAFE_RELEASE(dev); |
||||
SAFE_RELEASE(pD3D); |
||||
} |
||||
|
||||
// main func
|
||||
ENTRY_POINT(D3D9ExWinApp, "D3D9Ex interop sample"); |
||||
|
@ -1,396 +0,0 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <d3d9.h> |
||||
|
||||
#include <string> |
||||
#include <iostream> |
||||
#include <queue> |
||||
|
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
#include "winapp.hpp" |
||||
|
||||
#pragma comment (lib, "d3d9.lib") |
||||
|
||||
|
||||
class D3D9ExWinApp : public WinApp |
||||
{ |
||||
public: |
||||
D3D9ExWinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
WinApp(width, height, window_name) |
||||
{ |
||||
m_shutdown = false; |
||||
m_mode = 0; |
||||
m_modeStr[0] = cv::String("No processing"); |
||||
m_modeStr[1] = cv::String("Processing on CPU"); |
||||
m_modeStr[2] = cv::String("Processing on GPU"); |
||||
m_disableProcessing = false; |
||||
m_cap = cap; |
||||
} |
||||
|
||||
~D3D9ExWinApp() {} |
||||
|
||||
int onClose(void) |
||||
{ |
||||
m_shutdown = true; |
||||
cleanup(); |
||||
::DestroyWindow(m_hWnd); |
||||
return 0; |
||||
} |
||||
|
||||
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
||||
{ |
||||
switch (message) |
||||
{ |
||||
case WM_CHAR: |
||||
if (wParam >= '0' && wParam <= '2') |
||||
{ |
||||
m_mode = (char)wParam - '0'; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_SPACE) |
||||
{ |
||||
m_disableProcessing = !m_disableProcessing; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_ESCAPE) |
||||
{ |
||||
return onClose(); |
||||
} |
||||
break; |
||||
|
||||
case WM_CLOSE: |
||||
return onClose(); |
||||
|
||||
case WM_DESTROY: |
||||
::PostQuitMessage(0); |
||||
return 0; |
||||
} |
||||
|
||||
return ::DefWindowProc(hWnd, message, wParam, lParam); |
||||
} |
||||
|
||||
static float getFps() |
||||
{ |
||||
static std::queue<int64> time_queue; |
||||
|
||||
int64 now = cv::getTickCount(); |
||||
int64 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); |
||||
} |
||||
|
||||
int init(void) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
r = ::Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9Ex); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | |
||||
D3DCREATE_PUREDEVICE | |
||||
D3DCREATE_NOWINDOWCHANGES | |
||||
D3DCREATE_MULTITHREADED | |
||||
D3DCREATE_FPU_PRESERVE; |
||||
|
||||
D3DPRESENT_PARAMETERS d3dpp; |
||||
::ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); |
||||
|
||||
d3dpp.Windowed = true; |
||||
d3dpp.Flags = 0; |
||||
d3dpp.BackBufferCount = 0; |
||||
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; |
||||
d3dpp.BackBufferHeight = m_height; |
||||
d3dpp.BackBufferWidth = m_width; |
||||
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; |
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; |
||||
d3dpp.hDeviceWindow = m_hWnd; |
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; |
||||
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; |
||||
|
||||
r = m_pD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, flags, &d3dpp, NULL, &m_pD3D9DevEx); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D9DevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
r = m_pD3D9DevEx->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pSurface, NULL); |
||||
if (FAILED(r)) |
||||
{ |
||||
std::cerr << "Can't create surface for result" << std::endl; |
||||
return -1; |
||||
} |
||||
|
||||
if (cv::ocl::haveOpenCL()) |
||||
{ |
||||
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9DevEx); |
||||
} |
||||
|
||||
m_oclDevName = cv::ocl::useOpenCL() ? |
||||
cv::ocl::Context::getDefault().device(0).name() : |
||||
"No OpenCL device"; |
||||
|
||||
return 0; |
||||
} // init()
|
||||
|
||||
|
||||
int get_surface(LPDIRECT3DSURFACE9* ppSurface) |
||||
{ |
||||
HRESULT r; |
||||
|
||||
if (!m_cap.read(m_frame_bgr)) |
||||
return -1; |
||||
|
||||
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA); |
||||
|
||||
D3DLOCKED_RECT memDesc = { 0, NULL }; |
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
|
||||
r = m_pSurface->LockRect(&memDesc, &rc, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); |
||||
// copy video frame data to surface
|
||||
m_frame_rgba.copyTo(m); |
||||
|
||||
r = m_pSurface->UnlockRect(); |
||||
if (FAILED(r)) |
||||
{ |
||||
return r; |
||||
} |
||||
|
||||
*ppSurface = m_pSurface; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
void print_info(LPDIRECT3DSURFACE9 pSurface, int mode, float fps, cv::String oclDevName) |
||||
{ |
||||
HDC hDC; |
||||
|
||||
HRESULT r = pSurface->GetDC(&hDC); |
||||
if (FAILED(r)) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
HFONT hFont = (HFONT)::GetStockObject(SYSTEM_FONT); |
||||
|
||||
HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont); |
||||
|
||||
if (hOldFont) |
||||
{ |
||||
TEXTMETRIC tm; |
||||
::GetTextMetrics(hDC, &tm); |
||||
|
||||
char buf[256]; |
||||
int y = 0; |
||||
|
||||
buf[0] = 0; |
||||
sprintf(buf, "Mode: %s", m_modeStr[mode].c_str()); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
y += tm.tmHeight; |
||||
buf[0] = 0; |
||||
sprintf(buf, "FPS: %2.1f", fps); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
y += tm.tmHeight; |
||||
buf[0] = 0; |
||||
sprintf(buf, "OpenCL device: %s", oclDevName.c_str()); |
||||
::TextOut(hDC, 0, y, buf, (int)strlen(buf)); |
||||
|
||||
::SelectObject(hDC, hOldFont); |
||||
} |
||||
|
||||
r = pSurface->ReleaseDC(hDC); |
||||
|
||||
return; |
||||
} |
||||
|
||||
|
||||
int render() |
||||
{ |
||||
try |
||||
{ |
||||
if (m_shutdown) |
||||
return 0; |
||||
|
||||
HRESULT r; |
||||
LPDIRECT3DSURFACE9 pSurface; |
||||
|
||||
r = get_surface(&pSurface); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
switch (m_mode) |
||||
{ |
||||
case 0: |
||||
// no processing
|
||||
break; |
||||
|
||||
case 1: |
||||
{ |
||||
// process video frame on CPU
|
||||
D3DLOCKED_RECT memDesc = { 0, NULL }; |
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
|
||||
r = pSurface->LockRect(&memDesc, &rc, 0); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
cv::Mat m(m_height, m_width, CV_8UC4, memDesc.pBits, memDesc.Pitch); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on CPU
|
||||
cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
r = pSurface->UnlockRect(); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
case 2: |
||||
{ |
||||
// process video frame on GPU
|
||||
cv::UMat u; |
||||
|
||||
cv::directx::convertFromDirect3DSurface9(pSurface, u); |
||||
|
||||
if (!m_disableProcessing) |
||||
{ |
||||
// blur D3D9 surface with OpenCV on GPU with OpenCL
|
||||
cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); |
||||
} |
||||
|
||||
cv::directx::convertToDirect3DSurface9(u, pSurface); |
||||
|
||||
break; |
||||
} |
||||
|
||||
} // switch
|
||||
|
||||
print_info(pSurface, m_mode, getFps(), m_oclDevName); |
||||
|
||||
// traditional DX render pipeline:
|
||||
// BitBlt surface to backBuffer and flip backBuffer to frontBuffer
|
||||
r = m_pD3D9DevEx->StretchRect(pSurface, NULL, m_pBackBuffer, NULL, D3DTEXF_NONE); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
// present the back buffer contents to the display
|
||||
r = m_pD3D9DevEx->Present(NULL, NULL, NULL, NULL); |
||||
if (FAILED(r)) |
||||
{ |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cleanup(void) |
||||
{ |
||||
SAFE_RELEASE(m_pSurface); |
||||
SAFE_RELEASE(m_pBackBuffer); |
||||
SAFE_RELEASE(m_pD3D9DevEx); |
||||
SAFE_RELEASE(m_pD3D9Ex); |
||||
return 0; |
||||
} |
||||
|
||||
private: |
||||
bool m_shutdown; |
||||
int m_mode; |
||||
cv::String m_modeStr[3]; |
||||
int m_disableProcessing; |
||||
LPDIRECT3D9EX m_pD3D9Ex; |
||||
LPDIRECT3DDEVICE9EX m_pD3D9DevEx; |
||||
LPDIRECT3DSURFACE9 m_pBackBuffer; |
||||
LPDIRECT3DSURFACE9 m_pSurface; |
||||
cv::VideoCapture m_cap; |
||||
cv::Mat m_frame_bgr; |
||||
cv::Mat m_frame_rgba; |
||||
cv::ocl::Context m_oclCtx; |
||||
cv::String m_oclPlatformName; |
||||
cv::String m_oclDevName; |
||||
}; |
||||
|
||||
|
||||
using namespace cv; |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
cv::VideoCapture cap; |
||||
|
||||
if (argc > 1) |
||||
{ |
||||
cap.open(argv[1]); |
||||
} |
||||
else |
||||
cap.open(0); |
||||
|
||||
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH); |
||||
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT); |
||||
std::string wndname = "D3D9Ex Window"; |
||||
|
||||
D3D9ExWinApp app(width, height, wndname, cap); |
||||
|
||||
try |
||||
{ |
||||
app.Create(); |
||||
return app.run(); |
||||
} |
||||
|
||||
catch (cv::Exception& e) |
||||
{ |
||||
std::cerr << "Exception: " << e.what() << std::endl; |
||||
return 10; |
||||
} |
||||
|
||||
catch (...) |
||||
{ |
||||
std::cerr << "FATAL ERROR: Unknown exception" << std::endl; |
||||
return 11; |
||||
} |
||||
} |
@ -1,458 +0,0 @@ |
||||
//
|
||||
// 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 "opencv2/imgcodecs.hpp" |
||||
|
||||
#include <iostream> |
||||
#include <queue> |
||||
|
||||
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<int64> 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::Context::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::Context::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::Context& ctx = cv::directx::ocl::initializeContextFromDirect3DDevice9(dev); |
||||
#elif defined (USE_D3DEX) |
||||
cv::ocl::Context& ctx = cv::directx::ocl::initializeContextFromDirect3DDevice9Ex(dev); |
||||
#elif defined(USE_D3D10) |
||||
cv::ocl::Context& ctx = cv::directx::ocl::initializeContextFromD3D10Device(dev); |
||||
#elif defined(USE_D3D11) |
||||
cv::ocl::Context& 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<int>(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; |
||||
} |
||||
} |
@ -0,0 +1,185 @@ |
||||
#include <string> |
||||
#include <iostream> |
||||
#include <queue> |
||||
|
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/core/directx.hpp" |
||||
#include "opencv2/core/ocl.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/videoio.hpp" |
||||
|
||||
#include "winapp.hpp" |
||||
|
||||
#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; } |
||||
|
||||
|
||||
class D3DSample : public WinApp |
||||
{ |
||||
public: |
||||
enum MODE |
||||
{ |
||||
MODE_NOP, |
||||
MODE_CPU, |
||||
MODE_GPU |
||||
}; |
||||
|
||||
D3DSample(int width, int height, std::string& window_name, cv::VideoCapture& cap) : |
||||
WinApp(width, height, window_name) |
||||
{ |
||||
m_shutdown = false; |
||||
m_mode = MODE_NOP; |
||||
m_modeStr[0] = cv::String("No processing"); |
||||
m_modeStr[1] = cv::String("Processing on CPU"); |
||||
m_modeStr[2] = cv::String("Processing on GPU"); |
||||
m_disableProcessing = false; |
||||
m_cap = cap; |
||||
} |
||||
|
||||
~D3DSample() {} |
||||
|
||||
virtual int create() { return WinApp::create(); } |
||||
virtual int render() = 0; |
||||
virtual int cleanup() |
||||
{ |
||||
m_shutdown = true; |
||||
return WinApp::cleanup(); |
||||
} |
||||
|
||||
static float getFps() |
||||
{ |
||||
static std::queue<int64> time_queue; |
||||
|
||||
int64 now = cv::getTickCount(); |
||||
int64 then = 0; |
||||
time_queue.push(now); |
||||
|
||||
if (time_queue.size() >= 2) |
||||
then = time_queue.front(); |
||||
|
||||
if (time_queue.size() >= 25) |
||||
time_queue.pop(); |
||||
|
||||
size_t sz = time_queue.size(); |
||||
|
||||
float fps = sz * (float)cv::getTickFrequency() / (now - then); |
||||
|
||||
return fps; |
||||
} |
||||
|
||||
protected: |
||||
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
||||
{ |
||||
switch (message) |
||||
{ |
||||
case WM_CHAR: |
||||
if (wParam >= '0' && wParam <= '2') |
||||
{ |
||||
m_mode = static_cast<MODE>((char)wParam - '0'); |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_SPACE) |
||||
{ |
||||
m_disableProcessing = !m_disableProcessing; |
||||
return 0; |
||||
} |
||||
else if (wParam == VK_ESCAPE) |
||||
{ |
||||
return cleanup(); |
||||
} |
||||
break; |
||||
|
||||
case WM_CLOSE: |
||||
return cleanup(); |
||||
|
||||
case WM_DESTROY: |
||||
::PostQuitMessage(0); |
||||
return 0; |
||||
} |
||||
|
||||
return ::DefWindowProc(hWnd, message, wParam, lParam); |
||||
} |
||||
|
||||
// do render at idle
|
||||
virtual int idle() { return render(); } |
||||
|
||||
protected: |
||||
bool m_shutdown; |
||||
bool m_disableProcessing; |
||||
MODE m_mode; |
||||
cv::String m_modeStr[3]; |
||||
cv::VideoCapture m_cap; |
||||
cv::Mat m_frame_bgr; |
||||
cv::Mat m_frame_rgba; |
||||
}; |
||||
|
||||
|
||||
#define ENTRY_POINT(type, title) \ |
||||
static void help() \
|
||||
{ \
|
||||
printf( \
|
||||
"\nSample demonstrating interoperability of DirectX and OpenCL with OpenCV.\n" \
|
||||
"Hot keys: \n" \
|
||||
" 0 - no processing\n" \
|
||||
" 1 - blur DX surface on CPU through OpenCV\n" \
|
||||
" 2 - blur DX surface on GPU through OpenCV using OpenCL\n" \
|
||||
" ESC - exit\n\n"); \
|
||||
} \
|
||||
\
|
||||
static const char* keys = \
|
||||
{ \
|
||||
"{c camera | true | use camera or not}" \
|
||||
"{f file | | movie file name }" \
|
||||
"{h help | false | print help info }" \
|
||||
}; \
|
||||
\
|
||||
\
|
||||
int main(int argc, char** argv) \
|
||||
{ \
|
||||
cv::CommandLineParser parser(argc, argv, keys); \
|
||||
bool useCamera = parser.has("camera"); \
|
||||
string file = parser.get<string>("file"); \
|
||||
bool showHelp = parser.get<bool>("help"); \
|
||||
\
|
||||
if (showHelp) \
|
||||
help(); \
|
||||
\
|
||||
parser.printMessage(); \
|
||||
\
|
||||
cv::VideoCapture cap; \
|
||||
\
|
||||
if (useCamera) \
|
||||
cap.open(0); \
|
||||
else \
|
||||
cap.open(file.c_str()); \
|
||||
\
|
||||
if (!cap.isOpened()) \
|
||||
{ \
|
||||
printf("can not open camera or video file\n"); \
|
||||
return -1; \
|
||||
} \
|
||||
\
|
||||
int width = (int)cap.get(CAP_PROP_FRAME_WIDTH); \
|
||||
int height = (int)cap.get(CAP_PROP_FRAME_HEIGHT); \
|
||||
\
|
||||
std::string wndname = title; \
|
||||
\
|
||||
type app(width, height, wndname, cap); \
|
||||
\
|
||||
try \
|
||||
{ \
|
||||
app.create(); \
|
||||
return app.run(); \
|
||||
} \
|
||||
\
|
||||
catch (cv::Exception& e) \
|
||||
{ \
|
||||
std::cerr << "Exception: " << e.what() << std::endl; \
|
||||
return 10; \
|
||||
} \
|
||||
\
|
||||
catch (...) \
|
||||
{ \
|
||||
std::cerr << "FATAL ERROR: Unknown exception" << std::endl; \
|
||||
return 11; \
|
||||
} \
|
||||
} |
Loading…
Reference in new issue