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();
|
LEAVE_GL();
|
||||||
This->buffer_object = 0;
|
This->buffer_object = 0;
|
||||||
|
|
||||||
|
if(This->query)
|
||||||
|
{
|
||||||
|
wined3d_event_query_destroy(This->query);
|
||||||
|
This->query = NULL;
|
||||||
|
}
|
||||||
This->flags &= ~WINED3D_BUFFER_APPLESYNC;
|
This->flags &= ~WINED3D_BUFFER_APPLESYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,23 +779,68 @@ static DWORD STDMETHODCALLTYPE buffer_GetPriority(IWineD3DBuffer *iface)
|
||||||
return resource_get_priority((IWineD3DResource *)iface);
|
return resource_get_priority((IWineD3DResource *)iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The caller provides a context and GL locking and binds the buffer */
|
/* The caller provides a context and binds the buffer */
|
||||||
static void buffer_sync_apple(struct wined3d_buffer *This, DWORD flags)
|
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
|
/* No fencing needs to be done if the app promises not to overwrite
|
||||||
* existing data */
|
* existing data */
|
||||||
if(flags & WINED3DLOCK_NOOVERWRITE) return;
|
if(flags & WINED3DLOCK_NOOVERWRITE) return;
|
||||||
if(flags & WINED3DLOCK_DISCARD)
|
if(flags & WINED3DLOCK_DISCARD)
|
||||||
{
|
{
|
||||||
|
ENTER_GL();
|
||||||
GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, This->resource.size, NULL, This->buffer_object_usage));
|
GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, This->resource.size, NULL, This->buffer_object_usage));
|
||||||
checkGLcall("glBufferDataARB\n");
|
checkGLcall("glBufferDataARB\n");
|
||||||
|
LEAVE_GL();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop the unserialized updates for now */
|
if(!This->query)
|
||||||
FIXME("Implement fences for unserialized buffers\n");
|
{
|
||||||
|
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));
|
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)");
|
checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE)");
|
||||||
|
LEAVE_GL();
|
||||||
This->flags &= ~WINED3D_BUFFER_APPLESYNC;
|
This->flags &= ~WINED3D_BUFFER_APPLESYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,7 +876,9 @@ static void buffer_direct_upload(struct wined3d_buffer *This, const struct wined
|
||||||
DWORD syncflags = 0;
|
DWORD syncflags = 0;
|
||||||
if (flags & WINED3D_BUFFER_DISCARD) syncflags |= WINED3DLOCK_DISCARD;
|
if (flags & WINED3D_BUFFER_DISCARD) syncflags |= WINED3DLOCK_DISCARD;
|
||||||
if (flags & WINED3D_BUFFER_NOSYNC) syncflags |= WINED3DLOCK_NOOVERWRITE;
|
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));
|
map = GL_EXTCALL(glMapBufferARB(This->buffer_type_hint, GL_WRITE_ONLY_ARB));
|
||||||
checkGLcall("glMapBufferARB");
|
checkGLcall("glMapBufferARB");
|
||||||
|
@ -1216,7 +1268,12 @@ static HRESULT STDMETHODCALLTYPE buffer_Map(IWineD3DBuffer *iface, UINT offset,
|
||||||
}
|
}
|
||||||
else
|
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));
|
This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(This->buffer_type_hint, GL_READ_WRITE_ARB));
|
||||||
checkGLcall("glMapBufferARB");
|
checkGLcall("glMapBufferARB");
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,7 @@ void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
This->num_buffer_queries = 0;
|
||||||
if (!This->stateBlock->streamIsUP)
|
if (!This->stateBlock->streamIsUP)
|
||||||
{
|
{
|
||||||
WORD map = stream_info->use_map;
|
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_stream_info_element *element;
|
||||||
struct wined3d_buffer *buffer;
|
struct wined3d_buffer *buffer;
|
||||||
|
struct wined3d_event_query *query;
|
||||||
|
|
||||||
if (!(map & 1)) continue;
|
if (!(map & 1)) continue;
|
||||||
|
|
||||||
|
@ -327,6 +329,12 @@ void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
|
||||||
element->buffer_object = 0;
|
element->buffer_object = 0;
|
||||||
element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
|
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 */
|
/* Finished updating the screen, restore lock */
|
||||||
LEAVE_GL();
|
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. */
|
wglFlush(); /* Flush to ensure ordering across contexts. */
|
||||||
|
|
||||||
context_release(context);
|
context_release(context);
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
|
||||||
#define GLINFO_LOCATION (*gl_info)
|
#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;
|
struct wined3d_event_query *ret;
|
||||||
*query = NULL;
|
*query = NULL;
|
||||||
|
@ -45,13 +45,13 @@ static HRESULT wined3d_event_query_init(const struct wined3d_gl_info *gl_info, s
|
||||||
return WINED3D_OK;
|
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);
|
if (query->context) context_free_event_query(query);
|
||||||
HeapFree(GetProcessHeap(), 0, 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;
|
struct wined3d_context *context;
|
||||||
const struct wined3d_gl_info *gl_info;
|
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;
|
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;
|
const struct wined3d_gl_info *gl_info;
|
||||||
struct wined3d_context *context;
|
struct wined3d_context *context;
|
||||||
|
|
|
@ -1033,6 +1033,12 @@ enum wined3d_event_query_result
|
||||||
WINED3D_EVENT_QUERY_ERROR
|
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
|
struct wined3d_context
|
||||||
{
|
{
|
||||||
const struct wined3d_gl_info *gl_info;
|
const struct wined3d_gl_info *gl_info;
|
||||||
|
@ -1695,6 +1701,8 @@ struct IWineD3DDeviceImpl
|
||||||
/* Stream source management */
|
/* Stream source management */
|
||||||
struct wined3d_stream_info strided_streams;
|
struct wined3d_stream_info strided_streams;
|
||||||
const WineDirect3DVertexStridedData *up_strided;
|
const WineDirect3DVertexStridedData *up_strided;
|
||||||
|
struct wined3d_event_query *buffer_queries[MAX_ATTRIBS];
|
||||||
|
unsigned int num_buffer_queries;
|
||||||
|
|
||||||
/* Context management */
|
/* Context management */
|
||||||
struct wined3d_context **contexts;
|
struct wined3d_context **contexts;
|
||||||
|
@ -2495,6 +2503,7 @@ struct wined3d_buffer
|
||||||
LONG lock_count;
|
LONG lock_count;
|
||||||
struct wined3d_map_range *maps;
|
struct wined3d_map_range *maps;
|
||||||
ULONG maps_size, modified_areas;
|
ULONG maps_size, modified_areas;
|
||||||
|
struct wined3d_event_query *query;
|
||||||
|
|
||||||
/* conversion stuff */
|
/* conversion stuff */
|
||||||
UINT decl_change_count, full_conversion_count;
|
UINT decl_change_count, full_conversion_count;
|
||||||
|
|
Loading…
Reference in New Issue