diff --git a/host/platform/Windows/capture/DXGI/src/backend.h b/host/platform/Windows/capture/DXGI/src/backend.h index 999ffefe..9cab26c6 100644 --- a/host/platform/Windows/capture/DXGI/src/backend.h +++ b/host/platform/Windows/capture/DXGI/src/backend.h @@ -35,23 +35,37 @@ struct DXGICopyBackend const char * code; // create the copy backend - bool (*create)(struct DXGIInterface * intf); + bool (*create)(unsigned textures); // configure the copy backend with the specified format - bool (*configure)(unsigned width, unsigned height, - DXGI_FORMAT format, unsigned * pitch); + bool (*configure)( + unsigned width, + unsigned height, + DXGI_FORMAT format, + unsigned bpp, + unsigned * pitch); // free the copy backend void (*free)(void); - // called each captured frame after post processing to copy the frame - bool (*copyFrame)(struct Texture * tex, ID3D11Texture2D * src); + // called just before the copy starts + bool (*preCopy)(ID3D11Texture2D * src, unsigned textureIndex); + + // called to copy the full frame + bool (*copyFull)(ID3D11Texture2D * src, unsigned textureIndex); + + // called for each damage rect that needs to be copied + bool (*copyRect)(ID3D11Texture2D * src, unsigned textureIndex, + FrameDamageRect * rect); + + // called just after the copy has finished + bool (*postCopy)(ID3D11Texture2D * src, unsigned textureIndex); // maps the copied frame into memory - CaptureResult (*mapTexture)(struct Texture * tex); + CaptureResult (*mapTexture)(unsigned textureIndex, void ** map); // unmaps the copied frame from memory - void (*unmapTexture)(struct Texture * tex); + void (*unmapTexture)(unsigned textureIndex); // called just before the frame is released by the frontend void (*preRelease)(void); diff --git a/host/platform/Windows/capture/DXGI/src/d3d11.c b/host/platform/Windows/capture/DXGI/src/d3d11.c index 45200e71..602a9c8f 100644 --- a/host/platform/Windows/capture/DXGI/src/d3d11.c +++ b/host/platform/Windows/capture/DXGI/src/d3d11.c @@ -31,26 +31,29 @@ struct D3D11Backend { RunningAvg avgMapTime; uint64_t usleepMapTime; -}; -struct D3D11TexImpl -{ - ID3D11Texture2D ** cpu; + unsigned textures; + struct + { + uint64_t copyTime; + ID3D11Texture2D ** cpu; + } + texture[0]; }; #define TEXIMPL(x) ((struct D3D11TexImpl *)(x).impl) -static struct DXGIInterface * dxgi = NULL; static struct D3D11Backend * this = NULL; static void d3d11_free(void); -static bool d3d11_create(struct DXGIInterface * intf) +static bool d3d11_create(unsigned textures) { - dxgi = intf; - DEBUG_ASSERT(!this); - this = calloc(1, sizeof(struct D3D11Backend)); + this = calloc(1, + sizeof(struct D3D11Backend) + + sizeof(*this->texture) + textures); + if (!this) { DEBUG_ERROR("failed to allocate D3D11Backend struct"); @@ -58,11 +61,16 @@ static bool d3d11_create(struct DXGIInterface * intf) } this->avgMapTime = runningavg_new(10); + this->textures = textures; return true; } -static bool d3d11_configure(unsigned width, unsigned height, DXGI_FORMAT format, - unsigned * pitch) +static bool d3d11_configure( + unsigned width, + unsigned height, + DXGI_FORMAT format, + unsigned bpp, + unsigned * pitch) { HRESULT status; @@ -81,32 +89,22 @@ static bool d3d11_configure(unsigned width, unsigned height, DXGI_FORMAT format, .MiscFlags = 0 }; - for (int i = 0; i < dxgi->maxTextures; ++i) + comRef_defineLocal(ID3D11Texture2D, cpu); + for(int i = 0; i < this->textures; ++i) { - if (!(dxgi->texture[i].impl = - (struct D3D11TexImpl *)calloc(sizeof(struct D3D11TexImpl), 1))) - { - DEBUG_ERROR("Failed to allocate D3D11TexImpl struct"); - goto fail; - } - - struct D3D11TexImpl * teximpl = TEXIMPL(dxgi->texture[i]); - - status = ID3D11Device_CreateTexture2D(*dxgi->device, &cpuTexDesc, NULL, - (ID3D11Texture2D **)comRef_newGlobal(&teximpl->cpu)); - + status = ID3D11Device_CreateTexture2D(dxgi_getDevice(), &cpuTexDesc, NULL, cpu); if (FAILED(status)) { DEBUG_WINERROR("Failed to create CPU texture", status); goto fail; } + comRef_toGlobal(this->texture[i].cpu, cpu); } // map the texture simply to get the pitch and stride D3D11_MAPPED_SUBRESOURCE mapping; - status = ID3D11DeviceContext_Map(*dxgi->deviceContext, - *(ID3D11Resource **)TEXIMPL(dxgi->texture[0])->cpu, 0, - D3D11_MAP_READ, 0, &mapping); + status = ID3D11DeviceContext_Map(dxgi_getContext(), + *(ID3D11Resource **)this->texture[0].cpu, 0, D3D11_MAP_READ, 0, &mapping); if (FAILED(status)) { @@ -114,8 +112,8 @@ static bool d3d11_configure(unsigned width, unsigned height, DXGI_FORMAT format, goto fail; } - ID3D11DeviceContext_Unmap(*dxgi->deviceContext, - *(ID3D11Resource **)TEXIMPL(dxgi->texture[0])->cpu, 0); + ID3D11DeviceContext_Unmap(dxgi_getContext(), + *(ID3D11Resource **)this->texture[0].cpu, 0); *pitch = mapping.RowPitch; return true; @@ -129,81 +127,79 @@ static void d3d11_free(void) if (!this) return; - for (int i = 0; i < dxgi->maxTextures; ++i) - { - struct D3D11TexImpl * teximpl = TEXIMPL(dxgi->texture[i]); - free(teximpl); - teximpl = NULL; - } - runningavg_free(&this->avgMapTime); free(this); this = NULL; } -static bool d3d11_copyFrame(Texture * tex, ID3D11Texture2D * src) +static bool d3d11_preCopy(ID3D11Texture2D * src, unsigned textureIndex) { - struct D3D11TexImpl * teximpl = TEXIMPL(*tex); - ID3D11Texture2D * dst = *teximpl->cpu; - - INTERLOCKED_SECTION(dxgi->deviceContextLock, - { - tex->copyTime = microtime(); - - if (tex->texDamageCount < 0) - ID3D11DeviceContext_CopyResource(*dxgi->deviceContext, - (ID3D11Resource *)dst, (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, - }; - - if (dxgi->outputFormat == CAPTURE_FMT_BGR) - { - box.left = box.left * 3 / 4; - box.right = box.right * 3 / 4; - } - - ID3D11DeviceContext_CopySubresourceRegion(*dxgi->deviceContext, - (ID3D11Resource *)dst, 0, box.left, box.top, 0, - (ID3D11Resource *)src, 0, &box); - } - } - - ID3D11DeviceContext_Flush(*dxgi->deviceContext); - }); + dxgi_contextLock(); + this->texture[textureIndex].copyTime = microtime(); return true; } -static CaptureResult d3d11_mapTexture(Texture * tex) +static bool d3d11_copyFull(ID3D11Texture2D * src, unsigned textureIndex) { - struct D3D11TexImpl * teximpl = TEXIMPL(*tex); - D3D11_MAPPED_SUBRESOURCE map; + ID3D11Texture2D * dst = *this->texture[textureIndex].cpu; + + ID3D11DeviceContext_CopyResource(dxgi_getContext(), + (ID3D11Resource *)dst, (ID3D11Resource *)src); + + return true; +} + + +static bool d3d11_copyRect(ID3D11Texture2D * src, unsigned textureIndex, + FrameDamageRect * rect) +{ + ID3D11Texture2D * dst = *this->texture[textureIndex].cpu; + + 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_getContext(), + (ID3D11Resource *)dst, 0, box.left, box.top, 0, + (ID3D11Resource *)src, 0, &box); + + return true; +} + +static bool d3d11_postCopy(ID3D11Texture2D * src, unsigned textureIndex) +{ + ID3D11DeviceContext_Flush(dxgi_getContext()); + dxgi_contextUnlock(); + return true; +} + +static CaptureResult d3d11_mapTexture(unsigned textureIndex, void ** map) +{ + ID3D11Resource * cpu = *(ID3D11Resource **)this->texture[textureIndex].cpu; // sleep until it's close to time to map - const uint64_t delta = microtime() - tex->copyTime; + const uint64_t delta = microtime() - this->texture[textureIndex].copyTime; if (delta < this->usleepMapTime) usleep(this->usleepMapTime - delta); + D3D11_MAPPED_SUBRESOURCE mappedRes; + // 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 *)*teximpl->cpu, 0, D3D11_MAP_READ, 0x100000L, &map); - }); + dxgi_contextLock(); + status = ID3D11DeviceContext_Map(dxgi_getContext(), cpu, 0, D3D11_MAP_READ, + 0x100000L, &mappedRes); + dxgi_contextUnlock(); if (status == DXGI_ERROR_WAS_STILL_DRAWING) { if (i == 100) @@ -222,23 +218,23 @@ static CaptureResult d3d11_mapTexture(Texture * tex) break; } - tex->map = map.pData; + *map = mappedRes.pData; // update the sleep average and sleep for 80% of the average on the next call - runningavg_push(this->avgMapTime, microtime() - tex->copyTime); + runningavg_push(this->avgMapTime, + microtime() - this->texture[textureIndex].copyTime); + this->usleepMapTime = (uint64_t)(runningavg_calc(this->avgMapTime) * 0.8); return CAPTURE_RESULT_OK; } -static void d3d11_unmapTexture(Texture * tex) +static void d3d11_unmapTexture(unsigned textureIndex) { - struct D3D11TexImpl * teximpl = TEXIMPL(*tex); + ID3D11Resource * cpu = *(ID3D11Resource **)this->texture[textureIndex].cpu; - INTERLOCKED_SECTION(dxgi->deviceContextLock, { - ID3D11DeviceContext_Unmap(*dxgi->deviceContext, - (ID3D11Resource *)*teximpl->cpu, 0); - }); - tex->map = NULL; + dxgi_contextLock(); + ID3D11DeviceContext_Unmap(dxgi_getContext(), cpu, 0); + dxgi_contextUnlock(); } static void d3d11_preRelease(void) @@ -252,7 +248,10 @@ struct DXGICopyBackend copyBackendD3D11 = { .create = d3d11_create, .configure = d3d11_configure, .free = d3d11_free, - .copyFrame = d3d11_copyFrame, + .preCopy = d3d11_preCopy, + .copyFull = d3d11_copyFull, + .copyRect = d3d11_copyRect, + .postCopy = d3d11_postCopy, .mapTexture = d3d11_mapTexture, .unmapTexture = d3d11_unmapTexture, .preRelease = d3d11_preRelease, diff --git a/host/platform/Windows/capture/DXGI/src/d3d12.c b/host/platform/Windows/capture/DXGI/src/d3d12.c index d485f712..152ff4ea 100644 --- a/host/platform/Windows/capture/DXGI/src/d3d12.c +++ b/host/platform/Windows/capture/DXGI/src/d3d12.c @@ -1,5 +1,4 @@ /** - * Looking Glass * Copyright © 2017-2023 The Looking Glass Authors * https://looking-glass.io * @@ -58,7 +57,6 @@ struct D3D12Backend float copySleep; ID3D12Device ** device; ID3D12CommandQueue ** commandQueue; - struct D3D12Texture * texture; UINT64 fenceValue; ID3D12Fence ** fence; HANDLE event; @@ -66,10 +64,13 @@ struct D3D12Backend // shared handle cache struct SharedCache sharedCache[10]; int sharedCacheCount; + ID3D12Resource * d12src; + + unsigned textures; + struct D3D12Texture texture[0]; }; -static struct DXGIInterface * dxgi = NULL; -static struct D3D12Backend * this = NULL; +static struct D3D12Backend * this = NULL; typedef HRESULT (*D3D12CreateDevice_t)( IUnknown *pAdapter, @@ -85,18 +86,17 @@ typedef HRESULT (*D3D12GetDebugInterface_t)( static void d3d12_free(void); -static bool d3d12_create(struct DXGIInterface * intf) +static bool d3d12_create(unsigned textures) { DEBUG_ASSERT(!this); HRESULT status; - dxgi = intf; HMODULE d3d12 = LoadLibrary("d3d12.dll"); if (!d3d12) return false; - if (dxgi->debug) + if (dxgi_debug()) { D3D12GetDebugInterface_t D3D12GetDebugInterface = (D3D12GetDebugInterface_t) GetProcAddress(d3d12, "D3D12GetDebugInterface"); @@ -118,20 +118,17 @@ static bool d3d12_create(struct DXGIInterface * intf) if (!D3D12CreateDevice) return false; - this = calloc(1, sizeof(struct D3D12Backend)); + this = calloc(1, + sizeof(struct D3D12Backend) + + sizeof(*this->texture) * textures); + if (!this) { DEBUG_ERROR("failed to allocate D3D12Backend struct"); return false; } - this->texture = calloc(dxgi->maxTextures, sizeof(struct D3D12Texture)); - if (!this->texture) - { - DEBUG_ERROR("Failed to allocate memory"); - return false; - } - + this->textures = textures; this->copySleep = option_get_float("dxgi", "d3d12CopySleep"); DEBUG_INFO("Sleep before copy : %f ms", this->copySleep); @@ -139,8 +136,8 @@ static bool d3d12_create(struct DXGIInterface * intf) comRef_scopePush(); comRef_defineLocal(ID3D12Device, device); - status = D3D12CreateDevice(*(IUnknown **)dxgi->adapter, D3D_FEATURE_LEVEL_11_0, - &IID_ID3D12Device, (void **)device); + status = D3D12CreateDevice((IUnknown *)dxgi_getAdapter(), + D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)device); if (FAILED(status)) { @@ -200,8 +197,12 @@ exit: return result; } -static bool d3d12_configure(unsigned width, unsigned height, DXGI_FORMAT format, - unsigned * pitch) +static bool d3d12_configure( + unsigned width, + unsigned height, + DXGI_FORMAT format, + unsigned bpp, + unsigned * pitch) { bool result = false; HRESULT status; @@ -210,7 +211,7 @@ static bool d3d12_configure(unsigned width, unsigned height, DXGI_FORMAT format, this->width = width; this->height = height; this->format = format; - this->pitch = ALIGN_TO(width * dxgi->bpp, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + this->pitch = ALIGN_TO(width * bpp, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); D3D12_HEAP_PROPERTIES readbackHeapProperties = { @@ -237,7 +238,7 @@ static bool d3d12_configure(unsigned width, unsigned height, DXGI_FORMAT format, comRef_defineLocal(ID3D12CommandAllocator , commandAllocator ); comRef_defineLocal(ID3D12GraphicsCommandList, graphicsCommandList); comRef_defineLocal(ID3D12CommandList , commandList ); - for (int i = 0; i < dxgi->maxTextures; ++i) + for (int i = 0; i < this->textures; ++i) { status = ID3D12Device_CreateCommittedResource(*this->device, &readbackHeapProperties, @@ -306,8 +307,6 @@ static bool d3d12_configure(unsigned width, unsigned height, DXGI_FORMAT format, goto exit; } - dxgi->texture[i].impl = this->texture + i; - comRef_toGlobal(this->texture[i].tex , texture ); comRef_toGlobal(this->texture[i].fence , fence ); comRef_toGlobal(this->texture[i].commandAllocator , commandAllocator ); @@ -329,13 +328,9 @@ static void d3d12_free(void) if (!this) return; - if (this->texture) - { - for (int i = 0; i < dxgi->maxTextures; ++i) - if (this->texture[i].event) - CloseHandle(this->texture[i].event); - free(this->texture); - } + for (int i = 0; i < this->textures; ++i) + if (this->texture[i].event) + CloseHandle(this->texture[i].event); if (this->event) CloseHandle(this->event); @@ -344,86 +339,97 @@ static void d3d12_free(void) this = NULL; } -static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src) +static bool d3d12_preCopy(ID3D11Texture2D * src, unsigned textureIndex) { - // we need to flush the DX11 context explicity or we get tons of lag - ID3D11DeviceContext_Flush(*dxgi->deviceContext); - comRef_scopePush(); + bool result = false; - struct D3D12Texture * tex = parent->impl; - bool fail = true; - comRef_defineLocal(IDXGIResource1, res1); - ID3D12Resource * d12src = NULL; - HRESULT status; + // we need to flush the DX11 context explicity or we get tons of lag + dxgi_contextLock(); + ID3D11DeviceContext_Flush(dxgi_getContext()); + dxgi_contextUnlock(); if (this->copySleep > 0) nsleep((uint64_t)(this->copySleep * 1000000)); + this->d12src = NULL; if (this->sharedCacheCount > -1) { // see if there is a cached handle already available for this texture for(int i = 0; i < this->sharedCacheCount; ++i) if (this->sharedCache[i].tex == src) { - d12src = *this->sharedCache[i].d12src; - break; + this->d12src = *this->sharedCache[i].d12src; + result = true; + goto exit; } } - if (!d12src) + comRef_defineLocal(IDXGIResource1, res1); + HRESULT status = ID3D11Texture2D_QueryInterface(src, + &IID_IDXGIResource1, (void **)res1); + + if (FAILED(status)) { - status = ID3D11Texture2D_QueryInterface(src, - &IID_IDXGIResource1, (void **)res1); + DEBUG_WINERROR("Failed to get IDXGIResource1 from texture", status); + goto exit; + } - if (FAILED(status)) - { - DEBUG_WINERROR("Failed to get IDXGIResource1 from texture", status); - goto cleanup; - } + HANDLE handle; + status = IDXGIResource1_CreateSharedHandle(*res1, + NULL, DXGI_SHARED_RESOURCE_READ, NULL, &handle); - HANDLE handle; - status = IDXGIResource1_CreateSharedHandle(*res1, - NULL, DXGI_SHARED_RESOURCE_READ, NULL, &handle); + if (FAILED(status)) + { + DEBUG_WINERROR("Failed to get create shared handle for texture", status); + goto exit; + } - if (FAILED(status)) - { - DEBUG_WINERROR("Failed to get create shared handle for texture", status); - goto cleanup; - } + status = ID3D12Device_OpenSharedHandle(*this->device, + handle, &IID_ID3D12Resource, (void **)&this->d12src); - status = ID3D12Device_OpenSharedHandle(*this->device, - handle, &IID_ID3D12Resource, (void **)&d12src); - CloseHandle(handle); + CloseHandle(handle); - if (FAILED(status)) - { - DEBUG_WINERROR("Failed to open the shared handle for texture", status); - goto cleanup; - } + if (FAILED(status)) + { + DEBUG_WINERROR("Failed to open the shared handle for texture", status); + goto exit; + } - // store the texture for later use - if (this->sharedCacheCount < ARRAY_LENGTH(this->sharedCache)) + // store the texture for later use + if (this->sharedCacheCount < ARRAY_LENGTH(this->sharedCache)) + { + struct SharedCache *cache = &this->sharedCache[this->sharedCacheCount++]; + cache->tex = src; + *comRef_newGlobal(&cache->d12src) = (IUnknown *)this->d12src; + } + else + { + // too many handles to cache, disable the cache entirely + for(int i = 0; i < this->sharedCacheCount; ++i) { struct SharedCache *cache = &this->sharedCache[this->sharedCacheCount++]; - cache->tex = src; - *comRef_newGlobal(&cache->d12src) = (IUnknown *)d12src; - } - else - { - // too many handles to cache, disable the cache entirely - for(int i = 0; i < this->sharedCacheCount; ++i) - { - struct SharedCache *cache = &this->sharedCache[this->sharedCacheCount++]; - comRef_release(cache->d12src); - } - this->sharedCacheCount = -1; + comRef_release(cache->d12src); } + this->sharedCacheCount = -1; } + result = true; + +exit: + if (!result) + comRef_scopePop(); + + return result; +} + +static bool d3d12_copyFull(ID3D11Texture2D * src, unsigned textureIndex) +{ + struct D3D12Texture * tex = &this->texture[textureIndex]; + D3D12_TEXTURE_COPY_LOCATION srcLoc = { - .pResource = d12src, + .pResource = this->d12src, .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, .SubresourceIndex = 0 }; @@ -446,42 +452,69 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src) } }; - if (parent->texDamageCount < 0) + ID3D12GraphicsCommandList_CopyTextureRegion(*tex->graphicsCommandList, + &destLoc, 0, 0, 0, &srcLoc, NULL); + + return true; +} + + +static bool d3d12_copyRect(ID3D11Texture2D * src, unsigned textureIndex, + FrameDamageRect * rect) +{ + struct D3D12Texture * tex = &this->texture[textureIndex]; + + D3D12_TEXTURE_COPY_LOCATION srcLoc = { - ID3D12GraphicsCommandList_CopyTextureRegion(*tex->graphicsCommandList, - &destLoc, 0, 0, 0, &srcLoc, NULL); - } - else + .pResource = this->d12src, + .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + .SubresourceIndex = 0 + }; + + D3D12_TEXTURE_COPY_LOCATION destLoc = { - for (int i = 0; i < parent->texDamageCount; ++i) + .pResource = *tex->tex, + .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, + .PlacedFootprint = { - FrameDamageRect * rect = parent->texDamageRects + i; - D3D12_BOX box = + .Offset = 0, + .Footprint = { - .left = rect->x, - .top = rect->y, - .front = 0, - .back = 1, - .right = rect->x + rect->width, - .bottom = rect->y + rect->height, - }; - - if (dxgi->outputFormat == CAPTURE_FMT_BGR) - { - box.left = box.left * 3 / 4; - box.right = box.right * 3 / 4; + .Format = this->format, + .Width = this->width, + .Height = this->height, + .Depth = 1, + .RowPitch = this->pitch, } - - ID3D12GraphicsCommandList_CopyTextureRegion(*tex->graphicsCommandList, - &destLoc, box.left, box.top, 0, &srcLoc, &box); } - } + }; - status = ID3D12GraphicsCommandList_Close(*tex->graphicsCommandList); + D3D12_BOX box = + { + .left = rect->x, + .top = rect->y, + .front = 0, + .back = 1, + .right = rect->x + rect->width, + .bottom = rect->y + rect->height, + }; + + ID3D12GraphicsCommandList_CopyTextureRegion(*tex->graphicsCommandList, + &destLoc, box.left, box.top, 0, &srcLoc, &box); + + return true; +} + +static bool d3d12_postCopy(ID3D11Texture2D * src, unsigned textureIndex) +{ + bool result = false; + struct D3D12Texture * tex = &this->texture[textureIndex]; + + HRESULT status = ID3D12GraphicsCommandList_Close(*tex->graphicsCommandList); if (FAILED(status)) { DEBUG_WINERROR("Failed to close command list", status); - goto cleanup; + goto exit; } ID3D12CommandQueue_ExecuteCommandLists(*this->commandQueue, @@ -492,7 +525,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src) if (FAILED(status)) { DEBUG_WINERROR("Failed to signal capture fence", status); - goto cleanup; + goto exit; } ResetEvent(this->event); @@ -501,7 +534,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src) if (FAILED(status)) { DEBUG_WINERROR("Failed to signal capture fence event", status); - goto cleanup; + goto exit; } status = ID3D12CommandQueue_Signal(*this->commandQueue, @@ -509,7 +542,7 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src) if (FAILED(status)) { DEBUG_WINERROR("Failed to signal texture fence", status); - goto cleanup; + goto exit; } status = ID3D12Fence_SetEventOnCompletion(*tex->fence, @@ -517,18 +550,19 @@ static bool d3d12_copyFrame(Texture * parent, ID3D11Texture2D * src) if (FAILED(status)) { DEBUG_WINERROR("Failed to signal texture fence event", status); - goto cleanup; + goto exit; } - fail = false; -cleanup: - comRef_scopePop(); - return !fail; + result = true; + +exit: + comRef_scopePop(); //push is in pre-copy + return result; } -static CaptureResult d3d12_mapTexture(Texture * parent) +static CaptureResult d3d12_mapTexture(unsigned textureIndex, void ** map) { - struct D3D12Texture * tex = parent->impl; + struct D3D12Texture * tex = &this->texture[textureIndex]; HRESULT status; WaitForSingleObject(tex->event, INFINITE); @@ -553,7 +587,7 @@ static CaptureResult d3d12_mapTexture(Texture * parent) .Begin = 0, .End = this->pitch * this->height }; - status = ID3D12Resource_Map(*tex->tex, 0, &range, &parent->map); + status = ID3D12Resource_Map(*tex->tex, 0, &range, map); if (FAILED(status)) { @@ -564,9 +598,9 @@ static CaptureResult d3d12_mapTexture(Texture * parent) return CAPTURE_RESULT_OK; } -static void d3d12_unmapTexture(Texture * parent) +static void d3d12_unmapTexture(unsigned textureIndex) { - struct D3D12Texture * tex = parent->impl; + struct D3D12Texture * tex = &this->texture[textureIndex]; D3D12_RANGE range = { @@ -574,7 +608,6 @@ static void d3d12_unmapTexture(Texture * parent) .End = 0 }; ID3D12Resource_Unmap(*tex->tex, 0, &range); - parent->map = NULL; } static void d3d12_preRelease(void) @@ -589,7 +622,10 @@ struct DXGICopyBackend copyBackendD3D12 = .create = d3d12_create, .configure = d3d12_configure, .free = d3d12_free, - .copyFrame = d3d12_copyFrame, + .preCopy = d3d12_preCopy, + .copyFull = d3d12_copyFull, + .copyRect = d3d12_copyRect, + .postCopy = d3d12_postCopy, .mapTexture = d3d12_mapTexture, .unmapTexture = d3d12_unmapTexture, .preRelease = d3d12_preRelease, diff --git a/host/platform/Windows/capture/DXGI/src/dxgi.c b/host/platform/Windows/capture/DXGI/src/dxgi.c index 2c2a539f..91f09a8d 100644 --- a/host/platform/Windows/capture/DXGI/src/dxgi.c +++ b/host/platform/Windows/capture/DXGI/src/dxgi.c @@ -708,7 +708,7 @@ static bool dxgi_init(void) { if (!strcasecmp(copyBackend, backends[i]->code)) { - if (!backends[i]->create(this)) + if (!backends[i]->create(this->maxTextures)) { DEBUG_ERROR("Failed to initialize selected capture backend: %s", backends[i]->name); backends[i]->free(); @@ -795,7 +795,7 @@ static bool dxgi_deinit(void) Texture * tex = &this->texture[i]; if (!tex->map) continue; - this->backend->unmapTexture(tex); + this->backend->unmapTexture(i); tex->map = NULL; } @@ -1099,7 +1099,12 @@ static CaptureResult dxgi_capture(void) unsigned pitch = 0; LG_LOCK(this->deviceContextLock); - if (!this->backend->configure(cols, rows, this->dxgiFormat, &pitch)) + if (!this->backend->configure( + cols, + rows, + this->dxgiFormat, + this->bpp, + &pitch)) { LG_UNLOCK(this->deviceContextLock); DEBUG_ERROR("Failed to configure the copy backend"); @@ -1132,7 +1137,44 @@ static CaptureResult dxgi_capture(void) computeFrameDamage(tex); computeTexDamage(tex); - if (!this->backend->copyFrame(tex, dst)) + if (!this->backend->preCopy(dst, this->texWIndex)) + { + result = CAPTURE_RESULT_ERROR; + goto exit; + } + + if (tex->texDamageCount <= 0) + { + if (!this->backend->copyFull(dst, this->texWIndex)) + { + // call this so the backend can cleanup + this->backend->postCopy(dst, this->texWIndex); + result = CAPTURE_RESULT_ERROR; + goto exit; + } + } + else + { + for (int i = 0; i < tex->texDamageCount; ++i) + { + FrameDamageRect * rect = &tex->texDamageRects[i]; + + // correct the damage rect for BGR packed data + if (this->outputFormat == CAPTURE_FMT_BGR) + { + rect->x = (rect->x * 3 ) / 4; // round down + rect->width = (rect->width * 3 + 3) / 4; // round up + } + + if (!this->backend->copyRect(dst, this->texWIndex, rect)) + { + result = CAPTURE_RESULT_ERROR; + goto exit; + } + } + } + + if (!this->backend->postCopy(dst, this->texWIndex)) { result = CAPTURE_RESULT_ERROR; goto exit; @@ -1266,7 +1308,7 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameS Texture * tex = &this->texture[this->texRIndex]; - CaptureResult result = this->backend->mapTexture(tex); + CaptureResult result = this->backend->mapTexture(this->texRIndex, &tex->map); if (result != CAPTURE_RESULT_OK) return result; @@ -1355,7 +1397,8 @@ static CaptureResult dxgi_getFrame(FrameBuffer * frame, int frameIndex) damage->count = -1; } - this->backend->unmapTexture(tex); + this->backend->unmapTexture(this->texRIndex); + tex->map = NULL; tex->state = TEXTURE_STATE_UNUSED; if (++this->texRIndex == this->maxTextures) @@ -1549,6 +1592,36 @@ static void ppFreeAll(void) } } +IDXGIAdapter1 * dxgi_getAdapter(void) +{ + return *this->adapter; +} + +ID3D11Device * dxgi_getDevice(void) +{ + return *this->device; +} + +ID3D11DeviceContext * dxgi_getContext(void) +{ + return *this->deviceContext; +} + +void dxgi_contextLock(void) +{ + LG_LOCK(this->deviceContextLock); +}; + +void dxgi_contextUnlock(void) +{ + LG_UNLOCK(this->deviceContextLock); +}; + +bool dxgi_debug(void) +{ + return this->debug; +} + struct CaptureInterface Capture_DXGI = { .shortName = "DXGI", diff --git a/host/platform/Windows/capture/DXGI/src/dxgi_capture.h b/host/platform/Windows/capture/DXGI/src/dxgi_capture.h index 6811cdf3..e7baa6fa 100644 --- a/host/platform/Windows/capture/DXGI/src/dxgi_capture.h +++ b/host/platform/Windows/capture/DXGI/src/dxgi_capture.h @@ -50,7 +50,6 @@ typedef struct Texture unsigned int formatVer; volatile enum TextureState state; void * map; - uint64_t copyTime; uint32_t damageRectsCount; FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS]; int texDamageCount; @@ -63,11 +62,12 @@ typedef struct Texture } Texture; -struct FrameDamage +typedef struct FrameDamage { int count; FrameDamageRect rects[KVMFR_MAX_DAMAGE_RECTS]; -}; +} +FrameDamage; struct DXGIInterface { @@ -122,4 +122,11 @@ struct DXGIInterface struct FrameDamage frameDamage[LGMP_Q_FRAME_LEN]; }; +IDXGIAdapter1 * dxgi_getAdapter(void); +ID3D11Device * dxgi_getDevice(void); +ID3D11DeviceContext * dxgi_getContext(void); +void dxgi_contextLock(void); +void dxgi_contextUnlock(void); +bool dxgi_debug(void); + #endif diff --git a/host/platform/Windows/capture/DXGI/src/pp/rgb24.c b/host/platform/Windows/capture/DXGI/src/pp/rgb24.c index 8f0f29f9..2544585b 100644 --- a/host/platform/Windows/capture/DXGI/src/pp/rgb24.c +++ b/host/platform/Windows/capture/DXGI/src/pp/rgb24.c @@ -78,7 +78,7 @@ static bool rgb24_configure(void * opaque, if (!this.pshader) { - this.width = *cols * 3 / 4; + this.width = (*cols * 3 + 3) / 4; this.height = *rows; char sOutputWidth[6], sOutputHeight[6];