[PATCH 3/5] wined3d: Temporarily remove surface PBO support.

Stefan Dösinger stefan at codeweavers.com
Sat Nov 23 17:18:58 CST 2013


The implementation is strange and fairly ineffective in doing what PBOs
are supposed to do - avoiding pipeline stalls and redundant copying.
Removing it will make restructuring surfaces easier and avoid temporary
regressions. It will be re-added later.
---
 dlls/wined3d/surface.c         | 266 +++--------------------------------------
 dlls/wined3d/wined3d_private.h |  19 ++-
 2 files changed, 25 insertions(+), 260 deletions(-)

diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index f456bb9..f6aa7ee 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -42,8 +42,7 @@ static void surface_cleanup(struct wined3d_surface *surface)
 
     TRACE("surface %p.\n", surface);
 
-    if ((surface->flags & SFLAG_PBO) || surface->rb_multisample
-            || surface->rb_resolved || !list_empty(&surface->renderbuffers))
+    if (surface->rb_multisample || surface->rb_resolved || !list_empty(&surface->renderbuffers))
     {
         struct wined3d_renderbuffer_entry *entry, *entry2;
         const struct wined3d_gl_info *gl_info;
@@ -52,12 +51,6 @@ static void surface_cleanup(struct wined3d_surface *surface)
         context = context_acquire(surface->resource.device, NULL);
         gl_info = context->gl_info;
 
-        if (surface->flags & SFLAG_PBO)
-        {
-            TRACE("Deleting PBO %u.\n", surface->pbo);
-            GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
-        }
-
         if (surface->rb_multisample)
         {
             TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
@@ -517,70 +510,20 @@ static HRESULT surface_create_dib_section(struct wined3d_surface *surface)
     return WINED3D_OK;
 }
 
-static BOOL surface_need_pbo(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
-{
-    if (surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
-        return FALSE;
-    if (!(surface->flags & SFLAG_DYNLOCK))
-        return FALSE;
-    if (surface->flags & (SFLAG_CONVERTED | SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM))
-        return FALSE;
-    if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT])
-        return FALSE;
-
-    return TRUE;
-}
-
-static void surface_load_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
-{
-    struct wined3d_context *context;
-    GLenum error;
-
-    context = context_acquire(surface->resource.device, NULL);
-
-    GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
-    error = gl_info->gl_ops.gl.p_glGetError();
-    if (!surface->pbo || error != GL_NO_ERROR)
-        ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
-
-    TRACE("Binding PBO %u.\n", surface->pbo);
-
-    GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
-    checkGLcall("glBindBufferARB");
-
-    GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
-            surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
-    checkGLcall("glBufferDataARB");
-
-    GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
-    checkGLcall("glBindBufferARB");
-
-    /* We don't need the system memory anymore and we can't even use it for PBOs. */
-    if (!(surface->flags & SFLAG_CLIENT))
-        wined3d_resource_free_sysmem(&surface->resource);
-    surface->resource.allocatedMemory = NULL;
-    surface->flags |= SFLAG_PBO;
-    context_release(context);
-}
-
 static void surface_prepare_system_memory(struct wined3d_surface *surface)
 {
-    const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
-
     TRACE("surface %p.\n", surface);
 
-    if (!(surface->flags & SFLAG_PBO) && surface_need_pbo(surface, gl_info))
-        surface_load_pbo(surface, gl_info);
-    else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO))
+    if (!surface->resource.allocatedMemory)
     {
         /* Whatever surface we have, make sure that there is memory allocated
-         * for the downloaded copy, or a PBO to map. */
+         * for the downloaded copy. */
         if (!surface->resource.heap_memory && !wined3d_resource_allocate_sysmem(&surface->resource))
             ERR("Failed to allocate system memory.\n");
         surface->resource.allocatedMemory = surface->resource.heap_memory;
 
         if (surface->flags & SFLAG_INSYSMEM)
-            ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
+            ERR("Surface without memory has SFLAG_INSYSMEM set.\n");
     }
 }
 
@@ -769,8 +712,6 @@ static void surface_realize_palette(struct wined3d_surface *surface)
 
 static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
 {
-    struct wined3d_device *device = surface->resource.device;
-
     TRACE("surface %p, rect %s, flags %#x.\n",
             surface, wine_dbgstr_rect(rect), flags);
 
@@ -789,64 +730,16 @@ static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD
         surface_load_location(surface, SFLAG_INSYSMEM);
     }
 
