[host] add new D12 capture interface

Note, this capture interface is not yet feature complete but does seem
to be stable.
This commit is contained in:
Geoffrey McRae
2024-01-29 21:47:02 +11:00
parent e376e6fb53
commit 72b25b99bc
20 changed files with 1919 additions and 352 deletions

View File

@@ -7,15 +7,12 @@ add_library(capture_DXGI STATIC
src/d3d12.c
src/ods_capture.c
src/util.c
src/com_ref.c
src/pp/downsample.c
src/pp/sdrwhitelevel.c
src/pp/rgb24.c
)
add_definitions("-DCOBJMACROS -DINITGUID -DWIDL_C_INLINE_WRAPPERS")
target_link_libraries(capture_DXGI
lg_common
d3d11

View File

@@ -1,153 +0,0 @@
/**
* Looking Glass
* Copyright © 2017-2023 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
*/
#define COMREF_INTERNAL
#include "com_ref.h"
#include "common/debug.h"
#include "common/vector.h"
typedef struct
{
int scope;
IUnknown * value;
IUnknown *** ref;
}
COMRef;
static bool comInit = false;
static int comScope = -1;
static Vector comObjectsLocal = {0};
static Vector comObjectsGlobal = {0};
bool comRef_init(unsigned globals, unsigned locals)
{
if (comInit)
return true;
if (!vector_create(&comObjectsGlobal, sizeof(COMRef), globals))
return false;
if (!vector_create(&comObjectsLocal, sizeof(COMRef), locals))
{
vector_destroy(&comObjectsGlobal);
return false;
}
comInit = true;
return true;
}
void comRef_free(void)
{
if (!comInit)
return;
COMRef * ref;
if (comScope > -1)
{
DEBUG_WARN("There is %d unmatched `comRef_scopePush` calls", comScope+1);
vector_forEachRef(ref, &comObjectsLocal)
if (ref->value)
IUnknown_Release(ref->value);
}
vector_forEachRef(ref, &comObjectsGlobal)
{
if (ref->ref)
*ref->ref = NULL;
if (ref->value)
IUnknown_Release(ref->value);
}
comScope = -1;
vector_destroy(&comObjectsLocal);
vector_destroy(&comObjectsGlobal);
comInit = false;
}
static IUnknown ** comRef_new(Vector * vector, IUnknown *** dst)
{
DEBUG_ASSERT(comInit && "comRef has not been initialized");
// we must not allow the vector to grow as if the realloc moves to a new
// address it will invalidate any external pointers to members in it
DEBUG_ASSERT(vector_size(vector) < vector_capacity(vector) &&
"comRef vector too small!");
COMRef * ref = (COMRef *)vector_push(vector, NULL);
if (!ref)
{
DEBUG_ERROR("Failed to allocate ram for com object");
return NULL;
}
ref->scope = comScope;
ref->ref = dst;
ref->value = NULL;
if (dst)
*dst = &ref->value;
return &ref->value;
}
IUnknown ** comRef_newGlobal(IUnknown *** dst)
{
return comRef_new(&comObjectsGlobal, dst);
}
IUnknown ** comRef_newLocal(IUnknown *** dst)
{
IUnknown ** ret = comRef_new(&comObjectsLocal, NULL);
*dst = ret;
return ret;
}
void comRef_scopePush(void)
{
DEBUG_ASSERT(comInit && "comRef has not been initialized");
++comScope;
}
void comRef_scopePop(void)
{
DEBUG_ASSERT(comInit && "comRef has not been initialized");
DEBUG_ASSERT(comScope >= 0);
COMRef * ref;
while(vector_size(&comObjectsLocal) > 0)
{
ref = (COMRef *)vector_ptrTo(&comObjectsLocal,
vector_size(&comObjectsLocal) - 1);
if (ref->scope < comScope)
break;
if (ref->value)
IUnknown_Release(ref->value);
vector_pop(&comObjectsLocal);
}
--comScope;
}

View File

@@ -1,99 +0,0 @@
/**
* Looking Glass
* Copyright © 2017-2023 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 <stdbool.h>
#include <windows.h>
/**
* These functions are to assist in tracking and relasing COM objects
*/
/**
* Initialize the com object tracking
*/
bool comRef_init(unsigned globals, unsigned locals);
/**
* Release globals and deinitialize the com object tracking
*/
void comRef_free(void);
/**
* Create a new global COM reference
*/
IUnknown ** comRef_newGlobal(IUnknown *** dst);
/**
* Create a new locally scoped COM reference
*/
IUnknown ** comRef_newLocal(IUnknown *** dst);
/**
* Define and create a new locally scoped COM reference
*/
#define comRef_defineLocal(type, name) \
type ** name; \
comRef_newLocal(&name);
/**
* Release a COM reference immediately
* This is just a helper, the ref is still tracked if used again
*/
inline static ULONG comRef_release(IUnknown ** ref)
{
if (!ref)
return 0;
ULONG count = 0;
if (*ref)
count = IUnknown_Release(*ref);
*ref = NULL;
return count;
}
/**
* Create a new local scope
*/
void comRef_scopePush(void);
/**
* Exit from a local scope and release all locals
*/
void comRef_scopePop (void);
/**
* Macros to prevent needing to typecast calls to these methods
*/
#ifndef COMREF_INTERNAL
#define comRef_newGlobal(dst) comRef_newGlobal((IUnknown ***)(dst))
#define comRef_newLocal(dst) comRef_newLocal((IUnknown ***)(dst))
#define comRef_release(ref) comRef_release((IUnknown **)(ref))
#endif
/**
* Convert a local to a global
*/
#define comRef_toGlobal(dst, src) \
{ \
IUnknown ** global = comRef_newGlobal(&(dst)); \
DEBUG_ASSERT(global && "comRef_newGlobal failed\n"); \
*global = (IUnknown*)*(src); \
*(src) = NULL; \
}

View File

@@ -29,6 +29,8 @@
struct D3D11Backend
{
ComScope * comScope;
RunningAvg avgMapTime;
uint64_t usleepMapTime;
@@ -43,6 +45,9 @@ struct D3D11Backend
static struct D3D11Backend * this = NULL;
#define comRef_toGlobal(dst, src) \
_comRef_toGlobal(this->comScope, dst, src)
static bool d3d11_create(
void * ivshmemBase,
unsigned * alignSize,
@@ -62,6 +67,8 @@ static bool d3d11_create(
this->avgMapTime = runningavg_new(10);
this->textures = textures;
comRef_initGlobalScope(10, this->comScope);
return true;
}
@@ -72,6 +79,7 @@ static bool d3d11_configure(
unsigned bpp,
unsigned * pitch)
{
comRef_scopePush(10);
HRESULT status;
D3D11_TEXTURE2D_DESC texTexDesc =
@@ -116,9 +124,11 @@ static bool d3d11_configure(
*(ID3D11Resource **)this->texture[0].tex, 0);
*pitch = mapping.RowPitch;
comRef_scopePop();
return true;
fail:
comRef_scopePop();
return false;
}
@@ -128,6 +138,7 @@ static void d3d11_free(void)
return;
runningavg_free(&this->avgMapTime);
comRef_freeScope(&this->comScope);
free(this);
this = NULL;
}

View File

@@ -51,6 +51,8 @@ struct SharedCache
struct D3D12Backend
{
ComScope * comScope;
HMODULE d3d12;
unsigned width, height, pitch;
DXGI_FORMAT format;
@@ -78,6 +80,9 @@ struct D3D12Backend
static struct D3D12Backend * this = NULL;
#define comRef_toGlobal(dst, src) \
_comRef_toGlobal(this->comScope, dst, src)
typedef HRESULT (*D3D12CreateDevice_t)(
IUnknown *pAdapter,
D3D_FEATURE_LEVEL MinimumFeatureLevel,
@@ -99,7 +104,6 @@ static bool d3d12_create(
unsigned textures)
{
DEBUG_ASSERT(!this);
comRef_scopePush();
bool result = false;
HRESULT status;
@@ -113,6 +117,9 @@ static bool d3d12_create(
goto exit;
}
comRef_initGlobalScope(10, this->comScope);
comRef_scopePush(10);
this->d3d12 = LoadLibrary("d3d12.dll");
if (!this->d3d12)
goto exit;
@@ -252,7 +259,7 @@ static bool d3d12_configure(
{
bool result = false;
HRESULT status;
comRef_scopePush();
comRef_scopePush(10);
this->width = width;
this->height = height;
@@ -350,6 +357,7 @@ static void d3d12_free(void)
if (this->d3d12)
FreeLibrary(this->d3d12);
comRef_freeScope(&this->comScope);
free(this);
this = NULL;
}
@@ -360,7 +368,7 @@ static bool d3d12_preCopy(
unsigned frameBufferIndex,
FrameBuffer * frameBuffer)
{
comRef_scopePush();
comRef_scopePush(10);
bool result = false;
// we need to flush the DX11 context explicity or we get tons of lag
@@ -478,9 +486,7 @@ done:
nsleep((uint64_t)(this->copySleep * 1000000));
exit:
if (!result)
comRef_scopePop();
comRef_scopePop();
return result;
}
@@ -616,8 +622,6 @@ static bool d3d12_postCopy(ID3D11Texture2D * src, unsigned textureIndex)
result = true;
exit:
//push is in preCopy
comRef_scopePop();
return result;
}

View File

@@ -106,6 +106,8 @@ FrameDamage;
struct DXGIInterface
{
ComScope * comScope;
bool initialized;
LARGE_INTEGER perfFreq;
LARGE_INTEGER frameTime;
@@ -125,7 +127,6 @@ struct DXGIInterface
D3D_FEATURE_LEVEL featureLevel;
IDXGIOutputDuplication ** dup;
int maxTextures;
void * ivshmemBase;
Texture * texture;
int texRIndex;
int texWIndex;
@@ -140,6 +141,7 @@ struct DXGIInterface
CaptureGetPointerBuffer getPointerBufferFn;
CapturePostPointerBuffer postPointerBufferFn;
unsigned frameBuffers;
LGEvent * frameEvent;
unsigned int formatVer;
@@ -160,6 +162,7 @@ struct DXGIInterface
};
// locals
static struct DXGIInterface * this = NULL;
extern struct DXGICopyBackend copyBackendD3D11;
@@ -169,6 +172,11 @@ static struct DXGICopyBackend * backends[] = {
&copyBackendD3D11,
};
// defines
#define comRef_toGlobal(dst, src) \
_comRef_toGlobal(this->comScope, dst, src)
// forwards
static bool dxgi_deinit(void);
@@ -277,9 +285,9 @@ static void dxgi_initOptions(void)
}
static bool dxgi_create(
void * ivshmemBase,
CaptureGetPointerBuffer getPointerBufferFn,
CapturePostPointerBuffer postPointerBufferFn)
CapturePostPointerBuffer postPointerBufferFn,
unsigned frameBuffers)
{
DEBUG_ASSERT(!this);
this = calloc(1, sizeof(*this));
@@ -306,16 +314,18 @@ static bool dxgi_create(
this->allowRGB24 = option_get_bool("dxgi", "allowRGB24");
this->dwmFlush = option_get_bool("dxgi", "dwmFlush");
this->disableDamage = option_get_bool("dxgi", "disableDamage");
this->ivshmemBase = ivshmemBase;
this->texture = calloc(this->maxTextures, sizeof(*this->texture));
this->getPointerBufferFn = getPointerBufferFn;
this->postPointerBufferFn = postPointerBufferFn;
this->frameBuffers = frameBuffers;
return true;
}
static bool initVertexShader(void)
{
comRef_scopePush(10);
static const char * vshaderSrc =
"void main(\n"
" in uint vertexID : SV_VERTEXID,\n"
@@ -362,23 +372,16 @@ static bool initVertexShader(void)
}
comRef_toGlobal(this->vshader, vshader);
comRef_scopePop();
return true;
}
static bool dxgi_init(unsigned * alignSize)
static bool dxgi_init(void * ivshmemBase, unsigned * alignSize)
{
DEBUG_ASSERT(this);
if (!comRef_init(
20 + this->maxTextures * 16, //max total globals
20 //max total locals
))
{
DEBUG_ERROR("failed to intialize the comRef tracking");
return false;
}
comRef_scopePush();
comRef_initGlobalScope(20 + this->maxTextures * 16, this->comScope);
comRef_scopePush(20);
this->desktop = OpenInputDesktop(0, FALSE, GENERIC_READ);
if (!this->desktop)
@@ -411,9 +414,10 @@ static bool dxgi_init(unsigned * alignSize)
lgResetEvent(this->frameEvent);
comRef_defineLocal(IDXGIFactory1, factory);
status = CreateDXGIFactory2(this->debug ? DXGI_CREATE_FACTORY_DEBUG : 0,
&IID_IDXGIFactory1,
(void **)comRef_newGlobal(&this->factory));
(void **)factory);
if (FAILED(status))
{
@@ -429,7 +433,7 @@ static bool dxgi_init(unsigned * alignSize)
for (
int i = 0;
IDXGIFactory1_EnumAdapters1(*this->factory, i, adapter)
IDXGIFactory1_EnumAdapters1(*factory, i, adapter)
!= DXGI_ERROR_NOT_FOUND;
++i, comRef_release(adapter))
{
@@ -509,6 +513,7 @@ static bool dxgi_init(unsigned * alignSize)
goto fail;
}
comRef_toGlobal(this->factory, factory);
comRef_toGlobal(this->adapter, adapter);
comRef_toGlobal(this->output , output );
@@ -569,6 +574,8 @@ static bool dxgi_init(unsigned * alignSize)
goto fail;
}
comRef_defineLocal(ID3D11Device , device );
comRef_defineLocal(ID3D11DeviceContext, deviceContext);
status = D3D11CreateDevice(
*tmp,
D3D_DRIVER_TYPE_UNKNOWN,
@@ -577,11 +584,9 @@ static bool dxgi_init(unsigned * alignSize)
(this->debug ? D3D11_CREATE_DEVICE_DEBUG : 0),
featureLevels, featureLevelCount,
D3D11_SDK_VERSION,
(ID3D11Device **)comRef_newGlobal(&this->device),
device,
&this->featureLevel,
(ID3D11DeviceContext **)comRef_newGlobal(&this->deviceContext));
LG_LOCK_INIT(this->deviceContextLock);
deviceContext);
if (FAILED(status))
{
@@ -589,6 +594,10 @@ static bool dxgi_init(unsigned * alignSize)
goto fail;
}
comRef_toGlobal(this->device , device );
comRef_toGlobal(this->deviceContext, deviceContext);
LG_LOCK_INIT(this->deviceContextLock);
switch(outputDesc.Rotation)
{
case DXGI_MODE_ROTATION_ROTATE90:
@@ -648,6 +657,8 @@ static bool dxgi_init(unsigned * alignSize)
IDXGIDevice1_SetMaximumFrameLatency(*dxgi, 1);
}
comRef_defineLocal(IDXGIOutputDuplication, dup);
comRef_defineLocal(IDXGIOutput5, output5);
status = IDXGIOutput_QueryInterface(
*this->output, &IID_IDXGIOutput5, (void **)output5);
@@ -671,8 +682,7 @@ static bool dxgi_init(unsigned * alignSize)
for (int i = 0; i < 2; ++i)
{
status = IDXGIOutput1_DuplicateOutput(
*output1, (IUnknown *)*this->device,
(IDXGIOutputDuplication **)comRef_newGlobal(&this->dup));
*output1, *(IUnknown **)this->device, dup);
if (SUCCEEDED(status))
break;
@@ -703,7 +713,7 @@ static bool dxgi_init(unsigned * alignSize)
0,
ARRAY_LENGTH(supportedFormats),
supportedFormats,
(IDXGIOutputDuplication **)comRef_newGlobal(&this->dup));
dup);
if (SUCCEEDED(status))
break;
@@ -721,6 +731,8 @@ static bool dxgi_init(unsigned * alignSize)
goto fail;
}
comRef_toGlobal(this->dup, dup);
comRef_defineLocal(IDXGIOutput6, output6);
status = IDXGIOutput_QueryInterface(
*this->output, &IID_IDXGIOutput6, (void **)output6);
@@ -806,9 +818,9 @@ static bool dxgi_init(unsigned * alignSize)
if (!strcasecmp(copyBackend, backends[i]->code))
{
if (!backends[i]->create(
this->ivshmemBase,
ivshmemBase,
alignSize,
LGMP_Q_FRAME_LEN,
this->frameBuffers,
this->maxTextures))
{
DEBUG_ERROR("Failed to initialize selected capture backend: %s", backends[i]->name);
@@ -914,7 +926,7 @@ static bool dxgi_deinit(void)
dxgi_releaseFrame();
// this MUST run before backend->free() & ppFreeAll.
comRef_free();
comRef_freeScope(&this->comScope);
ppFreeAll();
if (this->backend)
@@ -1066,7 +1078,7 @@ static CaptureResult dxgi_capture(unsigned frameBufferIndex,
{
DEBUG_ASSERT(this);
DEBUG_ASSERT(this->initialized);
comRef_scopePush();
comRef_scopePush(10);
Texture * tex = NULL;
CaptureResult result;
@@ -1386,7 +1398,7 @@ static CaptureResult dxgi_capture(unsigned frameBufferIndex,
if (postPointer)
{
pointer.visible = this->lastPointerVisible;
this->postPointerBufferFn(pointer);
this->postPointerBufferFn(&pointer);
}
result = CAPTURE_RESULT_OK;
@@ -1395,7 +1407,8 @@ exit:
return result;
}
static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameSize)
static CaptureResult dxgi_waitFrame(unsigned frameBufferIndex,
CaptureFrame * frame, const size_t maxFrameSize)
{
DEBUG_ASSERT(this);
DEBUG_ASSERT(this->initialized);
@@ -1444,17 +1457,18 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameS
return CAPTURE_RESULT_OK;
}
static CaptureResult dxgi_getFrame(FrameBuffer * frame, int frameIndex)
static CaptureResult dxgi_getFrame(unsigned frameBufferIndex,
FrameBuffer * frame, const size_t maxFrameSize)
{
DEBUG_ASSERT(this);
DEBUG_ASSERT(this->initialized);
Texture * tex = &this->texture[this->texRIndex];
FrameDamage * damage = &this->frameDamage[frameIndex];
FrameDamage * damage = &this->frameDamage[frameBufferIndex];
if (this->backend->writeFrame)
{
CaptureResult result = this->backend->writeFrame(frameIndex, frame);
CaptureResult result = this->backend->writeFrame(frameBufferIndex, frame);
if (result != CAPTURE_RESULT_OK)
return result;
}
@@ -1500,7 +1514,7 @@ static CaptureResult dxgi_getFrame(FrameBuffer * frame, int frameIndex)
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
{
struct FrameDamage * damage = this->frameDamage + i;
if (i == frameIndex)
if (i == frameBufferIndex)
damage->count = 0;
else if (tex->damageRectsCount > 0 && damage->count >= 0 &&
damage->count + tex->damageRectsCount <= KVMFR_MAX_DAMAGE_RECTS)

View File

@@ -31,6 +31,8 @@
typedef struct Downsample
{
ComScope * comScope;
ID3D11Device ** device;
ID3D11DeviceContext ** context;
bool shareable;
@@ -43,6 +45,9 @@ typedef struct Downsample
Downsample;
static Downsample this = {0};
#define comRef_toGlobal(dst, src) \
_comRef_toGlobal(this.comScope, dst, src)
typedef struct
{
ID3D11Texture2D ** tex;
@@ -73,11 +78,14 @@ static bool downsample_setup(
this.device = device;
this.context = context;
this.shareable = shareable;
comRef_initGlobalScope(10, this.comScope);
return true;
}
static void downsample_finish(void)
{
comRef_freeScope(&this.comScope);
memset(&this, 0, sizeof(this));
}
@@ -96,7 +104,7 @@ static bool downsample_configure(void * opaque,
return true;
HRESULT status;
comRef_scopePush();
comRef_scopePush(10);
if (!this.pshader)
{

View File

@@ -29,6 +29,8 @@
typedef struct RGB24
{
ComScope * comScope;
ID3D11Device ** device;
ID3D11DeviceContext ** context;
bool shareable;
@@ -40,6 +42,9 @@ typedef struct RGB24
RGB24;
static RGB24 this = {0};
#define comRef_toGlobal(dst, src) \
_comRef_toGlobal(this.comScope, dst, src)
typedef struct
{
ID3D11Texture2D ** tex;
@@ -55,6 +60,7 @@ static bool rgb24_setup(
bool shareable
)
{
comRef_initGlobalScope(10, this.comScope);
this.device = device;
this.context = context;
this.shareable = shareable;
@@ -63,6 +69,7 @@ static bool rgb24_setup(
static void rgb24_finish(void)
{
comRef_freeScope(&this.comScope);
memset(&this, 0, sizeof(this));
}
@@ -74,7 +81,8 @@ static bool rgb24_configure(void * opaque,
RGB24Inst * inst = (RGB24Inst *)opaque;
HRESULT status;
comRef_scopePush();
comRef_scopePush(10);
if (!this.pshader)
{

View File

@@ -29,6 +29,8 @@
typedef struct SDRWhiteLevel
{
ComScope * comScope;
ID3D11Device ** device;
ID3D11DeviceContext ** context;
@@ -43,6 +45,9 @@ typedef struct SDRWhiteLevel
SDRWhiteLevel;
static SDRWhiteLevel this = {0};
#define comRef_toGlobal(dst, src) \
_comRef_toGlobal(this.comScope, dst, src)
typedef struct
{
ID3D11Texture2D ** tex;
@@ -66,13 +71,15 @@ static bool sdrWhiteLevel_setup(
)
{
bool result = false;
comRef_scopePush();
HRESULT status;
this.device = device;
this.context = context;
this.shareable = shareable;
comRef_initGlobalScope(10, this.comScope);
comRef_scopePush(10);
comRef_defineLocal(IDXGIOutput6, output6);
status = IDXGIOutput_QueryInterface(
*output, &IID_IDXGIOutput6, (void **)output6);
@@ -139,9 +146,8 @@ static bool sdrWhiteLevel_setup(
.MaxLOD = D3D11_FLOAT32_MAX
};
status = ID3D11Device_CreateSamplerState(
*this.device, &samplerDesc,
(ID3D11SamplerState **)comRef_newGlobal(&this.sampler));
comRef_defineLocal(ID3D11SamplerState, sampler);
status = ID3D11Device_CreateSamplerState(*this.device, &samplerDesc, sampler);
if (FAILED(status))
{
@@ -156,9 +162,10 @@ static bool sdrWhiteLevel_setup(
.BindFlags = D3D11_BIND_CONSTANT_BUFFER,
};
comRef_defineLocal(ID3D11Buffer, buffer);
status = ID3D11Device_CreateBuffer(
*this.device, &bufferDesc, NULL,
(ID3D11Buffer **)comRef_newGlobal(&this.buffer));
buffer);
if (FAILED(status))
{
@@ -169,6 +176,8 @@ static bool sdrWhiteLevel_setup(
updateConsts();
DEBUG_INFO("SDR White Level : %f" , this.sdrWhiteLevel);
comRef_toGlobal(this.sampler, sampler);
comRef_toGlobal(this.buffer , buffer );
result = true;
exit:
@@ -178,6 +187,7 @@ exit:
static void sdrWhiteLevel_finish(void)
{
comRef_freeScope(&this.comScope);
memset(&this, 0, sizeof(this));
}
@@ -225,7 +235,7 @@ static bool sdrWhiteLevel_configure(void * opaque,
if (inst->tex)
return true;
comRef_scopePush();
comRef_scopePush(10);
// create the output texture
D3D11_TEXTURE2D_DESC texDesc =