[c-host] dxgi: allow out of order frame mapping

This commit is contained in:
Geoffrey McRae 2019-05-27 15:26:58 +10:00
parent 438e9e0969
commit 5e201a32ca
2 changed files with 42 additions and 33 deletions

View File

@ -1 +1 @@
B1-rc2-6-g9554e82c47+1
B1-rc3-0-g438e9e0969+1

View File

@ -42,7 +42,8 @@ typedef struct Texture
enum TextureState state;
ID3D11Texture2D * tex;
D3D11_MAPPED_SUBRESOURCE map;
osEventHandle * evt;
osEventHandle * mapped;
osEventHandle * free;
}
Texture;
@ -75,7 +76,6 @@ struct iface
int texRIndex;
int texWIndex;
bool needsRelease;
osEventHandle * frameEvent;
osEventHandle * pointerEvent;
unsigned int width;
@ -132,7 +132,7 @@ static void dxgi_initOptions()
.name = "maxTextures",
.description = "The maximum number of frames to buffer before skipping",
.type = OPTION_TYPE_INT,
.value.x_int = 1
.value.x_int = 3
},
{0}
};
@ -150,19 +150,10 @@ static bool dxgi_create()
return false;
}
this->frameEvent = os_createEvent(true);
if (!this->frameEvent)
{
DEBUG_ERROR("failed to create the frame event");
free(this);
return false;
}
this->pointerEvent = os_createEvent(true);
if (!this->pointerEvent)
{
DEBUG_ERROR("failed to create the pointer event");
os_freeEvent(this->frameEvent);
free(this);
return false;
}
@ -205,7 +196,6 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
this->stop = false;
this->texRIndex = 0;
this->texWIndex = 0;
os_resetEvent(this->frameEvent);
status = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&this->factory);
if (FAILED(status))
@ -462,15 +452,22 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
goto fail;
}
this->texture[i].evt = os_createEvent(true);
if (!this->texture[i].evt)
this->texture[i].free = os_createEvent(true);
if (!this->texture[i].free)
{
DEBUG_ERROR("Failed to create the texture event");
DEBUG_ERROR("Failed to create the texture free event");
goto fail;
}
// pre-signal the events to flag as unused
os_signalEvent(this->texture[i].evt);
// pre-signal the free events to flag as unused
os_signalEvent(this->texture[i].free);
this->texture[i].mapped = os_createEvent(false);
if (!this->texture[i].mapped)
{
DEBUG_ERROR("Failed to create the texture mapped event");
goto fail;
}
}
// map the texture simply to get the pitch and stride
@ -496,7 +493,8 @@ fail:
static void dxgi_stop()
{
this->stop = true;
os_signalEvent(this->frameEvent );
os_signalEvent(this->texture[this->texRIndex].mapped);
os_signalEvent(this->pointerEvent);
}
@ -520,11 +518,18 @@ static bool dxgi_deinit()
this->texture[i].tex = NULL;
}
if (this->texture[i].evt)
if (this->texture[i].free)
{
os_signalEvent(this->texture[i].evt);
os_freeEvent(this->texture[i].evt);
this->texture[i].evt = NULL;
os_signalEvent(this->texture[i].free);
os_freeEvent(this->texture[i].free);
this->texture[i].free = NULL;
}
if (this->texture[i].mapped)
{
os_signalEvent(this->texture[i].mapped);
os_freeEvent(this->texture[i].mapped);
this->texture[i].mapped = NULL;
}
}
@ -582,7 +587,6 @@ static void dxgi_free()
if (this->initialized)
dxgi_deinit();
os_freeEvent(this->frameEvent );
os_freeEvent(this->pointerEvent);
free(this->texture);
@ -609,9 +613,12 @@ static CaptureResult dxgi_capture()
IDXGIResource * res;
// if the read texture is pending a mapping
if (this->texture[this->texRIndex].state == TEXTURE_STATE_PENDING_MAP)
for(int i = 0; i < this->maxTextures; ++i)
{
Texture * tex = &this->texture[this->texRIndex];
if (this->texture[i].state != TEXTURE_STATE_PENDING_MAP)
continue;
Texture * tex = &this->texture[i];
// try to map the resource, but don't wait for it
status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource*)tex->tex, 0, D3D11_MAP_READ, 0x100000L, &tex->map);
@ -627,7 +634,7 @@ static CaptureResult dxgi_capture()
// successful map, set the state and signal that there is a frame available
tex->state = TEXTURE_STATE_MAPPED;
os_signalEvent(this->frameEvent);
os_signalEvent(tex->mapped);
}
}
@ -660,7 +667,7 @@ static CaptureResult dxgi_capture()
Texture * tex = &this->texture[this->texWIndex];
// check if the texture is free, if not skip the frame to keep up
if (!os_waitEvent(tex->evt, 0))
if (!os_waitEvent(tex->free, 0))
{
/*
NOTE: This is only informational for when debugging, skipping frames is
@ -766,16 +773,18 @@ static CaptureResult dxgi_getFrame(CaptureFrame * frame)
assert(this);
assert(this->initialized);
if (!os_waitEvent(this->frameEvent, TIMEOUT_INFINITE))
Texture * tex = &this->texture[this->texRIndex];
if (!os_waitEvent(tex->mapped, TIMEOUT_INFINITE))
{
DEBUG_ERROR("Failed to wait on the frame event");
DEBUG_ERROR("Failed to wait on the texture map event");
return CAPTURE_RESULT_ERROR;
}
if (this->stop)
return CAPTURE_RESULT_REINIT;
Texture * tex = &this->texture[this->texRIndex];
// only reset the event if we used the texture
os_resetEvent(tex->mapped);
frame->width = this->width;
frame->height = this->height;
@ -784,7 +793,7 @@ static CaptureResult dxgi_getFrame(CaptureFrame * frame)
frame->format = this->format;
memcpy(frame->data, tex->map.pData, this->pitch * this->height);
os_signalEvent(tex->evt);
os_signalEvent(tex->free);
if (++this->texRIndex == this->maxTextures)
this->texRIndex = 0;