-    if (surface->flags & SFLAG_PBO)
-    {
-        const struct wined3d_gl_info *gl_info;
-        struct wined3d_context *context;
-
-        context = context_acquire(device, NULL);
-        gl_info = context->gl_info;
-
-        GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
-        checkGLcall("glBindBufferARB");
-
-        /* This shouldn't happen but could occur if some other function
-         * didn't handle the PBO properly. */
-        if (surface->resource.allocatedMemory)
-            ERR("The surface already has PBO memory allocated.\n");
-
-        surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
-        checkGLcall("glMapBufferARB");
-
-        /* Make sure the PBO isn't set anymore in order not to break non-PBO
-         * calls. */
-        GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
-        checkGLcall("glBindBufferARB");
-
-        context_release(context);
-    }
-
     if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
         surface_set_dirty(surface);
 }
 
 static void surface_unmap(struct wined3d_surface *surface)
 {
-    struct wined3d_device *device = surface->resource.device;
-
     TRACE("surface %p.\n", surface);
 
     memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
 
-    if (surface->flags & SFLAG_PBO)
-    {
-        const struct wined3d_gl_info *gl_info;
-        struct wined3d_context *context;
-
-        TRACE("Freeing PBO memory.\n");
-
-        context = context_acquire(device, NULL);
-        gl_info = context->gl_info;
-
-        GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
-        GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
-        GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
-        checkGLcall("glUnmapBufferARB");
-        context_release(context);
-
-        surface->resource.allocatedMemory = NULL;
-    }
-
     TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
 
     if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
@@ -1252,36 +1145,6 @@ HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *sur
     return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT);
 }
 
