mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-21 21:17:19 +00:00
[host] dxgi: d3d12 now writes direclty into ivshmem
This is still incomplete as d3d12 doesn't have any proper sync with the captured frame and as such is still not suggested for general usage. This change though is monumental for this project as it removes a full memory copy reducing bandwidth consumption enormously.
This commit is contained in:
parent
adaf40e2bf
commit
34e8a2255e
@ -116,17 +116,18 @@ typedef struct CaptureInterface
|
|||||||
void (*initOptions )(void);
|
void (*initOptions )(void);
|
||||||
|
|
||||||
bool(*create)(
|
bool(*create)(
|
||||||
|
void * ivshmemBase,
|
||||||
CaptureGetPointerBuffer getPointerBufferFn,
|
CaptureGetPointerBuffer getPointerBufferFn,
|
||||||
CapturePostPointerBuffer postPointerBufferFn
|
CapturePostPointerBuffer postPointerBufferFn
|
||||||
);
|
);
|
||||||
|
|
||||||
bool (*init )(void);
|
bool (*init )(unsigned * alignSize);
|
||||||
bool (*start )(void);
|
bool (*start )(void);
|
||||||
void (*stop )(void);
|
void (*stop )(void);
|
||||||
bool (*deinit )(void);
|
bool (*deinit )(void);
|
||||||
void (*free )(void);
|
void (*free )(void);
|
||||||
|
|
||||||
CaptureResult (*capture )(void);
|
CaptureResult (*capture )(unsigned frameBufferIndex, FrameBuffer * frame);
|
||||||
CaptureResult (*waitFrame )(CaptureFrame * frame, const size_t maxFrameSize);
|
CaptureResult (*waitFrame )(CaptureFrame * frame, const size_t maxFrameSize);
|
||||||
CaptureResult (*getFrame )(FrameBuffer * frame, int frameIndex);
|
CaptureResult (*getFrame )(FrameBuffer * frame, int frameIndex);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ add_library(capture_DXGI STATIC
|
|||||||
src/pp/rgb24.c
|
src/pp/rgb24.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_definitions("-DCOBJMACROS -DINITGUID")
|
add_definitions("-DCOBJMACROS -DINITGUID -DWIDL_C_INLINE_WRAPPERS")
|
||||||
|
|
||||||
target_link_libraries(capture_DXGI
|
target_link_libraries(capture_DXGI
|
||||||
lg_common
|
lg_common
|
||||||
|
@ -36,7 +36,11 @@ struct DXGICopyBackend
|
|||||||
const char * code;
|
const char * code;
|
||||||
|
|
||||||
// create the copy backend
|
// create the copy backend
|
||||||
bool (*create)(unsigned textures);
|
bool (*create)(
|
||||||
|
void * ivshmemBase,
|
||||||
|
unsigned * alignSize,
|
||||||
|
unsigned frameBuffers,
|
||||||
|
unsigned textures);
|
||||||
|
|
||||||
// configure the copy backend with the specified format
|
// configure the copy backend with the specified format
|
||||||
bool (*configure)(
|
bool (*configure)(
|
||||||
@ -50,7 +54,10 @@ struct DXGICopyBackend
|
|||||||
void (*free)(void);
|
void (*free)(void);
|
||||||
|
|
||||||
// called just before the copy starts
|
// called just before the copy starts
|
||||||
bool (*preCopy)(ID3D11Texture2D * src, unsigned textureIndex);
|
bool (*preCopy)(ID3D11Texture2D * src,
|
||||||
|
unsigned textureIndex,
|
||||||
|
unsigned frameBufferIndex,
|
||||||
|
FrameBuffer * frameBuffer);
|
||||||
|
|
||||||
// called to copy the full frame
|
// called to copy the full frame
|
||||||
bool (*copyFull)(ID3D11Texture2D * src, unsigned textureIndex);
|
bool (*copyFull)(ID3D11Texture2D * src, unsigned textureIndex);
|
||||||
@ -65,6 +72,9 @@ struct DXGICopyBackend
|
|||||||
// maps the copied frame into memory
|
// maps the copied frame into memory
|
||||||
CaptureResult (*mapTexture)(unsigned textureIndex, void ** map);
|
CaptureResult (*mapTexture)(unsigned textureIndex, void ** map);
|
||||||
|
|
||||||
|
// [optional] backend specific write into the FrameBuffer
|
||||||
|
CaptureResult (*writeFrame)(int textureIndex, FrameBuffer * frame);
|
||||||
|
|
||||||
// unmaps the copied frame from memory
|
// unmaps the copied frame from memory
|
||||||
void (*unmapTexture)(unsigned textureIndex);
|
void (*unmapTexture)(unsigned textureIndex);
|
||||||
|
|
||||||
|
@ -43,7 +43,11 @@ struct D3D11Backend
|
|||||||
|
|
||||||
static struct D3D11Backend * this = NULL;
|
static struct D3D11Backend * this = NULL;
|
||||||
|
|
||||||
static bool d3d11_create(unsigned textures)
|
static bool d3d11_create(
|
||||||
|
void * ivshmemBase,
|
||||||
|
unsigned * alignSize,
|
||||||
|
unsigned frameBuffers,
|
||||||
|
unsigned textures)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(!this);
|
DEBUG_ASSERT(!this);
|
||||||
this = calloc(1,
|
this = calloc(1,
|
||||||
@ -128,7 +132,11 @@ static void d3d11_free(void)
|
|||||||
this = NULL;
|
this = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool d3d11_preCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
static bool d3d11_preCopy(
|
||||||
|
ID3D11Texture2D * src,
|
||||||
|
unsigned textureIndex,
|
||||||
|
unsigned frameBufferIndex,
|
||||||
|
FrameBuffer * frameBuffer)
|
||||||
{
|
{
|
||||||
dxgi_contextLock();
|
dxgi_contextLock();
|
||||||
this->texture[textureIndex].copyTime = microtime();
|
this->texture[textureIndex].copyTime = microtime();
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
|
|
||||||
struct D3D12Texture
|
struct D3D12Texture
|
||||||
{
|
{
|
||||||
ID3D12Resource ** tex;
|
|
||||||
ID3D12CommandAllocator ** commandAllocator;
|
ID3D12CommandAllocator ** commandAllocator;
|
||||||
ID3D12CommandList ** commandList;
|
ID3D12CommandList ** commandList;
|
||||||
ID3D12GraphicsCommandList ** graphicsCommandList;
|
ID3D12GraphicsCommandList ** graphicsCommandList;
|
||||||
@ -58,6 +57,11 @@ struct D3D12Backend
|
|||||||
|
|
||||||
float copySleep;
|
float copySleep;
|
||||||
ID3D12Device ** device;
|
ID3D12Device ** device;
|
||||||
|
ID3D12Device3 ** device3;
|
||||||
|
void * ivshmemBase;
|
||||||
|
ID3D12Heap ** heap;
|
||||||
|
ID3D12Resource *** frameBuffers;
|
||||||
|
ID3D12Resource ** dstResource;
|
||||||
ID3D12CommandQueue ** commandQueue;
|
ID3D12CommandQueue ** commandQueue;
|
||||||
UINT64 fenceValue;
|
UINT64 fenceValue;
|
||||||
ID3D12Fence ** fence;
|
ID3D12Fence ** fence;
|
||||||
@ -88,7 +92,11 @@ typedef HRESULT (*D3D12GetDebugInterface_t)(
|
|||||||
|
|
||||||
static void d3d12_free(void);
|
static void d3d12_free(void);
|
||||||
|
|
||||||
static bool d3d12_create(unsigned textures)
|
static bool d3d12_create(
|
||||||
|
void * ivshmemBase,
|
||||||
|
unsigned * alignSize,
|
||||||
|
unsigned frameBuffers,
|
||||||
|
unsigned textures)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(!this);
|
DEBUG_ASSERT(!this);
|
||||||
comRef_scopePush();
|
comRef_scopePush();
|
||||||
@ -109,6 +117,13 @@ static bool d3d12_create(unsigned textures)
|
|||||||
if (!this->d3d12)
|
if (!this->d3d12)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
this->frameBuffers = calloc(frameBuffers, sizeof(*this->frameBuffers));
|
||||||
|
if (!this->frameBuffers)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to allocate the ID3D12Resource frame buffer array");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (dxgi_debug())
|
if (dxgi_debug())
|
||||||
{
|
{
|
||||||
D3D12GetDebugInterface_t D3D12GetDebugInterface = (D3D12GetDebugInterface_t)
|
D3D12GetDebugInterface_t D3D12GetDebugInterface = (D3D12GetDebugInterface_t)
|
||||||
@ -145,6 +160,33 @@ static bool d3d12_create(unsigned textures)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
comRef_defineLocal(ID3D12Device3, device3);
|
||||||
|
status = ID3D12Device_QueryInterface(
|
||||||
|
*device, &IID_ID3D12Device3, (void **)device3);
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_WINERROR("Failed to obtain the ID3D12Device3 interface", status);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
comRef_defineLocal(ID3D12Heap, heap);
|
||||||
|
status = ID3D12Device3_OpenExistingHeapFromAddress(
|
||||||
|
*device3,
|
||||||
|
ivshmemBase,
|
||||||
|
&IID_ID3D12Heap,
|
||||||
|
(void **)heap);
|
||||||
|
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_WINERROR("Failed to open the framebuffer as a heap", status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_HEAP_DESC heapDesc = ID3D12Heap_GetDesc(*heap);
|
||||||
|
DEBUG_INFO("ID3D12Heap : Size:%I64u Alignment:%I64u",
|
||||||
|
heapDesc.SizeInBytes, heapDesc.Alignment);
|
||||||
|
*alignSize = heapDesc.Alignment;
|
||||||
|
|
||||||
D3D12_COMMAND_QUEUE_DESC queueDesc =
|
D3D12_COMMAND_QUEUE_DESC queueDesc =
|
||||||
{
|
{
|
||||||
.Type = D3D12_COMMAND_LIST_TYPE_COPY,
|
.Type = D3D12_COMMAND_LIST_TYPE_COPY,
|
||||||
@ -186,7 +228,11 @@ static bool d3d12_create(unsigned textures)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->ivshmemBase = ivshmemBase;
|
||||||
|
|
||||||
comRef_toGlobal(this->device , device );
|
comRef_toGlobal(this->device , device );
|
||||||
|
comRef_toGlobal(this->device3 , device3 );
|
||||||
|
comRef_toGlobal(this->heap , heap );
|
||||||
comRef_toGlobal(this->commandQueue, commandQueue);
|
comRef_toGlobal(this->commandQueue, commandQueue);
|
||||||
comRef_toGlobal(this->fence , fence );
|
comRef_toGlobal(this->fence , fence );
|
||||||
|
|
||||||
@ -213,48 +259,12 @@ static bool d3d12_configure(
|
|||||||
this->format = format;
|
this->format = format;
|
||||||
this->pitch = ALIGN_TO(width * bpp, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
this->pitch = ALIGN_TO(width * bpp, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||||
|
|
||||||
D3D12_HEAP_PROPERTIES readbackHeapProperties =
|
|
||||||
{
|
|
||||||
.Type = D3D12_HEAP_TYPE_READBACK,
|
|
||||||
};
|
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC texDesc =
|
|
||||||
{
|
|
||||||
.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
|
|
||||||
.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
|
||||||
.Width = this->pitch * height,
|
|
||||||
.Height = 1,
|
|
||||||
.DepthOrArraySize = 1,
|
|
||||||
.MipLevels = 1,
|
|
||||||
.Format = DXGI_FORMAT_UNKNOWN,
|
|
||||||
.SampleDesc.Count = 1,
|
|
||||||
.SampleDesc.Quality = 0,
|
|
||||||
.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
|
||||||
.Flags = D3D12_RESOURCE_FLAG_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
comRef_defineLocal(ID3D12Resource , texture );
|
|
||||||
comRef_defineLocal(ID3D12Fence , fence );
|
comRef_defineLocal(ID3D12Fence , fence );
|
||||||
comRef_defineLocal(ID3D12CommandAllocator , commandAllocator );
|
comRef_defineLocal(ID3D12CommandAllocator , commandAllocator );
|
||||||
comRef_defineLocal(ID3D12GraphicsCommandList, graphicsCommandList);
|
comRef_defineLocal(ID3D12GraphicsCommandList, graphicsCommandList);
|
||||||
comRef_defineLocal(ID3D12CommandList , commandList );
|
comRef_defineLocal(ID3D12CommandList , commandList );
|
||||||
for (int i = 0; i < this->textures; ++i)
|
for (int i = 0; i < this->textures; ++i)
|
||||||
{
|
{
|
||||||
status = ID3D12Device_CreateCommittedResource(*this->device,
|
|
||||||
&readbackHeapProperties,
|
|
||||||
D3D12_HEAP_FLAG_NONE,
|
|
||||||
&texDesc,
|
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
||||||
NULL,
|
|
||||||
&IID_ID3D12Resource,
|
|
||||||
(void **)texture);
|
|
||||||
|
|
||||||
if (FAILED(status))
|
|
||||||
{
|
|
||||||
DEBUG_WINERROR("Failed to create texture", status);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->texture[i].event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
this->texture[i].event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
if (!this->texture[i].event)
|
if (!this->texture[i].event)
|
||||||
{
|
{
|
||||||
@ -307,7 +317,6 @@ static bool d3d12_configure(
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
comRef_toGlobal(this->texture[i].tex , texture );
|
|
||||||
comRef_toGlobal(this->texture[i].fence , fence );
|
comRef_toGlobal(this->texture[i].fence , fence );
|
||||||
comRef_toGlobal(this->texture[i].commandAllocator , commandAllocator );
|
comRef_toGlobal(this->texture[i].commandAllocator , commandAllocator );
|
||||||
comRef_toGlobal(this->texture[i].graphicsCommandList, graphicsCommandList);
|
comRef_toGlobal(this->texture[i].graphicsCommandList, graphicsCommandList);
|
||||||
@ -320,6 +329,7 @@ static bool d3d12_configure(
|
|||||||
|
|
||||||
exit:
|
exit:
|
||||||
comRef_scopePop();
|
comRef_scopePop();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,13 +338,15 @@ static void d3d12_free(void)
|
|||||||
if (!this)
|
if (!this)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < this->textures; ++i)
|
for(int i = 0; i < this->textures; ++i)
|
||||||
if (this->texture[i].event)
|
if (this->texture[i].event)
|
||||||
CloseHandle(this->texture[i].event);
|
CloseHandle(this->texture[i].event);
|
||||||
|
|
||||||
if (this->event)
|
if (this->event)
|
||||||
CloseHandle(this->event);
|
CloseHandle(this->event);
|
||||||
|
|
||||||
|
free(this->frameBuffers);
|
||||||
|
|
||||||
if (this->d3d12)
|
if (this->d3d12)
|
||||||
FreeLibrary(this->d3d12);
|
FreeLibrary(this->d3d12);
|
||||||
|
|
||||||
@ -342,7 +354,11 @@ static void d3d12_free(void)
|
|||||||
this = NULL;
|
this = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool d3d12_preCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
static bool d3d12_preCopy(
|
||||||
|
ID3D11Texture2D * src,
|
||||||
|
unsigned textureIndex,
|
||||||
|
unsigned frameBufferIndex,
|
||||||
|
FrameBuffer * frameBuffer)
|
||||||
{
|
{
|
||||||
comRef_scopePush();
|
comRef_scopePush();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
@ -352,9 +368,6 @@ static bool d3d12_preCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
|||||||
ID3D11DeviceContext_Flush(dxgi_getContext());
|
ID3D11DeviceContext_Flush(dxgi_getContext());
|
||||||
dxgi_contextUnlock();
|
dxgi_contextUnlock();
|
||||||
|
|
||||||
if (this->copySleep > 0)
|
|
||||||
nsleep((uint64_t)(this->copySleep * 1000000));
|
|
||||||
|
|
||||||
this->d12src = NULL;
|
this->d12src = NULL;
|
||||||
if (this->sharedCacheCount > -1)
|
if (this->sharedCacheCount > -1)
|
||||||
{
|
{
|
||||||
@ -363,8 +376,7 @@ static bool d3d12_preCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
|||||||
if (this->sharedCache[i].tex == src)
|
if (this->sharedCache[i].tex == src)
|
||||||
{
|
{
|
||||||
this->d12src = *this->sharedCache[i].d12src;
|
this->d12src = *this->sharedCache[i].d12src;
|
||||||
result = true;
|
goto framebuffer;
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,8 +431,52 @@ static bool d3d12_preCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
|||||||
this->sharedCacheCount = -1;
|
this->sharedCacheCount = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
framebuffer:
|
||||||
|
if (this->frameBuffers[frameBufferIndex])
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
// prepare a IVSHMEM backed texture for the provided framebuffer
|
||||||
|
D3D12_RESOURCE_DESC desc =
|
||||||
|
{
|
||||||
|
.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
|
||||||
|
.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
|
||||||
|
.Width = this->height * this->pitch,
|
||||||
|
.Height = 1,
|
||||||
|
.DepthOrArraySize = 1,
|
||||||
|
.MipLevels = 1,
|
||||||
|
.Format = DXGI_FORMAT_UNKNOWN,
|
||||||
|
.SampleDesc.Count = 1,
|
||||||
|
.SampleDesc.Quality = 0,
|
||||||
|
.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
||||||
|
.Flags = D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER
|
||||||
|
};
|
||||||
|
|
||||||
|
comRef_defineLocal(ID3D12Resource, resource);
|
||||||
|
status = ID3D12Device3_CreatePlacedResource(
|
||||||
|
*this->device3,
|
||||||
|
*this->heap,
|
||||||
|
(uintptr_t)framebuffer_get_data(frameBuffer) - (uintptr_t)this->ivshmemBase,
|
||||||
|
&desc,
|
||||||
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||||
|
NULL,
|
||||||
|
&IID_ID3D12Resource,
|
||||||
|
(void**)resource);
|
||||||
|
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_WINERROR("Failed to create D3D12 resource from heap", status);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
comRef_toGlobal(this->frameBuffers[frameBufferIndex], resource);
|
||||||
|
|
||||||
|
done:
|
||||||
|
this->dstResource = this->frameBuffers[frameBufferIndex];
|
||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
|
if (this->copySleep > 0)
|
||||||
|
nsleep((uint64_t)(this->copySleep * 1000000));
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (!result)
|
if (!result)
|
||||||
comRef_scopePop();
|
comRef_scopePop();
|
||||||
@ -441,7 +497,7 @@ static bool d3d12_copyFull(ID3D11Texture2D * src, unsigned textureIndex)
|
|||||||
|
|
||||||
D3D12_TEXTURE_COPY_LOCATION destLoc =
|
D3D12_TEXTURE_COPY_LOCATION destLoc =
|
||||||
{
|
{
|
||||||
.pResource = *tex->tex,
|
.pResource = *this->dstResource,
|
||||||
.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
||||||
.PlacedFootprint =
|
.PlacedFootprint =
|
||||||
{
|
{
|
||||||
@ -463,7 +519,6 @@ static bool d3d12_copyFull(ID3D11Texture2D * src, unsigned textureIndex)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool d3d12_copyRect(ID3D11Texture2D * src, unsigned textureIndex,
|
static bool d3d12_copyRect(ID3D11Texture2D * src, unsigned textureIndex,
|
||||||
FrameDamageRect * rect)
|
FrameDamageRect * rect)
|
||||||
{
|
{
|
||||||
@ -478,7 +533,7 @@ static bool d3d12_copyRect(ID3D11Texture2D * src, unsigned textureIndex,
|
|||||||
|
|
||||||
D3D12_TEXTURE_COPY_LOCATION destLoc =
|
D3D12_TEXTURE_COPY_LOCATION destLoc =
|
||||||
{
|
{
|
||||||
.pResource = *tex->tex,
|
.pResource = *this->dstResource,
|
||||||
.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
|
||||||
.PlacedFootprint =
|
.PlacedFootprint =
|
||||||
{
|
{
|
||||||
@ -561,7 +616,8 @@ static bool d3d12_postCopy(ID3D11Texture2D * src, unsigned textureIndex)
|
|||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
comRef_scopePop(); //push is in pre-copy
|
//push is in preCopy
|
||||||
|
comRef_scopePop();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,32 +643,17 @@ static CaptureResult d3d12_mapTexture(unsigned textureIndex, void ** map)
|
|||||||
return CAPTURE_RESULT_ERROR;
|
return CAPTURE_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_RANGE range =
|
return CAPTURE_RESULT_OK;
|
||||||
{
|
}
|
||||||
.Begin = 0,
|
|
||||||
.End = this->pitch * this->height
|
|
||||||
};
|
|
||||||
status = ID3D12Resource_Map(*tex->tex, 0, &range, map);
|
|
||||||
|
|
||||||
if (FAILED(status))
|
|
||||||
{
|
|
||||||
DEBUG_WINERROR("Failed to map the texture", status);
|
|
||||||
return CAPTURE_RESULT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static CaptureResult d3d12_writeFrame(int textureIndex, FrameBuffer * frame)
|
||||||
|
{
|
||||||
|
framebuffer_set_write_ptr(frame, this->height * this->pitch);
|
||||||
return CAPTURE_RESULT_OK;
|
return CAPTURE_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void d3d12_unmapTexture(unsigned textureIndex)
|
static void d3d12_unmapTexture(unsigned textureIndex)
|
||||||
{
|
{
|
||||||
struct D3D12Texture * tex = &this->texture[textureIndex];
|
|
||||||
|
|
||||||
D3D12_RANGE range =
|
|
||||||
{
|
|
||||||
.Begin = 0,
|
|
||||||
.End = 0
|
|
||||||
};
|
|
||||||
ID3D12Resource_Unmap(*tex->tex, 0, &range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void d3d12_preRelease(void)
|
static void d3d12_preRelease(void)
|
||||||
@ -632,6 +673,7 @@ struct DXGICopyBackend copyBackendD3D12 =
|
|||||||
.copyRect = d3d12_copyRect,
|
.copyRect = d3d12_copyRect,
|
||||||
.postCopy = d3d12_postCopy,
|
.postCopy = d3d12_postCopy,
|
||||||
.mapTexture = d3d12_mapTexture,
|
.mapTexture = d3d12_mapTexture,
|
||||||
|
.writeFrame = d3d12_writeFrame,
|
||||||
.unmapTexture = d3d12_unmapTexture,
|
.unmapTexture = d3d12_unmapTexture,
|
||||||
.preRelease = d3d12_preRelease,
|
.preRelease = d3d12_preRelease,
|
||||||
};
|
};
|
||||||
|
@ -125,6 +125,7 @@ struct DXGIInterface
|
|||||||
D3D_FEATURE_LEVEL featureLevel;
|
D3D_FEATURE_LEVEL featureLevel;
|
||||||
IDXGIOutputDuplication ** dup;
|
IDXGIOutputDuplication ** dup;
|
||||||
int maxTextures;
|
int maxTextures;
|
||||||
|
void * ivshmemBase;
|
||||||
Texture * texture;
|
Texture * texture;
|
||||||
int texRIndex;
|
int texRIndex;
|
||||||
int texWIndex;
|
int texWIndex;
|
||||||
@ -275,7 +276,10 @@ static void dxgi_initOptions(void)
|
|||||||
ppEarlyInit();
|
ppEarlyInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool dxgi_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostPointerBuffer postPointerBufferFn)
|
static bool dxgi_create(
|
||||||
|
void * ivshmemBase,
|
||||||
|
CaptureGetPointerBuffer getPointerBufferFn,
|
||||||
|
CapturePostPointerBuffer postPointerBufferFn)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(!this);
|
DEBUG_ASSERT(!this);
|
||||||
this = calloc(1, sizeof(*this));
|
this = calloc(1, sizeof(*this));
|
||||||
@ -302,6 +306,7 @@ static bool dxgi_create(CaptureGetPointerBuffer getPointerBufferFn, CapturePostP
|
|||||||
this->allowRGB24 = option_get_bool("dxgi", "allowRGB24");
|
this->allowRGB24 = option_get_bool("dxgi", "allowRGB24");
|
||||||
this->dwmFlush = option_get_bool("dxgi", "dwmFlush");
|
this->dwmFlush = option_get_bool("dxgi", "dwmFlush");
|
||||||
this->disableDamage = option_get_bool("dxgi", "disableDamage");
|
this->disableDamage = option_get_bool("dxgi", "disableDamage");
|
||||||
|
this->ivshmemBase = ivshmemBase;
|
||||||
this->texture = calloc(this->maxTextures, sizeof(*this->texture));
|
this->texture = calloc(this->maxTextures, sizeof(*this->texture));
|
||||||
this->getPointerBufferFn = getPointerBufferFn;
|
this->getPointerBufferFn = getPointerBufferFn;
|
||||||
this->postPointerBufferFn = postPointerBufferFn;
|
this->postPointerBufferFn = postPointerBufferFn;
|
||||||
@ -360,7 +365,7 @@ static bool initVertexShader(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool dxgi_init(void)
|
static bool dxgi_init(unsigned * alignSize)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(this);
|
DEBUG_ASSERT(this);
|
||||||
|
|
||||||
@ -800,7 +805,11 @@ static bool dxgi_init(void)
|
|||||||
{
|
{
|
||||||
if (!strcasecmp(copyBackend, backends[i]->code))
|
if (!strcasecmp(copyBackend, backends[i]->code))
|
||||||
{
|
{
|
||||||
if (!backends[i]->create(this->maxTextures))
|
if (!backends[i]->create(
|
||||||
|
this->ivshmemBase,
|
||||||
|
alignSize,
|
||||||
|
LGMP_Q_FRAME_LEN,
|
||||||
|
this->maxTextures))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize selected capture backend: %s", backends[i]->name);
|
DEBUG_ERROR("Failed to initialize selected capture backend: %s", backends[i]->name);
|
||||||
backends[i]->free();
|
backends[i]->free();
|
||||||
@ -1052,7 +1061,8 @@ static void computeTexDamage(Texture * tex)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CaptureResult dxgi_capture(void)
|
static CaptureResult dxgi_capture(unsigned frameBufferIndex,
|
||||||
|
FrameBuffer * frameBuffer)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(this);
|
DEBUG_ASSERT(this);
|
||||||
DEBUG_ASSERT(this->initialized);
|
DEBUG_ASSERT(this->initialized);
|
||||||
@ -1101,6 +1111,7 @@ static CaptureResult dxgi_capture(void)
|
|||||||
{
|
{
|
||||||
if (result == CAPTURE_RESULT_ERROR)
|
if (result == CAPTURE_RESULT_ERROR)
|
||||||
DEBUG_WINERROR("AcquireNextFrame failed", status);
|
DEBUG_WINERROR("AcquireNextFrame failed", status);
|
||||||
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1230,7 +1241,8 @@ static CaptureResult dxgi_capture(void)
|
|||||||
computeFrameDamage(tex);
|
computeFrameDamage(tex);
|
||||||
computeTexDamage(tex);
|
computeTexDamage(tex);
|
||||||
|
|
||||||
if (!this->backend->preCopy(dst, this->texWIndex))
|
if (!this->backend->preCopy(dst, this->texWIndex,
|
||||||
|
frameBufferIndex, frameBuffer))
|
||||||
{
|
{
|
||||||
result = CAPTURE_RESULT_ERROR;
|
result = CAPTURE_RESULT_ERROR;
|
||||||
goto exit;
|
goto exit;
|
||||||
@ -1440,39 +1452,48 @@ static CaptureResult dxgi_getFrame(FrameBuffer * frame, int frameIndex)
|
|||||||
Texture * tex = &this->texture[this->texRIndex];
|
Texture * tex = &this->texture[this->texRIndex];
|
||||||
FrameDamage * damage = &this->frameDamage[frameIndex];
|
FrameDamage * damage = &this->frameDamage[frameIndex];
|
||||||
|
|
||||||
if (tex->damageRectsCount == 0 ||
|
if (this->backend->writeFrame)
|
||||||
damage->count < 0 ||
|
|
||||||
damage->count + tex->damageRectsCount > KVMFR_MAX_DAMAGE_RECTS)
|
|
||||||
{
|
{
|
||||||
// damage all
|
CaptureResult result = this->backend->writeFrame(frameIndex, frame);
|
||||||
framebuffer_write(frame, tex->map, this->pitch * this->dataHeight);
|
if (result != CAPTURE_RESULT_OK)
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(damage->rects + damage->count, tex->damageRects,
|
if (tex->damageRectsCount == 0 ||
|
||||||
tex->damageRectsCount * sizeof(*tex->damageRects));
|
damage->count < 0 ||
|
||||||
damage->count += tex->damageRectsCount;
|
damage->count + tex->damageRectsCount > KVMFR_MAX_DAMAGE_RECTS)
|
||||||
|
|
||||||
if (this->outputFormat == CAPTURE_FMT_BGR_32)
|
|
||||||
{
|
{
|
||||||
FrameDamageRect scaledDamageRects[damage->count];
|
// damage all
|
||||||
for (int i = 0; i < ARRAYSIZE(scaledDamageRects); i++) {
|
framebuffer_write(frame, tex->map, this->pitch * this->dataHeight);
|
||||||
FrameDamageRect rect = damage->rects[i];
|
|
||||||
int originalX = rect.x;
|
|
||||||
int scaledX = originalX * 3 / 4;
|
|
||||||
rect.x = scaledX;
|
|
||||||
rect.width = (((originalX + rect.width) * 3 + 3) / 4) - scaledX;
|
|
||||||
|
|
||||||
scaledDamageRects[i] = rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
rectsBufferToFramebuffer(scaledDamageRects, damage->count, this->bpp, frame,
|
|
||||||
this->pitch, this->dataHeight, tex->map, this->pitch);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rectsBufferToFramebuffer(damage->rects, damage->count, this->bpp, frame,
|
memcpy(damage->rects + damage->count, tex->damageRects,
|
||||||
this->pitch, this->dataHeight, tex->map, this->pitch);
|
tex->damageRectsCount * sizeof(*tex->damageRects));
|
||||||
|
damage->count += tex->damageRectsCount;
|
||||||
|
|
||||||
|
if (this->outputFormat == CAPTURE_FMT_BGR_32)
|
||||||
|
{
|
||||||
|
FrameDamageRect scaledDamageRects[damage->count];
|
||||||
|
for (int i = 0; i < ARRAYSIZE(scaledDamageRects); i++) {
|
||||||
|
FrameDamageRect rect = damage->rects[i];
|
||||||
|
int originalX = rect.x;
|
||||||
|
int scaledX = originalX * 3 / 4;
|
||||||
|
rect.x = scaledX;
|
||||||
|
rect.width = (((originalX + rect.width) * 3 + 3) / 4) - scaledX;
|
||||||
|
|
||||||
|
scaledDamageRects[i] = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
rectsBufferToFramebuffer(scaledDamageRects, damage->count, this->bpp, frame,
|
||||||
|
this->pitch, this->dataHeight, tex->map, this->pitch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rectsBufferToFramebuffer(damage->rects, damage->count, this->bpp, frame,
|
||||||
|
this->pitch, this->dataHeight, tex->map, this->pitch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,8 +185,9 @@ static void nvfbc_initOptions(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool nvfbc_create(
|
static bool nvfbc_create(
|
||||||
CaptureGetPointerBuffer getPointerBufferFn,
|
void * ivshmemBase,
|
||||||
CapturePostPointerBuffer postPointerBufferFn)
|
CaptureGetPointerBuffer getPointerBufferFn,
|
||||||
|
CapturePostPointerBuffer postPointerBufferFn)
|
||||||
{
|
{
|
||||||
if (!NvFBCInit())
|
if (!NvFBCInit())
|
||||||
return false;
|
return false;
|
||||||
@ -220,7 +221,7 @@ static void updateScale(void)
|
|||||||
this->targetHeight = this->height;
|
this->targetHeight = this->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nvfbc_init(void)
|
static bool nvfbc_init(unsigned * alignSize)
|
||||||
{
|
{
|
||||||
int adapterIndex = option_get_int("nvfbc", "adapterIndex");
|
int adapterIndex = option_get_int("nvfbc", "adapterIndex");
|
||||||
|
|
||||||
@ -447,7 +448,8 @@ static void nvfbc_free(void)
|
|||||||
NvFBCFree();
|
NvFBCFree();
|
||||||
}
|
}
|
||||||
|
|
||||||
static CaptureResult nvfbc_capture(void)
|
static CaptureResult nvfbc_capture(unsigned frameBufferIndex,
|
||||||
|
FrameBuffer * frameBuffer)
|
||||||
{
|
{
|
||||||
// this is a bit of a hack as it causes this thread to block until the next
|
// this is a bit of a hack as it causes this thread to block until the next
|
||||||
// present keeping us locked with the refresh rate of the monitor being
|
// present keeping us locked with the refresh rate of the monitor being
|
||||||
|
@ -89,10 +89,13 @@ struct app
|
|||||||
unsigned int pointerIndex;
|
unsigned int pointerIndex;
|
||||||
unsigned int pointerShapeIndex;
|
unsigned int pointerShapeIndex;
|
||||||
|
|
||||||
long pageSize;
|
unsigned alignSize;
|
||||||
size_t maxFrameSize;
|
size_t maxFrameSize;
|
||||||
PLGMPHostQueue frameQueue;
|
PLGMPHostQueue frameQueue;
|
||||||
PLGMPMemory frameMemory[LGMP_Q_FRAME_LEN];
|
PLGMPMemory frameMemory[LGMP_Q_FRAME_LEN];
|
||||||
|
KVMFRFrame * frame [LGMP_Q_FRAME_LEN];
|
||||||
|
FrameBuffer * frameBuffer[LGMP_Q_FRAME_LEN];
|
||||||
|
|
||||||
unsigned int frameIndex;
|
unsigned int frameIndex;
|
||||||
bool frameValid;
|
bool frameValid;
|
||||||
uint32_t frameSerial;
|
uint32_t frameSerial;
|
||||||
@ -243,7 +246,7 @@ static bool sendFrame(void)
|
|||||||
if (++app.frameIndex == LGMP_Q_FRAME_LEN)
|
if (++app.frameIndex == LGMP_Q_FRAME_LEN)
|
||||||
app.frameIndex = 0;
|
app.frameIndex = 0;
|
||||||
|
|
||||||
KVMFRFrame * fi = lgmpHostMemPtr(app.frameMemory[app.frameIndex]);
|
KVMFRFrame * fi = app.frame[app.frameIndex];
|
||||||
KVMFRFrameFlags flags =
|
KVMFRFrameFlags flags =
|
||||||
(frame.hdr ? FRAME_FLAG_HDR : 0) |
|
(frame.hdr ? FRAME_FLAG_HDR : 0) |
|
||||||
(frame.hdrPQ ? FRAME_FLAG_HDR_PQ : 0);
|
(frame.hdrPQ ? FRAME_FLAG_HDR_PQ : 0);
|
||||||
@ -311,7 +314,7 @@ static bool sendFrame(void)
|
|||||||
fi->frameHeight = frame.frameHeight;
|
fi->frameHeight = frame.frameHeight;
|
||||||
fi->stride = frame.stride;
|
fi->stride = frame.stride;
|
||||||
fi->pitch = frame.pitch;
|
fi->pitch = frame.pitch;
|
||||||
fi->offset = app.pageSize - sizeof(FrameBuffer);
|
// fi->offset is initialized at startup
|
||||||
fi->flags = flags;
|
fi->flags = flags;
|
||||||
fi->damageRectsCount = frame.damageRectsCount;
|
fi->damageRectsCount = frame.damageRectsCount;
|
||||||
memcpy(fi->damageRects, frame.damageRects,
|
memcpy(fi->damageRects, frame.damageRects,
|
||||||
@ -319,10 +322,7 @@ static bool sendFrame(void)
|
|||||||
|
|
||||||
app.frameValid = true;
|
app.frameValid = true;
|
||||||
|
|
||||||
// put the framebuffer on the border of the next page
|
framebuffer_prepare(app.frameBuffer[app.frameIndex]);
|
||||||
// this is to allow for aligned DMA transfers by the receiver
|
|
||||||
FrameBuffer * fb = (FrameBuffer *)(((uint8_t*)fi) + fi->offset);
|
|
||||||
framebuffer_prepare(fb);
|
|
||||||
|
|
||||||
/* we post and then get the frame, this is intentional! */
|
/* we post and then get the frame, this is intentional! */
|
||||||
if ((status = lgmpHostQueuePost(app.frameQueue, 0,
|
if ((status = lgmpHostQueuePost(app.frameQueue, 0,
|
||||||
@ -332,7 +332,7 @@ static bool sendFrame(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.iface->getFrame(fb, app.frameIndex);
|
app.iface->getFrame(app.frameBuffer[app.frameIndex], app.frameIndex);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,13 +392,13 @@ static bool captureStart(void)
|
|||||||
{
|
{
|
||||||
if (app.state == APP_STATE_IDLE)
|
if (app.state == APP_STATE_IDLE)
|
||||||
{
|
{
|
||||||
if (!app.iface->init())
|
if (!app.iface->init(&app.alignSize))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to initialize the capture device");
|
DEBUG_ERROR("Failed to initialize the capture device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app.iface->start && !app.iface->start())
|
if (app.iface->start && app.iface->start())
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to start the capture device");
|
DEBUG_ERROR("Failed to start the capture device");
|
||||||
return false;
|
return false;
|
||||||
@ -720,18 +720,26 @@ static bool lgmpSetup(struct IVSHMEM * shmDev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.maxFrameSize = lgmpHostMemAvail(app.lgmp);
|
app.maxFrameSize = lgmpHostMemAvail(app.lgmp);
|
||||||
app.maxFrameSize = (app.maxFrameSize - (app.pageSize - 1)) & ~(app.pageSize - 1);
|
app.maxFrameSize = (app.maxFrameSize - (app.alignSize - 1)) & ~(app.alignSize - 1);
|
||||||
app.maxFrameSize /= LGMP_Q_FRAME_LEN;
|
app.maxFrameSize /= LGMP_Q_FRAME_LEN;
|
||||||
DEBUG_INFO("Max Frame Size : %u MiB", (unsigned int)(app.maxFrameSize / 1048576LL));
|
DEBUG_INFO("Max Frame Size : %u MiB", (unsigned int)(app.maxFrameSize / 1048576LL));
|
||||||
|
|
||||||
for(int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
|
for(int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
|
||||||
{
|
{
|
||||||
if ((status = lgmpHostMemAllocAligned(app.lgmp, app.maxFrameSize,
|
if ((status = lgmpHostMemAllocAligned(app.lgmp, app.maxFrameSize,
|
||||||
app.pageSize, &app.frameMemory[i])) != LGMP_OK)
|
app.alignSize, &app.frameMemory[i])) != LGMP_OK)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("lgmpHostMemAlloc Failed (Frame): %s", lgmpStatusString(status));
|
DEBUG_ERROR("lgmpHostMemAlloc Failed (Frame): %s", lgmpStatusString(status));
|
||||||
goto fail_lgmp;
|
goto fail_lgmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.frame[i] = lgmpHostMemPtr(app.frameMemory[i]);
|
||||||
|
|
||||||
|
/* put the framebuffer on the border of the next page, this is to allow for
|
||||||
|
aligned DMA transfers by the receiver */
|
||||||
|
const unsigned alignOffset = app.alignSize - sizeof(FrameBuffer);
|
||||||
|
app.frame[i]->offset = alignOffset;
|
||||||
|
app.frameBuffer[i] = (FrameBuffer *)(((uint8_t*)app.frame[i]) + alignOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lgCreateTimer(10, lgmpTimer, NULL, &app.lgmpTimer))
|
if (!lgCreateTimer(10, lgmpTimer, NULL, &app.lgmpTimer))
|
||||||
@ -828,7 +836,7 @@ int app_main(int argc, char * argv[])
|
|||||||
DEBUG_INFO("Max Pointer Size : %u KiB", (unsigned int)MAX_POINTER_SIZE / 1024);
|
DEBUG_INFO("Max Pointer Size : %u KiB", (unsigned int)MAX_POINTER_SIZE / 1024);
|
||||||
DEBUG_INFO("KVMFR Version : %u", KVMFR_VERSION);
|
DEBUG_INFO("KVMFR Version : %u", KVMFR_VERSION);
|
||||||
|
|
||||||
app.pageSize = sysinfo_getPageSize();
|
app.alignSize = sysinfo_getPageSize();
|
||||||
app.frameValid = false;
|
app.frameValid = false;
|
||||||
app.pointerShapeValid = false;
|
app.pointerShapeValid = false;
|
||||||
|
|
||||||
@ -847,13 +855,16 @@ int app_main(int argc, char * argv[])
|
|||||||
|
|
||||||
DEBUG_INFO("Trying : %s", iface->getName());
|
DEBUG_INFO("Trying : %s", iface->getName());
|
||||||
|
|
||||||
if (!iface->create(captureGetPointerBuffer, capturePostPointerBuffer))
|
if (!iface->create(
|
||||||
|
shmDev.mem,
|
||||||
|
captureGetPointerBuffer,
|
||||||
|
capturePostPointerBuffer))
|
||||||
{
|
{
|
||||||
iface = NULL;
|
iface = NULL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iface->init())
|
if (iface->init(&app.alignSize))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
iface->free();
|
iface->free();
|
||||||
@ -953,7 +964,14 @@ int app_main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t captureStart = microtime();
|
const uint64_t captureStart = microtime();
|
||||||
const CaptureResult result = app.iface->capture();
|
|
||||||
|
unsigned nextIndex = app.frameIndex + 1;
|
||||||
|
if (nextIndex == LGMP_Q_FRAME_LEN)
|
||||||
|
nextIndex = 0;
|
||||||
|
|
||||||
|
const CaptureResult result = app.iface->capture(
|
||||||
|
nextIndex, app.frameBuffer[nextIndex]);
|
||||||
|
|
||||||
if (likely(result == CAPTURE_RESULT_OK))
|
if (likely(result == CAPTURE_RESULT_OK))
|
||||||
previousFrameTime = captureStart;
|
previousFrameTime = captureStart;
|
||||||
else if (likely(result == CAPTURE_RESULT_TIMEOUT))
|
else if (likely(result == CAPTURE_RESULT_TIMEOUT))
|
||||||
|
17505
vendor/directx/d3d12.h
vendored
17505
vendor/directx/d3d12.h
vendored
File diff suppressed because it is too large
Load Diff
8925
vendor/directx/d3d12sdklayers.h
vendored
8925
vendor/directx/d3d12sdklayers.h
vendored
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user