mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-22 05:27:20 +00:00
[host] initial rewrite of DXGI capture
This commit is contained in:
parent
dba6720724
commit
f90c258c34
@ -23,7 +23,11 @@ using namespace Capture;
|
|||||||
|
|
||||||
DXGI::DXGI() :
|
DXGI::DXGI() :
|
||||||
m_initialized(false),
|
m_initialized(false),
|
||||||
m_manager(NULL)
|
m_dxgiFactory(NULL),
|
||||||
|
m_device(NULL),
|
||||||
|
m_deviceContext(NULL),
|
||||||
|
m_dup(NULL),
|
||||||
|
m_texture(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,31 +41,158 @@ bool DXGI::Initialize()
|
|||||||
if (m_initialized)
|
if (m_initialized)
|
||||||
DeInitialize();
|
DeInitialize();
|
||||||
|
|
||||||
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
|
HRESULT status;
|
||||||
|
|
||||||
|
status = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void **)(&m_dxgiFactory));
|
||||||
|
if (FAILED(status))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("CoInitializeEx failed");
|
DEBUG_ERROR("Failed to create DXGIFactory: %08x", status);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_manager = new DXGIManager();
|
bool done = false;
|
||||||
m_manager->SetCaptureSource(CSDesktop);
|
CComPtr<IDXGIAdapter1> adapter;
|
||||||
|
for (int i = 0; m_dxgiFactory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++)
|
||||||
|
{
|
||||||
|
CComPtr<IDXGIOutput> output;
|
||||||
|
for (int i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; i++)
|
||||||
|
{
|
||||||
|
DXGI_OUTPUT_DESC outputDesc;
|
||||||
|
output->GetDesc(&outputDesc);
|
||||||
|
if (!outputDesc.AttachedToDesktop)
|
||||||
|
{
|
||||||
|
output.Release();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
RECT rect;
|
m_output = output;
|
||||||
m_manager->GetOutputRect(rect);
|
if (!m_output)
|
||||||
m_width = rect.right - rect.left;
|
{
|
||||||
m_height = rect.bottom - rect.top;
|
output.Release();
|
||||||
|
adapter.Release();
|
||||||
|
DEBUG_ERROR("Failed to get IDXGIOutput1");
|
||||||
|
DeInitialize();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_width = outputDesc.DesktopCoordinates.right - outputDesc.DesktopCoordinates.left;
|
||||||
|
m_height = outputDesc.DesktopCoordinates.bottom - outputDesc.DesktopCoordinates.top;
|
||||||
|
|
||||||
|
output.Release();
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
break;
|
||||||
|
|
||||||
|
adapter.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!done)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to locate a valid output device");
|
||||||
|
DeInitialize();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const D3D_FEATURE_LEVEL featureLevels[] = {
|
||||||
|
D3D_FEATURE_LEVEL_10_1,
|
||||||
|
D3D_FEATURE_LEVEL_10_0,
|
||||||
|
D3D_FEATURE_LEVEL_9_3,
|
||||||
|
D3D_FEATURE_LEVEL_9_2,
|
||||||
|
D3D_FEATURE_LEVEL_9_1
|
||||||
|
};
|
||||||
|
|
||||||
|
status = D3D11CreateDevice(
|
||||||
|
adapter,
|
||||||
|
D3D_DRIVER_TYPE_UNKNOWN,
|
||||||
|
NULL,
|
||||||
|
D3D11_CREATE_DEVICE_DEBUG,
|
||||||
|
featureLevels, ARRAYSIZE(featureLevels),
|
||||||
|
D3D11_SDK_VERSION,
|
||||||
|
&m_device,
|
||||||
|
&m_featureLevel,
|
||||||
|
&m_deviceContext
|
||||||
|
);
|
||||||
|
adapter.Release();
|
||||||
|
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to create D3D11 device");
|
||||||
|
DeInitialize();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CComQIPtr<IDXGIDevice1> device1 = m_device;
|
||||||
|
if (!device1)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to get IDXGIDevice1");
|
||||||
|
DeInitialize();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = m_output->DuplicateOutput(m_device, &m_dup);
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("DuplicateOutput Failed: %08x", status);
|
||||||
|
DeInitialize();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D11_TEXTURE2D_DESC texDesc;
|
||||||
|
ZeroMemory(&texDesc, sizeof(texDesc));
|
||||||
|
texDesc.Width = m_width;
|
||||||
|
texDesc.Height = m_height;
|
||||||
|
texDesc.MipLevels = 1;
|
||||||
|
texDesc.ArraySize = 1;
|
||||||
|
texDesc.SampleDesc.Count = 1;
|
||||||
|
texDesc.SampleDesc.Quality = 0;
|
||||||
|
texDesc.Usage = D3D11_USAGE_STAGING;
|
||||||
|
texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
texDesc.BindFlags = 0;
|
||||||
|
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||||
|
texDesc.MiscFlags = 0;
|
||||||
|
|
||||||
|
status = m_device->CreateTexture2D(&texDesc, NULL, &m_texture);
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to create texture: %08x", status);
|
||||||
|
DeInitialize();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_memcpy.Initialize())
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to initialize memcpy");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DXGI::DeInitialize()
|
void DXGI::DeInitialize()
|
||||||
{
|
{
|
||||||
if (m_manager)
|
m_memcpy.DeInitialize();
|
||||||
{
|
|
||||||
delete m_manager;
|
if (m_texture)
|
||||||
m_manager = NULL;
|
m_texture.Release();
|
||||||
}
|
|
||||||
|
if (m_dup)
|
||||||
|
m_dup.Release();
|
||||||
|
|
||||||
|
if (m_output)
|
||||||
|
m_output.Release();
|
||||||
|
|
||||||
|
if (m_deviceContext)
|
||||||
|
m_deviceContext.Release();
|
||||||
|
|
||||||
|
if (m_device)
|
||||||
|
m_device.Release();
|
||||||
|
|
||||||
|
if (m_dxgiFactory)
|
||||||
|
m_dxgiFactory.Release();
|
||||||
|
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
}
|
}
|
||||||
@ -84,7 +215,7 @@ FrameComp DXGI::GetFrameCompression()
|
|||||||
|
|
||||||
size_t DXGI::GetMaxFrameSize()
|
size_t DXGI::GetMaxFrameSize()
|
||||||
{
|
{
|
||||||
if (!m_initialized);
|
if (!m_initialized)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return m_width * m_height * 4;
|
return m_width * m_height * 4;
|
||||||
@ -92,26 +223,85 @@ size_t DXGI::GetMaxFrameSize()
|
|||||||
|
|
||||||
bool DXGI::GrabFrame(FrameInfo & frame)
|
bool DXGI::GrabFrame(FrameInfo & frame)
|
||||||
{
|
{
|
||||||
RECT rect;
|
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||||
m_manager->GetOutputRect(rect);
|
CComPtr<IDXGIResource> res;
|
||||||
m_width = rect.right - rect.left;
|
|
||||||
m_height = rect.bottom - rect.top;
|
|
||||||
|
|
||||||
HRESULT result;
|
HRESULT status;
|
||||||
for(int i = 0; i < 2; ++i)
|
for(int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
result = m_manager->GetOutputBits((BYTE*)frame.buffer, rect);
|
status = m_dup->AcquireNextFrame(INFINITE, &frameInfo, &res);
|
||||||
if (SUCCEEDED(result))
|
if (SUCCEEDED(status))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// desktop switch, mode change or switch DWM on or off
|
||||||
|
if (status == DXGI_ERROR_ACCESS_LOST)
|
||||||
|
{
|
||||||
|
DeInitialize();
|
||||||
|
if (!Initialize())
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to re-initialize after access was lost");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown failure
|
||||||
|
DEBUG_INFO("AcquireNextFrame failed: %08x", status);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(result))
|
// retry count exceeded
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to acquire next frame");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CComQIPtr<ID3D11Texture2D> src = res;
|
||||||
|
if (!src)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to get src ID3D11Texture2D");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
|
src->GetDesc(&desc);
|
||||||
|
|
||||||
|
m_deviceContext->CopyResource(m_texture, src);
|
||||||
|
m_dup->ReleaseFrame();
|
||||||
|
res.Release();
|
||||||
|
src.Release();
|
||||||
|
|
||||||
|
CComQIPtr<IDXGISurface1> surface = m_texture;
|
||||||
|
if (!surface)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to get IDXGISurface1");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DXGI_MAPPED_RECT rect;
|
||||||
|
status = surface->Map(&rect, DXGI_MAP_READ);
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to map surface: %08x", status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_width = desc.Width;
|
||||||
|
m_height = desc.Height;
|
||||||
|
|
||||||
|
frame.width = desc.Width;
|
||||||
|
frame.height = desc.Height;
|
||||||
|
frame.stride = rect.Pitch / 4;
|
||||||
|
frame.outSize = min(frame.bufferSize, m_height * rect.Pitch);
|
||||||
|
m_memcpy.Copy(frame.buffer, rect.pBits, frame.outSize);
|
||||||
|
|
||||||
|
status = surface->Unmap();
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to unmap surface: %08x", status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
frame.width = m_width;
|
|
||||||
frame.height = m_height;
|
|
||||||
frame.stride = m_width;
|
|
||||||
frame.outSize = m_width * m_height * 4;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -19,10 +19,13 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ICapture.h"
|
#include "ICapture.h"
|
||||||
#include <vendor\DXGICapture\DXGIManager.h>
|
#include "MTMemcpy.h"
|
||||||
|
|
||||||
#define W32_LEAN_AND_MEAN
|
#define W32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <dxgi1_2.h>
|
||||||
|
#include <d3d11.h>
|
||||||
|
#include <atlbase.h>
|
||||||
|
|
||||||
namespace Capture
|
namespace Capture
|
||||||
{
|
{
|
||||||
@ -40,8 +43,16 @@ namespace Capture
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_initialized;
|
bool m_initialized;
|
||||||
DXGIManager * m_manager;
|
MTMemcpy m_memcpy;
|
||||||
unsigned int m_width;
|
unsigned int m_width;
|
||||||
unsigned int m_height;
|
unsigned int m_height;
|
||||||
|
|
||||||
|
CComPtr<IDXGIFactory1> m_dxgiFactory;
|
||||||
|
CComPtr<ID3D11Device> m_device;
|
||||||
|
D3D_FEATURE_LEVEL m_featureLevel;
|
||||||
|
CComPtr<ID3D11DeviceContext> m_deviceContext;
|
||||||
|
CComQIPtr<IDXGIOutput1> m_output;
|
||||||
|
CComPtr<IDXGIOutputDuplication> m_dup;
|
||||||
|
CComPtr<ID3D11Texture2D> m_texture;
|
||||||
};
|
};
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user