-/* Context activation is done by the caller. */
-static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
-{
-    if (surface->flags & SFLAG_DIBSECTION)
-    {
-        surface->resource.allocatedMemory = surface->dib.bitmap_data;
-    }
-    else
-    {
-        if (!surface->resource.heap_memory)
-            wined3d_resource_allocate_sysmem(&surface->resource);
-        else if (!(surface->flags & SFLAG_CLIENT))
-            ERR("Surface %p has heap_memory %p and flags %#x.\n",
-                    surface, surface->resource.heap_memory, surface->flags);
-
-        surface->resource.allocatedMemory = surface->resource.heap_memory;
-    }
-
-    GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
-    checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
-    GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
-            surface->resource.size, surface->resource.allocatedMemory));
-    checkGLcall("glGetBufferSubDataARB");
-    GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
-    checkGLcall("glDeleteBuffersARB");
-
-    surface->pbo = 0;
-    surface->flags &= ~SFLAG_PBO;
-}
-
 static BOOL surface_init_sysmem(struct wined3d_surface *surface)
 {
     if (!surface->resource.allocatedMemory)
@@ -1335,8 +1198,8 @@ static void surface_unload(struct wined3d_resource *resource)
          * or the depth stencil into an FBO the texture or render buffer will be removed
          * and all flags get lost
          */
-        if (!(surface->flags & SFLAG_PBO))
-            surface_init_sysmem(surface);
+        surface_init_sysmem(surface);
+
         /* We also get here when the ddraw swapchain is destroyed, for example
          * for a mode switch. In this case this surface won't necessarily be
          * an implicit surface. We have to mark it lost so that the
@@ -1355,10 +1218,6 @@ static void surface_unload(struct wined3d_resource *resource)
     context = context_acquire(device, NULL);
     gl_info = context->gl_info;
 
-    /* Destroy PBOs, but load them into real sysmem before */
-    if (surface->flags & SFLAG_PBO)
-        surface_remove_pbo(surface, gl_info);
-
     /* Destroy fbo render buffers. This is needed for implicit render targets, for
      * all application-created targets the application has to release the surface
      * before calling _Reset
@@ -1541,21 +1400,9 @@ static void surface_download_data(struct wined3d_surface *surface, const struct
                 surface, surface->texture_level, format->glFormat, format->glType,
                 surface->resource.allocatedMemory);
 
-        if (surface->flags & SFLAG_PBO)
-        {
-            GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
-            checkGLcall("glBindBufferARB");
-            GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
-            checkGLcall("glGetCompressedTexImageARB");
-            GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
-            checkGLcall("glBindBufferARB");
-        }
-        else
-        {
-            GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
-                    surface->texture_level, surface->resource.allocatedMemory));
-            checkGLcall("glGetCompressedTexImageARB");
-        }
+        GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
+                surface->texture_level, surface->resource.allocatedMemory));
+        checkGLcall("glGetCompressedTexImageARB");
     }
     else
     {
@@ -1588,24 +1435,9 @@ static void surface_download_data(struct wined3d_surface *surface, const struct
         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
                 surface, surface->texture_level, gl_format, gl_type, mem);
 
-        if (surface->flags & SFLAG_PBO)
-        {
-            GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
-            checkGLcall("glBindBufferARB");
-
-            gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
-                    gl_format, gl_type, NULL);
-            checkGLcall("glGetTexImage");
-
-            GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
-            checkGLcall("glBindBufferARB");
-        }
-        else
-        {
-            gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
-                    gl_format, gl_type, mem);
-            checkGLcall("glGetTexImage");
-        }
+        gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
+                gl_format, gl_type, mem);
+        checkGLcall("glGetTexImage");
 
         if (surface->flags & SFLAG_NONPOW2)
         {
@@ -2040,7 +1872,7 @@ HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const P
         surface_load_location(dst_surface, SFLAG_INTEXTURE);
     wined3d_texture_bind(dst_surface->container, context, FALSE);
 
-    data.buffer_object = src_surface->pbo;
+    data.buffer_object = 0;
     data.addr = src_surface->resource.allocatedMemory;
     src_pitch = wined3d_surface_get_pitch(src_surface);
 
@@ -3329,8 +3161,7 @@ HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
         if (FAILED(hr))
             return WINED3DERR_INVALIDCALL;
 
-        /* Use the DIB section from now on if we are not using a PBO. */
-        if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
+        if (!(surface->flags & SFLAG_PIN_SYSMEM))
         {
             wined3d_resource_free_sysmem(&surface->resource);
             surface->resource.allocatedMemory = surface->dib.bitmap_data;
@@ -3345,9 +3176,7 @@ HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
         return hr;
     }
 
-    /* Sync the DIB with the PBO. This can't be done earlier because Map()
-     * activates the allocatedMemory. */
-    if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
+    if (surface->flags & SFLAG_PIN_SYSMEM)
         memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
 
     if (surface->resource.format->id == WINED3DFMT_P8_UINT
@@ -3409,8 +3238,7 @@ HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
         return WINEDDERR_NODC;
     }
 
-    /* Copy the contents of the DIB over to the PBO. */
-    if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
+    if ((surface->flags & SFLAG_PIN_SYSMEM) && surface->resource.allocatedMemory)
         memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
 
     /* We locked first, so unlock now. */
@@ -3531,17 +3359,6 @@ static void read_from_framebuffer(struct wined3d_surface *surface, void *dest, U
             bpp = surface->resource.format->byte_count;
     }
 
-    if (surface->flags & SFLAG_PBO)
-    {
-        GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
-        checkGLcall("glBindBufferARB");
-        if (mem)
-        {
-            ERR("mem not null for pbo -- unexpected\n");
-            mem = NULL;
-        }
-    }
-
     /* Save old pixel store pack state */
     gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
     checkGLcall("glGetIntegerv");
@@ -3571,25 +3388,6 @@ static void read_from_framebuffer(struct wined3d_surface *surface, void *dest, U
     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
     checkGLcall("glPixelStorei");
 
-    if (surface->flags & SFLAG_PBO)
-    {
-        GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
-        checkGLcall("glBindBufferARB");
-
-        /* Check if we need to flip the image. If we need to flip use glMapBufferARB
-         * to get a pointer to it and perform the flipping in software. This is a lot
-         * faster than calling glReadPixels for each line. In case we want more speed
-         * we should rerender it flipped in a FBO and read the data back from the FBO. */
-        if (!srcIsUpsideDown)
-        {
-            GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
-            checkGLcall("glBindBufferARB");
-
-            mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
-            checkGLcall("glMapBufferARB");
-        }
-    }
-
     /* TODO: Merge this with the palettization loop below for P8 targets */
     if (!srcIsUpsideDown)
     {
@@ -3618,13 +3416,6 @@ static void read_from_framebuffer(struct wined3d_surface *surface, void *dest, U
             bottom -= pitch;
         }
         HeapFree(GetProcessHeap(), 0, row);
-
-        /* Unmap the temp PBO buffer */
-        if (surface->flags & SFLAG_PBO)
-        {
-            GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
-            GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
-        }
     }
 
     /* For P8 textures we need to perform an inverse palette lookup. This is
@@ -4034,13 +3825,6 @@ void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
         back->resource.heap_memory = tmp;
     }
 
-    /* Flip the PBO */
-    {
-        GLuint tmp_pbo = front->pbo;
-        front->pbo = back->pbo;
-        back->pbo = tmp_pbo;
-    }
-
     /* Flip the opengl texture */
     {
         GLuint tmp;
@@ -5182,15 +4966,6 @@ static HRESULT surface_load_texture(struct wined3d_surface *surface,
     width = surface->resource.width;
     src_pitch = wined3d_surface_get_pitch(surface);
 
-    /* Don't use PBOs for converted surfaces. During PBO conversion we look at
-     * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
-     * called. */
-    if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
-    {
-        TRACE("Removing the pbo attached to surface %p.\n", surface);
-        surface_remove_pbo(surface, gl_info);
-    }
-
     if (format.convert)
     {
         /* This code is entered for texture formats which need a fixup. */
@@ -5236,14 +5011,14 @@ static HRESULT surface_load_texture(struct wined3d_surface *surface,
         mem = surface->resource.allocatedMemory;
     }
 
-    data.buffer_object = surface->pbo;
+    data.buffer_object = 0;
     data.addr = mem;
     surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
 
     context_release(context);
 
     /* Don't delete PBO memory. */
-    if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
+    if (mem != surface->resource.allocatedMemory)
         HeapFree(GetProcessHeap(), 0, mem);
 
     return WINED3D_OK;
@@ -5293,11 +5068,6 @@ HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location)
     if (surface->flags & location)
     {
         TRACE("Location already up to date.\n");
-
-        if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
-                && surface_need_pbo(surface, gl_info))
-            surface_load_pbo(surface, gl_info);
-
         return WINED3D_OK;
     }
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index d7e1c5f..7feb777 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2191,8 +2191,6 @@ struct wined3d_surface
     /* A method to retrieve the drawable size. Not in the Vtable to make it changeable */
     void (*get_drawable_size)(const struct wined3d_context *context, UINT *width, UINT *height);
 
-    /* PBO */
-    GLuint                    pbo;
     GLuint rb_multisample;
     GLuint rb_resolved;
     GLint texture_level;
@@ -2290,20 +2288,18 @@ void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back) D
 #define SFLAG_USERPTR           0x00000800 /* The application allocated the memory for this surface. */
 #define SFLAG_ALLOCATED         0x00001000 /* A GL texture is allocated for this surface. */
 #define SFLAG_SRGBALLOCATED     0x00002000 /* A sRGB GL texture is allocated for this surface. */
-#define SFLAG_PBO               0x00004000 /* The surface has a PBO. */
-#define SFLAG_INSYSMEM          0x00008000 /* The system memory copy is current. */
-#define SFLAG_INTEXTURE         0x00010000 /* The GL texture is current. */
-#define SFLAG_INSRGBTEX         0x00020000 /* The GL sRGB texture is current. */
-#define SFLAG_INDRAWABLE        0x00040000 /* The GL drawable is current. */
-#define SFLAG_INRB_MULTISAMPLE  0x00080000 /* The multisample renderbuffer is current. */
-#define SFLAG_INRB_RESOLVED     0x00100000 /* The resolved renderbuffer is current. */
-#define SFLAG_DISCARDED         0x00200000 /* Surface was discarded, allocating new location is enough. */
+#define SFLAG_INSYSMEM          0x00004000 /* The system memory copy is current. */
+#define SFLAG_INTEXTURE         0x00008000 /* The GL texture is current. */
+#define SFLAG_INSRGBTEX         0x00010000 /* The GL sRGB texture is current. */
+#define SFLAG_INDRAWABLE        0x00020000 /* The GL drawable is current. */
+#define SFLAG_INRB_MULTISAMPLE  0x00040000 /* The multisample renderbuffer is current. */
+#define SFLAG_INRB_RESOLVED     0x00080000 /* The resolved renderbuffer is current. */
+#define SFLAG_DISCARDED         0x00100000 /* Surface was discarded, allocating new location is enough. */
 
 /* In some conditions the surface memory must not be freed:
  * SFLAG_CONVERTED: Converting the data back would take too long
  * SFLAG_DIBSECTION: The dib code manages the memory
  * SFLAG_DYNLOCK: Avoid freeing the data for performance
- * SFLAG_PBO: PBOs don't use 'normal' memory. It is either allocated by the driver or must be NULL.
  * SFLAG_CLIENT: OpenGL uses our memory as backup
  */
 #define SFLAG_DONOTFREE     (SFLAG_CONVERTED        | \
@@ -2311,7 +2307,6 @@ void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back) D
                              SFLAG_CLIENT           | \
                              SFLAG_DIBSECTION       | \
                              SFLAG_USERPTR          | \
-                             SFLAG_PBO              | \
                              SFLAG_PIN_SYSMEM)
 
 #define SFLAG_LOCATIONS     (SFLAG_INSYSMEM         | \
-- 
1.8.3.2




More information about the wine-patches mailing list