From 12755257898e72cf47798b467a5467fef56eed9e Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Mon, 17 Feb 2014 14:46:01 +0200 Subject: [PATCH] wined3d: Use an rbtree for storing shaders for texture format conversion/blitting. --- dlls/wined3d/arb_program_shader.c | 183 +++++++++++++++++------------- 1 file changed, 107 insertions(+), 76 deletions(-) diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 93a6e3117e1..d7e9ef76428 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -6768,22 +6768,72 @@ const struct fragment_pipeline arbfp_fragment_pipeline = { arbfp_fragmentstate_template, }; -struct arbfp_blit_priv { - GLenum yuy2_rect_shader, yuy2_2d_shader; - GLenum uyvy_rect_shader, uyvy_2d_shader; - GLenum yv12_rect_shader, yv12_2d_shader; - GLenum nv12_rect_shader, nv12_2d_shader; - GLenum p8_rect_shader, p8_2d_shader; +struct arbfp_blit_type +{ + enum complex_fixup fixup; + GLenum textype; +}; + +struct arbfp_blit_desc +{ + GLenum shader; + struct arbfp_blit_type type; + struct wine_rb_entry entry; +}; + +struct arbfp_blit_priv +{ + struct wine_rb_tree shaders; GLuint palette_texture; }; +static int arbfp_blit_type_compare(const void *key, const struct wine_rb_entry *entry) +{ + const struct arbfp_blit_type *ka = key; + const struct arbfp_blit_type *kb = &WINE_RB_ENTRY_VALUE(entry, const struct arbfp_blit_desc, entry)->type; + + if (ka->fixup != kb->fixup) + return ka->fixup < kb->fixup ? -1 : 1; + if (ka->textype != kb->textype) + return ka->textype < kb->textype ? -1 : 1; + return 0; +} + +/* Context activation is done by the caller. */ +static void arbfp_free_blit_shader(struct wine_rb_entry *entry, void *context) +{ + const struct wined3d_gl_info *gl_info = context; + struct arbfp_blit_desc *entry_arb = WINE_RB_ENTRY_VALUE(entry, struct arbfp_blit_desc, entry); + + GL_EXTCALL(glDeleteProgramsARB(1, &entry_arb->shader)); + checkGLcall("glDeleteProgramsARB(1, &entry_arb->shader)"); + HeapFree(GetProcessHeap(), 0, entry_arb); +} + +const struct wine_rb_functions wined3d_arbfp_blit_rb_functions = +{ + wined3d_rb_alloc, + wined3d_rb_realloc, + wined3d_rb_free, + arbfp_blit_type_compare, +}; + static HRESULT arbfp_blit_alloc(struct wined3d_device *device) { - device->blit_priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct arbfp_blit_priv)); - if(!device->blit_priv) { - ERR("Out of memory\n"); + struct arbfp_blit_priv *priv; + + if (!(priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*priv)))) + return E_OUTOFMEMORY; + + if (wine_rb_init(&priv->shaders, &wined3d_arbfp_blit_rb_functions) == -1) + { + ERR("Failed to initialize rbtree.\n"); + HeapFree(GetProcessHeap(), 0, priv); return E_OUTOFMEMORY; } + + device->blit_priv = priv; + return WINED3D_OK; } @@ -6793,17 +6843,8 @@ static void arbfp_blit_free(struct wined3d_device *device) const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; struct arbfp_blit_priv *priv = device->blit_priv; - GL_EXTCALL(glDeleteProgramsARB(1, &priv->yuy2_rect_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->yuy2_2d_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->uyvy_rect_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->uyvy_2d_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->yv12_rect_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->yv12_2d_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->nv12_rect_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->nv12_2d_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->p8_rect_shader)); - GL_EXTCALL(glDeleteProgramsARB(1, &priv->p8_2d_shader)); - checkGLcall("Delete yuv and p8 programs"); + wine_rb_destroy(&priv->shaders, arbfp_free_blit_shader, &device->adapter->gl_info); + checkGLcall("Delete blit programs"); if (priv->palette_texture) gl_info->gl_ops.gl.p_glDeleteTextures(1, &priv->palette_texture); @@ -7196,6 +7237,7 @@ static BOOL gen_nv12_read(struct wined3d_shader_buffer *buffer, GLenum textype, return TRUE; } +/* Context activation is done by the caller. */ static GLuint gen_p8_shader(struct arbfp_blit_priv *priv, const struct wined3d_gl_info *gl_info, GLenum textype) { @@ -7249,11 +7291,6 @@ static GLuint gen_p8_shader(struct arbfp_blit_priv *priv, shader_arb_dump_program_source(buffer.buffer); } - if (textype == GL_TEXTURE_RECTANGLE_ARB) - priv->p8_rect_shader = shader; - else - priv->p8_2d_shader = shader; - shader_buffer_free(&buffer); return shader; @@ -7428,33 +7465,6 @@ static GLuint gen_yuv_shader(struct arbfp_blit_priv *priv, const struct wined3d_ shader_buffer_free(&buffer); - switch (yuv_fixup) - { - case COMPLEX_FIXUP_YUY2: - if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->yuy2_rect_shader = shader; - else priv->yuy2_2d_shader = shader; - break; - - case COMPLEX_FIXUP_UYVY: - if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->uyvy_rect_shader = shader; - else priv->uyvy_2d_shader = shader; - break; - - case COMPLEX_FIXUP_YV12: - if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->yv12_rect_shader = shader; - else priv->yv12_2d_shader = shader; - break; - - case COMPLEX_FIXUP_NV12: - if (textype == GL_TEXTURE_RECTANGLE_ARB) - priv->nv12_rect_shader = shader; - else - priv->nv12_2d_shader = shader; - break; - default: - ERR("Unsupported complex fixup: %d\n", yuv_fixup); - } - return shader; } @@ -7467,6 +7477,9 @@ static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context, enum complex_fixup fixup; const struct wined3d_gl_info *gl_info = context->gl_info; GLenum textype = surface->container->target; + struct wine_rb_entry *entry; + struct arbfp_blit_type type; + struct arbfp_blit_desc *desc; if (surface->flags & SFLAG_CONVERTED) { @@ -7487,39 +7500,57 @@ static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context, fixup = get_complex_fixup(surface->resource.format->color_fixup); - switch(fixup) + type.fixup = fixup; + type.textype = textype; + entry = wine_rb_get(&priv->shaders, &type); + if (entry) { - case COMPLEX_FIXUP_YUY2: - shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->yuy2_rect_shader : priv->yuy2_2d_shader; - break; + desc = WINE_RB_ENTRY_VALUE(entry, struct arbfp_blit_desc, entry); + shader = desc->shader; + } + else + { + switch (fixup) + { + case COMPLEX_FIXUP_P8: + shader = gen_p8_shader(priv, gl_info, textype); + break; - case COMPLEX_FIXUP_UYVY: - shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->uyvy_rect_shader : priv->uyvy_2d_shader; - break; + default: + shader = gen_yuv_shader(priv, gl_info, fixup, textype); + break; + } - case COMPLEX_FIXUP_YV12: - shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->yv12_rect_shader : priv->yv12_2d_shader; - break; - - case COMPLEX_FIXUP_NV12: - shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->nv12_rect_shader : priv->nv12_2d_shader; - break; - - case COMPLEX_FIXUP_P8: - shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->p8_rect_shader : priv->p8_2d_shader; - if (!shader) shader = gen_p8_shader(priv, gl_info, textype); - - upload_palette(surface, context); - break; - - default: + if (!shader) + { FIXME("Unsupported complex fixup %#x, not setting a shader\n", fixup); gl_info->gl_ops.gl.p_glEnable(textype); checkGLcall("glEnable(textype)"); return E_NOTIMPL; + } + + desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*desc)); + if (!desc) + goto err_out; + + desc->type.textype = textype; + desc->type.fixup = fixup; + desc->shader = shader; + if (wine_rb_put(&priv->shaders, &desc->type, &desc->entry) == -1) + { +err_out: + ERR("Out of memory\n"); + GL_EXTCALL(glDeleteProgramsARB(1, &shader)); + checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &shader))"); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0)); + checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0)"); + HeapFree(GetProcessHeap(), 0, desc); + return E_OUTOFMEMORY; + } } - if (!shader) shader = gen_yuv_shader(priv, gl_info, fixup, textype); + if (fixup == COMPLEX_FIXUP_P8) + upload_palette(surface, context); gl_info->gl_ops.gl.p_glEnable(GL_FRAGMENT_PROGRAM_ARB); checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)");