GDI를 사용한 화면 덤프는 끔찍하게 느리다.
그래서 그래픽카드의 도움을 받기로 했다.
#include <stdio.h>
#include <stdlib.h>
#include <d3d11.h>
#include <DXGI.h>
#include <dxgi1_2.h>
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "dxgi.lib")
/**
@brief 텍스쳐 생성함수
*/
ID3D11Texture2D* CreateTexture(ID3D11Device* d3d11, int width, int height, DXGI_FORMAT colorformat)
{
D3D11_TEXTURE2D_DESC td;
ID3D11Texture2D* OutputTexVal;
if (!d3d11) return NULL;
memset(&td, 0, sizeof(td));
td.Width = width;
td.Height = height;
td.MipLevels = 1;
td.ArraySize = 1;
td.Format = colorformat;
td.BindFlags = 0;
td.SampleDesc.Count = 1;
td.Usage = D3D11_USAGE_STAGING;
td.CPUAccessFlags = D3D11_CPU_ACCESS_READ; /*이 개체에 CPU가 접근 할 수 있도록 셋팅*/
d3d11->CreateTexture2D(&td, NULL, &OutputTexVal);
if (!OutputTexVal) return NULL;
return OutputTexVal;
}
int main()
{
IDXGIFactory1* pFactory;
IDXGIAdapter* pAdapter;
IDXGIOutput* pOut;
DXGI_OUTPUT_DESC outdesc;
IDXGIOutput1* pOut1;
IDXGIOutputDuplication* pDup;
DXGI_OUTDUPL_FRAME_INFO dupframeinfo;
IDXGIResource* res;
ID3D11Texture2D* pTex, *pTmpTex;
IDXGISurface1* pSurface;
DXGI_MAPPED_RECT map;
IDXGIDevice1* pDxgiDev;
D3D11_TEXTURE2D_DESC texdesc;
ID3D11Device* d3d11;
D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_9_1;
ID3D11DeviceContext* d3d11context;
CreateDXGIFactory1(__uuidof(IDXGIFactory2), (void**)&pFactory); /*팩토리 생성*/
pFactory->EnumAdapters(0, &pAdapter); /*만들어진 팩토리로 어댑터 얻기*/
pAdapter->EnumOutputs(0, &pOut); /*어댑터에 물린 디스플레이 얻기 (여기선 0번 화면) */
pOut->GetDesc(&outdesc);
pOut->QueryInterface(__uuidof(IDXGIOutput1), (void**)&pOut1); /*출력개체 확장 얻어오기*/
/*d3d11 디바이스 및 컨텍스트 생성*/
D3D11CreateDevice(pAdapter, D3D_DRIVER_TYPE_UNKNOWN, 0, 0, 0, 0, D3D11_SDK_VERSION, &d3d11, &fl, &d3d11context);
d3d11->QueryInterface(__uuidof(IDXGIDevice1), (void**)&pDxgiDev); /*DXGI 인터페이스 얻어오기*/
pOut1->DuplicateOutput(d3d11, &pDup); /*Duplicator 얻어오기*/
pDup->AcquireNextFrame(16, &dupframeinfo, &res); /*현재 화면 프레임 얻어오기 (16ms 안에 얻어오기) */
res->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&pTmpTex); /*얻어온 리소스는 텍스쳐로*/
pTmpTex->GetDesc(&texdesc);
pTex = CreateTexture(d3d11, texdesc.Width, texdesc.Height, texdesc.Format); /*저 텍스쳐는 CPU가 바로 사용 할 수 없으므로 새로 만듬*/
d3d11context->CopyResource(pTex, pTmpTex); /*화면 복사*/
pTex->QueryInterface(__uuidof(IDXGISurface1), (void**)&pSurface); /*서페이스 얻어오고*/
pSurface->Map(&map, DXGI_MAP_READ); /*메모리 얻어오기*/
return 0;
}
|
cs |
pSurface->Map 이후 성공 했다면 map.pBits 포인터는 이렇게 생겼다.
물론 한번 딱 얻어오고 끝나지 않고 지속적으로 얻어오고 싶을때도 있을것이다.
화면을 얻어오는 매서드는 IDXGIOutputDuplication (여기서는 pDup) 의 AcquireNextFrame() 인데, 재호출 하기 전에 얻어온 리소스를 해제 해야한다.
pSurface->Map() 으로 매핑했던 리소스를 pSurface->Unmap() 으로 풀어준 후 pDup->ReleaseFrame() 으로 해제한 후엔 다시 pDup->AcquireNextFrame() 을 호출하여 화면을 갱신할 수 있다.
그러면 이 내용을 적용하여 main 함수만 다시 적절히 수정 해보자.
int main()
{
IDXGIFactory1* pFactory;
IDXGIAdapter* pAdapter;
IDXGIOutput* pOut;
DXGI_OUTPUT_DESC outdesc;
IDXGIOutput1* pOut1;
IDXGIOutputDuplication* pDup;
DXGI_OUTDUPL_FRAME_INFO dupframeinfo;
IDXGIResource* res;
ID3D11Texture2D* pTex, * pTmpTex;
IDXGISurface1* pSurface;
DXGI_MAPPED_RECT map;
IDXGIDevice1* pDxgiDev;
D3D11_TEXTURE2D_DESC texdesc;
ID3D11Device* d3d11;
D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_9_1;
ID3D11DeviceContext* d3d11context;
CreateDXGIFactory1(__uuidof(IDXGIFactory2), (void**)&pFactory); /*팩토리 생성*/
pFactory->EnumAdapters(0, &pAdapter); /*만들어진 팩토리로 어댑터 얻기*/
pAdapter->EnumOutputs(0, &pOut); /*어댑터에 물린 디스플레이 얻기 (여기선 0번 화면)*/
pOut->GetDesc(&outdesc);
pOut->QueryInterface(__uuidof(IDXGIOutput1), (void**)&pOut1); /*출력개체 확장 얻어오기*/
/*d3d11 디바이스 및 컨텍스트 생성*/
D3D11CreateDevice(pAdapter, D3D_DRIVER_TYPE_UNKNOWN, 0, 0, 0, 0, D3D11_SDK_VERSION, &d3d11, &fl, &d3d11context);
d3d11->QueryInterface(__uuidof(IDXGIDevice1), (void**)&pDxgiDev); /*DXGI 인터페이스 얻어오기*/
pOut1->DuplicateOutput(d3d11, &pDup); /*Duplicator 얻어오기*/
pDup->AcquireNextFrame(16, &dupframeinfo, &res); /*현재 화면 프레임 얻어오기 (16ms 안에 얻어오기)*/
res->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&pTmpTex); /*얻어온 리소스는 텍스쳐로*/
pTmpTex->GetDesc(&texdesc); /*화면 크기 등의 정보를 얻기 위함*/
pDup->ReleaseFrame(); /*일단 다시 해제*/
pTex = CreateTexture(d3d11, texdesc.Width, texdesc.Height, texdesc.Format); /*저 텍스쳐는 CPU가 바로 사용 할 수 없으므로 새로 만듬*/
int i = 0;
while (1) {
pDup->AcquireNextFrame(16, &dupframeinfo, &res); /*현재 화면 프레임 얻어오기 (16ms 안에 얻어오기)*/
res->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&pTmpTex); /*얻어온 리소스는 텍스쳐로*/
d3d11context->CopyResource(pTex, pTmpTex); /*화면 복사*/
pTex->QueryInterface(__uuidof(IDXGISurface1), (void**)&pSurface); /*서페이스 얻어오고*/
pSurface->Map(&map, DXGI_MAP_READ); /*메모리 얻어오기*/
/*뭔가 하고싶은거 있으면 이 사이에 하면댐. 일단 여기서는 화면 좌상단의 1픽셀 데이터만 표시 해봄.*/
printf("\rLOOP#%d : %02x %02x %02x %02x", i++, map.pBits[0], map.pBits[1], map.pBits[2], map.pBits[3]);
pSurface->Unmap(); /* 쓴거 해제*/
pDup->ReleaseFrame(); /*쓴거 해제*/
}
pTex->Release();
return 0;
}
|
cs |
실행 결과 :
'뻘짓' 카테고리의 다른 글
libvpx를 통한 인코딩 예제 (0) | 2020.09.07 |
---|---|
libvpx 빌드하기 (파일 첨부 되어있음) (0) | 2020.09.05 |
OpenSSL을 통한 소수 생성 (랜덤) (1) | 2020.09.02 |
무선랜 인터페이스 얻어오기 (0) | 2020.08.31 |
다이렉트X를 통한 그래픽카드 이름 얻어오기 (0) | 2020.08.03 |