removed original samples and replace them with new ones. modified new samples (reduce code duplication, add cmd line params and short description)
This commit is contained in:
parent
3cb4954d70
commit
f0197006e0
@ -1,138 +1,299 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <d3d10.h>
|
#include <d3d10.h>
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
#pragma comment (lib, "d3d10.lib")
|
#pragma comment (lib, "d3d10.lib")
|
||||||
|
|
||||||
#define USE_D3D10
|
|
||||||
#define WINDOW_NAME "OpenCV Direct3D 10 Sample"
|
|
||||||
|
|
||||||
IDXGISwapChain *swapchain = NULL;
|
using namespace std;
|
||||||
ID3D10Device *dev = NULL;
|
using namespace cv;
|
||||||
ID3D10Texture2D *pBackBufferTexture = NULL;
|
|
||||||
ID3D10Texture2D *pCPUWriteTexture = NULL;
|
|
||||||
ID3D10Texture2D *pInputTexture = NULL;
|
|
||||||
ID3D10RenderTargetView *backbuffer = NULL;
|
|
||||||
|
|
||||||
#include "d3d_base.inl.hpp"
|
class D3D10WinApp : public D3DSample
|
||||||
|
|
||||||
bool initDirect3D()
|
|
||||||
{
|
{
|
||||||
DXGI_SWAP_CHAIN_DESC scd;
|
public:
|
||||||
|
D3D10WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
|
||||||
|
D3DSample(width, height, window_name, cap) {}
|
||||||
|
|
||||||
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
|
~D3D10WinApp() {}
|
||||||
|
|
||||||
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(
|
int create(void)
|
||||||
NULL,
|
|
||||||
D3D10_DRIVER_TYPE_HARDWARE,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
D3D10_SDK_VERSION,
|
|
||||||
&scd,
|
|
||||||
&swapchain,
|
|
||||||
&dev)))
|
|
||||||
{
|
{
|
||||||
return false;
|
// base initialization
|
||||||
}
|
D3DSample::create();
|
||||||
|
|
||||||
if (FAILED(swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBufferTexture)))
|
// initialize DirectX
|
||||||
{
|
HRESULT r;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(dev->CreateRenderTargetView(pBackBufferTexture, NULL, &backbuffer)))
|
DXGI_SWAP_CHAIN_DESC scd;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->OMSetRenderTargets(1, &backbuffer, NULL);
|
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
|
||||||
|
|
||||||
D3D10_VIEWPORT viewport;
|
scd.BufferCount = 1; // one back buffer
|
||||||
ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT));
|
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
|
||||||
viewport.Width = WIDTH;
|
scd.BufferDesc.Width = m_width; // set the back buffer width
|
||||||
viewport.Height = HEIGHT;
|
scd.BufferDesc.Height = m_height; // set the back buffer height
|
||||||
viewport.MinDepth = 0.0f;
|
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
|
||||||
viewport.MaxDepth = 0.0f;
|
scd.OutputWindow = m_hWnd; // the window to be used
|
||||||
dev->RSSetViewports(1, &viewport);
|
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
|
||||||
|
|
||||||
return true;
|
r = ::D3D10CreateDeviceAndSwapChain(
|
||||||
}
|
NULL,
|
||||||
|
D3D10_DRIVER_TYPE_HARDWARE,
|
||||||
bool initDirect3DTextures()
|
NULL,
|
||||||
{
|
0,
|
||||||
{ // Create texture for demo 0
|
D3D10_SDK_VERSION,
|
||||||
D3D10_TEXTURE2D_DESC desc = { 0 };
|
&scd,
|
||||||
desc.Width = WIDTH;
|
&m_pD3D10SwapChain,
|
||||||
desc.Height = HEIGHT;
|
&m_pD3D10Dev);
|
||||||
desc.MipLevels = desc.ArraySize = 1;
|
if (FAILED(r))
|
||||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
desc.SampleDesc.Count = 1;
|
|
||||||
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
|
||||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
|
||||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
|
||||||
if (FAILED(dev->CreateTexture2D(&desc, NULL, &pCPUWriteTexture)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't create texture for CPU write sample" << std::endl;
|
return -1;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{ // Create Read-only texture
|
r = m_pD3D10SwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&m_pBackBuffer);
|
||||||
cv::Mat inputMat = getInputTexture();
|
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 };
|
D3D10_TEXTURE2D_DESC desc = { 0 };
|
||||||
desc.Width = inputMat.size().width;
|
|
||||||
desc.Height = inputMat.size().height;
|
desc.Width = m_width;
|
||||||
desc.MipLevels = desc.ArraySize = 1;
|
desc.Height = m_height;
|
||||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
desc.MipLevels = 1;
|
||||||
|
desc.ArraySize = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
||||||
desc.Usage = D3D10_USAGE_IMMUTABLE;
|
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||||
desc.CPUAccessFlags = cv::ocl::useOpenCL() ? 0 : D3D10_CPU_ACCESS_READ;
|
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||||
|
|
||||||
D3D10_SUBRESOURCE_DATA srInitData;
|
r = m_pD3D10Dev->CreateTexture2D(&desc, NULL, &m_pSurface);
|
||||||
srInitData.pSysMem = inputMat.ptr();
|
if (FAILED(r))
|
||||||
srInitData.SysMemPitch = (UINT)inputMat.step[0];
|
|
||||||
|
|
||||||
if (FAILED(dev->CreateTexture2D(&desc, &srInitData, &pInputTexture)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't create texture with input image" << std::endl;
|
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)
|
m_oclDevName = cv::ocl::useOpenCL() ?
|
||||||
{
|
cv::ocl::Context::getDefault().device(0).name() :
|
||||||
if (swapchain) swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
|
"No OpenCL device";
|
||||||
|
|
||||||
SAFE_RELEASE(swapchain);
|
return 0;
|
||||||
SAFE_RELEASE(pCPUWriteTexture);
|
} // create()
|
||||||
SAFE_RELEASE(pInputTexture);
|
|
||||||
SAFE_RELEASE(pBackBufferTexture);
|
|
||||||
SAFE_RELEASE(backbuffer);
|
|
||||||
SAFE_RELEASE(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void render(void)
|
// get media data on DX surface for further processing
|
||||||
{
|
int get_surface(ID3D10Texture2D** ppSurface)
|
||||||
// check to make sure you have a valid Direct3D device
|
{
|
||||||
CV_Assert(dev);
|
HRESULT r;
|
||||||
|
|
||||||
renderToD3DObject();
|
if (!m_cap.read(m_frame_bgr))
|
||||||
|
return -1;
|
||||||
|
|
||||||
// switch the back buffer and the front buffer
|
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA);
|
||||||
swapchain->Present(0, 0);
|
|
||||||
}
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 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 <windows.h>
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
#pragma comment (lib, "d3d11.lib")
|
#pragma comment (lib, "d3d11.lib")
|
||||||
|
|
||||||
#define USE_D3D11
|
|
||||||
#define WINDOW_NAME "OpenCV Direct3D 11 Sample"
|
|
||||||
|
|
||||||
IDXGISwapChain *swapchain = NULL;
|
using namespace std;
|
||||||
ID3D11Device *dev = NULL;
|
using namespace cv;
|
||||||
ID3D11DeviceContext *devcon = NULL;
|
|
||||||
ID3D11Texture2D *pBackBufferTexture = NULL;
|
|
||||||
ID3D11Texture2D *pCPUWriteTexture = NULL;
|
|
||||||
ID3D11Texture2D *pInputTexture = NULL;
|
|
||||||
ID3D11RenderTargetView *backbuffer = NULL;
|
|
||||||
|
|
||||||
#include "d3d_base.inl.hpp"
|
class D3D11WinApp : public D3DSample
|
||||||
|
|
||||||
bool initDirect3D()
|
|
||||||
{
|
{
|
||||||
DXGI_SWAP_CHAIN_DESC scd;
|
public:
|
||||||
|
D3D11WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
|
||||||
|
D3DSample(width, height, window_name, cap) {}
|
||||||
|
|
||||||
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
|
~D3D11WinApp() {}
|
||||||
|
|
||||||
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(
|
int create(void)
|
||||||
NULL,
|
|
||||||
D3D_DRIVER_TYPE_HARDWARE,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
D3D11_SDK_VERSION,
|
|
||||||
&scd,
|
|
||||||
&swapchain,
|
|
||||||
&dev,
|
|
||||||
NULL,
|
|
||||||
&devcon)))
|
|
||||||
{
|
{
|
||||||
return false;
|
// base initialization
|
||||||
}
|
D3DSample::create();
|
||||||
|
|
||||||
if (FAILED(swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBufferTexture)))
|
// initialize DirectX
|
||||||
{
|
HRESULT r;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(dev->CreateRenderTargetView(pBackBufferTexture, NULL, &backbuffer)))
|
DXGI_SWAP_CHAIN_DESC scd;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
|
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
|
||||||
|
|
||||||
D3D11_VIEWPORT viewport = { 0 };
|
scd.BufferCount = 1; // one back buffer
|
||||||
viewport.Width = WIDTH;
|
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
|
||||||
viewport.Height = HEIGHT;
|
scd.BufferDesc.Width = m_width; // set the back buffer width
|
||||||
viewport.MinDepth = 0.0f;
|
scd.BufferDesc.Height = m_height; // set the back buffer height
|
||||||
viewport.MaxDepth = 0.0f;
|
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
|
||||||
devcon->RSSetViewports(1, &viewport);
|
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
|
||||||
|
|
||||||
return true;
|
r = ::D3D11CreateDeviceAndSwapChain(
|
||||||
}
|
NULL,
|
||||||
|
D3D_DRIVER_TYPE_HARDWARE,
|
||||||
bool initDirect3DTextures()
|
NULL,
|
||||||
{
|
0,
|
||||||
{ // Create texture for demo 0
|
NULL,
|
||||||
D3D11_TEXTURE2D_DESC desc = { 0 };
|
0,
|
||||||
desc.Width = WIDTH;
|
D3D11_SDK_VERSION,
|
||||||
desc.Height = HEIGHT;
|
&scd,
|
||||||
desc.MipLevels = desc.ArraySize = 1;
|
&m_pD3D11SwapChain,
|
||||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
&m_pD3D11Dev,
|
||||||
desc.SampleDesc.Count = 1;
|
NULL,
|
||||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
&m_pD3D11Ctx);
|
||||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
if (FAILED(r))
|
||||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
||||||
if (FAILED(dev->CreateTexture2D(&desc, NULL, &pCPUWriteTexture)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't create texture for CPU write sample" << std::endl;
|
return -1;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{ // Create Read-only texture
|
r = m_pD3D11SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&m_pBackBuffer);
|
||||||
cv::Mat inputMat = getInputTexture();
|
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 };
|
D3D11_TEXTURE2D_DESC desc = { 0 };
|
||||||
desc.Width = inputMat.size().width;
|
|
||||||
desc.Height = inputMat.size().height;
|
desc.Width = m_width;
|
||||||
desc.MipLevels = desc.ArraySize = 1;
|
desc.Height = m_height;
|
||||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
desc.MipLevels = 1;
|
||||||
|
desc.ArraySize = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
desc.SampleDesc.Count = 1;
|
desc.SampleDesc.Count = 1;
|
||||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
desc.Usage = D3D11_USAGE_IMMUTABLE;
|
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||||
desc.CPUAccessFlags = cv::ocl::useOpenCL() ? 0 : D3D11_CPU_ACCESS_READ;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||||
|
|
||||||
D3D11_SUBRESOURCE_DATA srInitData;
|
r = m_pD3D11Dev->CreateTexture2D(&desc, NULL, &m_pSurface);
|
||||||
srInitData.pSysMem = inputMat.ptr();
|
if (FAILED(r))
|
||||||
srInitData.SysMemPitch = (UINT)inputMat.step[0];
|
|
||||||
|
|
||||||
if (FAILED(dev->CreateTexture2D(&desc, &srInitData, &pInputTexture)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't create texture with input image" << std::endl;
|
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)
|
m_oclDevName = cv::ocl::useOpenCL() ?
|
||||||
{
|
cv::ocl::Context::getDefault().device(0).name() :
|
||||||
if (swapchain) swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
|
"No OpenCL device";
|
||||||
|
|
||||||
SAFE_RELEASE(swapchain);
|
return 0;
|
||||||
SAFE_RELEASE(pCPUWriteTexture);
|
} // create()
|
||||||
SAFE_RELEASE(pInputTexture);
|
|
||||||
SAFE_RELEASE(pBackBufferTexture);
|
|
||||||
SAFE_RELEASE(backbuffer);
|
|
||||||
SAFE_RELEASE(dev);
|
|
||||||
SAFE_RELEASE(devcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void render(void)
|
// get media data on DX surface for further processing
|
||||||
{
|
int get_surface(ID3D11Texture2D** ppSurface)
|
||||||
// check to make sure you have a valid Direct3D device
|
{
|
||||||
CV_Assert(dev);
|
HRESULT r;
|
||||||
|
|
||||||
renderToD3DObject();
|
if (!m_cap.read(m_frame_bgr))
|
||||||
|
return -1;
|
||||||
|
|
||||||
// switch the back buffer and the front buffer
|
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2BGRA);
|
||||||
swapchain->Present(0, 0);
|
|
||||||
}
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 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 <windows.h>
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
#pragma comment (lib, "d3d9.lib")
|
#pragma comment (lib, "d3d9.lib")
|
||||||
|
|
||||||
#define USE_D3D9
|
|
||||||
#define WINDOW_NAME "OpenCV Direct3D 9 Sample"
|
|
||||||
|
|
||||||
IDirect3D9 *pD3D = NULL;
|
using namespace std;
|
||||||
IDirect3DDevice9 *dev = NULL;
|
using namespace cv;
|
||||||
IDirect3DSurface9 *pBackBuffer = NULL;
|
|
||||||
IDirect3DSurface9 *pCPUWriteSurface = NULL; // required name
|
|
||||||
IDirect3DSurface9 *pReadOnlySurface = NULL; // required name
|
|
||||||
HANDLE readOnlySurfaceShared = 0; // required name
|
|
||||||
IDirect3DSurface9 *pSurface = NULL; // required name
|
|
||||||
HANDLE surfaceShared = 0; // required name
|
|
||||||
|
|
||||||
#include "d3d_base.inl.hpp"
|
class D3D9WinApp : public D3DSample
|
||||||
|
|
||||||
bool initDirect3D(void)
|
|
||||||
{
|
{
|
||||||
if (NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
|
public:
|
||||||
|
D3D9WinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
|
||||||
|
D3DSample(width, height, window_name, cap) {}
|
||||||
|
|
||||||
|
~D3D9WinApp() {}
|
||||||
|
|
||||||
|
int create(void)
|
||||||
{
|
{
|
||||||
return false;
|
// base initialization
|
||||||
}
|
D3DSample::create();
|
||||||
|
|
||||||
D3DPRESENT_PARAMETERS d3dpp;
|
// initialize DirectX
|
||||||
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
|
HRESULT r;
|
||||||
|
|
||||||
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_NOWINDOWCHANGES
|
m_pD3D9 = ::Direct3DCreate9(D3D_SDK_VERSION);
|
||||||
| D3DCREATE_MULTITHREADED;
|
if (NULL == m_pD3D9)
|
||||||
|
|
||||||
d3dpp.Windowed = true;
|
|
||||||
d3dpp.Flags = 0;
|
|
||||||
d3dpp.BackBufferCount = 0;
|
|
||||||
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
|
|
||||||
d3dpp.BackBufferHeight = HEIGHT;
|
|
||||||
d3dpp.BackBufferWidth = WIDTH;
|
|
||||||
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
|
|
||||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
||||||
d3dpp.hDeviceWindow = hWnd;
|
|
||||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
||||||
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
|
|
||||||
|
|
||||||
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, flags, &d3dpp, &dev)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool initDirect3DTextures()
|
|
||||||
{
|
|
||||||
// Note: sharing is not supported on some platforms
|
|
||||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSurface, NULL/*&surfaceShared*/)))
|
|
||||||
{
|
|
||||||
std::cerr << "Can't create surface for result" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: sharing is not supported on some platforms
|
|
||||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pReadOnlySurface, NULL/*&readOnlySurfaceShared*/)))
|
|
||||||
{
|
|
||||||
std::cerr << "Can't create read only surface" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IDirect3DSurface9* pTmpSurface;
|
|
||||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pTmpSurface, NULL)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't create temp surface for CPU write" << std::endl;
|
return -1;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3DLOCKED_RECT memDesc = {0, NULL};
|
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING |
|
||||||
RECT rc = {0, 0, WIDTH, HEIGHT};
|
D3DCREATE_PUREDEVICE |
|
||||||
if (SUCCEEDED(pTmpSurface->LockRect(&memDesc, &rc, 0)))
|
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))
|
||||||
{
|
{
|
||||||
cv::Mat m(cv::Size(WIDTH, HEIGHT), CV_8UC4, memDesc.pBits, (int)memDesc.Pitch);
|
return -1;
|
||||||
getInputTexture().copyTo(m);
|
|
||||||
pTmpSurface->UnlockRect();
|
|
||||||
dev->StretchRect(pTmpSurface, NULL, pReadOnlySurface, NULL, D3DTEXF_NONE);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
r = m_pD3D9Dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
|
||||||
|
if (FAILED(r))
|
||||||
{
|
{
|
||||||
std::cerr << "Can't LockRect() on surface" << std::endl;
|
return -1;
|
||||||
}
|
}
|
||||||
pTmpSurface->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pCPUWriteSurface, NULL)))
|
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 CPU write" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void render(void)
|
|
||||||
{
|
|
||||||
// check to make sure you have a valid Direct3D device
|
|
||||||
CV_Assert(dev);
|
|
||||||
|
|
||||||
renderToD3DObject();
|
|
||||||
|
|
||||||
if (g_sampleType == 0)
|
|
||||||
{
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
else if (g_sampleType == 1)
|
|
||||||
{
|
|
||||||
if (FAILED(dev->StretchRect(pCPUWriteSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't StretchRect()" << std::endl;
|
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())
|
||||||
if (FAILED(dev->StretchRect(pSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't StretchRect()" << std::endl;
|
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9Dev);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(dev -> BeginScene()))
|
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)
|
||||||
{
|
{
|
||||||
// end the scene
|
HRESULT r;
|
||||||
dev -> EndScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
// present the back buffer contents to the display
|
if (!m_cap.read(m_frame_bgr))
|
||||||
dev->Present(NULL, NULL, NULL, NULL);
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
void cleanUp (void)
|
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA);
|
||||||
{
|
|
||||||
SAFE_RELEASE(pCPUWriteSurface);
|
D3DLOCKED_RECT memDesc = { 0, NULL };
|
||||||
SAFE_RELEASE(pReadOnlySurface);
|
RECT rc = { 0, 0, m_width, m_height };
|
||||||
SAFE_RELEASE(pSurface);
|
|
||||||
SAFE_RELEASE(pBackBuffer);
|
r = m_pSurface->LockRect(&memDesc, &rc, 0);
|
||||||
SAFE_RELEASE(dev);
|
if (FAILED(r))
|
||||||
SAFE_RELEASE(pD3D);}
|
{
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
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 << "Exception: " << e.what() << std::endl;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} // render()
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
} // print_info()
|
||||||
|
|
||||||
|
|
||||||
|
int cleanup(void)
|
||||||
|
{
|
||||||
|
SAFE_RELEASE(m_pSurface);
|
||||||
|
SAFE_RELEASE(m_pBackBuffer);
|
||||||
|
SAFE_RELEASE(m_pD3D9Dev);
|
||||||
|
SAFE_RELEASE(m_pD3D9);
|
||||||
|
D3DSample::cleanup();
|
||||||
|
return 0;
|
||||||
|
} // cleanup()
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 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 <windows.h>
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
#pragma comment (lib, "d3d9.lib")
|
#pragma comment (lib, "d3d9.lib")
|
||||||
|
|
||||||
#define USE_D3DEX
|
|
||||||
#define WINDOW_NAME "OpenCV Direct3D 9 Ex Sample"
|
|
||||||
|
|
||||||
IDirect3D9Ex *pD3D = NULL;
|
using namespace std;
|
||||||
IDirect3DDevice9Ex *dev = NULL;
|
using namespace cv;
|
||||||
IDirect3DSurface9 *pBackBuffer = NULL;
|
|
||||||
IDirect3DSurface9 *pCPUWriteSurface = NULL; // required name
|
|
||||||
IDirect3DSurface9 *pReadOnlySurface = NULL; // required name
|
|
||||||
HANDLE readOnlySurfaceShared = 0; // required name
|
|
||||||
IDirect3DSurface9 *pSurface = NULL; // required name
|
|
||||||
HANDLE surfaceShared = 0; // required name
|
|
||||||
|
|
||||||
#include "d3d_base.inl.hpp"
|
class D3D9ExWinApp : public D3DSample
|
||||||
|
|
||||||
bool initDirect3D(void)
|
|
||||||
{
|
{
|
||||||
if (FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D)))
|
public:
|
||||||
|
D3D9ExWinApp(int width, int height, std::string& window_name, cv::VideoCapture& cap) :
|
||||||
|
D3DSample(width, height, window_name, cap) {}
|
||||||
|
|
||||||
|
~D3D9ExWinApp() {}
|
||||||
|
|
||||||
|
int create(void)
|
||||||
{
|
{
|
||||||
return false;
|
// base initialization
|
||||||
}
|
D3DSample::create();
|
||||||
|
|
||||||
D3DDISPLAYMODEEX ddm;
|
// initialize DirectX
|
||||||
ZeroMemory(&ddm, sizeof(ddm));
|
HRESULT r;
|
||||||
ddm.Size = sizeof(D3DDISPLAYMODEEX);
|
|
||||||
D3DDISPLAYROTATION rotation;
|
|
||||||
if (FAILED(pD3D->GetAdapterDisplayModeEx(D3DADAPTER_DEFAULT, &ddm, &rotation)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DPRESENT_PARAMETERS d3dpp;
|
r = ::Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9Ex);
|
||||||
ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
|
if (FAILED(r))
|
||||||
|
|
||||||
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_NOWINDOWCHANGES
|
|
||||||
| D3DCREATE_MULTITHREADED;
|
|
||||||
|
|
||||||
d3dpp.Windowed = true;
|
|
||||||
d3dpp.Flags = 0;
|
|
||||||
d3dpp.BackBufferCount = 0;
|
|
||||||
d3dpp.BackBufferFormat = ddm.Format;
|
|
||||||
d3dpp.BackBufferHeight = HEIGHT;
|
|
||||||
d3dpp.BackBufferWidth = WIDTH;
|
|
||||||
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
|
|
||||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
||||||
d3dpp.hDeviceWindow = hWnd;
|
|
||||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
||||||
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
|
|
||||||
|
|
||||||
if (FAILED(pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, flags, &d3dpp, NULL, &dev)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool initDirect3DTextures()
|
|
||||||
{
|
|
||||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSurface, &surfaceShared)))
|
|
||||||
{
|
|
||||||
std::cerr << "Can't create surface for result" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pReadOnlySurface, &readOnlySurfaceShared)))
|
|
||||||
{
|
|
||||||
std::cerr << "Can't create read only surface" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IDirect3DSurface9* pTmpSurface;
|
|
||||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pTmpSurface, NULL)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't create temp surface for CPU write" << std::endl;
|
return -1;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3DLOCKED_RECT memDesc = {0, NULL};
|
DWORD flags = D3DCREATE_HARDWARE_VERTEXPROCESSING |
|
||||||
RECT rc = {0, 0, WIDTH, HEIGHT};
|
D3DCREATE_PUREDEVICE |
|
||||||
if (SUCCEEDED(pTmpSurface->LockRect(&memDesc, &rc, 0)))
|
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))
|
||||||
{
|
{
|
||||||
cv::Mat m(cv::Size(WIDTH, HEIGHT), CV_8UC4, memDesc.pBits, (int)memDesc.Pitch);
|
return -1;
|
||||||
getInputTexture().copyTo(m);
|
|
||||||
pTmpSurface->UnlockRect();
|
|
||||||
dev->StretchRect(pTmpSurface, NULL, pReadOnlySurface, NULL, D3DTEXF_NONE);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
r = m_pD3D9DevEx->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
|
||||||
|
if (FAILED(r))
|
||||||
{
|
{
|
||||||
std::cerr << "Can't LockRect() on surface" << std::endl;
|
return -1;
|
||||||
}
|
}
|
||||||
pTmpSurface->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(dev->CreateOffscreenPlainSurface(WIDTH, HEIGHT, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pCPUWriteSurface, NULL)))
|
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 CPU write" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void render(void)
|
|
||||||
{
|
|
||||||
// check to make sure you have a valid Direct3D device
|
|
||||||
CV_Assert(dev);
|
|
||||||
|
|
||||||
renderToD3DObject();
|
|
||||||
|
|
||||||
if (g_sampleType == 0)
|
|
||||||
{
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
else if (g_sampleType == 1)
|
|
||||||
{
|
|
||||||
if (FAILED(dev->StretchRect(pCPUWriteSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't StretchRect()" << std::endl;
|
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())
|
||||||
if (FAILED(dev->StretchRect(pSurface, NULL, pBackBuffer, NULL, D3DTEXF_NONE)))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Can't StretchRect()" << std::endl;
|
m_oclCtx = cv::directx::ocl::initializeContextFromDirect3DDevice9(m_pD3D9DevEx);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED(dev -> BeginScene()))
|
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)
|
||||||
{
|
{
|
||||||
// end the scene
|
HRESULT r;
|
||||||
dev -> EndScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
// present the back buffer contents to the display
|
if (!m_cap.read(m_frame_bgr))
|
||||||
dev->Present(NULL, NULL, NULL, NULL);
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
void cleanUp (void)
|
cv::cvtColor(m_frame_bgr, m_frame_rgba, CV_RGB2RGBA);
|
||||||
{
|
|
||||||
SAFE_RELEASE(pCPUWriteSurface);
|
D3DLOCKED_RECT memDesc = { 0, NULL };
|
||||||
SAFE_RELEASE(pReadOnlySurface);
|
RECT rc = { 0, 0, m_width, m_height };
|
||||||
SAFE_RELEASE(pSurface);
|
|
||||||
SAFE_RELEASE(pBackBuffer);
|
r = m_pSurface->LockRect(&memDesc, &rc, 0);
|
||||||
SAFE_RELEASE(dev);
|
if (FAILED(r))
|
||||||
SAFE_RELEASE(pD3D);
|
{
|
||||||
}
|
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()
|
||||||
|
{
|
||||||
|
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_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} // render()
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
} // print_info()
|
||||||
|
|
||||||
|
|
||||||
|
int cleanup(void)
|
||||||
|
{
|
||||||
|
SAFE_RELEASE(m_pSurface);
|
||||||
|
SAFE_RELEASE(m_pBackBuffer);
|
||||||
|
SAFE_RELEASE(m_pD3D9DevEx);
|
||||||
|
SAFE_RELEASE(m_pD3D9Ex);
|
||||||
|
D3DSample::cleanup();
|
||||||
|
return 0;
|
||||||
|
} // cleanup()
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
185
samples/directx/d3dsample.hpp
Normal file
185
samples/directx/d3dsample.hpp
Normal file
@ -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; \
|
||||||
|
} \
|
||||||
|
}
|
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
#define WINCLASS "WinAppWnd"
|
#define WINCLASS "WinAppWnd"
|
||||||
|
|
||||||
#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; }
|
|
||||||
|
|
||||||
class WinApp
|
class WinApp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -16,14 +14,13 @@ public:
|
|||||||
m_height = height;
|
m_height = height;
|
||||||
m_window_name = window_name;
|
m_window_name = window_name;
|
||||||
m_hInstance = ::GetModuleHandle(NULL);
|
m_hInstance = ::GetModuleHandle(NULL);
|
||||||
|
m_hWnd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~WinApp()
|
virtual ~WinApp() {}
|
||||||
{
|
|
||||||
::UnregisterClass(WINCLASS, m_hInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Create()
|
|
||||||
|
virtual int create()
|
||||||
{
|
{
|
||||||
WNDCLASSEX wcex;
|
WNDCLASSEX wcex;
|
||||||
|
|
||||||
@ -41,9 +38,12 @@ public:
|
|||||||
wcex.hIconSm = 0;
|
wcex.hIconSm = 0;
|
||||||
|
|
||||||
ATOM wc = ::RegisterClassEx(&wcex);
|
ATOM wc = ::RegisterClassEx(&wcex);
|
||||||
|
if (!wc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
RECT rc = { 0, 0, m_width, m_height };
|
RECT rc = { 0, 0, m_width, m_height };
|
||||||
::AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
|
if(!::AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false))
|
||||||
|
return -1;
|
||||||
|
|
||||||
m_hWnd = ::CreateWindow(
|
m_hWnd = ::CreateWindow(
|
||||||
(LPCTSTR)wc, m_window_name.c_str(),
|
(LPCTSTR)wc, m_window_name.c_str(),
|
||||||
@ -58,10 +58,9 @@ public:
|
|||||||
::UpdateWindow(m_hWnd);
|
::UpdateWindow(m_hWnd);
|
||||||
::SetFocus(m_hWnd);
|
::SetFocus(m_hWnd);
|
||||||
|
|
||||||
return init();
|
return 0;
|
||||||
}
|
} // create()
|
||||||
|
|
||||||
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) = 0;
|
|
||||||
|
|
||||||
int run()
|
int run()
|
||||||
{
|
{
|
||||||
@ -78,23 +77,32 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
render();
|
idle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<int>(msg.wParam);
|
return static_cast<int>(msg.wParam);
|
||||||
}
|
} // run()
|
||||||
|
|
||||||
|
|
||||||
|
virtual int cleanup()
|
||||||
|
{
|
||||||
|
::DestroyWindow(m_hWnd);
|
||||||
|
::UnregisterClass(WINCLASS, m_hInstance);
|
||||||
|
return 0;
|
||||||
|
} // cleanup()
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// dispatch message handling to method of class
|
||||||
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
WinApp* pWnd;
|
WinApp* pWnd;
|
||||||
|
|
||||||
if (message == WM_NCCREATE)
|
if (message == WM_NCCREATE)
|
||||||
{
|
{
|
||||||
LPCREATESTRUCT pCreateStruct = ((LPCREATESTRUCT)lParam);
|
LPCREATESTRUCT pCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
||||||
pWnd = (WinApp*)(pCreateStruct->lpCreateParams);
|
pWnd = static_cast<WinApp*>(pCreateStruct->lpCreateParams);
|
||||||
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pWnd);
|
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
pWnd = GetObjectFromWindow(hWnd);
|
pWnd = GetObjectFromWindow(hWnd);
|
||||||
@ -103,15 +111,14 @@ protected:
|
|||||||
return pWnd->WndProc(hWnd, message, wParam, lParam);
|
return pWnd->WndProc(hWnd, message, wParam, lParam);
|
||||||
else
|
else
|
||||||
return ::DefWindowProc(hWnd, message, wParam, lParam);
|
return ::DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
}
|
} // StaticWndProc()
|
||||||
|
|
||||||
inline static WinApp* GetObjectFromWindow(HWND hWnd)
|
inline static WinApp* GetObjectFromWindow(HWND hWnd) { return (WinApp*)::GetWindowLongPtr(hWnd, GWLP_USERDATA); }
|
||||||
{
|
|
||||||
return (WinApp*)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int init() = 0;
|
// actual wnd message handling
|
||||||
virtual int render() = 0;
|
virtual LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) = 0;
|
||||||
|
// idle processing
|
||||||
|
virtual int idle() = 0;
|
||||||
|
|
||||||
HINSTANCE m_hInstance;
|
HINSTANCE m_hInstance;
|
||||||
HWND m_hWnd;
|
HWND m_hWnd;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user