wined3d: Implement manual buffer fencing.
This commit is contained in:
parent
fd13a6ae23
commit
1181762f99
|
@ -108,6 +108,11 @@ static void delete_gl_buffer(struct wined3d_buffer *This)
|
|||
LEAVE_GL();
|
||||
This->buffer_object = 0;
|
||||
|
||||
if(This->query)
|
||||
{
|
||||
wined3d_event_query_destroy(This->query);
|
||||
This->query = NULL;
|
||||
}
|
||||
This->flags &= ~WINED3D_BUFFER_APPLESYNC;
|
||||
}
|
||||
|
||||
|
@ -774,23 +779,68 @@ static DWORD STDMETHODCALLTYPE buffer_GetPriority(IWineD3DBuffer *iface)
|
|||
return resource_get_priority((IWineD3DResource *)iface);
|
||||
}
|
||||
|
||||
/* The caller provides a context and GL locking and binds the buffer */
|
||||
static void buffer_sync_apple(struct wined3d_buffer *This, DWORD flags)
|
||||
/* The caller provides a context and binds the buffer */
|
||||
static void buffer_sync_apple(struct wined3d_buffer *This, DWORD flags, const struct wined3d_gl_info *gl_info)
|
||||
{
|
||||
enum wined3d_event_query_result ret;
|
||||
|
||||
/* No fencing needs to be done if the app promises not to overwrite
|
||||
* existing data */
|
||||
if(flags & WINED3DLOCK_NOOVERWRITE) return;
|
||||
if(flags & WINED3DLOCK_DISCARD)
|
||||
{
|
||||
ENTER_GL();
|
||||
GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, This->resource.size, NULL, This->buffer_object_usage));
|
||||
checkGLcall("glBufferDataARB\n");
|
||||
LEAVE_GL();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Drop the unserialized updates for now */
|
||||
FIXME("Implement fences for unserialized buffers\n");
|
||||
if(!This->query)
|
||||
{
|
||||
HRESULT hr;
|
||||
TRACE("Creating event query for buffer %p\n", This);
|
||||
|
||||
hr = wined3d_event_query_init(gl_info, &This->query);
|
||||
if(FAILED(hr))
|
||||
{
|
||||
ERR("Failed to create an event query, dropping async buffer locks\n");
|
||||
goto drop_query;
|
||||
}
|
||||
/* Since we don't know about old draws a glFinish is needed once */
|
||||
wglFinish();
|
||||
return;
|
||||
}
|
||||
TRACE("Synchronizing buffer %p\n", This);
|
||||
ret = wined3d_event_query_finish(This->query, This->resource.device);
|
||||
switch(ret)
|
||||
{
|
||||
case WINED3D_EVENT_QUERY_NOT_STARTED:
|
||||
case WINED3D_EVENT_QUERY_OK:
|
||||
/* All done */
|
||||
return;
|
||||
|
||||
case WINED3D_EVENT_QUERY_WRONG_THREAD:
|
||||
WARN("Cannot synchronize buffer lock due to a thread conflict\n");
|
||||
goto drop_query;
|
||||
|
||||
default:
|
||||
ERR("wined3d_event_query_finish returned %u, dropping async buffer locks\n", ret);
|
||||
goto drop_query;
|
||||
}
|
||||
|
||||
drop_query:
|
||||
if(This->query)
|
||||
{
|
||||
wined3d_event_query_destroy(This->query);
|
||||
This->query = NULL;
|
||||
}
|
||||
|
||||
wglFinish();
|
||||
ENTER_GL();
|
||||
GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE));
|
||||
checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE)");
|
||||
LEAVE_GL();
|
||||
This->flags &= ~WINED3D_BUFFER_APPLESYNC;
|
||||
}
|
||||
|
||||
|
@ -826,7 +876,9 @@ static void buffer_direct_upload(struct wined3d_buffer *This, const struct wined
|
|||
DWORD syncflags = 0;
|
||||
if (flags & WINED3D_BUFFER_DISCARD) syncflags |= WINED3DLOCK_DISCARD;
|
||||
if (flags & WINED3D_BUFFER_NOSYNC) syncflags |= WINED3DLOCK_NOOVERWRITE;
|
||||
buffer_sync_apple(This, syncflags);
|
||||
LEAVE_GL();
|
||||
buffer_sync_apple(This, syncflags, gl_info);
|
||||
ENTER_GL();
|
||||
}
|
||||
map = GL_EXTCALL(glMapBufferARB(This->buffer_type_hint, GL_WRITE_ONLY_ARB));
|
||||
checkGLcall("glMapBufferARB");
|
||||
|
@ -1216,7 +1268,12 @@ static HRESULT STDMETHODCALLTYPE buffer_Map(IWineD3DBuffer *iface, UINT offset,
|
|||
}
|
||||
else
|
||||
{
|
||||
if(This->flags & WINED3D_BUFFER_APPLESYNC) buffer_sync_apple(This, flags);
|
||||
if(This->flags & WINED3D_BUFFER_APPLESYNC)
|
||||
{
|
||||
LEAVE_GL();
|
||||
buffer_sync_apple(This, flags, gl_info);
|
||||
ENTER_GL();
|
||||
}
|
||||
This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(This->buffer_type_hint, GL_READ_WRITE_ARB));
|
||||
checkGLcall("glMapBufferARB");
|
||||
}
|
||||
|
|
|
@ -305,6 +305,7 @@ void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
|
|||
}
|
||||
}
|
||||
|
||||
This->num_buffer_queries = 0;
|
||||
if (!This->stateBlock->streamIsUP)
|
||||
{
|
||||
WORD map = stream_info->use_map;
|
||||
|
@ -314,6 +315,7 @@ void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
|
|||
{
|
||||
struct wined3d_stream_info_element *element;
|
||||
struct wined3d_buffer *buffer;
|
||||
struct wined3d_event_query *query;
|
||||
|
||||
if (!(map & 1)) continue;
|
||||
|
||||
|
@ -327,6 +329,12 @@ void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
|
|||
element->buffer_object = 0;
|
||||
element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
|
||||
}
|
||||
|
||||
query = ((struct wined3d_buffer *) buffer)->query;
|
||||
if(query)
|
||||
{
|
||||
This->buffer_queries[This->num_buffer_queries++] = query;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -689,6 +689,11 @@ void drawPrimitive(IWineD3DDevice *iface, UINT index_count, UINT StartIdx, UINT
|
|||
/* Finished updating the screen, restore lock */
|
||||
LEAVE_GL();
|
||||
|
||||
for(i = 0; i < This->num_buffer_queries; i++)
|
||||
{
|
||||
wined3d_event_query_issue(This->buffer_queries[i], This);
|
||||
}
|
||||
|
||||
wglFlush(); /* Flush to ensure ordering across contexts. */
|
||||
|
||||
context_release(context);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
||||
#define GLINFO_LOCATION (*gl_info)
|
||||
|
||||
static HRESULT wined3d_event_query_init(const struct wined3d_gl_info *gl_info, struct wined3d_event_query **query)
|
||||
HRESULT wined3d_event_query_init(const struct wined3d_gl_info *gl_info, struct wined3d_event_query **query)
|
||||
{
|
||||
struct wined3d_event_query *ret;
|
||||
*query = NULL;
|
||||
|
@ -45,13 +45,13 @@ static HRESULT wined3d_event_query_init(const struct wined3d_gl_info *gl_info, s
|
|||
return WINED3D_OK;
|
||||
}
|
||||
|
||||
static void wined3d_event_query_destroy(struct wined3d_event_query *query)
|
||||
void wined3d_event_query_destroy(struct wined3d_event_query *query)
|
||||
{
|
||||
if (query->context) context_free_event_query(query);
|
||||
HeapFree(GetProcessHeap(), 0, query);
|
||||
}
|
||||
|
||||
static enum wined3d_event_query_result wined3d_event_query_test(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
|
||||
enum wined3d_event_query_result wined3d_event_query_test(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
|
||||
{
|
||||
struct wined3d_context *context;
|
||||
const struct wined3d_gl_info *gl_info;
|
||||
|
@ -125,7 +125,75 @@ static enum wined3d_event_query_result wined3d_event_query_test(struct wined3d_e
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void wined3d_event_query_issue(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
|
||||
enum wined3d_event_query_result wined3d_event_query_finish(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
|
||||
{
|
||||
struct wined3d_context *context;
|
||||
const struct wined3d_gl_info *gl_info;
|
||||
enum wined3d_event_query_result ret;
|
||||
|
||||
TRACE("(%p)\n", query);
|
||||
|
||||
if (!query->context)
|
||||
{
|
||||
TRACE("Query not started\n");
|
||||
return WINED3D_EVENT_QUERY_NOT_STARTED;
|
||||
}
|
||||
gl_info = query->context->gl_info;
|
||||
|
||||
if (query->context->tid != GetCurrentThreadId() && !gl_info->supported[ARB_SYNC])
|
||||
{
|
||||
/* A glFinish does not reliably wait for draws in other contexts. The caller has
|
||||
* to find its own way to cope with the thread switch
|
||||
*/
|
||||
WARN("Event query finished from wrong thread\n");
|
||||
return WINED3D_EVENT_QUERY_WRONG_THREAD;
|
||||
}
|
||||
|
||||
context = context_acquire(device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
|
||||
|
||||
ENTER_GL();
|
||||
if (gl_info->supported[ARB_SYNC])
|
||||
{
|
||||
GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, ~(GLuint64)0));
|
||||
checkGLcall("glClientWaitSync");
|
||||
|
||||
switch (gl_ret)
|
||||
{
|
||||
case GL_ALREADY_SIGNALED:
|
||||
case GL_CONDITION_SATISFIED:
|
||||
ret = WINED3D_EVENT_QUERY_OK;
|
||||
break;
|
||||
|
||||
/* We don't expect a timeout for a ~584 year wait */
|
||||
default:
|
||||
ERR("glClientWaitSync returned %#x.\n", gl_ret);
|
||||
ret = WINED3D_EVENT_QUERY_ERROR;
|
||||
}
|
||||
}
|
||||
else if (context->gl_info->supported[APPLE_FENCE])
|
||||
{
|
||||
GL_EXTCALL(glFinishFenceAPPLE(query->object.id));
|
||||
checkGLcall("glFinishFenceAPPLE");
|
||||
ret = WINED3D_EVENT_QUERY_OK;
|
||||
}
|
||||
else if (context->gl_info->supported[NV_FENCE])
|
||||
{
|
||||
GL_EXTCALL(glFinishFenceNV(query->object.id));
|
||||
checkGLcall("glFinishFenceNV");
|
||||
ret = WINED3D_EVENT_QUERY_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Event query created without GL support\n");
|
||||
ret = WINED3D_EVENT_QUERY_ERROR;
|
||||
}
|
||||
LEAVE_GL();
|
||||
|
||||
context_release(context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wined3d_event_query_issue(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
|
||||
{
|
||||
const struct wined3d_gl_info *gl_info;
|
||||
struct wined3d_context *context;
|
||||
|
|
|
@ -1033,6 +1033,12 @@ enum wined3d_event_query_result
|
|||
WINED3D_EVENT_QUERY_ERROR
|
||||
};
|
||||
|
||||
HRESULT wined3d_event_query_init(const struct wined3d_gl_info *gl_info, struct wined3d_event_query **query) DECLSPEC_HIDDEN;
|
||||
void wined3d_event_query_destroy(struct wined3d_event_query *query) DECLSPEC_HIDDEN;
|
||||
enum wined3d_event_query_result wined3d_event_query_test(struct wined3d_event_query *query, IWineD3DDeviceImpl *device) DECLSPEC_HIDDEN;
|
||||
enum wined3d_event_query_result wined3d_event_query_finish(struct wined3d_event_query *query, IWineD3DDeviceImpl *device) DECLSPEC_HIDDEN;
|
||||
void wined3d_event_query_issue(struct wined3d_event_query *query, IWineD3DDeviceImpl *device) DECLSPEC_HIDDEN;
|
||||
|
||||
struct wined3d_context
|
||||
{
|
||||
const struct wined3d_gl_info *gl_info;
|
||||
|
@ -1695,6 +1701,8 @@ struct IWineD3DDeviceImpl
|
|||
/* Stream source management */
|
||||
struct wined3d_stream_info strided_streams;
|
||||
const WineDirect3DVertexStridedData *up_strided;
|
||||
struct wined3d_event_query *buffer_queries[MAX_ATTRIBS];
|
||||
unsigned int num_buffer_queries;
|
||||
|
||||
/* Context management */
|
||||
struct wined3d_context **contexts;
|
||||
|
@ -2495,6 +2503,7 @@ struct wined3d_buffer
|
|||
LONG lock_count;
|
||||
struct wined3d_map_range *maps;
|
||||
ULONG maps_size, modified_areas;
|
||||
struct wined3d_event_query *query;
|
||||
|
||||
/* conversion stuff */
|
||||
UINT decl_change_count, full_conversion_count;
|
||||
|
|
Loading…
Reference in New Issue