Commit 1181762f authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: Implement manual buffer fencing.

parent fd13a6ae
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment