wined3d: Create a FBO for each combination of render targets and depth stencil.
The main reason for this change is crappy performance for reconfiguring FBOs.
This commit is contained in:
parent
3a8ab00fe1
commit
45820046e8
|
@ -194,14 +194,14 @@ static void context_check_fbo_status(IWineD3DDevice *iface)
|
|||
/* Dump the FBO attachments */
|
||||
for (i = 0; i < GL_LIMITS(buffers); ++i)
|
||||
{
|
||||
attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_color_attachments[i];
|
||||
attachment = (IWineD3DSurfaceImpl *)This->activeContext->current_fbo->render_targets[i];
|
||||
if (attachment)
|
||||
{
|
||||
FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
|
||||
attachment->pow2Width, attachment->pow2Height);
|
||||
}
|
||||
}
|
||||
attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_depth_attachment;
|
||||
attachment = (IWineD3DSurfaceImpl *)This->activeContext->current_fbo->depth_stencil;
|
||||
if (attachment)
|
||||
{
|
||||
FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
|
||||
|
@ -210,67 +210,109 @@ static void context_check_fbo_status(IWineD3DDevice *iface)
|
|||
}
|
||||
}
|
||||
|
||||
static BOOL context_depth_mismatch_fbo(IWineD3DDevice *iface)
|
||||
static struct fbo_entry *context_create_fbo_entry(IWineD3DDevice *iface)
|
||||
{
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
|
||||
IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
|
||||
struct fbo_entry *entry;
|
||||
|
||||
if (!ds_impl) return FALSE;
|
||||
entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
|
||||
entry->render_targets = HeapAlloc(GetProcessHeap(), 0, GL_LIMITS(buffers) * sizeof(*entry->render_targets));
|
||||
memcpy(entry->render_targets, This->render_targets, GL_LIMITS(buffers) * sizeof(*entry->render_targets));
|
||||
entry->depth_stencil = This->stencilBufferTarget;
|
||||
entry->attached = FALSE;
|
||||
entry->id = 0;
|
||||
|
||||
if (ds_impl->current_renderbuffer)
|
||||
{
|
||||
return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
|
||||
rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
|
||||
}
|
||||
|
||||
return (rt_impl->pow2Width != ds_impl->pow2Width ||
|
||||
rt_impl->pow2Height != ds_impl->pow2Height);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void context_apply_fbo_state(IWineD3DDevice *iface)
|
||||
void context_destroy_fbo_entry(IWineD3DDeviceImpl *This, struct fbo_entry *entry)
|
||||
{
|
||||
if (entry->id)
|
||||
{
|
||||
TRACE("Destroy FBO %d\n", entry->id);
|
||||
context_destroy_fbo(This, &entry->id);
|
||||
}
|
||||
list_remove(&entry->entry);
|
||||
HeapFree(GetProcessHeap(), 0, entry->render_targets);
|
||||
HeapFree(GetProcessHeap(), 0, entry);
|
||||
}
|
||||
|
||||
|
||||
static struct fbo_entry *context_find_fbo_entry(IWineD3DDevice *iface, WineD3DContext *context)
|
||||
{
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
struct fbo_entry *entry;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
|
||||
{
|
||||
if (!memcmp(entry->render_targets, This->render_targets, GL_LIMITS(buffers) * sizeof(*entry->render_targets))
|
||||
&& entry->depth_stencil == This->stencilBufferTarget)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
entry = context_create_fbo_entry(iface);
|
||||
list_add_head(&context->fbo_list, &entry->entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void context_apply_fbo_entry(IWineD3DDevice *iface, struct fbo_entry *entry)
|
||||
{
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
WineD3DContext *context = This->activeContext;
|
||||
unsigned int i;
|
||||
|
||||
if (This->render_offscreen)
|
||||
{
|
||||
context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &context->fbo);
|
||||
context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &entry->id);
|
||||
|
||||
if (!entry->attached)
|
||||
{
|
||||
/* Apply render targets */
|
||||
for (i = 0; i < GL_LIMITS(buffers); ++i)
|
||||
{
|
||||
IWineD3DSurface *render_target = This->render_targets[i];
|
||||
if (context->fbo_color_attachments[i] != render_target)
|
||||
{
|
||||
context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, i, render_target);
|
||||
context->fbo_color_attachments[i] = render_target;
|
||||
}
|
||||
context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, i, render_target);
|
||||
}
|
||||
|
||||
/* Apply depth targets */
|
||||
if (context->fbo_depth_attachment != This->stencilBufferTarget || context_depth_mismatch_fbo(iface))
|
||||
{
|
||||
if (This->stencilBufferTarget) {
|
||||
unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
|
||||
unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
|
||||
|
||||
if (This->stencilBufferTarget)
|
||||
{
|
||||
surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
|
||||
}
|
||||
context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, This->stencilBufferTarget, TRUE);
|
||||
context->fbo_depth_attachment = This->stencilBufferTarget;
|
||||
surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
|
||||
}
|
||||
context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, This->stencilBufferTarget, TRUE);
|
||||
|
||||
entry->attached = TRUE;
|
||||
} else {
|
||||
for (i = 0; i < GL_LIMITS(buffers); ++i)
|
||||
{
|
||||
if (This->render_targets[i])
|
||||
This->draw_buffers[i] = GL_COLOR_ATTACHMENT0_EXT + i;
|
||||
else
|
||||
This->draw_buffers[i] = GL_NONE;
|
||||
context_apply_attachment_filter_states(iface, This->render_targets[i], FALSE);
|
||||
}
|
||||
if (This->stencilBufferTarget)
|
||||
context_apply_attachment_filter_states(iface, This->stencilBufferTarget, FALSE);
|
||||
}
|
||||
|
||||
for (i = 0; i < GL_LIMITS(buffers); ++i)
|
||||
{
|
||||
if (This->render_targets[i])
|
||||
This->draw_buffers[i] = GL_COLOR_ATTACHMENT0_EXT + i;
|
||||
else
|
||||
This->draw_buffers[i] = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void context_apply_fbo_state(IWineD3DDevice *iface)
|
||||
{
|
||||
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
|
||||
WineD3DContext *context = This->activeContext;
|
||||
|
||||
if (This->render_offscreen)
|
||||
{
|
||||
context->current_fbo = context_find_fbo_entry(iface, context);
|
||||
context_apply_fbo_entry(iface, context->current_fbo);
|
||||
} else {
|
||||
context->current_fbo = NULL;
|
||||
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
}
|
||||
|
||||
|
@ -726,12 +768,7 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
|
|||
|
||||
TRACE("Successfully created new context %p\n", ret);
|
||||
|
||||
ret->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
|
||||
if (!ret->fbo_color_attachments)
|
||||
{
|
||||
ERR("Out of memory!\n");
|
||||
goto out;
|
||||
}
|
||||
list_init(&ret->fbo_list);
|
||||
|
||||
/* Set up the context defaults */
|
||||
oldCtx = pwglGetCurrentContext();
|
||||
|
@ -827,7 +864,6 @@ WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *tar
|
|||
return ret;
|
||||
|
||||
out:
|
||||
HeapFree(GetProcessHeap(), 0, ret->fbo_color_attachments);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -884,6 +920,7 @@ static void RemoveContextFromArray(IWineD3DDeviceImpl *This, WineD3DContext *con
|
|||
*
|
||||
*****************************************************************************/
|
||||
void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) {
|
||||
struct fbo_entry *entry, *entry2;
|
||||
|
||||
TRACE("Destroying ctx %p\n", context);
|
||||
|
||||
|
@ -895,9 +932,8 @@ void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) {
|
|||
|
||||
ENTER_GL();
|
||||
|
||||
if (context->fbo) {
|
||||
TRACE("Destroy FBO %d\n", context->fbo);
|
||||
context_destroy_fbo(This, &context->fbo);
|
||||
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry) {
|
||||
context_destroy_fbo_entry(This, entry);
|
||||
}
|
||||
if (context->src_fbo) {
|
||||
TRACE("Destroy src FBO %d\n", context->src_fbo);
|
||||
|
@ -910,9 +946,6 @@ void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) {
|
|||
|
||||
LEAVE_GL();
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, context->fbo_color_attachments);
|
||||
context->fbo_color_attachments = NULL;
|
||||
|
||||
/* Cleanup the GL context */
|
||||
pwglMakeCurrent(NULL, NULL);
|
||||
if(context->isPBuffer) {
|
||||
|
|
|
@ -6174,8 +6174,8 @@ static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONS
|
|||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
checkGLcall("glClear");
|
||||
|
||||
if (This->render_offscreen) {
|
||||
context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
|
||||
if (This->activeContext->current_fbo) {
|
||||
context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
|
||||
} else {
|
||||
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
checkGLcall("glBindFramebuffer()");
|
||||
|
@ -6567,8 +6567,8 @@ void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED
|
|||
|
||||
IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
|
||||
|
||||
if (This->render_offscreen) {
|
||||
context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
|
||||
if (This->activeContext->current_fbo) {
|
||||
context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
|
||||
} else {
|
||||
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
checkGLcall("glBindFramebuffer()");
|
||||
|
@ -7376,14 +7376,20 @@ static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IW
|
|||
}
|
||||
|
||||
for (i = 0; i < This->numContexts; ++i) {
|
||||
struct fbo_entry *entry, *entry2;
|
||||
int j;
|
||||
for (j = 0; j < GL_LIMITS(buffers); ++j) {
|
||||
if (This->contexts[i]->fbo_color_attachments[j] == (IWineD3DSurface *)resource) {
|
||||
This->contexts[i]->fbo_color_attachments[j] = NULL;
|
||||
|
||||
LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->contexts[i]->fbo_list, struct fbo_entry, entry) {
|
||||
BOOL destroyed = FALSE;
|
||||
for (j = 0; !destroyed && j < GL_LIMITS(buffers); ++j) {
|
||||
if (entry->render_targets[j] == (IWineD3DSurface *)resource) {
|
||||
context_destroy_fbo_entry(This, entry);
|
||||
destroyed = TRUE;
|
||||
}
|
||||
}
|
||||
if (!destroyed && entry->depth_stencil == (IWineD3DSurface *)resource) {
|
||||
context_destroy_fbo_entry(This, entry);
|
||||
}
|
||||
}
|
||||
if (This->contexts[i]->fbo_depth_attachment == (IWineD3DSurface *)resource) {
|
||||
This->contexts[i]->fbo_depth_attachment = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4004,8 +4004,8 @@ void surface_load_ds_location(IWineD3DSurface *iface, DWORD location) {
|
|||
depth_blt((IWineD3DDevice *)device, device->depth_blt_texture, This->currentDesc.Width, This->currentDesc.Height);
|
||||
checkGLcall("depth_blt");
|
||||
|
||||
if (device->render_offscreen) {
|
||||
context_bind_fbo((IWineD3DDevice *)device, GL_FRAMEBUFFER_EXT, &device->activeContext->fbo);
|
||||
if (device->activeContext->current_fbo) {
|
||||
context_bind_fbo((IWineD3DDevice *)device, GL_FRAMEBUFFER_EXT, &device->activeContext->current_fbo->id);
|
||||
} else {
|
||||
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
checkGLcall("glBindFramebuffer()");
|
||||
|
@ -4026,8 +4026,8 @@ void surface_load_ds_location(IWineD3DSurface *iface, DWORD location) {
|
|||
depth_blt((IWineD3DDevice *)device, This->glDescription.textureName, This->currentDesc.Width, This->currentDesc.Height);
|
||||
checkGLcall("depth_blt");
|
||||
|
||||
if (device->render_offscreen) {
|
||||
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, device->activeContext->fbo));
|
||||
if (device->activeContext->current_fbo) {
|
||||
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, device->activeContext->current_fbo->id));
|
||||
checkGLcall("glBindFramebuffer()");
|
||||
}
|
||||
|
||||
|
|
|
@ -613,9 +613,8 @@ struct WineD3DContext {
|
|||
GLint aux_buffers;
|
||||
|
||||
/* FBOs */
|
||||
IWineD3DSurface **fbo_color_attachments;
|
||||
IWineD3DSurface *fbo_depth_attachment;
|
||||
GLuint fbo;
|
||||
struct list fbo_list;
|
||||
struct fbo_entry *current_fbo;
|
||||
GLuint src_fbo;
|
||||
GLuint dst_fbo;
|
||||
};
|
||||
|
@ -1260,6 +1259,15 @@ typedef struct {
|
|||
UINT height;
|
||||
} renderbuffer_entry_t;
|
||||
|
||||
struct fbo_entry
|
||||
{
|
||||
struct list entry;
|
||||
IWineD3DSurface **render_targets;
|
||||
IWineD3DSurface *depth_stencil;
|
||||
BOOL attached;
|
||||
GLuint id;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* IWineD3DClipp implementation structure
|
||||
*/
|
||||
|
@ -2435,4 +2443,5 @@ void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED
|
|||
IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip);
|
||||
void depth_blt(IWineD3DDevice *iface, GLuint texture, GLsizei w, GLsizei h);
|
||||
|
||||
void context_destroy_fbo_entry(IWineD3DDeviceImpl *This, struct fbo_entry *entry);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue