mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-12-22 13:52:57 +00:00
[host] dxgi: refactor to support additional copy backends
This commit is contained in:
parent
36892839f3
commit
137171a8a2
5 changed files with 407 additions and 210 deletions
|
@ -3,6 +3,8 @@ project(capture_DXGI LANGUAGES C)
|
|||
|
||||
add_library(capture_DXGI STATIC
|
||||
src/dxgi.c
|
||||
src/d3d11.c
|
||||
src/util.c
|
||||
)
|
||||
|
||||
add_definitions("-DCOBJMACROS -DINITGUID")
|
||||
|
|
198
host/platform/Windows/capture/DXGI/src/d3d11.c
Normal file
198
host/platform/Windows/capture/DXGI/src/d3d11.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2021 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "dxgi_capture.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include "common/debug.h"
|
||||
#include "common/runningavg.h"
|
||||
#include "common/windebug.h"
|
||||
|
||||
struct D3D11Backend
|
||||
{
|
||||
RunningAvg avgMapTime;
|
||||
uint64_t usleepMapTime;
|
||||
};
|
||||
|
||||
static struct DXGIInterface * dxgi = NULL;
|
||||
static struct D3D11Backend * this = NULL;
|
||||
|
||||
static void d3d11_free(void);
|
||||
|
||||
static bool d3d11_create(struct DXGIInterface * intf)
|
||||
{
|
||||
HRESULT status;
|
||||
dxgi = intf;
|
||||
|
||||
assert(!this);
|
||||
this = calloc(1, sizeof(struct D3D11Backend));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("failed to allocate D3D11Backend struct");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->avgMapTime = runningavg_new(10);
|
||||
|
||||
D3D11_TEXTURE2D_DESC texDesc;
|
||||
memset(&texDesc, 0, sizeof(texDesc));
|
||||
texDesc.Width = dxgi->width;
|
||||
texDesc.Height = dxgi->height;
|
||||
texDesc.MipLevels = 1;
|
||||
texDesc.ArraySize = 1;
|
||||
texDesc.SampleDesc.Count = 1;
|
||||
texDesc.SampleDesc.Quality = 0;
|
||||
texDesc.Usage = D3D11_USAGE_STAGING;
|
||||
texDesc.Format = dxgi->dxgiFormat;
|
||||
texDesc.BindFlags = 0;
|
||||
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
texDesc.MiscFlags = 0;
|
||||
|
||||
for (int i = 0; i < dxgi->maxTextures; ++i)
|
||||
{
|
||||
status = ID3D11Device_CreateTexture2D(dxgi->device, &texDesc, NULL, (ID3D11Texture2D **)&dxgi->texture[i].impl);
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create texture", status);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
// map the texture simply to get the pitch and stride
|
||||
D3D11_MAPPED_SUBRESOURCE mapping;
|
||||
status = ID3D11DeviceContext_Map(dxgi->deviceContext, (ID3D11Resource *)dxgi->texture[0].impl, 0, D3D11_MAP_READ, 0, &mapping);
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to map the texture", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dxgi->pitch = mapping.RowPitch;
|
||||
dxgi->stride = mapping.RowPitch / dxgi->bpp;
|
||||
ID3D11DeviceContext_Unmap(dxgi->deviceContext, (ID3D11Resource *)dxgi->texture[0].impl, 0);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
d3d11_free();
|
||||
return false;
|
||||
}
|
||||
|
||||
static void d3d11_free(void)
|
||||
{
|
||||
assert(this);
|
||||
|
||||
for (int i = 0; i < dxgi->maxTextures; ++i)
|
||||
if (dxgi->texture[i].impl)
|
||||
ID3D11Texture2D_Release((ID3D11Texture2D *) dxgi->texture[i].impl);
|
||||
|
||||
runningavg_free(&this->avgMapTime);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static bool d3d11_copyFrame(Texture * tex, ID3D11Texture2D * src)
|
||||
{
|
||||
INTERLOCKED_SECTION(dxgi->deviceContextLock,
|
||||
{
|
||||
tex->copyTime = microtime();
|
||||
|
||||
if (tex->texDamageCount < 0)
|
||||
ID3D11DeviceContext_CopyResource(dxgi->deviceContext,
|
||||
(ID3D11Resource *)tex->impl, (ID3D11Resource *)src);
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tex->texDamageCount; ++i)
|
||||
{
|
||||
FrameDamageRect * rect = tex->texDamageRects + i;
|
||||
D3D11_BOX box = {
|
||||
.left = rect->x, .top = rect->y, .front = 0, .back = 1,
|
||||
.right = rect->x + rect->width, .bottom = rect->y + rect->height,
|
||||
};
|
||||
ID3D11DeviceContext_CopySubresourceRegion(dxgi->deviceContext,
|
||||
(ID3D11Resource *)tex->impl, 0, rect->x, rect->y, 0,
|
||||
(ID3D11Resource *)src, 0, &box);
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11DeviceContext_Flush(dxgi->deviceContext);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
static CaptureResult d3d11_mapTexture(Texture * tex)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
|
||||
// sleep until it's close to time to map
|
||||
const uint64_t delta = microtime() - tex->copyTime;
|
||||
if (delta < this->usleepMapTime)
|
||||
usleep(this->usleepMapTime - delta);
|
||||
|
||||
// try to map the resource, but don't wait for it
|
||||
for (int i = 0; ; ++i)
|
||||
{
|
||||
HRESULT status;
|
||||
|
||||
INTERLOCKED_SECTION(dxgi->deviceContextLock, {
|
||||
status = ID3D11DeviceContext_Map(dxgi->deviceContext, (ID3D11Resource *) tex->impl,
|
||||
0, D3D11_MAP_READ, 0x100000L, &map);
|
||||
});
|
||||
if (status == DXGI_ERROR_WAS_STILL_DRAWING)
|
||||
{
|
||||
if (i == 100)
|
||||
return CAPTURE_RESULT_TIMEOUT;
|
||||
|
||||
usleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to map the texture", status);
|
||||
return CAPTURE_RESULT_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
tex->map = map.pData;
|
||||
|
||||
// update the sleep average and sleep for 80% of the average on the next call
|
||||
runningavg_push(this->avgMapTime, microtime() - tex->copyTime);
|
||||
this->usleepMapTime = (uint64_t)(runningavg_calc(this->avgMapTime) * 0.8);
|
||||
return CAPTURE_RESULT_OK;
|
||||
}
|
||||
|
||||
static void d3d11_unmapTexture(Texture * tex)
|
||||
{
|
||||
INTERLOCKED_SECTION(dxgi->deviceContextLock, {
|
||||
ID3D11DeviceContext_Unmap(dxgi->deviceContext, (ID3D11Resource *) tex->impl, 0);
|
||||
});
|
||||
tex->map = NULL;
|
||||
}
|
||||
|
||||
struct DXGICopyBackend copyBackendD3D11 = {
|
||||
.name = "Direct3D 11",
|
||||
.create = d3d11_create,
|
||||
.free = d3d11_free,
|
||||
.copyFrame = d3d11_copyFrame,
|
||||
.mapTexture = d3d11_mapTexture,
|
||||
.unmapTexture = d3d11_unmapTexture,
|
||||
};
|
|
@ -36,89 +36,23 @@
|
|||
#include <dxgi1_2.h>
|
||||
#include <dxgi1_5.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3d12.h>
|
||||
#include <d3dcommon.h>
|
||||
#include <versionhelpers.h>
|
||||
#include <dwmapi.h>
|
||||
|
||||
#include "dxgi_extra.h"
|
||||
#include "dxgi_capture.h"
|
||||
|
||||
#define LOCKED(...) INTERLOCKED_SECTION(this->deviceContextLock, __VA_ARGS__)
|
||||
|
||||
enum TextureState
|
||||
{
|
||||
TEXTURE_STATE_UNUSED,
|
||||
TEXTURE_STATE_PENDING_MAP,
|
||||
TEXTURE_STATE_MAPPED
|
||||
};
|
||||
|
||||
typedef struct Texture
|
||||
{
|
||||
unsigned int formatVer;
|
||||
volatile enum TextureState state;
|
||||
ID3D11Texture2D * tex;
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
uint64_t copyTime;
|
||||
uint32_t damageRectsCount;
|
||||
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
int32_t texDamageCount;
|
||||
FrameDamageRect texDamageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
}
|
||||
Texture;
|
||||
|
||||
struct FrameDamage
|
||||
{
|
||||
int count;
|
||||
FrameDamageRect rects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
};
|
||||
|
||||
// locals
|
||||
struct iface
|
||||
{
|
||||
bool initialized;
|
||||
LARGE_INTEGER perfFreq;
|
||||
LARGE_INTEGER frameTime;
|
||||
bool stop;
|
||||
HDESK desktop;
|
||||
IDXGIFactory1 * factory;
|
||||
IDXGIAdapter1 * adapter;
|
||||
IDXGIOutput * output;
|
||||
ID3D11Device * device;
|
||||
ID3D11DeviceContext * deviceContext;
|
||||
LG_Lock deviceContextLock;
|
||||
bool useAcquireLock;
|
||||
bool dwmFlush;
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
IDXGIOutputDuplication * dup;
|
||||
int maxTextures;
|
||||
Texture * texture;
|
||||
int texRIndex;
|
||||
int texWIndex;
|
||||
atomic_int texReady;
|
||||
bool needsRelease;
|
||||
static struct DXGIInterface * this = NULL;
|
||||
|
||||
RunningAvg avgMapTime;
|
||||
uint64_t usleepMapTime;
|
||||
|
||||
CaptureGetPointerBuffer getPointerBufferFn;
|
||||
CapturePostPointerBuffer postPointerBufferFn;
|
||||
LGEvent * frameEvent;
|
||||
|
||||
unsigned int formatVer;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int pitch;
|
||||
unsigned int stride;
|
||||
CaptureFormat format;
|
||||
CaptureRotation rotation;
|
||||
|
||||
int lastPointerX, lastPointerY;
|
||||
bool lastPointerVisible;
|
||||
|
||||
struct FrameDamage frameDamage[LGMP_Q_FRAME_LEN];
|
||||
extern struct DXGICopyBackend copyBackendD3D11;
|
||||
static struct DXGICopyBackend * backends[] = {
|
||||
©BackendD3D11,
|
||||
};
|
||||
|
||||
static struct iface * this = NULL;
|
||||
|
||||
// forwards
|
||||
|
||||
static bool dxgi_deinit();
|
||||
|
@ -182,7 +116,7 @@ static bool dxgi_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostP
|
|||
this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("failed to allocate iface struct");
|
||||
DEBUG_ERROR("failed to allocate DXGIInterface struct");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -203,7 +137,6 @@ static bool dxgi_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostP
|
|||
this->texture = calloc(this->maxTextures, sizeof(*this->texture));
|
||||
this->getPointerBufferFn = getPointerBufferFn;
|
||||
this->postPointerBufferFn = postPointerBufferFn;
|
||||
this->avgMapTime = runningavg_new(10);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -240,9 +173,6 @@ static bool dxgi_init(void)
|
|||
this->texWIndex = 0;
|
||||
atomic_store(&this->texReady, 0);
|
||||
|
||||
runningavg_reset(this->avgMapTime);
|
||||
this->usleepMapTime = 0;
|
||||
|
||||
lgResetEvent(this->frameEvent);
|
||||
|
||||
status = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&this->factory);
|
||||
|
@ -534,9 +464,11 @@ static bool dxgi_init(void)
|
|||
|
||||
DXGI_OUTDUPL_DESC dupDesc;
|
||||
IDXGIOutputDuplication_GetDesc(this->dup, &dupDesc);
|
||||
DEBUG_INFO("Source Format : %s", GetDXGIFormatStr(dupDesc.ModeDesc.Format));
|
||||
|
||||
uint8_t bpp = 4;
|
||||
this->dxgiFormat = dupDesc.ModeDesc.Format;
|
||||
DEBUG_INFO("Source Format : %s", GetDXGIFormatStr(this->dxgiFormat));
|
||||
|
||||
this->bpp = 4;
|
||||
switch(dupDesc.ModeDesc.Format)
|
||||
{
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM : this->format = CAPTURE_FMT_BGRA ; break;
|
||||
|
@ -545,7 +477,7 @@ static bool dxgi_init(void)
|
|||
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
this->format = CAPTURE_FMT_RGBA16F;
|
||||
bpp = 8;
|
||||
this->bpp = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -553,42 +485,26 @@ static bool dxgi_init(void)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC texDesc;
|
||||
memset(&texDesc, 0, sizeof(texDesc));
|
||||
texDesc.Width = this->width;
|
||||
texDesc.Height = this->height;
|
||||
texDesc.MipLevels = 1;
|
||||
texDesc.ArraySize = 1;
|
||||
texDesc.SampleDesc.Count = 1;
|
||||
texDesc.SampleDesc.Quality = 0;
|
||||
texDesc.Usage = D3D11_USAGE_STAGING;
|
||||
texDesc.Format = dupDesc.ModeDesc.Format;
|
||||
texDesc.BindFlags = 0;
|
||||
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
texDesc.MiscFlags = 0;
|
||||
|
||||
for (int i = 0; i < this->maxTextures; ++i)
|
||||
for (int i = 0; i < ARRAY_LENGTH(backends); ++i)
|
||||
{
|
||||
this->texture[i].texDamageCount = -1;
|
||||
status = ID3D11Device_CreateTexture2D(this->device, &texDesc, NULL, &this->texture[i].tex);
|
||||
if (FAILED(status))
|
||||
if (backends[i]->create(this))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create texture", status);
|
||||
goto fail;
|
||||
this->backend = backends[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// map the texture simply to get the pitch and stride
|
||||
D3D11_MAPPED_SUBRESOURCE mapping;
|
||||
status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource *)this->texture[0].tex, 0, D3D11_MAP_READ, 0, &mapping);
|
||||
if (FAILED(status))
|
||||
if (!this->backend)
|
||||
{
|
||||
DEBUG_WINERROR("Failed to map the texture", status);
|
||||
DEBUG_ERROR("Could not find a usable copy backend");
|
||||
goto fail;
|
||||
}
|
||||
this->pitch = mapping.RowPitch;
|
||||
this->stride = mapping.RowPitch / bpp;
|
||||
ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource *)this->texture[0].tex, 0);
|
||||
|
||||
DEBUG_INFO("Copy backend : %s", this->backend->name);
|
||||
DEBUG_INFO("AcquireLock : %s", this->useAcquireLock ? "enabled" : "disabled");
|
||||
|
||||
for (int i = 0; i < this->maxTextures; ++i)
|
||||
this->texture[i].texDamageCount = -1;
|
||||
|
||||
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
|
||||
this->frameDamage[i].count = -1;
|
||||
|
@ -612,21 +528,25 @@ static bool dxgi_deinit(void)
|
|||
{
|
||||
DEBUG_ASSERT(this);
|
||||
|
||||
for (int i = 0; i < this->maxTextures; ++i)
|
||||
{
|
||||
if (this->texture[i].map)
|
||||
{
|
||||
this->backend->unmapTexture(this->texture + i);
|
||||
this->texture[i].map = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->backend)
|
||||
{
|
||||
this->backend->free();
|
||||
this->backend = NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->maxTextures; ++i)
|
||||
{
|
||||
this->texture[i].state = TEXTURE_STATE_UNUSED;
|
||||
|
||||
if (this->texture[i].map.pData)
|
||||
{
|
||||
ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)this->texture[i].tex, 0);
|
||||
this->texture[i].map.pData = NULL;
|
||||
}
|
||||
|
||||
if (this->texture[i].tex)
|
||||
{
|
||||
ID3D11Texture2D_Release(this->texture[i].tex);
|
||||
this->texture[i].tex = NULL;
|
||||
}
|
||||
this->texture[i].impl = NULL;
|
||||
}
|
||||
|
||||
if (this->dup)
|
||||
|
@ -692,8 +612,6 @@ static void dxgi_free(void)
|
|||
dxgi_deinit();
|
||||
|
||||
free(this->texture);
|
||||
|
||||
runningavg_free(&this->avgMapTime);
|
||||
free(this);
|
||||
this = NULL;
|
||||
}
|
||||
|
@ -792,6 +710,20 @@ static void computeFrameDamage(Texture * tex)
|
|||
tex->damageRectsCount = dirtyRectsCount + actuallyMovedRectsCount;
|
||||
}
|
||||
|
||||
static void computeTexDamage(Texture * tex)
|
||||
{
|
||||
if (tex->texDamageCount < 0 || tex->damageRectsCount == 0 ||
|
||||
tex->texDamageCount + tex->damageRectsCount > KVMFR_MAX_DAMAGE_RECTS)
|
||||
tex->texDamageCount = -1;
|
||||
else
|
||||
{
|
||||
memcpy(tex->texDamageRects + tex->texDamageCount, tex->damageRects,
|
||||
tex->damageRectsCount * sizeof(FrameDamageRect));
|
||||
tex->texDamageCount += tex->damageRectsCount;
|
||||
tex->texDamageCount = rectsMergeOverlapping(tex->texDamageRects, tex->texDamageCount);
|
||||
}
|
||||
}
|
||||
|
||||
static CaptureResult dxgi_capture(void)
|
||||
{
|
||||
DEBUG_ASSERT(this);
|
||||
|
@ -881,57 +813,22 @@ static CaptureResult dxgi_capture(void)
|
|||
|
||||
if (copyFrame || copyPointer)
|
||||
{
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
|
||||
LOCKED(
|
||||
{
|
||||
if (copyFrame)
|
||||
{
|
||||
computeFrameDamage(tex);
|
||||
|
||||
if (tex->texDamageCount < 0 || tex->damageRectsCount == 0 ||
|
||||
tex->texDamageCount + tex->damageRectsCount > KVMFR_MAX_DAMAGE_RECTS)
|
||||
tex->texDamageCount = -1;
|
||||
else
|
||||
{
|
||||
memcpy(tex->texDamageRects + tex->texDamageCount, tex->damageRects,
|
||||
tex->damageRectsCount * sizeof(*tex->damageRects));
|
||||
tex->texDamageCount += tex->damageRectsCount;
|
||||
tex->texDamageCount = rectsMergeOverlapping(tex->texDamageRects, tex->texDamageCount);
|
||||
}
|
||||
|
||||
// issue the copy from GPU to CPU RAM
|
||||
tex->copyTime = microtime();
|
||||
if (tex->texDamageCount < 0)
|
||||
ID3D11DeviceContext_CopyResource(this->deviceContext,
|
||||
(ID3D11Resource *)tex->tex, (ID3D11Resource *)src);
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < tex->texDamageCount; ++i)
|
||||
{
|
||||
FrameDamageRect * rect = tex->texDamageRects + i;
|
||||
D3D11_BOX box = {
|
||||
.left = rect->x, .top = rect->y, .front = 0, .back = 1,
|
||||
.right = rect->x + rect->width, .bottom = rect->y + rect->height,
|
||||
};
|
||||
ID3D11DeviceContext_CopySubresourceRegion(this->deviceContext,
|
||||
(ID3D11Resource *)tex->tex, 0, rect->x, rect->y, 0,
|
||||
(ID3D11Resource *)src, 0, &box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (copyPointer)
|
||||
{
|
||||
// grab the pointer shape
|
||||
status = IDXGIOutputDuplication_GetFramePointerShape(
|
||||
this->dup, bufferSize, pointerShape, &pointerShapeSize, &shapeInfo);
|
||||
}
|
||||
|
||||
ID3D11DeviceContext_Flush(this->deviceContext);
|
||||
});
|
||||
|
||||
if (copyFrame)
|
||||
{
|
||||
if (this->useAcquireLock)
|
||||
{
|
||||
LOCKED({ computeFrameDamage(tex); });
|
||||
}
|
||||
else
|
||||
computeFrameDamage(tex);
|
||||
computeTexDamage(tex);
|
||||
|
||||
if (!this->backend->copyFrame(tex, src))
|
||||
{
|
||||
ID3D11Texture2D_Release(src);
|
||||
return CAPTURE_RESULT_ERROR;
|
||||
}
|
||||
|
||||
ID3D11Texture2D_Release(src);
|
||||
|
||||
for (int i = 0; i < this->maxTextures; ++i)
|
||||
|
@ -966,6 +863,18 @@ static CaptureResult dxgi_capture(void)
|
|||
|
||||
if (copyPointer)
|
||||
{
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
|
||||
if (this->useAcquireLock)
|
||||
{
|
||||
LOCKED({
|
||||
status = IDXGIOutputDuplication_GetFramePointerShape(
|
||||
this->dup, bufferSize, pointerShape, &pointerShapeSize, &shapeInfo);
|
||||
});
|
||||
}
|
||||
else
|
||||
status = IDXGIOutputDuplication_GetFramePointerShape(
|
||||
this->dup, bufferSize, pointerShape, &pointerShapeSize, &shapeInfo);
|
||||
|
||||
result = dxgi_hResultToCaptureResult(status);
|
||||
if (result != CAPTURE_RESULT_OK)
|
||||
{
|
||||
|
@ -1046,37 +955,9 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameS
|
|||
|
||||
Texture * tex = &this->texture[this->texRIndex];
|
||||
|
||||
// sleep until it's close to time to map
|
||||
const uint64_t delta = microtime() - tex->copyTime;
|
||||
if (delta < this->usleepMapTime)
|
||||
usleep(this->usleepMapTime - delta);
|
||||
|
||||
// try to map the resource, but don't wait for it
|
||||
for (int i = 0; ; ++i)
|
||||
{
|
||||
HRESULT status;
|
||||
LOCKED({status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource*)tex->tex, 0, D3D11_MAP_READ, 0x100000L, &tex->map);});
|
||||
if (status == DXGI_ERROR_WAS_STILL_DRAWING)
|
||||
{
|
||||
if (i == 100)
|
||||
return CAPTURE_RESULT_TIMEOUT;
|
||||
|
||||
usleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to map the texture", status);
|
||||
return CAPTURE_RESULT_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// update the sleep average and sleep for 80% of the average on the next call
|
||||
runningavg_push(this->avgMapTime, microtime() - tex->copyTime);
|
||||
this->usleepMapTime = (uint64_t)(runningavg_calc(this->avgMapTime) * 0.8);
|
||||
CaptureResult result = this->backend->mapTexture(tex);
|
||||
if (result != CAPTURE_RESULT_OK)
|
||||
return result;
|
||||
|
||||
tex->state = TEXTURE_STATE_MAPPED;
|
||||
|
||||
|
@ -1112,14 +993,14 @@ static CaptureResult dxgi_getFrame(FrameBuffer * frame,
|
|||
damage->count + tex->damageRectsCount > KVMFR_MAX_DAMAGE_RECTS;
|
||||
|
||||
if (damageAll)
|
||||
framebuffer_write(frame, tex->map.pData, this->pitch * height);
|
||||
framebuffer_write(frame, tex->map, this->pitch * height);
|
||||
else
|
||||
{
|
||||
memcpy(damage->rects + damage->count, tex->damageRects,
|
||||
tex->damageRectsCount * sizeof(*tex->damageRects));
|
||||
damage->count += tex->damageRectsCount;
|
||||
rectsBufferToFramebuffer(damage->rects, damage->count, frame, this->pitch,
|
||||
height, tex->map.pData, this->pitch);
|
||||
height, tex->map, this->pitch);
|
||||
}
|
||||
|
||||
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
|
||||
|
@ -1138,7 +1019,7 @@ static CaptureResult dxgi_getFrame(FrameBuffer * frame,
|
|||
damage->count = -1;
|
||||
}
|
||||
|
||||
LOCKED({ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)tex->tex, 0);});
|
||||
this->backend->unmapTexture(tex);
|
||||
tex->state = TEXTURE_STATE_UNUSED;
|
||||
|
||||
if (++this->texRIndex == this->maxTextures)
|
||||
|
|
118
host/platform/Windows/capture/DXGI/src/dxgi_capture.h
Normal file
118
host/platform/Windows/capture/DXGI/src/dxgi_capture.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2021 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcommon.h>
|
||||
|
||||
#include "common/KVMFR.h"
|
||||
#include "common/event.h"
|
||||
#include "common/locking.h"
|
||||
#include "common/types.h"
|
||||
#include "interface/capture.h"
|
||||
|
||||
enum TextureState
|
||||
{
|
||||
TEXTURE_STATE_UNUSED,
|
||||
TEXTURE_STATE_PENDING_MAP,
|
||||
TEXTURE_STATE_MAPPED
|
||||
};
|
||||
|
||||
typedef struct Texture
|
||||
{
|
||||
unsigned int formatVer;
|
||||
volatile enum TextureState state;
|
||||
void * map;
|
||||
uint64_t copyTime;
|
||||
uint32_t damageRectsCount;
|
||||
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
int32_t texDamageCount;
|
||||
FrameDamageRect texDamageRects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
|
||||
void * impl;
|
||||
}
|
||||
Texture;
|
||||
|
||||
struct FrameDamage
|
||||
{
|
||||
int count;
|
||||
FrameDamageRect rects[KVMFR_MAX_DAMAGE_RECTS];
|
||||
};
|
||||
|
||||
struct DXGICopyBackend;
|
||||
|
||||
struct DXGIInterface
|
||||
{
|
||||
bool initialized;
|
||||
LARGE_INTEGER perfFreq;
|
||||
LARGE_INTEGER frameTime;
|
||||
bool stop;
|
||||
HDESK desktop;
|
||||
IDXGIFactory1 * factory;
|
||||
IDXGIAdapter1 * adapter;
|
||||
IDXGIOutput * output;
|
||||
ID3D11Device * device;
|
||||
ID3D11DeviceContext * deviceContext;
|
||||
LG_Lock deviceContextLock;
|
||||
bool useAcquireLock;
|
||||
bool dwmFlush;
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
IDXGIOutputDuplication * dup;
|
||||
int maxTextures;
|
||||
Texture * texture;
|
||||
int texRIndex;
|
||||
int texWIndex;
|
||||
atomic_int texReady;
|
||||
bool needsRelease;
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
struct DXGICopyBackend * backend;
|
||||
|
||||
CaptureGetPointerBuffer getPointerBufferFn;
|
||||
CapturePostPointerBuffer postPointerBufferFn;
|
||||
LGEvent * frameEvent;
|
||||
|
||||
unsigned int formatVer;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int pitch;
|
||||
unsigned int stride;
|
||||
unsigned int bpp;
|
||||
CaptureFormat format;
|
||||
CaptureRotation rotation;
|
||||
|
||||
int lastPointerX, lastPointerY;
|
||||
bool lastPointerVisible;
|
||||
|
||||
struct FrameDamage frameDamage[LGMP_Q_FRAME_LEN];
|
||||
};
|
||||
|
||||
struct DXGICopyBackend
|
||||
{
|
||||
const char * name;
|
||||
bool (*create)(struct DXGIInterface * intf);
|
||||
void (*free)(void);
|
||||
bool (*copyFrame)(Texture * tex, ID3D11Texture2D * src);
|
||||
CaptureResult (*mapTexture)(Texture * tex);
|
||||
void (*unmapTexture)(Texture * tex);
|
||||
};
|
||||
|
||||
const char * GetDXGIFormatStr(DXGI_FORMAT format);
|
|
@ -18,9 +18,7 @@
|
|||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <dxgi.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcommon.h>
|
||||
#include "dxgi_capture.h"
|
||||
|
||||
static const char * DXGI_FORMAT_STR[] = {
|
||||
"DXGI_FORMAT_UNKNOWN",
|
||||
|
@ -147,9 +145,9 @@ static const char * DXGI_FORMAT_STR[] = {
|
|||
"DXGI_FORMAT_V408"
|
||||
};
|
||||
|
||||
static const char * GetDXGIFormatStr(DXGI_FORMAT format)
|
||||
const char * GetDXGIFormatStr(DXGI_FORMAT format)
|
||||
{
|
||||
if (format > sizeof(DXGI_FORMAT_STR) / sizeof(const char *))
|
||||
return DXGI_FORMAT_STR[0];
|
||||
return DXGI_FORMAT_STR[format];
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue