mirror of https://github.com/opencv/opencv.git
parent
4af2eb22ab
commit
450a276f87
5 changed files with 1714 additions and 0 deletions
@ -0,0 +1,397 @@ |
||||
#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; |
||||
} |
||||
} |
@ -0,0 +1,403 @@ |
||||
#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; |
||||
} |
||||
} |
@ -0,0 +1,396 @@ |
||||
#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; |
||||
} |
||||
} |
@ -0,0 +1,396 @@ |
||||
#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; |
||||
} |
||||
} |
@ -0,0 +1,122 @@ |
||||
#define WIN32_LEAN_AND_MEAN |
||||
#include <windows.h> |
||||
#include <string> |
||||
|
||||
|
||||
#define WINCLASS "WinAppWnd" |
||||
|
||||
#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; } |
||||
|
||||
class WinApp |
||||
{ |
||||
public: |
||||
WinApp(int width, int height, std::string& window_name) |
||||
{ |
||||
m_width = width; |
||||
m_height = height; |
||||
m_window_name = window_name; |
||||
m_hInstance = ::GetModuleHandle(NULL); |
||||
} |
||||
|
||||
virtual ~WinApp() |
||||
{ |
||||
::UnregisterClass(WINCLASS, m_hInstance); |
||||
} |
||||
|
||||
int Create() |
||||
{ |
||||
WNDCLASSEX wcex; |
||||
|
||||
wcex.cbSize = sizeof(WNDCLASSEX); |
||||
wcex.style = CS_HREDRAW | CS_VREDRAW; |
||||
wcex.lpfnWndProc = &WinApp::StaticWndProc; |
||||
wcex.cbClsExtra = 0; |
||||
wcex.cbWndExtra = 0; |
||||
wcex.hInstance = m_hInstance; |
||||
wcex.hIcon = LoadIcon(0, IDI_APPLICATION); |
||||
wcex.hCursor = LoadCursor(0, IDC_ARROW); |
||||
wcex.hbrBackground = 0; |
||||
wcex.lpszMenuName = 0L; |
||||
wcex.lpszClassName = WINCLASS; |
||||
wcex.hIconSm = 0; |
||||
|
||||
ATOM wc = ::RegisterClassEx(&wcex); |
||||
|
||||
RECT rc = { 0, 0, m_width, m_height }; |
||||
::AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false); |
||||
|
||||
m_hWnd = ::CreateWindow( |
||||
(LPCTSTR)wc, m_window_name.c_str(), |
||||
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, |
||||
rc.right - rc.left, rc.bottom - rc.top, |
||||
NULL, NULL, m_hInstance, (void*)this); |
||||
|
||||
if (!m_hWnd) |
||||
return -1; |
||||
|
||||
::ShowWindow(m_hWnd, SW_SHOW); |
||||
::UpdateWindow(m_hWnd); |
||||
::SetFocus(m_hWnd); |
||||
|
||||
return init(); |
||||
} |
||||
|
||||
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) = 0; |
||||
|
||||
int run() |
||||
{ |
||||
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(); |
||||
} |
||||
} |
||||
|
||||
return static_cast<int>(msg.wParam); |
||||
} |
||||
|
||||
protected: |
||||
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) |
||||
{ |
||||
WinApp* pWnd; |
||||
|
||||
if (message == WM_NCCREATE) |
||||
{ |
||||
LPCREATESTRUCT pCreateStruct = ((LPCREATESTRUCT)lParam); |
||||
pWnd = (WinApp*)(pCreateStruct->lpCreateParams); |
||||
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pWnd); |
||||
} |
||||
|
||||
pWnd = GetObjectFromWindow(hWnd); |
||||
|
||||
if (pWnd) |
||||
return pWnd->WndProc(hWnd, message, wParam, lParam); |
||||
else |
||||
return ::DefWindowProc(hWnd, message, wParam, lParam); |
||||
} |
||||
|
||||
inline static WinApp* GetObjectFromWindow(HWND hWnd) |
||||
{ |
||||
return (WinApp*)::GetWindowLongPtr(hWnd, GWLP_USERDATA); |
||||
} |
||||
|
||||
virtual int init() = 0; |
||||
virtual int render() = 0; |
||||
|
||||
HINSTANCE m_hInstance; |
||||
HWND m_hWnd; |
||||
int m_width; |
||||
int m_height; |
||||
std::string m_window_name; |
||||
}; |
||||
|
Loading…
Reference in new issue