[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; enum TextureState state;
ID3D11Texture2D * tex; ID3D11Texture2D * tex;
D3D11_MAPPED_SUBRESOURCE map; D3D11_MAPPED_SUBRESOURCE map;
osEventHandle * evt; osEventHandle * mapped;
osEventHandle * free;
} }
Texture; Texture;
@ -75,7 +76,6 @@ struct iface
int texRIndex; int texRIndex;
int texWIndex; int texWIndex;
bool needsRelease; bool needsRelease;
osEventHandle * frameEvent;
osEventHandle * pointerEvent; osEventHandle * pointerEvent;
unsigned int width; unsigned int width;
@ -132,7 +132,7 @@ static void dxgi_initOptions()
.name = "maxTextures", .name = "maxTextures",
.description = "The maximum number of frames to buffer before skipping", .description = "The maximum number of frames to buffer before skipping",
.type = OPTION_TYPE_INT, .type = OPTION_TYPE_INT,
.value.x_int = 1 .value.x_int = 3
}, },
{0} {0}
}; };
@ -150,19 +150,10 @@ static bool dxgi_create()
return false; 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); this->pointerEvent = os_createEvent(true);
if (!this->pointerEvent) if (!this->pointerEvent)
{ {
DEBUG_ERROR("failed to create the pointer event"); DEBUG_ERROR("failed to create the pointer event");
os_freeEvent(this->frameEvent);
free(this); free(this);
return false; return false;
} }
@ -205,7 +196,6 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
this->stop = false; this->stop = false;
this->texRIndex = 0; this->texRIndex = 0;
this->texWIndex = 0; this->texWIndex = 0;
os_resetEvent(this->frameEvent);
status = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&this->factory); status = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&this->factory);
if (FAILED(status)) if (FAILED(status))
@ -462,15 +452,22 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
goto fail; goto fail;
} }
this->texture[i].evt = os_createEvent(true); this->texture[i].free = os_createEvent(true);
if (!this->texture[i].evt) if (!this->texture[i].free)
{ {
DEBUG_ERROR("Failed to create the texture event"); DEBUG_ERROR("Failed to create the texture free event");
goto fail; goto fail;
} }
// pre-signal the events to flag as unused // pre-signal the free events to flag as unused
os_signalEvent(this->texture[i].evt); 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 // map the texture simply to get the pitch and stride
@ -496,7 +493,8 @@ fail:
static void dxgi_stop() static void dxgi_stop()
{ {
this->stop = true; this->stop = true;
os_signalEvent(this->frameEvent );
os_signalEvent(this->texture[this->texRIndex].mapped);
os_signalEvent(this->pointerEvent); os_signalEvent(this->pointerEvent);
} }
@ -520,11 +518,18 @@ static bool dxgi_deinit()
this->texture[i].tex = NULL; this->texture[i].tex = NULL;
} }
if (this->texture[i].evt) if (this->texture[i].free)
{ {
os_signalEvent(this->texture[i].evt); os_signalEvent(this->texture[i].free);
os_freeEvent(this->texture[i].evt); os_freeEvent(this->texture[i].free);
this->texture[i].evt = NULL; 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) if (this->initialized)
dxgi_deinit(); dxgi_deinit();
os_freeEvent(this->frameEvent );
os_freeEvent(this->pointerEvent); os_freeEvent(this->pointerEvent);
free(this->texture); free(this->texture);
@ -609,9 +613,12 @@ static CaptureResult dxgi_capture()
IDXGIResource * res; IDXGIResource * res;
// if the read texture is pending a mapping // 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 // 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); 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 // successful map, set the state and signal that there is a frame available
tex->state = TEXTURE_STATE_MAPPED; 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]; Texture * tex = &this->texture[this->texWIndex];
// check if the texture is free, if not skip the frame to keep up // 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 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);
assert(this->initialized); 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; return CAPTURE_RESULT_ERROR;
} }
if (this->stop) if (this->stop)
return CAPTURE_RESULT_REINIT; 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->width = this->width;
frame->height = this->height; frame->height = this->height;
@ -784,7 +793,7 @@ static CaptureResult dxgi_getFrame(CaptureFrame * frame)
frame->format = this->format; frame->format = this->format;
memcpy(frame->data, tex->map.pData, this->pitch * this->height); memcpy(frame->data, tex->map.pData, this->pitch * this->height);
os_signalEvent(tex->evt); os_signalEvent(tex->free);
if (++this->texRIndex == this->maxTextures) if (++this->texRIndex == this->maxTextures)
this->texRIndex = 0; this->texRIndex = 0;