wined3d: Get rid of the now redundant SFLAG_SWAPCHAIN surface flag.
[wine] / dlls / wined3d / surface.c
1 /*
2  * IWineD3DSurface Implementation
3  *
4  * Copyright 1998 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2002-2005 Jason Edmeades
7  * Copyright 2002-2003 Raphael Junqueira
8  * Copyright 2004 Christian Costa
9  * Copyright 2005 Oliver Stieber
10  * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11  * Copyright 2007-2008 Henri Verbeet
12  * Copyright 2006-2008 Roderick Colenbrander
13  * Copyright 2009 Henri Verbeet for CodeWeavers
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Lesser General Public
17  * License as published by the Free Software Foundation; either
18  * version 2.1 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public
26  * License along with this library; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29
30 #include "config.h"
31 #include "wine/port.h"
32 #include "wined3d_private.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d);
36
37 static void surface_cleanup(IWineD3DSurfaceImpl *This)
38 {
39     TRACE("(%p) : Cleaning up.\n", This);
40
41     if (This->texture_name || (This->Flags & SFLAG_PBO) || !list_empty(&This->renderbuffers))
42     {
43         const struct wined3d_gl_info *gl_info;
44         renderbuffer_entry_t *entry, *entry2;
45         struct wined3d_context *context;
46
47         context = context_acquire(This->resource.device, NULL);
48         gl_info = context->gl_info;
49
50         ENTER_GL();
51
52         if (This->texture_name)
53         {
54             TRACE("Deleting texture %u.\n", This->texture_name);
55             glDeleteTextures(1, &This->texture_name);
56         }
57
58         if (This->Flags & SFLAG_PBO)
59         {
60             TRACE("Deleting PBO %u.\n", This->pbo);
61             GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
62         }
63
64         LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry)
65         {
66             TRACE("Deleting renderbuffer %u.\n", entry->id);
67             gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
68             HeapFree(GetProcessHeap(), 0, entry);
69         }
70
71         LEAVE_GL();
72
73         context_release(context);
74     }
75
76     if (This->Flags & SFLAG_DIBSECTION)
77     {
78         /* Release the DC. */
79         SelectObject(This->hDC, This->dib.holdbitmap);
80         DeleteDC(This->hDC);
81         /* Release the DIB section. */
82         DeleteObject(This->dib.DIBsection);
83         This->dib.bitmap_data = NULL;
84         This->resource.allocatedMemory = NULL;
85     }
86
87     if (This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
88     if (This->overlay_dest) list_remove(&This->overlay_entry);
89
90     HeapFree(GetProcessHeap(), 0, This->palette9);
91
92     resource_cleanup((IWineD3DResource *)This);
93 }
94
95 void surface_set_container(IWineD3DSurfaceImpl *surface, enum wined3d_container_type type, IWineD3DBase *container)
96 {
97     TRACE("surface %p, container %p.\n", surface, container);
98
99     if (type == WINED3D_CONTAINER_SWAPCHAIN)
100     {
101         surface->get_drawable_size = get_drawable_size_swapchain;
102     }
103     else
104     {
105         switch (wined3d_settings.offscreen_rendering_mode)
106         {
107             case ORM_FBO:
108                 surface->get_drawable_size = get_drawable_size_fbo;
109                 break;
110
111             case ORM_BACKBUFFER:
112                 surface->get_drawable_size = get_drawable_size_backbuffer;
113                 break;
114
115             default:
116                 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
117                 return;
118         }
119     }
120
121     surface->container.type = type;
122     surface->container.u.base = container;
123 }
124
125 struct blt_info
126 {
127     GLenum binding;
128     GLenum bind_target;
129     enum tex_types tex_type;
130     GLfloat coords[4][3];
131 };
132
133 struct float_rect
134 {
135     float l;
136     float t;
137     float r;
138     float b;
139 };
140
141 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
142 {
143     f->l = ((r->left * 2.0f) / w) - 1.0f;
144     f->t = ((r->top * 2.0f) / h) - 1.0f;
145     f->r = ((r->right * 2.0f) / w) - 1.0f;
146     f->b = ((r->bottom * 2.0f) / h) - 1.0f;
147 }
148
149 static void surface_get_blt_info(GLenum target, const RECT *rect_in, GLsizei w, GLsizei h, struct blt_info *info)
150 {
151     GLfloat (*coords)[3] = info->coords;
152     RECT rect;
153     struct float_rect f;
154
155     if (rect_in)
156         rect = *rect_in;
157     else
158     {
159         rect.left = 0;
160         rect.top = h;
161         rect.right = w;
162         rect.bottom = 0;
163     }
164
165     switch (target)
166     {
167         default:
168             FIXME("Unsupported texture target %#x\n", target);
169             /* Fall back to GL_TEXTURE_2D */
170         case GL_TEXTURE_2D:
171             info->binding = GL_TEXTURE_BINDING_2D;
172             info->bind_target = GL_TEXTURE_2D;
173             info->tex_type = tex_2d;
174             coords[0][0] = (float)rect.left / w;
175             coords[0][1] = (float)rect.top / h;
176             coords[0][2] = 0.0f;
177
178             coords[1][0] = (float)rect.right / w;
179             coords[1][1] = (float)rect.top / h;
180             coords[1][2] = 0.0f;
181
182             coords[2][0] = (float)rect.left / w;
183             coords[2][1] = (float)rect.bottom / h;
184             coords[2][2] = 0.0f;
185
186             coords[3][0] = (float)rect.right / w;
187             coords[3][1] = (float)rect.bottom / h;
188             coords[3][2] = 0.0f;
189             break;
190
191         case GL_TEXTURE_RECTANGLE_ARB:
192             info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
193             info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
194             info->tex_type = tex_rect;
195             coords[0][0] = rect.left;   coords[0][1] = rect.top;     coords[0][2] = 0.0f;
196             coords[1][0] = rect.right;  coords[1][1] = rect.top;     coords[1][2] = 0.0f;
197             coords[2][0] = rect.left;   coords[2][1] = rect.bottom;  coords[2][2] = 0.0f;
198             coords[3][0] = rect.right;  coords[3][1] = rect.bottom;  coords[3][2] = 0.0f;
199             break;
200
201         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
202             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
203             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
204             info->tex_type = tex_cube;
205             cube_coords_float(&rect, w, h, &f);
206
207             coords[0][0] =  1.0f;   coords[0][1] = -f.t;   coords[0][2] = -f.l;
208             coords[1][0] =  1.0f;   coords[1][1] = -f.t;   coords[1][2] = -f.r;
209             coords[2][0] =  1.0f;   coords[2][1] = -f.b;   coords[2][2] = -f.l;
210             coords[3][0] =  1.0f;   coords[3][1] = -f.b;   coords[3][2] = -f.r;
211             break;
212
213         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
214             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
215             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
216             info->tex_type = tex_cube;
217             cube_coords_float(&rect, w, h, &f);
218
219             coords[0][0] = -1.0f;   coords[0][1] = -f.t;   coords[0][2] = f.l;
220             coords[1][0] = -1.0f;   coords[1][1] = -f.t;   coords[1][2] = f.r;
221             coords[2][0] = -1.0f;   coords[2][1] = -f.b;   coords[2][2] = f.l;
222             coords[3][0] = -1.0f;   coords[3][1] = -f.b;   coords[3][2] = f.r;
223             break;
224
225         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
226             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
227             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
228             info->tex_type = tex_cube;
229             cube_coords_float(&rect, w, h, &f);
230
231             coords[0][0] = f.l;   coords[0][1] =  1.0f;   coords[0][2] = f.t;
232             coords[1][0] = f.r;   coords[1][1] =  1.0f;   coords[1][2] = f.t;
233             coords[2][0] = f.l;   coords[2][1] =  1.0f;   coords[2][2] = f.b;
234             coords[3][0] = f.r;   coords[3][1] =  1.0f;   coords[3][2] = f.b;
235             break;
236
237         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
238             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
239             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
240             info->tex_type = tex_cube;
241             cube_coords_float(&rect, w, h, &f);
242
243             coords[0][0] = f.l;   coords[0][1] = -1.0f;   coords[0][2] = -f.t;
244             coords[1][0] = f.r;   coords[1][1] = -1.0f;   coords[1][2] = -f.t;
245             coords[2][0] = f.l;   coords[2][1] = -1.0f;   coords[2][2] = -f.b;
246             coords[3][0] = f.r;   coords[3][1] = -1.0f;   coords[3][2] = -f.b;
247             break;
248
249         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
250             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
251             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
252             info->tex_type = tex_cube;
253             cube_coords_float(&rect, w, h, &f);
254
255             coords[0][0] = f.l;   coords[0][1] = -f.t;   coords[0][2] =  1.0f;
256             coords[1][0] = f.r;   coords[1][1] = -f.t;   coords[1][2] =  1.0f;
257             coords[2][0] = f.l;   coords[2][1] = -f.b;   coords[2][2] =  1.0f;
258             coords[3][0] = f.r;   coords[3][1] = -f.b;   coords[3][2] =  1.0f;
259             break;
260
261         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
262             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
263             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
264             info->tex_type = tex_cube;
265             cube_coords_float(&rect, w, h, &f);
266
267             coords[0][0] = -f.l;   coords[0][1] = -f.t;   coords[0][2] = -1.0f;
268             coords[1][0] = -f.r;   coords[1][1] = -f.t;   coords[1][2] = -1.0f;
269             coords[2][0] = -f.l;   coords[2][1] = -f.b;   coords[2][2] = -1.0f;
270             coords[3][0] = -f.r;   coords[3][1] = -f.b;   coords[3][2] = -1.0f;
271             break;
272     }
273 }
274
275 static inline void surface_get_rect(IWineD3DSurfaceImpl *This, const RECT *rect_in, RECT *rect_out)
276 {
277     if (rect_in)
278         *rect_out = *rect_in;
279     else
280     {
281         rect_out->left = 0;
282         rect_out->top = 0;
283         rect_out->right = This->currentDesc.Width;
284         rect_out->bottom = This->currentDesc.Height;
285     }
286 }
287
288 /* GL locking and context activation is done by the caller */
289 void draw_textured_quad(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, const RECT *dst_rect, WINED3DTEXTUREFILTERTYPE Filter)
290 {
291     IWineD3DBaseTextureImpl *texture;
292     struct blt_info info;
293
294     surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
295
296     glEnable(info.bind_target);
297     checkGLcall("glEnable(bind_target)");
298
299     /* Bind the texture */
300     glBindTexture(info.bind_target, src_surface->texture_name);
301     checkGLcall("glBindTexture");
302
303     /* Filtering for StretchRect */
304     glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
305             wined3d_gl_mag_filter(magLookup, Filter));
306     checkGLcall("glTexParameteri");
307     glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
308             wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
309     checkGLcall("glTexParameteri");
310     glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
311     glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
312     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
313     checkGLcall("glTexEnvi");
314
315     /* Draw a quad */
316     glBegin(GL_TRIANGLE_STRIP);
317     glTexCoord3fv(info.coords[0]);
318     glVertex2i(dst_rect->left, dst_rect->top);
319
320     glTexCoord3fv(info.coords[1]);
321     glVertex2i(dst_rect->right, dst_rect->top);
322
323     glTexCoord3fv(info.coords[2]);
324     glVertex2i(dst_rect->left, dst_rect->bottom);
325
326     glTexCoord3fv(info.coords[3]);
327     glVertex2i(dst_rect->right, dst_rect->bottom);
328     glEnd();
329
330     /* Unbind the texture */
331     glBindTexture(info.bind_target, 0);
332     checkGLcall("glBindTexture(info->bind_target, 0)");
333
334     /* We changed the filtering settings on the texture. Inform the
335      * container about this to get the filters reset properly next draw. */
336     if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)src_surface, &IID_IWineD3DBaseTexture, (void **)&texture)))
337     {
338         texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
339         texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
340         texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
341         IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture);
342     }
343 }
344
345 HRESULT surface_init(IWineD3DSurfaceImpl *surface, WINED3DSURFTYPE surface_type, UINT alignment,
346         UINT width, UINT height, UINT level, BOOL lockable, BOOL discard, WINED3DMULTISAMPLE_TYPE multisample_type,
347         UINT multisample_quality, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format,
348         WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
349 {
350     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
351     const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info);
352     void (*cleanup)(IWineD3DSurfaceImpl *This);
353     unsigned int resource_size;
354     HRESULT hr;
355
356     if (multisample_quality > 0)
357     {
358         FIXME("multisample_quality set to %u, substituting 0\n", multisample_quality);
359         multisample_quality = 0;
360     }
361
362     /* FIXME: Check that the format is supported by the device. */
363
364     resource_size = wined3d_format_calculate_size(format_desc, alignment, width, height);
365
366     /* Look at the implementation and set the correct Vtable. */
367     switch (surface_type)
368     {
369         case SURFACE_OPENGL:
370             surface->lpVtbl = &IWineD3DSurface_Vtbl;
371             cleanup = surface_cleanup;
372             break;
373
374         case SURFACE_GDI:
375             surface->lpVtbl = &IWineGDISurface_Vtbl;
376             cleanup = surface_gdi_cleanup;
377             break;
378
379         default:
380             ERR("Requested unknown surface implementation %#x.\n", surface_type);
381             return WINED3DERR_INVALIDCALL;
382     }
383
384     hr = resource_init((IWineD3DResource *)surface, WINED3DRTYPE_SURFACE,
385             device, resource_size, usage, format_desc, pool, parent, parent_ops);
386     if (FAILED(hr))
387     {
388         WARN("Failed to initialize resource, returning %#x.\n", hr);
389         return hr;
390     }
391
392     /* "Standalone" surface. */
393     surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
394
395     surface->currentDesc.Width = width;
396     surface->currentDesc.Height = height;
397     surface->currentDesc.MultiSampleType = multisample_type;
398     surface->currentDesc.MultiSampleQuality = multisample_quality;
399     surface->texture_level = level;
400     list_init(&surface->overlays);
401
402     /* Flags */
403     surface->Flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
404     if (discard) surface->Flags |= SFLAG_DISCARD;
405     if (lockable || format == WINED3DFMT_D16_LOCKABLE) surface->Flags |= SFLAG_LOCKABLE;
406
407     /* Quick lockable sanity check.
408      * TODO: remove this after surfaces, usage and lockability have been debugged properly
409      * this function is too deep to need to care about things like this.
410      * Levels need to be checked too, since they all affect what can be done. */
411     switch (pool)
412     {
413         case WINED3DPOOL_SCRATCH:
414             if(!lockable)
415             {
416                 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
417                         "which are mutually exclusive, setting lockable to TRUE.\n");
418                 lockable = TRUE;
419             }
420             break;
421
422         case WINED3DPOOL_SYSTEMMEM:
423             if (!lockable)
424                 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
425             break;
426
427         case WINED3DPOOL_MANAGED:
428             if (usage & WINED3DUSAGE_DYNAMIC)
429                 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
430             break;
431
432         case WINED3DPOOL_DEFAULT:
433             if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
434                 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
435             break;
436
437         default:
438             FIXME("Unknown pool %#x.\n", pool);
439             break;
440     };
441
442     if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3DPOOL_DEFAULT)
443     {
444         FIXME("Trying to create a render target that isn't in the default pool.\n");
445     }
446
447     /* Mark the texture as dirty so that it gets loaded first time around. */
448     surface_add_dirty_rect(surface, NULL);
449     list_init(&surface->renderbuffers);
450
451     TRACE("surface %p, memory %p, size %u\n", surface, surface->resource.allocatedMemory, surface->resource.size);
452
453     /* Call the private setup routine */
454     hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)surface);
455     if (FAILED(hr))
456     {
457         ERR("Private setup failed, returning %#x\n", hr);
458         cleanup(surface);
459         return hr;
460     }
461
462     return hr;
463 }
464
465 static void surface_force_reload(IWineD3DSurfaceImpl *surface)
466 {
467     surface->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
468 }
469
470 void surface_set_texture_name(IWineD3DSurfaceImpl *surface, GLuint new_name, BOOL srgb)
471 {
472     GLuint *name;
473     DWORD flag;
474
475     TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
476
477     if(srgb)
478     {
479         name = &surface->texture_name_srgb;
480         flag = SFLAG_INSRGBTEX;
481     }
482     else
483     {
484         name = &surface->texture_name;
485         flag = SFLAG_INTEXTURE;
486     }
487
488     if (!*name && new_name)
489     {
490         /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
491          * surface has no texture name yet. See if we can get rid of this. */
492         if (surface->Flags & flag)
493             ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
494         surface_modify_location(surface, flag, FALSE);
495     }
496
497     *name = new_name;
498     surface_force_reload(surface);
499 }
500
501 void surface_set_texture_target(IWineD3DSurfaceImpl *surface, GLenum target)
502 {
503     TRACE("surface %p, target %#x.\n", surface, target);
504
505     if (surface->texture_target != target)
506     {
507         if (target == GL_TEXTURE_RECTANGLE_ARB)
508         {
509             surface->Flags &= ~SFLAG_NORMCOORD;
510         }
511         else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
512         {
513             surface->Flags |= SFLAG_NORMCOORD;
514         }
515     }
516     surface->texture_target = target;
517     surface_force_reload(surface);
518 }
519
520 /* Context activation is done by the caller. */
521 static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This, BOOL srgb) {
522     DWORD active_sampler;
523
524     /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
525      * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
526      * gl states. The current texture unit should always be a valid one.
527      *
528      * To be more specific, this is tricky because we can implicitly be called
529      * from sampler() in state.c. This means we can't touch anything other than
530      * whatever happens to be the currently active texture, or we would risk
531      * marking already applied sampler states dirty again.
532      *
533      * TODO: Track the current active texture per GL context instead of using glGet
534      */
535     GLint active_texture;
536     ENTER_GL();
537     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
538     LEAVE_GL();
539     active_sampler = This->resource.device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
540
541     if (active_sampler != WINED3D_UNMAPPED_STAGE)
542     {
543         IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_SAMPLER(active_sampler));
544     }
545     IWineD3DSurface_BindTexture((IWineD3DSurface *)This, srgb);
546 }
547
548 /* This function checks if the primary render target uses the 8bit paletted format. */
549 static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device)
550 {
551     if (device->render_targets && device->render_targets[0])
552     {
553         IWineD3DSurfaceImpl *render_target = device->render_targets[0];
554         if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
555                 && (render_target->resource.format_desc->format == WINED3DFMT_P8_UINT))
556             return TRUE;
557     }
558     return FALSE;
559 }
560
561 /* This call just downloads data, the caller is responsible for binding the
562  * correct texture. */
563 /* Context activation is done by the caller. */
564 static void surface_download_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
565 {
566     const struct wined3d_format_desc *format_desc = This->resource.format_desc;
567
568     /* Only support read back of converted P8 surfaces */
569     if (This->Flags & SFLAG_CONVERTED && format_desc->format != WINED3DFMT_P8_UINT)
570     {
571         FIXME("Read back converted textures unsupported, format=%s\n", debug_d3dformat(format_desc->format));
572         return;
573     }
574
575     ENTER_GL();
576
577     if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
578     {
579         TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
580                 This, This->texture_level, format_desc->glFormat, format_desc->glType,
581                 This->resource.allocatedMemory);
582
583         if (This->Flags & SFLAG_PBO)
584         {
585             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
586             checkGLcall("glBindBufferARB");
587             GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target, This->texture_level, NULL));
588             checkGLcall("glGetCompressedTexImageARB");
589             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
590             checkGLcall("glBindBufferARB");
591         }
592         else
593         {
594             GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target,
595                     This->texture_level, This->resource.allocatedMemory));
596             checkGLcall("glGetCompressedTexImageARB");
597         }
598
599         LEAVE_GL();
600     } else {
601         void *mem;
602         GLenum format = format_desc->glFormat;
603         GLenum type = format_desc->glType;
604         int src_pitch = 0;
605         int dst_pitch = 0;
606
607         /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
608         if (format_desc->format == WINED3DFMT_P8_UINT && primary_render_target_is_p8(This->resource.device))
609         {
610             format = GL_ALPHA;
611             type = GL_UNSIGNED_BYTE;
612         }
613
614         if (This->Flags & SFLAG_NONPOW2) {
615             unsigned char alignment = This->resource.device->surface_alignment;
616             src_pitch = format_desc->byte_count * This->pow2Width;
617             dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
618             src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
619             mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
620         } else {
621             mem = This->resource.allocatedMemory;
622         }
623
624         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
625                 This, This->texture_level, format, type, mem);
626
627         if(This->Flags & SFLAG_PBO) {
628             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
629             checkGLcall("glBindBufferARB");
630
631             glGetTexImage(This->texture_target, This->texture_level, format, type, NULL);
632             checkGLcall("glGetTexImage");
633
634             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
635             checkGLcall("glBindBufferARB");
636         } else {
637             glGetTexImage(This->texture_target, This->texture_level, format, type, mem);
638             checkGLcall("glGetTexImage");
639         }
640         LEAVE_GL();
641
642         if (This->Flags & SFLAG_NONPOW2) {
643             const BYTE *src_data;
644             BYTE *dst_data;
645             UINT y;
646             /*
647              * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
648              * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
649              * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
650              *
651              * We're doing this...
652              *
653              * instead of boxing the texture :
654              * |<-texture width ->|  -->pow2width|   /\
655              * |111111111111111111|              |   |
656              * |222 Texture 222222| boxed empty  | texture height
657              * |3333 Data 33333333|              |   |
658              * |444444444444444444|              |   \/
659              * -----------------------------------   |
660              * |     boxed  empty | boxed empty  | pow2height
661              * |                  |              |   \/
662              * -----------------------------------
663              *
664              *
665              * we're repacking the data to the expected texture width
666              *
667              * |<-texture width ->|  -->pow2width|   /\
668              * |111111111111111111222222222222222|   |
669              * |222333333333333333333444444444444| texture height
670              * |444444                           |   |
671              * |                                 |   \/
672              * |                                 |   |
673              * |            empty                | pow2height
674              * |                                 |   \/
675              * -----------------------------------
676              *
677              * == is the same as
678              *
679              * |<-texture width ->|    /\
680              * |111111111111111111|
681              * |222222222222222222|texture height
682              * |333333333333333333|
683              * |444444444444444444|    \/
684              * --------------------
685              *
686              * this also means that any references to allocatedMemory should work with the data as if were a
687              * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
688              *
689              * internally the texture is still stored in a boxed format so any references to textureName will
690              * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
691              *
692              * Performance should not be an issue, because applications normally do not lock the surfaces when
693              * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
694              * and doesn't have to be re-read.
695              */
696             src_data = mem;
697             dst_data = This->resource.allocatedMemory;
698             TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
699             for (y = 1 ; y < This->currentDesc.Height; y++) {
700                 /* skip the first row */
701                 src_data += src_pitch;
702                 dst_data += dst_pitch;
703                 memcpy(dst_data, src_data, dst_pitch);
704             }
705
706             HeapFree(GetProcessHeap(), 0, mem);
707         }
708     }
709
710     /* Surface has now been downloaded */
711     This->Flags |= SFLAG_INSYSMEM;
712 }
713
714 /* This call just uploads data, the caller is responsible for binding the
715  * correct texture. */
716 /* Context activation is done by the caller. */
717 static void surface_upload_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
718         const struct wined3d_format_desc *format_desc, BOOL srgb, const GLvoid *data)
719 {
720     GLsizei width = This->currentDesc.Width;
721     GLsizei height = This->currentDesc.Height;
722     GLenum internal;
723
724     if (srgb)
725     {
726         internal = format_desc->glGammaInternal;
727     }
728     else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(This))
729     {
730         internal = format_desc->rtInternal;
731     }
732     else
733     {
734         internal = format_desc->glInternal;
735     }
736
737     TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
738             This, internal, width, height, format_desc->glFormat, format_desc->glType, data);
739     TRACE("target %#x, level %u, resource size %u.\n",
740             This->texture_target, This->texture_level, This->resource.size);
741
742     if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
743
744     ENTER_GL();
745
746     if (This->Flags & SFLAG_PBO)
747     {
748         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
749         checkGLcall("glBindBufferARB");
750
751         TRACE("(%p) pbo: %#x, data: %p.\n", This, This->pbo, data);
752         data = NULL;
753     }
754
755     if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
756     {
757         TRACE("Calling glCompressedTexSubImage2DARB.\n");
758
759         GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
760                 0, 0, width, height, internal, This->resource.size, data));
761         checkGLcall("glCompressedTexSubImage2DARB");
762     }
763     else
764     {
765         TRACE("Calling glTexSubImage2D.\n");
766
767         glTexSubImage2D(This->texture_target, This->texture_level,
768                 0, 0, width, height, format_desc->glFormat, format_desc->glType, data);
769         checkGLcall("glTexSubImage2D");
770     }
771
772     if (This->Flags & SFLAG_PBO)
773     {
774         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
775         checkGLcall("glBindBufferARB");
776     }
777
778     LEAVE_GL();
779
780     if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
781     {
782         IWineD3DDeviceImpl *device = This->resource.device;
783         unsigned int i;
784
785         for (i = 0; i < device->numContexts; ++i)
786         {
787             context_surface_update(device->contexts[i], This);
788         }
789     }
790 }
791
792 /* This call just allocates the texture, the caller is responsible for binding
793  * the correct texture. */
794 /* Context activation is done by the caller. */
795 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
796         const struct wined3d_format_desc *format_desc, BOOL srgb)
797 {
798     BOOL enable_client_storage = FALSE;
799     GLsizei width = This->pow2Width;
800     GLsizei height = This->pow2Height;
801     const BYTE *mem = NULL;
802     GLenum internal;
803
804     if (srgb)
805     {
806         internal = format_desc->glGammaInternal;
807     }
808     else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(This))
809     {
810         internal = format_desc->rtInternal;
811     }
812     else
813     {
814         internal = format_desc->glInternal;
815     }
816
817     if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
818
819     TRACE("(%p) : Creating surface (target %#x)  level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
820             This, This->texture_target, This->texture_level, debug_d3dformat(format_desc->format),
821             internal, width, height, format_desc->glFormat, format_desc->glType);
822
823     ENTER_GL();
824
825     if (gl_info->supported[APPLE_CLIENT_STORAGE])
826     {
827         if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) {
828             /* In some cases we want to disable client storage.
829              * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
830              * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
831              * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
832              * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
833              */
834             glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
835             checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
836             This->Flags &= ~SFLAG_CLIENT;
837             enable_client_storage = TRUE;
838         } else {
839             This->Flags |= SFLAG_CLIENT;
840
841             /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
842              * it might point into a pbo. Instead use heapMemory, but get the alignment right.
843              */
844             mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
845         }
846     }
847
848     if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED && mem)
849     {
850         GL_EXTCALL(glCompressedTexImage2DARB(This->texture_target, This->texture_level,
851                 internal, width, height, 0, This->resource.size, mem));
852         checkGLcall("glCompressedTexImage2DARB");
853     }
854     else
855     {
856         glTexImage2D(This->texture_target, This->texture_level,
857                 internal, width, height, 0, format_desc->glFormat, format_desc->glType, mem);
858         checkGLcall("glTexImage2D");
859     }
860
861     if(enable_client_storage) {
862         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
863         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
864     }
865     LEAVE_GL();
866 }
867
868 /* In D3D the depth stencil dimensions have to be greater than or equal to the
869  * render target dimensions. With FBOs, the dimensions have to be an exact match. */
870 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
871 /* GL locking is done by the caller */
872 void surface_set_compatible_renderbuffer(IWineD3DSurfaceImpl *surface, unsigned int width, unsigned int height)
873 {
874     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
875     renderbuffer_entry_t *entry;
876     GLuint renderbuffer = 0;
877     unsigned int src_width, src_height;
878
879     src_width = surface->pow2Width;
880     src_height = surface->pow2Height;
881
882     /* A depth stencil smaller than the render target is not valid */
883     if (width > src_width || height > src_height) return;
884
885     /* Remove any renderbuffer set if the sizes match */
886     if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
887             || (width == src_width && height == src_height))
888     {
889         surface->current_renderbuffer = NULL;
890         return;
891     }
892
893     /* Look if we've already got a renderbuffer of the correct dimensions */
894     LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, renderbuffer_entry_t, entry)
895     {
896         if (entry->width == width && entry->height == height)
897         {
898             renderbuffer = entry->id;
899             surface->current_renderbuffer = entry;
900             break;
901         }
902     }
903
904     if (!renderbuffer)
905     {
906         gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
907         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
908         gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
909                 surface->resource.format_desc->glInternal, width, height);
910
911         entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
912         entry->width = width;
913         entry->height = height;
914         entry->id = renderbuffer;
915         list_add_head(&surface->renderbuffers, &entry->entry);
916
917         surface->current_renderbuffer = entry;
918     }
919
920     checkGLcall("set_compatible_renderbuffer");
921 }
922
923 GLenum surface_get_gl_buffer(IWineD3DSurfaceImpl *surface)
924 {
925     IWineD3DSwapChainImpl *swapchain = surface->container.u.swapchain;
926
927     TRACE("surface %p.\n", surface);
928
929     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
930     {
931         ERR("Surface %p is not on a swapchain.\n", surface);
932         return GL_NONE;
933     }
934
935     if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
936     {
937         if (swapchain->render_to_fbo)
938         {
939             TRACE("Returning GL_COLOR_ATTACHMENT0\n");
940             return GL_COLOR_ATTACHMENT0;
941         }
942         TRACE("Returning GL_BACK\n");
943         return GL_BACK;
944     }
945     else if (surface == swapchain->front_buffer)
946     {
947         TRACE("Returning GL_FRONT\n");
948         return GL_FRONT;
949     }
950
951     FIXME("Higher back buffer, returning GL_BACK\n");
952     return GL_BACK;
953 }
954
955 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
956 void surface_add_dirty_rect(IWineD3DSurfaceImpl *surface, const RECT *dirty_rect)
957 {
958     IWineD3DBaseTexture *baseTexture = NULL;
959
960     TRACE("surface %p, dirty_rect %s.\n", surface, wine_dbgstr_rect(dirty_rect));
961
962     if (!(surface->Flags & SFLAG_INSYSMEM) && (surface->Flags & SFLAG_INTEXTURE))
963         /* No partial locking for textures yet. */
964         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
965
966     surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
967     if (dirty_rect)
968     {
969         surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
970         surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
971         surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
972         surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
973     }
974     else
975     {
976         surface->dirtyRect.left = 0;
977         surface->dirtyRect.top = 0;
978         surface->dirtyRect.right = surface->currentDesc.Width;
979         surface->dirtyRect.bottom = surface->currentDesc.Height;
980     }
981
982     /* if the container is a basetexture then mark it dirty. */
983     if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)surface,
984             &IID_IWineD3DBaseTexture, (void **)&baseTexture)))
985     {
986         TRACE("Passing to container\n");
987         IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
988         IWineD3DBaseTexture_Release(baseTexture);
989     }
990 }
991
992 static BOOL surface_convert_color_to_argb(IWineD3DSurfaceImpl *This, DWORD color, DWORD *argb_color)
993 {
994     IWineD3DDeviceImpl *device = This->resource.device;
995
996     switch(This->resource.format_desc->format)
997     {
998         case WINED3DFMT_P8_UINT:
999             {
1000                 DWORD alpha;
1001
1002                 if (primary_render_target_is_p8(device))
1003                     alpha = color << 24;
1004                 else
1005                     alpha = 0xFF000000;
1006
1007                 if (This->palette) {
1008                     *argb_color = (alpha |
1009                             (This->palette->palents[color].peRed << 16) |
1010                             (This->palette->palents[color].peGreen << 8) |
1011                             (This->palette->palents[color].peBlue));
1012                 } else {
1013                     *argb_color = alpha;
1014                 }
1015             }
1016             break;
1017
1018         case WINED3DFMT_B5G6R5_UNORM:
1019             {
1020                 if (color == 0xFFFF) {
1021                     *argb_color = 0xFFFFFFFF;
1022                 } else {
1023                     *argb_color = ((0xFF000000) |
1024                             ((color & 0xF800) << 8) |
1025                             ((color & 0x07E0) << 5) |
1026                             ((color & 0x001F) << 3));
1027                 }
1028             }
1029             break;
1030
1031         case WINED3DFMT_B8G8R8_UNORM:
1032         case WINED3DFMT_B8G8R8X8_UNORM:
1033             *argb_color = 0xFF000000 | color;
1034             break;
1035
1036         case WINED3DFMT_B8G8R8A8_UNORM:
1037             *argb_color = color;
1038             break;
1039
1040         default:
1041             ERR("Unhandled conversion from %s to ARGB!\n", debug_d3dformat(This->resource.format_desc->format));
1042             return FALSE;
1043     }
1044     return TRUE;
1045 }
1046
1047 static ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface)
1048 {
1049     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1050     ULONG ref = InterlockedDecrement(&This->resource.ref);
1051     TRACE("(%p) : Releasing from %d\n", This, ref + 1);
1052
1053     if (!ref)
1054     {
1055         surface_cleanup(This);
1056         This->resource.parent_ops->wined3d_object_destroyed(This->resource.parent);
1057
1058         TRACE("(%p) Released.\n", This);
1059         HeapFree(GetProcessHeap(), 0, This);
1060     }
1061
1062     return ref;
1063 }
1064
1065 /* ****************************************************
1066    IWineD3DSurface IWineD3DResource parts follow
1067    **************************************************** */
1068
1069 void surface_internal_preload(IWineD3DSurfaceImpl *surface, enum WINED3DSRGB srgb)
1070 {
1071     /* TODO: check for locks */
1072     IWineD3DDeviceImpl *device = surface->resource.device;
1073     IWineD3DBaseTexture *baseTexture = NULL;
1074
1075     TRACE("(%p)Checking to see if the container is a base texture\n", surface);
1076     if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)surface,
1077             &IID_IWineD3DBaseTexture, (void **)&baseTexture)))
1078     {
1079         IWineD3DBaseTextureImpl *tex_impl = (IWineD3DBaseTextureImpl *)baseTexture;
1080         TRACE("Passing to container\n");
1081         tex_impl->baseTexture.internal_preload(baseTexture, srgb);
1082         IWineD3DBaseTexture_Release(baseTexture);
1083     } else {
1084         struct wined3d_context *context = NULL;
1085
1086         TRACE("(%p) : About to load surface\n", surface);
1087
1088         if (!device->isInDraw) context = context_acquire(device, NULL);
1089
1090         if (surface->resource.format_desc->format == WINED3DFMT_P8_UINT
1091                 || surface->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
1092         {
1093             if (palette9_changed(surface))
1094             {
1095                 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1096                 /* TODO: This is not necessarily needed with hw palettized texture support */
1097                 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1098                 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
1099                 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
1100             }
1101         }
1102
1103         IWineD3DSurface_LoadTexture((IWineD3DSurface *)surface, srgb == SRGB_SRGB ? TRUE : FALSE);
1104
1105         if (surface->resource.pool == WINED3DPOOL_DEFAULT)
1106         {
1107             /* Tell opengl to try and keep this texture in video ram (well mostly) */
1108             GLclampf tmp;
1109             tmp = 0.9f;
1110             ENTER_GL();
1111             glPrioritizeTextures(1, &surface->texture_name, &tmp);
1112             LEAVE_GL();
1113         }
1114
1115         if (context) context_release(context);
1116     }
1117 }
1118
1119 static void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface)
1120 {
1121     surface_internal_preload((IWineD3DSurfaceImpl *)iface, SRGB_ANY);
1122 }
1123
1124 /* Context activation is done by the caller. */
1125 static void surface_remove_pbo(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
1126 {
1127     This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1128     This->resource.allocatedMemory =
1129             (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1130
1131     ENTER_GL();
1132     GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1133     checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, This->pbo)");
1134     GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, This->resource.size, This->resource.allocatedMemory));
1135     checkGLcall("glGetBufferSubDataARB");
1136     GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
1137     checkGLcall("glDeleteBuffersARB");
1138     LEAVE_GL();
1139
1140     This->pbo = 0;
1141     This->Flags &= ~SFLAG_PBO;
1142 }
1143
1144 BOOL surface_init_sysmem(IWineD3DSurfaceImpl *surface)
1145 {
1146     if (!surface->resource.allocatedMemory)
1147     {
1148         surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1149                 surface->resource.size + RESOURCE_ALIGNMENT);
1150         if (!surface->resource.heapMemory)
1151         {
1152             ERR("Out of memory\n");
1153             return FALSE;
1154         }
1155         surface->resource.allocatedMemory =
1156             (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1157     }
1158     else
1159     {
1160         memset(surface->resource.allocatedMemory, 0, surface->resource.size);
1161     }
1162
1163     surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1164
1165     return TRUE;
1166 }
1167
1168 static void WINAPI IWineD3DSurfaceImpl_UnLoad(IWineD3DSurface *iface) {
1169     IWineD3DBaseTexture *texture = NULL;
1170     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1171     IWineD3DDeviceImpl *device = This->resource.device;
1172     const struct wined3d_gl_info *gl_info;
1173     renderbuffer_entry_t *entry, *entry2;
1174     struct wined3d_context *context;
1175
1176     TRACE("(%p)\n", iface);
1177
1178     if(This->resource.pool == WINED3DPOOL_DEFAULT) {
1179         /* Default pool resources are supposed to be destroyed before Reset is called.
1180          * Implicit resources stay however. So this means we have an implicit render target
1181          * or depth stencil. The content may be destroyed, but we still have to tear down
1182          * opengl resources, so we cannot leave early.
1183          *
1184          * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1185          * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1186          * or the depth stencil into an FBO the texture or render buffer will be removed
1187          * and all flags get lost
1188          */
1189         surface_init_sysmem(This);
1190     }
1191     else
1192     {
1193         /* Load the surface into system memory */
1194         surface_load_location(This, SFLAG_INSYSMEM, NULL);
1195         surface_modify_location(This, SFLAG_INDRAWABLE, FALSE);
1196     }
1197     surface_modify_location(This, SFLAG_INTEXTURE, FALSE);
1198     surface_modify_location(This, SFLAG_INSRGBTEX, FALSE);
1199     This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1200
1201     context = context_acquire(device, NULL);
1202     gl_info = context->gl_info;
1203
1204     /* Destroy PBOs, but load them into real sysmem before */
1205     if (This->Flags & SFLAG_PBO)
1206         surface_remove_pbo(This, gl_info);
1207
1208     /* Destroy fbo render buffers. This is needed for implicit render targets, for
1209      * all application-created targets the application has to release the surface
1210      * before calling _Reset
1211      */
1212     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
1213         ENTER_GL();
1214         gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1215         LEAVE_GL();
1216         list_remove(&entry->entry);
1217         HeapFree(GetProcessHeap(), 0, entry);
1218     }
1219     list_init(&This->renderbuffers);
1220     This->current_renderbuffer = NULL;
1221
1222     /* If we're in a texture, the texture name belongs to the texture. Otherwise,
1223      * destroy it
1224      */
1225     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **) &texture);
1226     if(!texture) {
1227         ENTER_GL();
1228         glDeleteTextures(1, &This->texture_name);
1229         This->texture_name = 0;
1230         glDeleteTextures(1, &This->texture_name_srgb);
1231         This->texture_name_srgb = 0;
1232         LEAVE_GL();
1233     } else {
1234         IWineD3DBaseTexture_Release(texture);
1235     }
1236
1237     context_release(context);
1238
1239     resource_unload((IWineD3DResourceImpl *)This);
1240 }
1241
1242 /* ******************************************************
1243    IWineD3DSurface IWineD3DSurface parts follow
1244    ****************************************************** */
1245
1246 /* Read the framebuffer back into the surface */
1247 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, const RECT *rect, void *dest, UINT pitch)
1248 {
1249     IWineD3DDeviceImpl *device = This->resource.device;
1250     const struct wined3d_gl_info *gl_info;
1251     struct wined3d_context *context;
1252     BYTE *mem;
1253     GLint fmt;
1254     GLint type;
1255     BYTE *row, *top, *bottom;
1256     int i;
1257     BOOL bpp;
1258     RECT local_rect;
1259     BOOL srcIsUpsideDown;
1260     GLint rowLen = 0;
1261     GLint skipPix = 0;
1262     GLint skipRow = 0;
1263
1264     if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1265         static BOOL warned = FALSE;
1266         if(!warned) {
1267             ERR("The application tries to lock the render target, but render target locking is disabled\n");
1268             warned = TRUE;
1269         }
1270         return;
1271     }
1272
1273     /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
1274      * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
1275      * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
1276      * context->last_was_blit set on the unlock.
1277      */
1278     context = context_acquire(device, This);
1279     context_apply_blit_state(context, device);
1280     gl_info = context->gl_info;
1281
1282     ENTER_GL();
1283
1284     /* Select the correct read buffer, and give some debug output.
1285      * There is no need to keep track of the current read buffer or reset it, every part of the code
1286      * that reads sets the read buffer as desired.
1287      */
1288     if (surface_is_offscreen(This))
1289     {
1290         /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1291          * Read from the back buffer
1292          */
1293         TRACE("Locking offscreen render target\n");
1294         glReadBuffer(device->offscreenBuffer);
1295         srcIsUpsideDown = TRUE;
1296     }
1297     else
1298     {
1299         /* Onscreen surfaces are always part of a swapchain */
1300         GLenum buffer = surface_get_gl_buffer(This);
1301         TRACE("Locking %#x buffer\n", buffer);
1302         glReadBuffer(buffer);
1303         checkGLcall("glReadBuffer");
1304         srcIsUpsideDown = FALSE;
1305     }
1306
1307     /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
1308     if(!rect) {
1309         local_rect.left = 0;
1310         local_rect.top = 0;
1311         local_rect.right = This->currentDesc.Width;
1312         local_rect.bottom = This->currentDesc.Height;
1313     } else {
1314         local_rect = *rect;
1315     }
1316     /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
1317
1318     switch(This->resource.format_desc->format)
1319     {
1320         case WINED3DFMT_P8_UINT:
1321         {
1322             if (primary_render_target_is_p8(device))
1323             {
1324                 /* In case of P8 render targets the index is stored in the alpha component */
1325                 fmt = GL_ALPHA;
1326                 type = GL_UNSIGNED_BYTE;
1327                 mem = dest;
1328                 bpp = This->resource.format_desc->byte_count;
1329             } else {
1330                 /* GL can't return palettized data, so read ARGB pixels into a
1331                  * separate block of memory and convert them into palettized format
1332                  * in software. Slow, but if the app means to use palettized render
1333                  * targets and locks it...
1334                  *
1335                  * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
1336                  * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
1337                  * for the color channels when palettizing the colors.
1338                  */
1339                 fmt = GL_RGB;
1340                 type = GL_UNSIGNED_BYTE;
1341                 pitch *= 3;
1342                 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
1343                 if(!mem) {
1344                     ERR("Out of memory\n");
1345                     LEAVE_GL();
1346                     return;
1347                 }
1348                 bpp = This->resource.format_desc->byte_count * 3;
1349             }
1350         }
1351         break;
1352
1353         default:
1354             mem = dest;
1355             fmt = This->resource.format_desc->glFormat;
1356             type = This->resource.format_desc->glType;
1357             bpp = This->resource.format_desc->byte_count;
1358     }
1359
1360     if(This->Flags & SFLAG_PBO) {
1361         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1362         checkGLcall("glBindBufferARB");
1363         if(mem != NULL) {
1364             ERR("mem not null for pbo -- unexpected\n");
1365             mem = NULL;
1366         }
1367     }
1368
1369     /* Save old pixel store pack state */
1370     glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
1371     checkGLcall("glGetIntegerv");
1372     glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
1373     checkGLcall("glGetIntegerv");
1374     glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
1375     checkGLcall("glGetIntegerv");
1376
1377     /* Setup pixel store pack state -- to glReadPixels into the correct place */
1378     glPixelStorei(GL_PACK_ROW_LENGTH, This->currentDesc.Width);
1379     checkGLcall("glPixelStorei");
1380     glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
1381     checkGLcall("glPixelStorei");
1382     glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
1383     checkGLcall("glPixelStorei");
1384
1385     glReadPixels(local_rect.left, (!srcIsUpsideDown) ? (This->currentDesc.Height - local_rect.bottom) : local_rect.top ,
1386                  local_rect.right - local_rect.left,
1387                  local_rect.bottom - local_rect.top,
1388                  fmt, type, mem);
1389     checkGLcall("glReadPixels");
1390
1391     /* Reset previous pixel store pack state */
1392     glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
1393     checkGLcall("glPixelStorei");
1394     glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
1395     checkGLcall("glPixelStorei");
1396     glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
1397     checkGLcall("glPixelStorei");
1398
1399     if(This->Flags & SFLAG_PBO) {
1400         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1401         checkGLcall("glBindBufferARB");
1402
1403         /* Check if we need to flip the image. If we need to flip use glMapBufferARB
1404          * to get a pointer to it and perform the flipping in software. This is a lot
1405          * faster than calling glReadPixels for each line. In case we want more speed
1406          * we should rerender it flipped in a FBO and read the data back from the FBO. */
1407         if(!srcIsUpsideDown) {
1408             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1409             checkGLcall("glBindBufferARB");
1410
1411             mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1412             checkGLcall("glMapBufferARB");
1413         }
1414     }
1415
1416     /* TODO: Merge this with the palettization loop below for P8 targets */
1417     if(!srcIsUpsideDown) {
1418         UINT len, off;
1419         /* glReadPixels returns the image upside down, and there is no way to prevent this.
1420             Flip the lines in software */
1421         len = (local_rect.right - local_rect.left) * bpp;
1422         off = local_rect.left * bpp;
1423
1424         row = HeapAlloc(GetProcessHeap(), 0, len);
1425         if(!row) {
1426             ERR("Out of memory\n");
1427             if (This->resource.format_desc->format == WINED3DFMT_P8_UINT) HeapFree(GetProcessHeap(), 0, mem);
1428             LEAVE_GL();
1429             return;
1430         }
1431
1432         top = mem + pitch * local_rect.top;
1433         bottom = mem + pitch * (local_rect.bottom - 1);
1434         for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
1435             memcpy(row, top + off, len);
1436             memcpy(top + off, bottom + off, len);
1437             memcpy(bottom + off, row, len);
1438             top += pitch;
1439             bottom -= pitch;
1440         }
1441         HeapFree(GetProcessHeap(), 0, row);
1442
1443         /* Unmap the temp PBO buffer */
1444         if(This->Flags & SFLAG_PBO) {
1445             GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1446             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1447         }
1448     }
1449
1450     LEAVE_GL();
1451     context_release(context);
1452
1453     /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
1454      * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
1455      * the same color but we have no choice.
1456      * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
1457      */
1458     if (This->resource.format_desc->format == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
1459     {
1460         const PALETTEENTRY *pal = NULL;
1461         DWORD width = pitch / 3;
1462         int x, y, c;
1463
1464         if(This->palette) {
1465             pal = This->palette->palents;
1466         } else {
1467             ERR("Palette is missing, cannot perform inverse palette lookup\n");
1468             HeapFree(GetProcessHeap(), 0, mem);
1469             return ;
1470         }
1471
1472         for(y = local_rect.top; y < local_rect.bottom; y++) {
1473             for(x = local_rect.left; x < local_rect.right; x++) {
1474                 /*                      start              lines            pixels      */
1475                 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
1476                 const BYTE *green = blue  + 1;
1477                 const BYTE *red = green + 1;
1478
1479                 for(c = 0; c < 256; c++) {
1480                     if(*red   == pal[c].peRed   &&
1481                        *green == pal[c].peGreen &&
1482                        *blue  == pal[c].peBlue)
1483                     {
1484                         *((BYTE *) dest + y * width + x) = c;
1485                         break;
1486                     }
1487                 }
1488             }
1489         }
1490         HeapFree(GetProcessHeap(), 0, mem);
1491     }
1492 }
1493
1494 /* Read the framebuffer contents into a texture */
1495 static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb)
1496 {
1497     IWineD3DDeviceImpl *device = This->resource.device;
1498     const struct wined3d_gl_info *gl_info;
1499     struct wined3d_context *context;
1500
1501     if (!surface_is_offscreen(This))
1502     {
1503         /* We would need to flip onscreen surfaces, but there's no efficient
1504          * way to do that here. It makes more sense for the caller to
1505          * explicitly go through sysmem. */
1506         ERR("Not supported for onscreen targets.\n");
1507         return;
1508     }
1509
1510     /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
1511      * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
1512      * states in the stateblock, and no driver was found yet that had bugs in that regard.
1513      */
1514     context = context_acquire(device, This);
1515     gl_info = context->gl_info;
1516
1517     surface_prepare_texture(This, gl_info, srgb);
1518     surface_bind_and_dirtify(This, srgb);
1519
1520     TRACE("Reading back offscreen render target %p.\n", This);
1521
1522     ENTER_GL();
1523
1524     glReadBuffer(device->offscreenBuffer);
1525     checkGLcall("glReadBuffer");
1526
1527     glCopyTexSubImage2D(This->texture_target, This->texture_level,
1528             0, 0, 0, 0, This->currentDesc.Width, This->currentDesc.Height);
1529     checkGLcall("glCopyTexSubImage2D");
1530
1531     LEAVE_GL();
1532
1533     context_release(context);
1534 }
1535
1536 /* Context activation is done by the caller. */
1537 static void surface_prepare_texture_internal(IWineD3DSurfaceImpl *surface,
1538         const struct wined3d_gl_info *gl_info, BOOL srgb)
1539 {
1540     DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1541     CONVERT_TYPES convert;
1542     struct wined3d_format_desc desc;
1543
1544     if (surface->Flags & alloc_flag) return;
1545
1546     d3dfmt_get_conv(surface, TRUE, TRUE, &desc, &convert);
1547     if(convert != NO_CONVERSION || desc.convert) surface->Flags |= SFLAG_CONVERTED;
1548     else surface->Flags &= ~SFLAG_CONVERTED;
1549
1550     surface_bind_and_dirtify(surface, srgb);
1551     surface_allocate_surface(surface, gl_info, &desc, srgb);
1552     surface->Flags |= alloc_flag;
1553 }
1554
1555 /* Context activation is done by the caller. */
1556 void surface_prepare_texture(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
1557 {
1558     IWineD3DBaseTextureImpl *texture;
1559
1560     if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)surface,
1561             &IID_IWineD3DBaseTexture, (void **)&texture)))
1562     {
1563         UINT sub_count = texture->baseTexture.level_count * texture->baseTexture.layer_count;
1564         UINT i;
1565
1566         TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
1567
1568         for (i = 0; i < sub_count; ++i)
1569         {
1570             IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)texture->baseTexture.sub_resources[i];
1571             surface_prepare_texture_internal(s, gl_info, srgb);
1572         }
1573
1574         IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture);
1575
1576         return;
1577     }
1578
1579     surface_prepare_texture_internal(surface, gl_info, srgb);
1580 }
1581
1582 static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This)
1583 {
1584     IWineD3DDeviceImpl *device = This->resource.device;
1585     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1586
1587     /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
1588      * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
1589      * changed
1590      */
1591     if(!(This->Flags & SFLAG_DYNLOCK)) {
1592         This->lockCount++;
1593         /* MAXLOCKCOUNT is defined in wined3d_private.h */
1594         if(This->lockCount > MAXLOCKCOUNT) {
1595             TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
1596             This->Flags |= SFLAG_DYNLOCK;
1597         }
1598     }
1599
1600     /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
1601      * Also don't create a PBO for systemmem surfaces.
1602      */
1603     if (gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && (This->Flags & SFLAG_DYNLOCK)
1604             && !(This->Flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2))
1605             && (This->resource.pool != WINED3DPOOL_SYSTEMMEM))
1606     {
1607         GLenum error;
1608         struct wined3d_context *context;
1609
1610         context = context_acquire(device, NULL);
1611         ENTER_GL();
1612
1613         GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
1614         error = glGetError();
1615         if(This->pbo == 0 || error != GL_NO_ERROR) {
1616             ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
1617         }
1618
1619         TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
1620
1621         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1622         checkGLcall("glBindBufferARB");
1623
1624         GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
1625         checkGLcall("glBufferDataARB");
1626
1627         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1628         checkGLcall("glBindBufferARB");
1629
1630         /* We don't need the system memory anymore and we can't even use it for PBOs */
1631         if(!(This->Flags & SFLAG_CLIENT)) {
1632             HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
1633             This->resource.heapMemory = NULL;
1634         }
1635         This->resource.allocatedMemory = NULL;
1636         This->Flags |= SFLAG_PBO;
1637         LEAVE_GL();
1638         context_release(context);
1639     }
1640     else if (!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO))
1641     {
1642         /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
1643          * or a pbo to map
1644          */
1645         if(!This->resource.heapMemory) {
1646             This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1647         }
1648         This->resource.allocatedMemory =
1649                 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1650         if(This->Flags & SFLAG_INSYSMEM) {
1651             ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
1652         }
1653     }
1654 }
1655
1656 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
1657     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1658     IWineD3DDeviceImpl *device = This->resource.device;
1659     const RECT *pass_rect = pRect;
1660
1661     TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
1662             iface, pLockedRect, wine_dbgstr_rect(pRect), Flags);
1663
1664     /* This is also done in the base class, but we have to verify this before loading any data from
1665      * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
1666      * may interfere, and all other bad things may happen
1667      */
1668     if (This->Flags & SFLAG_LOCKED) {
1669         WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
1670         return WINED3DERR_INVALIDCALL;
1671     }
1672     This->Flags |= SFLAG_LOCKED;
1673
1674     if (!(This->Flags & SFLAG_LOCKABLE))
1675     {
1676         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
1677     }
1678
1679     if (Flags & WINED3DLOCK_DISCARD) {
1680         /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
1681         TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
1682         surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1683         This->Flags |= SFLAG_INSYSMEM;
1684         goto lock_end;
1685     }
1686
1687     if (This->Flags & SFLAG_INSYSMEM) {
1688         TRACE("Local copy is up to date, not downloading data\n");
1689         surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1690         goto lock_end;
1691     }
1692
1693     /* surface_load_location() does not check if the rectangle specifies
1694      * the full surface. Most callers don't need that, so do it here. */
1695     if (pRect && pRect->top == 0 && pRect->left == 0
1696             && pRect->right == This->currentDesc.Width
1697             && pRect->bottom == This->currentDesc.Height)
1698     {
1699         pass_rect = NULL;
1700     }
1701
1702     if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
1703             && ((This->container.type == WINED3D_CONTAINER_SWAPCHAIN) || This == device->render_targets[0])))
1704     {
1705         surface_load_location(This, SFLAG_INSYSMEM, pass_rect);
1706     }
1707
1708 lock_end:
1709     if (This->Flags & SFLAG_PBO)
1710     {
1711         const struct wined3d_gl_info *gl_info;
1712         struct wined3d_context *context;
1713
1714         context = context_acquire(device, NULL);
1715         gl_info = context->gl_info;
1716
1717         ENTER_GL();
1718         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1719         checkGLcall("glBindBufferARB");
1720
1721         /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
1722         if(This->resource.allocatedMemory) {
1723             ERR("The surface already has PBO memory allocated!\n");
1724         }
1725
1726         This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1727         checkGLcall("glMapBufferARB");
1728
1729         /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
1730         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1731         checkGLcall("glBindBufferARB");
1732
1733         LEAVE_GL();
1734         context_release(context);
1735     }
1736
1737     if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
1738         /* Don't dirtify */
1739     } else {
1740         IWineD3DBaseTexture *pBaseTexture;
1741         /**
1742          * Dirtify on lock
1743          * as seen in msdn docs
1744          */
1745         surface_add_dirty_rect(This, pRect);
1746
1747         /** Dirtify Container if needed */
1748         if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture))) {
1749             TRACE("Making container dirty\n");
1750             IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
1751             IWineD3DBaseTexture_Release(pBaseTexture);
1752         } else {
1753             TRACE("Surface is standalone, no need to dirty the container\n");
1754         }
1755     }
1756
1757     return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
1758 }
1759
1760 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem) {
1761     GLint  prev_store;
1762     GLint  prev_rasterpos[4];
1763     GLint skipBytes = 0;
1764     UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);    /* target is argb, 4 byte */
1765     IWineD3DDeviceImpl *device = This->resource.device;
1766     const struct wined3d_gl_info *gl_info;
1767     struct wined3d_context *context;
1768
1769     /* Activate the correct context for the render target */
1770     context = context_acquire(device, This);
1771     context_apply_blit_state(context, device);
1772     gl_info = context->gl_info;
1773
1774     ENTER_GL();
1775
1776     if (!surface_is_offscreen(This))
1777     {
1778         GLenum buffer = surface_get_gl_buffer(This);
1779         TRACE("Unlocking %#x buffer.\n", buffer);
1780         context_set_draw_buffer(context, buffer);
1781     }
1782     else
1783     {
1784         /* Primary offscreen render target */
1785         TRACE("Offscreen render target.\n");
1786         context_set_draw_buffer(context, device->offscreenBuffer);
1787     }
1788
1789     glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
1790     checkGLcall("glGetIntegerv");
1791     glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
1792     checkGLcall("glGetIntegerv");
1793     glPixelZoom(1.0f, -1.0f);
1794     checkGLcall("glPixelZoom");
1795
1796     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
1797     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
1798     glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
1799
1800     glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
1801     checkGLcall("glRasterPos3i");
1802
1803     /* Some drivers(radeon dri, others?) don't like exceptions during
1804      * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
1805      * after ReleaseDC. Reading it will cause an exception, which x11drv will
1806      * catch to put the dib section in InSync mode, which leads to a crash
1807      * and a blocked x server on my radeon card.
1808      *
1809      * The following lines read the dib section so it is put in InSync mode
1810      * before glDrawPixels is called and the crash is prevented. There won't
1811      * be any interfering gdi accesses, because UnlockRect is called from
1812      * ReleaseDC, and the app won't use the dc any more afterwards.
1813      */
1814     if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) {
1815         volatile BYTE read;
1816         read = This->resource.allocatedMemory[0];
1817     }
1818
1819     if(This->Flags & SFLAG_PBO) {
1820         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1821         checkGLcall("glBindBufferARB");
1822     }
1823
1824     /* When the surface is locked we only have to refresh the locked part else we need to update the whole image */
1825     if(This->Flags & SFLAG_LOCKED) {
1826         glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1827                      (This->lockedRect.bottom - This->lockedRect.top)-1,
1828                      fmt, type,
1829                      mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1830         checkGLcall("glDrawPixels");
1831     } else {
1832         glDrawPixels(This->currentDesc.Width,
1833                      This->currentDesc.Height,
1834                      fmt, type, mem);
1835         checkGLcall("glDrawPixels");
1836     }
1837
1838     if(This->Flags & SFLAG_PBO) {
1839         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1840         checkGLcall("glBindBufferARB");
1841     }
1842
1843     glPixelZoom(1.0f, 1.0f);
1844     checkGLcall("glPixelZoom");
1845
1846     glRasterPos3iv(&prev_rasterpos[0]);
1847     checkGLcall("glRasterPos3iv");
1848
1849     /* Reset to previous pack row length */
1850     glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1851     checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH)");
1852
1853     LEAVE_GL();
1854     context_release(context);
1855 }
1856
1857 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1858     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1859     IWineD3DDeviceImpl *device = This->resource.device;
1860     BOOL fullsurface;
1861
1862     if (!(This->Flags & SFLAG_LOCKED)) {
1863         WARN("trying to Unlock an unlocked surf@%p\n", This);
1864         return WINEDDERR_NOTLOCKED;
1865     }
1866
1867     if (This->Flags & SFLAG_PBO)
1868     {
1869         const struct wined3d_gl_info *gl_info;
1870         struct wined3d_context *context;
1871
1872         TRACE("Freeing PBO memory\n");
1873
1874         context = context_acquire(device, NULL);
1875         gl_info = context->gl_info;
1876
1877         ENTER_GL();
1878         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1879         GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1880         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1881         checkGLcall("glUnmapBufferARB");
1882         LEAVE_GL();
1883         context_release(context);
1884
1885         This->resource.allocatedMemory = NULL;
1886     }
1887
1888     TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1889
1890     if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1891         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1892         goto unlock_end;
1893     }
1894
1895     if (This->container.type == WINED3D_CONTAINER_SWAPCHAIN
1896             || (device->render_targets && This == device->render_targets[0]))
1897     {
1898         if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1899             static BOOL warned = FALSE;
1900             if(!warned) {
1901                 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1902                 warned = TRUE;
1903             }
1904             goto unlock_end;
1905         }
1906
1907         if(This->dirtyRect.left   == 0 &&
1908            This->dirtyRect.top    == 0 &&
1909            This->dirtyRect.right  == This->currentDesc.Width &&
1910            This->dirtyRect.bottom == This->currentDesc.Height) {
1911             fullsurface = TRUE;
1912         } else {
1913             /* TODO: Proper partial rectangle tracking */
1914             fullsurface = FALSE;
1915             This->Flags |= SFLAG_INSYSMEM;
1916         }
1917
1918         switch(wined3d_settings.rendertargetlock_mode) {
1919             case RTL_READTEX:
1920                 surface_load_location(This, SFLAG_INTEXTURE, NULL /* partial texture loading not supported yet */);
1921                 /* drop through */
1922
1923             case RTL_READDRAW:
1924                 surface_load_location(This, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
1925                 break;
1926         }
1927
1928         if(!fullsurface) {
1929             /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite
1930              * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where
1931              * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy
1932              * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is
1933              * not fully up to date because only a subrectangle was read in LockRect.
1934              */
1935             This->Flags &= ~SFLAG_INSYSMEM;
1936             This->Flags |= SFLAG_INDRAWABLE;
1937         }
1938
1939         This->dirtyRect.left   = This->currentDesc.Width;
1940         This->dirtyRect.top    = This->currentDesc.Height;
1941         This->dirtyRect.right  = 0;
1942         This->dirtyRect.bottom = 0;
1943     }
1944     else if (This == device->depth_stencil)
1945     {
1946         FIXME("Depth Stencil buffer locking is not implemented\n");
1947     } else {
1948         /* The rest should be a normal texture */
1949         IWineD3DBaseTextureImpl *impl;
1950         /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1951          * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1952          * states need resetting
1953          */
1954         if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1955             if (impl->baseTexture.bindCount)
1956                 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(impl->baseTexture.sampler));
1957             IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1958         }
1959     }
1960
1961     unlock_end:
1962     This->Flags &= ~SFLAG_LOCKED;
1963     memset(&This->lockedRect, 0, sizeof(RECT));
1964
1965     /* Overlays have to be redrawn manually after changes with the GL implementation */
1966     if(This->overlay_dest) {
1967         IWineD3DSurface_DrawOverlay(iface);
1968     }
1969     return WINED3D_OK;
1970 }
1971
1972 static void surface_release_client_storage(IWineD3DSurfaceImpl *surface)
1973 {
1974     struct wined3d_context *context;
1975
1976     context = context_acquire(surface->resource.device, NULL);
1977
1978     ENTER_GL();
1979     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1980     if (surface->texture_name)
1981     {
1982         surface_bind_and_dirtify(surface, FALSE);
1983         glTexImage2D(surface->texture_target, surface->texture_level,
1984                 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
1985     }
1986     if (surface->texture_name_srgb)
1987     {
1988         surface_bind_and_dirtify(surface, TRUE);
1989         glTexImage2D(surface->texture_target, surface->texture_level,
1990                 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
1991     }
1992     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1993
1994     LEAVE_GL();
1995     context_release(context);
1996
1997     surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
1998     surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
1999     surface_force_reload(surface);
2000 }
2001
2002 static HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC)
2003 {
2004     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2005     WINED3DLOCKED_RECT lock;
2006     HRESULT hr;
2007     RGBQUAD col[256];
2008
2009     TRACE("(%p)->(%p)\n",This,pHDC);
2010
2011     if(This->Flags & SFLAG_USERPTR) {
2012         ERR("Not supported on surfaces with an application-provided surfaces\n");
2013         return WINEDDERR_NODC;
2014     }
2015
2016     /* Give more detailed info for ddraw */
2017     if (This->Flags & SFLAG_DCINUSE)
2018         return WINEDDERR_DCALREADYCREATED;
2019
2020     /* Can't GetDC if the surface is locked */
2021     if (This->Flags & SFLAG_LOCKED)
2022         return WINED3DERR_INVALIDCALL;
2023
2024     memset(&lock, 0, sizeof(lock)); /* To be sure */
2025
2026     /* Create a DIB section if there isn't a hdc yet */
2027     if (!This->hDC)
2028     {
2029         if (This->Flags & SFLAG_CLIENT)
2030         {
2031             surface_load_location(This, SFLAG_INSYSMEM, NULL);
2032             surface_release_client_storage(This);
2033         }
2034         hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
2035         if(FAILED(hr)) return WINED3DERR_INVALIDCALL;
2036
2037         /* Use the dib section from now on if we are not using a PBO */
2038         if(!(This->Flags & SFLAG_PBO))
2039             This->resource.allocatedMemory = This->dib.bitmap_data;
2040     }
2041
2042     /* Lock the surface */
2043     hr = IWineD3DSurface_LockRect(iface,
2044                                   &lock,
2045                                   NULL,
2046                                   0);
2047
2048     if(This->Flags & SFLAG_PBO) {
2049         /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
2050         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
2051     }
2052
2053     if(FAILED(hr)) {
2054         ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
2055         /* keep the dib section */
2056         return hr;
2057     }
2058
2059     if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
2060             || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
2061     {
2062         /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
2063             D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
2064         unsigned int n;
2065         const PALETTEENTRY *pal = NULL;
2066
2067         if(This->palette) {
2068             pal = This->palette->palents;
2069         } else {
2070             IWineD3DSurfaceImpl *dds_primary;
2071             IWineD3DSwapChainImpl *swapchain;
2072             swapchain = (IWineD3DSwapChainImpl *)This->resource.device->swapchains[0];
2073             dds_primary = swapchain->front_buffer;
2074             if (dds_primary && dds_primary->palette)
2075                 pal = dds_primary->palette->palents;
2076         }
2077
2078         if (pal) {
2079             for (n=0; n<256; n++) {
2080                 col[n].rgbRed   = pal[n].peRed;
2081                 col[n].rgbGreen = pal[n].peGreen;
2082                 col[n].rgbBlue  = pal[n].peBlue;
2083                 col[n].rgbReserved = 0;
2084             }
2085             SetDIBColorTable(This->hDC, 0, 256, col);
2086         }
2087     }
2088
2089     *pHDC = This->hDC;
2090     TRACE("returning %p\n",*pHDC);
2091     This->Flags |= SFLAG_DCINUSE;
2092
2093     return WINED3D_OK;
2094 }
2095
2096 static HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC)
2097 {
2098     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2099
2100     TRACE("(%p)->(%p)\n",This,hDC);
2101
2102     if (!(This->Flags & SFLAG_DCINUSE))
2103         return WINEDDERR_NODC;
2104
2105     if (This->hDC !=hDC) {
2106         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
2107         return WINEDDERR_NODC;
2108     }
2109
2110     if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) {
2111         /* Copy the contents of the DIB over to the PBO */
2112         memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
2113     }
2114
2115     /* we locked first, so unlock now */
2116     IWineD3DSurface_UnlockRect(iface);
2117
2118     This->Flags &= ~SFLAG_DCINUSE;
2119
2120     return WINED3D_OK;
2121 }
2122
2123 /* ******************************************************
2124    IWineD3DSurface Internal (No mapping to directx api) parts follow
2125    ****************************************************** */
2126
2127 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, struct wined3d_format_desc *desc, CONVERT_TYPES *convert)
2128 {
2129     BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
2130     IWineD3DDeviceImpl *device = This->resource.device;
2131     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2132     BOOL blit_supported = FALSE;
2133
2134     /* Copy the default values from the surface. Below we might perform fixups */
2135     /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2136     *desc = *This->resource.format_desc;
2137     *convert = NO_CONVERSION;
2138
2139     /* Ok, now look if we have to do any conversion */
2140     switch(This->resource.format_desc->format)
2141     {
2142         case WINED3DFMT_P8_UINT:
2143             /* ****************
2144                 Paletted Texture
2145                 **************** */
2146
2147             /* Below the call to blit_supported is disabled for Wine 1.2 because the function isn't operating correctly yet.
2148              * At the moment 8-bit blits are handled in software and if certain GL extensions are around, surface conversion
2149              * is performed at upload time. The blit_supported call recognizes it as a destination fixup. This type of upload 'fixup'
2150              * and 8-bit to 8-bit blits need to be handled by the blit_shader.
2151              * TODO: get rid of this #if 0
2152              */
2153 #if 0
2154             blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
2155                                                              &rect, This->resource.usage, This->resource.pool,
2156                                                              This->resource.format_desc, &rect, This->resource.usage,
2157                                                              This->resource.pool, This->resource.format_desc);
2158 #endif
2159             blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2160
2161             /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2162              * texturing. Further also use conversion in case of color keying.
2163              * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2164              * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2165              * conflicts with this.
2166              */
2167             if (!((blit_supported && device->render_targets && This == device->render_targets[0]))
2168                     || colorkey_active || !use_texturing)
2169             {
2170                 desc->glFormat = GL_RGBA;
2171                 desc->glInternal = GL_RGBA;
2172                 desc->glType = GL_UNSIGNED_BYTE;
2173                 desc->conv_byte_count = 4;
2174                 if(colorkey_active) {
2175                     *convert = CONVERT_PALETTED_CK;
2176                 } else {
2177                     *convert = CONVERT_PALETTED;
2178                 }
2179             }
2180             break;
2181
2182         case WINED3DFMT_B2G3R3_UNORM:
2183             /* **********************
2184                 GL_UNSIGNED_BYTE_3_3_2
2185                 ********************** */
2186             if (colorkey_active) {
2187                 /* This texture format will never be used.. So do not care about color keying
2188                     up until the point in time it will be needed :-) */
2189                 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2190             }
2191             break;
2192
2193         case WINED3DFMT_B5G6R5_UNORM:
2194             if (colorkey_active) {
2195                 *convert = CONVERT_CK_565;
2196                 desc->glFormat = GL_RGBA;
2197                 desc->glInternal = GL_RGB5_A1;
2198                 desc->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2199                 desc->conv_byte_count = 2;
2200             }
2201             break;
2202
2203         case WINED3DFMT_B5G5R5X1_UNORM:
2204             if (colorkey_active) {
2205                 *convert = CONVERT_CK_5551;
2206                 desc->glFormat = GL_BGRA;
2207                 desc->glInternal = GL_RGB5_A1;
2208                 desc->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2209                 desc->conv_byte_count = 2;
2210             }
2211             break;
2212
2213         case WINED3DFMT_B8G8R8_UNORM:
2214             if (colorkey_active) {
2215                 *convert = CONVERT_CK_RGB24;
2216                 desc->glFormat = GL_RGBA;
2217                 desc->glInternal = GL_RGBA8;
2218                 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2219                 desc->conv_byte_count = 4;
2220             }
2221             break;
2222
2223         case WINED3DFMT_B8G8R8X8_UNORM:
2224             if (colorkey_active) {
2225                 *convert = CONVERT_RGB32_888;
2226                 desc->glFormat = GL_RGBA;
2227                 desc->glInternal = GL_RGBA8;
2228                 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2229                 desc->conv_byte_count = 4;
2230             }
2231             break;
2232
2233         default:
2234             break;
2235     }
2236
2237     return WINED3D_OK;
2238 }
2239
2240 void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
2241 {
2242     IWineD3DDeviceImpl *device = This->resource.device;
2243     IWineD3DPaletteImpl *pal = This->palette;
2244     BOOL index_in_alpha = FALSE;
2245     unsigned int i;
2246
2247     /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
2248      * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
2249      * is slow. Further RGB->P8 conversion is not possible because palettes can have
2250      * duplicate entries. Store the color key in the unused alpha component to speed the
2251      * download up and to make conversion unneeded. */
2252     index_in_alpha = primary_render_target_is_p8(device);
2253
2254     if (!pal)
2255     {
2256         UINT dxVersion = ((IWineD3DImpl *)device->wined3d)->dxVersion;
2257
2258         /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
2259         if (dxVersion <= 7)
2260         {
2261             ERR("This code should never get entered for DirectDraw!, expect problems\n");
2262             if (index_in_alpha)
2263             {
2264                 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
2265                  * there's no palette at this time. */
2266                 for (i = 0; i < 256; i++) table[i][3] = i;
2267             }
2268         }
2269         else
2270         {
2271             /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
2272              * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
2273              * capability flag is present (wine does advertise this capability) */
2274             for (i = 0; i < 256; ++i)
2275             {
2276                 table[i][0] = device->palettes[device->currentPalette][i].peRed;
2277                 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
2278                 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
2279                 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
2280             }
2281         }
2282     }
2283     else
2284     {
2285         TRACE("Using surface palette %p\n", pal);
2286         /* Get the surface's palette */
2287         for (i = 0; i < 256; ++i)
2288         {
2289             table[i][0] = pal->palents[i].peRed;
2290             table[i][1] = pal->palents[i].peGreen;
2291             table[i][2] = pal->palents[i].peBlue;
2292
2293             /* When index_in_alpha is set the palette index is stored in the
2294              * alpha component. In case of a readback we can then read
2295              * GL_ALPHA. Color keying is handled in BltOverride using a
2296              * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
2297              * color key itself is passed to glAlphaFunc in other cases the
2298              * alpha component of pixels that should be masked away is set to 0. */
2299             if (index_in_alpha)
2300             {
2301                 table[i][3] = i;
2302             }
2303             else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
2304                     && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
2305             {
2306                 table[i][3] = 0x00;
2307             }
2308             else if(pal->Flags & WINEDDPCAPS_ALPHA)
2309             {
2310                 table[i][3] = pal->palents[i].peFlags;
2311             }
2312             else
2313             {
2314                 table[i][3] = 0xFF;
2315             }
2316         }
2317     }
2318 }
2319
2320 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
2321         UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
2322 {
2323     const BYTE *source;
2324     BYTE *dest;
2325     TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
2326
2327     switch (convert) {
2328         case NO_CONVERSION:
2329         {
2330             memcpy(dst, src, pitch * height);
2331             break;
2332         }
2333         case CONVERT_PALETTED:
2334         case CONVERT_PALETTED_CK:
2335         {
2336             IWineD3DPaletteImpl* pal = This->palette;
2337             BYTE table[256][4];
2338             unsigned int x, y;
2339
2340             if( pal == NULL) {
2341                 /* TODO: If we are a sublevel, try to get the palette from level 0 */
2342             }
2343
2344             d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
2345
2346             for (y = 0; y < height; y++)
2347             {
2348                 source = src + pitch * y;
2349                 dest = dst + outpitch * y;
2350                 /* This is an 1 bpp format, using the width here is fine */
2351                 for (x = 0; x < width; x++) {
2352                     BYTE color = *source++;
2353                     *dest++ = table[color][0];
2354                     *dest++ = table[color][1];
2355                     *dest++ = table[color][2];
2356                     *dest++ = table[color][3];
2357                 }
2358             }
2359         }
2360         break;
2361
2362         case CONVERT_CK_565:
2363         {
2364             /* Converting the 565 format in 5551 packed to emulate color-keying.
2365
2366               Note : in all these conversion, it would be best to average the averaging
2367                       pixels to get the color of the pixel that will be color-keyed to
2368                       prevent 'color bleeding'. This will be done later on if ever it is
2369                       too visible.
2370
2371               Note2: Nvidia documents say that their driver does not support alpha + color keying
2372                      on the same surface and disables color keying in such a case
2373             */
2374             unsigned int x, y;
2375             const WORD *Source;
2376             WORD *Dest;
2377
2378             TRACE("Color keyed 565\n");
2379
2380             for (y = 0; y < height; y++) {
2381                 Source = (const WORD *)(src + y * pitch);
2382                 Dest = (WORD *) (dst + y * outpitch);
2383                 for (x = 0; x < width; x++ ) {
2384                     WORD color = *Source++;
2385                     *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
2386                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2387                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2388                         *Dest |= 0x0001;
2389                     }
2390                     Dest++;
2391                 }
2392             }
2393         }
2394         break;
2395
2396         case CONVERT_CK_5551:
2397         {
2398             /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
2399             unsigned int x, y;
2400             const WORD *Source;
2401             WORD *Dest;
2402             TRACE("Color keyed 5551\n");
2403             for (y = 0; y < height; y++) {
2404                 Source = (const WORD *)(src + y * pitch);
2405                 Dest = (WORD *) (dst + y * outpitch);
2406                 for (x = 0; x < width; x++ ) {
2407                     WORD color = *Source++;
2408                     *Dest = color;
2409                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2410                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2411                         *Dest |= (1 << 15);
2412                     }
2413                     else {
2414                         *Dest &= ~(1 << 15);
2415                     }
2416                     Dest++;
2417                 }
2418             }
2419         }
2420         break;
2421
2422         case CONVERT_CK_RGB24:
2423         {
2424             /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
2425             unsigned int x, y;
2426             for (y = 0; y < height; y++)
2427             {
2428                 source = src + pitch * y;
2429                 dest = dst + outpitch * y;
2430                 for (x = 0; x < width; x++) {
2431                     DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
2432                     DWORD dstcolor = color << 8;
2433                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2434                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2435                         dstcolor |= 0xff;
2436                     }
2437                     *(DWORD*)dest = dstcolor;
2438                     source += 3;
2439                     dest += 4;
2440                 }
2441             }
2442         }
2443         break;
2444
2445         case CONVERT_RGB32_888:
2446         {
2447             /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
2448             unsigned int x, y;
2449             for (y = 0; y < height; y++)
2450             {
2451                 source = src + pitch * y;
2452                 dest = dst + outpitch * y;
2453                 for (x = 0; x < width; x++) {
2454                     DWORD color = 0xffffff & *(const DWORD*)source;
2455                     DWORD dstcolor = color << 8;
2456                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2457                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2458                         dstcolor |= 0xff;
2459                     }
2460                     *(DWORD*)dest = dstcolor;
2461                     source += 4;
2462                     dest += 4;
2463                 }
2464             }
2465         }
2466         break;
2467
2468         default:
2469             ERR("Unsupported conversion type %#x.\n", convert);
2470     }
2471     return WINED3D_OK;
2472 }
2473
2474 BOOL palette9_changed(IWineD3DSurfaceImpl *This)
2475 {
2476     IWineD3DDeviceImpl *device = This->resource.device;
2477
2478     if (This->palette || (This->resource.format_desc->format != WINED3DFMT_P8_UINT
2479             && This->resource.format_desc->format != WINED3DFMT_P8_UINT_A8_UNORM))
2480     {
2481         /* If a ddraw-style palette is attached assume no d3d9 palette change.
2482          * Also the palette isn't interesting if the surface format isn't P8 or A8P8
2483          */
2484         return FALSE;
2485     }
2486
2487     if (This->palette9)
2488     {
2489         if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
2490         {
2491             return FALSE;
2492         }
2493     } else {
2494         This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2495     }
2496     memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
2497     return TRUE;
2498 }
2499
2500 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
2501     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2502     DWORD flag = srgb_mode ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2503
2504     if (!(This->Flags & flag)) {
2505         TRACE("Reloading because surface is dirty\n");
2506     } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2507               ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
2508               /* Reload: vice versa  OR */
2509               ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
2510               /* Also reload: Color key is active AND the color key has changed */
2511               ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
2512                 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
2513                 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
2514         TRACE("Reloading because of color keying\n");
2515         /* To perform the color key conversion we need a sysmem copy of
2516          * the surface. Make sure we have it
2517          */
2518
2519         surface_load_location(This, SFLAG_INSYSMEM, NULL);
2520         /* Make sure the texture is reloaded because of the color key change, this kills performance though :( */
2521         /* TODO: This is not necessarily needed with hw palettized texture support */
2522         surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
2523     } else {
2524         TRACE("surface is already in texture\n");
2525         return WINED3D_OK;
2526     }
2527
2528     /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2529      *  These resources are not bound by device size or format restrictions. Because of this,
2530      *  these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2531      *  However, these resources can always be created, locked, and copied.
2532      */
2533     if (This->resource.pool == WINED3DPOOL_SCRATCH )
2534     {
2535         FIXME("(%p) Operation not supported for scratch textures\n",This);
2536         return WINED3DERR_INVALIDCALL;
2537     }
2538
2539     surface_load_location(This, flag, NULL /* no partial locking for textures yet */);
2540
2541     if (!(This->Flags & SFLAG_DONOTFREE)) {
2542         HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
2543         This->resource.allocatedMemory = NULL;
2544         This->resource.heapMemory = NULL;
2545         surface_modify_location(This, SFLAG_INSYSMEM, FALSE);
2546     }
2547
2548     return WINED3D_OK;
2549 }
2550
2551 /* Context activation is done by the caller. */
2552 static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
2553     /* TODO: check for locks */
2554     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2555     IWineD3DBaseTexture *baseTexture = NULL;
2556
2557     TRACE("(%p)Checking to see if the container is a base texture\n", This);
2558     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2559         TRACE("Passing to container\n");
2560         IWineD3DBaseTexture_BindTexture(baseTexture, srgb);
2561         IWineD3DBaseTexture_Release(baseTexture);
2562     }
2563     else
2564     {
2565         GLuint *name;
2566
2567         TRACE("(%p) : Binding surface\n", This);
2568
2569         name = srgb ? &This->texture_name_srgb : &This->texture_name;
2570
2571         ENTER_GL();
2572
2573         if (!This->texture_level)
2574         {
2575             if (!*name) {
2576                 glGenTextures(1, name);
2577                 checkGLcall("glGenTextures");
2578                 TRACE("Surface %p given name %d\n", This, *name);
2579
2580                 glBindTexture(This->texture_target, *name);
2581                 checkGLcall("glBindTexture");
2582                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2583                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
2584                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2585                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
2586                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2587                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)");
2588                 glTexParameteri(This->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2589                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
2590                 glTexParameteri(This->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2591                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
2592             }
2593             /* This is where we should be reducing the amount of GLMemoryUsed */
2594         } else if (*name) {
2595             /* Mipmap surfaces should have a base texture container */
2596             ERR("Mipmap surface has a glTexture bound to it!\n");
2597         }
2598
2599         glBindTexture(This->texture_target, *name);
2600         checkGLcall("glBindTexture");
2601
2602         LEAVE_GL();
2603     }
2604 }
2605
2606 static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2607     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2608     HRESULT hr;
2609
2610     TRACE("(%p) : Calling base function first\n", This);
2611     hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
2612     if(SUCCEEDED(hr)) {
2613         This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
2614         TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This, This->resource.format_desc->glFormat,
2615                 This->resource.format_desc->glInternal, This->resource.format_desc->glType);
2616     }
2617     return hr;
2618 }
2619
2620 static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2621     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2622
2623     if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2624         WARN("Surface is locked or the HDC is in use\n");
2625         return WINED3DERR_INVALIDCALL;
2626     }
2627
2628     if(Mem && Mem != This->resource.allocatedMemory) {
2629         void *release = NULL;
2630
2631         /* Do I have to copy the old surface content? */
2632         if(This->Flags & SFLAG_DIBSECTION) {
2633                 /* Release the DC. No need to hold the critical section for the update
2634                  * Thread because this thread runs only on front buffers, but this method
2635                  * fails for render targets in the check above.
2636                  */
2637                 SelectObject(This->hDC, This->dib.holdbitmap);
2638                 DeleteDC(This->hDC);
2639                 /* Release the DIB section */
2640                 DeleteObject(This->dib.DIBsection);
2641                 This->dib.bitmap_data = NULL;
2642                 This->resource.allocatedMemory = NULL;
2643                 This->hDC = NULL;
2644                 This->Flags &= ~SFLAG_DIBSECTION;
2645         } else if(!(This->Flags & SFLAG_USERPTR)) {
2646             release = This->resource.heapMemory;
2647             This->resource.heapMemory = NULL;
2648         }
2649         This->resource.allocatedMemory = Mem;
2650         This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
2651
2652         /* Now the surface memory is most up do date. Invalidate drawable and texture */
2653         surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
2654
2655         /* For client textures opengl has to be notified */
2656         if (This->Flags & SFLAG_CLIENT)
2657             surface_release_client_storage(This);
2658
2659         /* Now free the old memory if any */
2660         HeapFree(GetProcessHeap(), 0, release);
2661     } else if(This->Flags & SFLAG_USERPTR) {
2662         /* LockRect and GetDC will re-create the dib section and allocated memory */
2663         This->resource.allocatedMemory = NULL;
2664         /* HeapMemory should be NULL already */
2665         if(This->resource.heapMemory != NULL) ERR("User pointer surface has heap memory allocated\n");
2666         This->Flags &= ~SFLAG_USERPTR;
2667
2668         if (This->Flags & SFLAG_CLIENT)
2669             surface_release_client_storage(This);
2670     }
2671     return WINED3D_OK;
2672 }
2673
2674 void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
2675
2676     /* Flip the surface contents */
2677     /* Flip the DC */
2678     {
2679         HDC tmp;
2680         tmp = front->hDC;
2681         front->hDC = back->hDC;
2682         back->hDC = tmp;
2683     }
2684
2685     /* Flip the DIBsection */
2686     {
2687         HBITMAP tmp;
2688         BOOL hasDib = front->Flags & SFLAG_DIBSECTION;
2689         tmp = front->dib.DIBsection;
2690         front->dib.DIBsection = back->dib.DIBsection;
2691         back->dib.DIBsection = tmp;
2692
2693         if(back->Flags & SFLAG_DIBSECTION) front->Flags |= SFLAG_DIBSECTION;
2694         else front->Flags &= ~SFLAG_DIBSECTION;
2695         if(hasDib) back->Flags |= SFLAG_DIBSECTION;
2696         else back->Flags &= ~SFLAG_DIBSECTION;
2697     }
2698
2699     /* Flip the surface data */
2700     {
2701         void* tmp;
2702
2703         tmp = front->dib.bitmap_data;
2704         front->dib.bitmap_data = back->dib.bitmap_data;
2705         back->dib.bitmap_data = tmp;
2706
2707         tmp = front->resource.allocatedMemory;
2708         front->resource.allocatedMemory = back->resource.allocatedMemory;
2709         back->resource.allocatedMemory = tmp;
2710
2711         tmp = front->resource.heapMemory;
2712         front->resource.heapMemory = back->resource.heapMemory;
2713         back->resource.heapMemory = tmp;
2714     }
2715
2716     /* Flip the PBO */
2717     {
2718         GLuint tmp_pbo = front->pbo;
2719         front->pbo = back->pbo;
2720         back->pbo = tmp_pbo;
2721     }
2722
2723     /* client_memory should not be different, but just in case */
2724     {
2725         BOOL tmp;
2726         tmp = front->dib.client_memory;
2727         front->dib.client_memory = back->dib.client_memory;
2728         back->dib.client_memory = tmp;
2729     }
2730
2731     /* Flip the opengl texture */
2732     {
2733         GLuint tmp;
2734
2735         tmp = back->texture_name;
2736         back->texture_name = front->texture_name;
2737         front->texture_name = tmp;
2738
2739         tmp = back->texture_name_srgb;
2740         back->texture_name_srgb = front->texture_name_srgb;
2741         front->texture_name_srgb = tmp;
2742     }
2743
2744     {
2745         DWORD tmp_flags = back->Flags;
2746         back->Flags = front->Flags;
2747         front->Flags = tmp_flags;
2748     }
2749 }
2750
2751 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2752     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2753     IWineD3DSwapChainImpl *swapchain = NULL;
2754     HRESULT hr;
2755     TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2756
2757     /* Flipping is only supported on RenderTargets and overlays*/
2758     if( !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)) ) {
2759         WARN("Tried to flip a non-render target, non-overlay surface\n");
2760         return WINEDDERR_NOTFLIPPABLE;
2761     }
2762
2763     if(This->resource.usage & WINED3DUSAGE_OVERLAY) {
2764         flip_surface(This, (IWineD3DSurfaceImpl *) override);
2765
2766         /* Update the overlay if it is visible */
2767         if(This->overlay_dest) {
2768             return IWineD3DSurface_DrawOverlay((IWineD3DSurface *) This);
2769         } else {
2770             return WINED3D_OK;
2771         }
2772     }
2773
2774     if(override) {
2775         /* DDraw sets this for the X11 surfaces, so don't confuse the user
2776          * FIXME("(%p) Target override is not supported by now\n", This);
2777          * Additionally, it isn't really possible to support triple-buffering
2778          * properly on opengl at all
2779          */
2780     }
2781
2782     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
2783     if(!swapchain) {
2784         ERR("Flipped surface is not on a swapchain\n");
2785         return WINEDDERR_NOTFLIPPABLE;
2786     }
2787
2788     /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
2789      * and only d3d8 and d3d9 apps specify the presentation interval
2790      */
2791     if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
2792         /* Most common case first to avoid wasting time on all the other cases */
2793         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
2794     } else if(Flags & WINEDDFLIP_NOVSYNC) {
2795         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2796     } else if(Flags & WINEDDFLIP_INTERVAL2) {
2797         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
2798     } else if(Flags & WINEDDFLIP_INTERVAL3) {
2799         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
2800     } else {
2801         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
2802     }
2803
2804     /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2805     hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
2806             NULL, NULL, swapchain->win_handle, NULL, 0);
2807     IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2808     return hr;
2809 }
2810
2811 /* Does a direct frame buffer -> texture copy. Stretching is done
2812  * with single pixel copy calls
2813  */
2814 static void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
2815         const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
2816 {
2817     IWineD3DDeviceImpl *device = dst_surface->resource.device;
2818     float xrel, yrel;
2819     UINT row;
2820     struct wined3d_context *context;
2821     BOOL upsidedown = FALSE;
2822     RECT dst_rect = *dst_rect_in;
2823
2824     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2825      * glCopyTexSubImage is a bit picky about the parameters we pass to it
2826      */
2827     if(dst_rect.top > dst_rect.bottom) {
2828         UINT tmp = dst_rect.bottom;
2829         dst_rect.bottom = dst_rect.top;
2830         dst_rect.top = tmp;
2831         upsidedown = TRUE;
2832     }
2833
2834     context = context_acquire(device, src_surface);
2835     context_apply_blit_state(context, device);
2836     surface_internal_preload(dst_surface, SRGB_RGB);
2837     ENTER_GL();
2838
2839     /* Bind the target texture */
2840     glBindTexture(dst_surface->texture_target, dst_surface->texture_name);
2841     checkGLcall("glBindTexture");
2842     if (surface_is_offscreen(src_surface))
2843     {
2844         TRACE("Reading from an offscreen target\n");
2845         upsidedown = !upsidedown;
2846         glReadBuffer(device->offscreenBuffer);
2847     }
2848     else
2849     {
2850         glReadBuffer(surface_get_gl_buffer(src_surface));
2851     }
2852     checkGLcall("glReadBuffer");
2853
2854     xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
2855     yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
2856
2857     if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2858     {
2859         FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2860
2861         if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
2862             ERR("Texture filtering not supported in direct blit\n");
2863         }
2864     }
2865     else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
2866             && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2867     {
2868         ERR("Texture filtering not supported in direct blit\n");
2869     }
2870
2871     if (upsidedown
2872             && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2873             && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2874     {
2875         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2876
2877         glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2878                 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
2879                 src_rect->left, src_surface->currentDesc.Height - src_rect->bottom,
2880                 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2881     } else {
2882         UINT yoffset = src_surface->currentDesc.Height - src_rect->top + dst_rect.top - 1;
2883         /* I have to process this row by row to swap the image,
2884          * otherwise it would be upside down, so stretching in y direction
2885          * doesn't cost extra time
2886          *
2887          * However, stretching in x direction can be avoided if not necessary
2888          */
2889         for(row = dst_rect.top; row < dst_rect.bottom; row++) {
2890             if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2891             {
2892                 /* Well, that stuff works, but it's very slow.
2893                  * find a better way instead
2894                  */
2895                 UINT col;
2896
2897                 for (col = dst_rect.left; col < dst_rect.right; ++col)
2898                 {
2899                     glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2900                             dst_rect.left + col /* x offset */, row /* y offset */,
2901                             src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
2902                 }
2903             }
2904             else
2905             {
2906                 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2907                         dst_rect.left /* x offset */, row /* y offset */,
2908                         src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
2909             }
2910         }
2911     }
2912     checkGLcall("glCopyTexSubImage2D");
2913
2914     LEAVE_GL();
2915     context_release(context);
2916
2917     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
2918      * path is never entered
2919      */
2920     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2921 }
2922
2923 /* Uses the hardware to stretch and flip the image */
2924 static void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
2925         const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
2926 {
2927     IWineD3DDeviceImpl *device = dst_surface->resource.device;
2928     GLuint src, backup = 0;
2929     IWineD3DSwapChainImpl *src_swapchain = NULL;
2930     float left, right, top, bottom; /* Texture coordinates */
2931     UINT fbwidth = src_surface->currentDesc.Width;
2932     UINT fbheight = src_surface->currentDesc.Height;
2933     struct wined3d_context *context;
2934     GLenum drawBuffer = GL_BACK;
2935     GLenum texture_target;
2936     BOOL noBackBufferBackup;
2937     BOOL src_offscreen;
2938     BOOL upsidedown = FALSE;
2939     RECT dst_rect = *dst_rect_in;
2940
2941     TRACE("Using hwstretch blit\n");
2942     /* Activate the Proper context for reading from the source surface, set it up for blitting */
2943     context = context_acquire(device, src_surface);
2944     context_apply_blit_state(context, device);
2945     surface_internal_preload(dst_surface, SRGB_RGB);
2946
2947     src_offscreen = surface_is_offscreen(src_surface);
2948     noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
2949     if (!noBackBufferBackup && !src_surface->texture_name)
2950     {
2951         /* Get it a description */
2952         surface_internal_preload(src_surface, SRGB_RGB);
2953     }
2954     ENTER_GL();
2955
2956     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2957      * This way we don't have to wait for the 2nd readback to finish to leave this function.
2958      */
2959     if (context->aux_buffers >= 2)
2960     {
2961         /* Got more than one aux buffer? Use the 2nd aux buffer */
2962         drawBuffer = GL_AUX1;
2963     }
2964     else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
2965     {
2966         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2967         drawBuffer = GL_AUX0;
2968     }
2969
2970     if(noBackBufferBackup) {
2971         glGenTextures(1, &backup);
2972         checkGLcall("glGenTextures");
2973         glBindTexture(GL_TEXTURE_2D, backup);
2974         checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2975         texture_target = GL_TEXTURE_2D;
2976     } else {
2977         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2978          * we are reading from the back buffer, the backup can be used as source texture
2979          */
2980         texture_target = src_surface->texture_target;
2981         glBindTexture(texture_target, src_surface->texture_name);
2982         checkGLcall("glBindTexture(texture_target, src_surface->texture_name)");
2983         glEnable(texture_target);
2984         checkGLcall("glEnable(texture_target)");
2985
2986         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2987         src_surface->Flags &= ~SFLAG_INTEXTURE;
2988     }
2989
2990     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2991      * glCopyTexSubImage is a bit picky about the parameters we pass to it
2992      */
2993     if(dst_rect.top > dst_rect.bottom) {
2994         UINT tmp = dst_rect.bottom;
2995         dst_rect.bottom = dst_rect.top;
2996         dst_rect.top = tmp;
2997         upsidedown = TRUE;
2998     }
2999
3000     if (src_offscreen)
3001     {
3002         TRACE("Reading from an offscreen target\n");
3003         upsidedown = !upsidedown;
3004         glReadBuffer(device->offscreenBuffer);
3005     }
3006     else
3007     {
3008         glReadBuffer(surface_get_gl_buffer(src_surface));
3009     }
3010
3011     /* TODO: Only back up the part that will be overwritten */
3012     glCopyTexSubImage2D(texture_target, 0,
3013                         0, 0 /* read offsets */,
3014                         0, 0,
3015                         fbwidth,
3016                         fbheight);
3017
3018     checkGLcall("glCopyTexSubImage2D");
3019
3020     /* No issue with overriding these - the sampler is dirty due to blit usage */
3021     glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
3022             wined3d_gl_mag_filter(magLookup, Filter));
3023     checkGLcall("glTexParameteri");
3024     glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
3025             wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
3026     checkGLcall("glTexParameteri");
3027
3028     IWineD3DSurface_GetContainer((IWineD3DSurface *)src_surface, &IID_IWineD3DSwapChain, (void **)&src_swapchain);
3029     if (src_swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)src_swapchain);
3030     if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
3031     {
3032         src = backup ? backup : src_surface->texture_name;
3033     }
3034     else
3035     {
3036         glReadBuffer(GL_FRONT);
3037         checkGLcall("glReadBuffer(GL_FRONT)");
3038
3039         glGenTextures(1, &src);
3040         checkGLcall("glGenTextures(1, &src)");
3041         glBindTexture(GL_TEXTURE_2D, src);
3042         checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
3043
3044         /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3045          * out for power of 2 sizes
3046          */
3047         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
3048                 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
3049         checkGLcall("glTexImage2D");
3050         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3051                             0, 0 /* read offsets */,
3052                             0, 0,
3053                             fbwidth,
3054                             fbheight);
3055
3056         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3057         checkGLcall("glTexParameteri");
3058         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3059         checkGLcall("glTexParameteri");
3060
3061         glReadBuffer(GL_BACK);
3062         checkGLcall("glReadBuffer(GL_BACK)");
3063
3064         if(texture_target != GL_TEXTURE_2D) {
3065             glDisable(texture_target);
3066             glEnable(GL_TEXTURE_2D);
3067             texture_target = GL_TEXTURE_2D;
3068         }
3069     }
3070     checkGLcall("glEnd and previous");
3071
3072     left = src_rect->left;
3073     right = src_rect->right;
3074
3075     if (upsidedown)
3076     {
3077         top = src_surface->currentDesc.Height - src_rect->top;
3078         bottom = src_surface->currentDesc.Height - src_rect->bottom;
3079     }
3080     else
3081     {
3082         top = src_surface->currentDesc.Height - src_rect->bottom;
3083         bottom = src_surface->currentDesc.Height - src_rect->top;
3084     }
3085
3086     if (src_surface->Flags & SFLAG_NORMCOORD)
3087     {
3088         left /= src_surface->pow2Width;
3089         right /= src_surface->pow2Width;
3090         top /= src_surface->pow2Height;
3091         bottom /= src_surface->pow2Height;
3092     }
3093
3094     /* draw the source texture stretched and upside down. The correct surface is bound already */
3095     glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
3096     glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
3097
3098     context_set_draw_buffer(context, drawBuffer);
3099     glReadBuffer(drawBuffer);
3100
3101     glBegin(GL_QUADS);
3102         /* bottom left */
3103         glTexCoord2f(left, bottom);
3104         glVertex2i(0, fbheight);
3105
3106         /* top left */
3107         glTexCoord2f(left, top);
3108         glVertex2i(0, fbheight - dst_rect.bottom - dst_rect.top);
3109
3110         /* top right */
3111         glTexCoord2f(right, top);
3112         glVertex2i(dst_rect.right - dst_rect.left, fbheight - dst_rect.bottom - dst_rect.top);
3113
3114         /* bottom right */
3115         glTexCoord2f(right, bottom);
3116         glVertex2i(dst_rect.right - dst_rect.left, fbheight);
3117     glEnd();
3118     checkGLcall("glEnd and previous");
3119
3120     if (texture_target != dst_surface->texture_target)
3121     {
3122         glDisable(texture_target);
3123         glEnable(dst_surface->texture_target);
3124         texture_target = dst_surface->texture_target;
3125     }
3126
3127     /* Now read the stretched and upside down image into the destination texture */
3128     glBindTexture(texture_target, dst_surface->texture_name);
3129     checkGLcall("glBindTexture");
3130     glCopyTexSubImage2D(texture_target,
3131                         0,
3132                         dst_rect.left, dst_rect.top, /* xoffset, yoffset */
3133                         0, 0, /* We blitted the image to the origin */
3134                         dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3135     checkGLcall("glCopyTexSubImage2D");
3136
3137     if(drawBuffer == GL_BACK) {
3138         /* Write the back buffer backup back */
3139         if(backup) {
3140             if(texture_target != GL_TEXTURE_2D) {
3141                 glDisable(texture_target);
3142                 glEnable(GL_TEXTURE_2D);
3143                 texture_target = GL_TEXTURE_2D;
3144             }
3145             glBindTexture(GL_TEXTURE_2D, backup);
3146             checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3147         }
3148         else
3149         {
3150             if (texture_target != src_surface->texture_target)
3151             {
3152                 glDisable(texture_target);
3153                 glEnable(src_surface->texture_target);
3154                 texture_target = src_surface->texture_target;
3155             }
3156             glBindTexture(src_surface->texture_target, src_surface->texture_name);
3157             checkGLcall("glBindTexture(src_surface->texture_target, src_surface->texture_name)");
3158         }
3159
3160         glBegin(GL_QUADS);
3161             /* top left */
3162             glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
3163             glVertex2i(0, 0);
3164
3165             /* bottom left */
3166             glTexCoord2f(0.0f, 0.0f);
3167             glVertex2i(0, fbheight);
3168
3169             /* bottom right */
3170             glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
3171             glVertex2i(fbwidth, src_surface->currentDesc.Height);
3172
3173             /* top right */
3174             glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
3175                     (float)fbheight / (float)src_surface->pow2Height);
3176             glVertex2i(fbwidth, 0);
3177         glEnd();
3178     }
3179     glDisable(texture_target);
3180     checkGLcall("glDisable(texture_target)");
3181
3182     /* Cleanup */
3183     if (src != src_surface->texture_name && src != backup)
3184     {
3185         glDeleteTextures(1, &src);
3186         checkGLcall("glDeleteTextures(1, &src)");
3187     }
3188     if(backup) {
3189         glDeleteTextures(1, &backup);
3190         checkGLcall("glDeleteTextures(1, &backup)");
3191     }
3192
3193     LEAVE_GL();
3194
3195     if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
3196
3197     context_release(context);
3198
3199     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3200      * path is never entered
3201      */
3202     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
3203 }
3204
3205 /* Until the blit_shader is ready, define some prototypes here. */
3206 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
3207                                const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
3208                                const struct wined3d_format_desc *src_format_desc,
3209                                const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
3210                                const struct wined3d_format_desc *dst_format_desc);
3211
3212 /* Front buffer coordinates are always full screen coordinates, but our GL
3213  * drawable is limited to the window's client area. The sysmem and texture
3214  * copies do have the full screen size. Note that GL has a bottom-left
3215  * origin, while D3D has a top-left origin. */
3216 void surface_translate_frontbuffer_coords(IWineD3DSurfaceImpl *surface, HWND window, RECT *rect)
3217 {
3218     POINT offset = {0, surface->currentDesc.Height};
3219     RECT windowsize;
3220
3221     GetClientRect(window, &windowsize);
3222     offset.y -= windowsize.bottom - windowsize.top;
3223     ScreenToClient(window, &offset);
3224     OffsetRect(rect, offset.x, offset.y);
3225 }
3226
3227 static BOOL surface_is_full_rect(IWineD3DSurfaceImpl *surface, const RECT *r)
3228 {
3229     if ((r->left && r->right) || abs(r->right - r->left) != surface->currentDesc.Width)
3230         return FALSE;
3231     if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->currentDesc.Height)
3232         return FALSE;
3233     return TRUE;
3234 }
3235
3236 /* blit between surface locations. onscreen on different swapchains is not supported.
3237  * depth / stencil is not supported. */
3238 static void surface_blt_fbo(IWineD3DDeviceImpl *device, const WINED3DTEXTUREFILTERTYPE filter,
3239         IWineD3DSurfaceImpl *src_surface, DWORD src_location, const RECT *src_rect_in,
3240         IWineD3DSurfaceImpl *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
3241 {
3242     const struct wined3d_gl_info *gl_info;
3243     struct wined3d_context *context;
3244     RECT src_rect, dst_rect;
3245     GLenum gl_filter;
3246
3247     TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
3248     TRACE("src_surface %p, src_location %s, src_rect %s,\n",
3249             src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
3250     TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
3251             dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
3252
3253     src_rect = *src_rect_in;
3254     dst_rect = *dst_rect_in;
3255
3256     switch (filter)
3257     {
3258         case WINED3DTEXF_LINEAR:
3259             gl_filter = GL_LINEAR;
3260             break;
3261
3262         default:
3263             FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
3264         case WINED3DTEXF_NONE:
3265         case WINED3DTEXF_POINT:
3266             gl_filter = GL_NEAREST;
3267             break;
3268     }
3269
3270     if (src_location == SFLAG_INDRAWABLE && surface_is_offscreen(src_surface))
3271         src_location = SFLAG_INTEXTURE;
3272     if (dst_location == SFLAG_INDRAWABLE && surface_is_offscreen(dst_surface))
3273         dst_location = SFLAG_INTEXTURE;
3274
3275     /* Make sure the locations are up-to-date. Loading the destination
3276      * surface isn't required if the entire surface is overwritten. (And is
3277      * in fact harmful if we're being called by surface_load_location() with
3278      * the purpose of loading the destination surface.) */
3279     surface_load_location(src_surface, src_location, NULL);
3280     if (!surface_is_full_rect(dst_surface, &dst_rect))
3281         surface_load_location(dst_surface, dst_location, NULL);
3282
3283     if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
3284     else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
3285     else context = context_acquire(device, NULL);
3286
3287     if (!context->valid)
3288     {
3289         context_release(context);
3290         WARN("Invalid context, skipping blit.\n");
3291         return;
3292     }
3293
3294     gl_info = context->gl_info;
3295
3296     if (src_location == SFLAG_INDRAWABLE)
3297     {
3298         GLenum buffer = surface_get_gl_buffer(src_surface);
3299
3300         TRACE("Source surface %p is onscreen.\n", src_surface);
3301
3302         if (buffer == GL_FRONT)
3303             surface_translate_frontbuffer_coords(src_surface, context->win_handle, &src_rect);
3304
3305         src_rect.top = src_surface->currentDesc.Height - src_rect.top;
3306         src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom;
3307
3308         ENTER_GL();
3309         context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
3310         glReadBuffer(buffer);
3311         checkGLcall("glReadBuffer()");
3312     }
3313     else
3314     {
3315         TRACE("Source surface %p is offscreen.\n", src_surface);
3316         ENTER_GL();
3317         context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
3318         glReadBuffer(GL_COLOR_ATTACHMENT0);
3319         checkGLcall("glReadBuffer()");
3320     }
3321     LEAVE_GL();
3322
3323     if (dst_location == SFLAG_INDRAWABLE)
3324     {
3325         GLenum buffer = surface_get_gl_buffer(dst_surface);
3326
3327         TRACE("Destination surface %p is onscreen.\n", dst_surface);
3328
3329         if (buffer == GL_FRONT)
3330             surface_translate_frontbuffer_coords(dst_surface, context->win_handle, &dst_rect);
3331
3332         dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top;
3333         dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom;
3334
3335         ENTER_GL();
3336         context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
3337         context_set_draw_buffer(context, buffer);
3338     }
3339     else
3340     {
3341         TRACE("Destination surface %p is offscreen.\n", dst_surface);
3342
3343         ENTER_GL();
3344         context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
3345         context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
3346     }
3347
3348     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3349     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
3350     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
3351     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
3352     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
3353
3354     glDisable(GL_SCISSOR_TEST);
3355     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
3356
3357     gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
3358             dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
3359     checkGLcall("glBlitFramebuffer()");
3360
3361     LEAVE_GL();
3362
3363     if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
3364
3365     context_release(context);
3366 }
3367
3368 /* Not called from the VTable */
3369 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *DestRect,
3370         IWineD3DSurfaceImpl *src_surface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx,
3371         WINED3DTEXTUREFILTERTYPE Filter)
3372 {
3373     IWineD3DDeviceImpl *device = dst_surface->resource.device;
3374     IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
3375     RECT dst_rect, src_rect;
3376
3377     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
3378             dst_surface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
3379             Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
3380
3381     /* Get the swapchain. One of the surfaces has to be a primary surface */
3382     if (dst_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
3383     {
3384         WARN("Destination is in sysmem, rejecting gl blt\n");
3385         return WINED3DERR_INVALIDCALL;
3386     }
3387     IWineD3DSurface_GetContainer((IWineD3DSurface *)dst_surface, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
3388     if (dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)dstSwapchain);
3389     if (src_surface)
3390     {
3391         if (src_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
3392         {
3393             WARN("Src is in sysmem, rejecting gl blt\n");
3394             return WINED3DERR_INVALIDCALL;
3395         }
3396         IWineD3DSurface_GetContainer((IWineD3DSurface *)src_surface, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
3397         if (srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)srcSwapchain);
3398     }
3399
3400     /* Early sort out of cases where no render target is used */
3401     if (!dstSwapchain && !srcSwapchain
3402             && src_surface != device->render_targets[0]
3403             && dst_surface != device->render_targets[0])
3404     {
3405         TRACE("No surface is render target, not using hardware blit.\n");
3406         return WINED3DERR_INVALIDCALL;
3407     }
3408
3409     /* No destination color keying supported */
3410     if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
3411         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3412         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3413         return WINED3DERR_INVALIDCALL;
3414     }
3415
3416     surface_get_rect(dst_surface, DestRect, &dst_rect);
3417     if (src_surface) surface_get_rect(src_surface, SrcRect, &src_rect);
3418
3419     /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
3420     if (dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->back_buffers
3421             && dst_surface == dstSwapchain->front_buffer
3422             && src_surface == dstSwapchain->back_buffers[0])
3423     {
3424         /* Half-Life does a Blt from the back buffer to the front buffer,
3425          * Full surface size, no flags... Use present instead
3426          *
3427          * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
3428          */
3429
3430         /* Check rects - IWineD3DDevice_Present doesn't handle them */
3431         while(1)
3432         {
3433             TRACE("Looking if a Present can be done...\n");
3434             /* Source Rectangle must be full surface */
3435             if (src_rect.left || src_rect.top
3436                     || src_rect.right != src_surface->currentDesc.Width
3437                     || src_rect.bottom != src_surface->currentDesc.Height)
3438             {
3439                 TRACE("No, Source rectangle doesn't match\n");
3440                 break;
3441             }
3442
3443             /* No stretching may occur */
3444             if(src_rect.right != dst_rect.right - dst_rect.left ||
3445                src_rect.bottom != dst_rect.bottom - dst_rect.top) {
3446                 TRACE("No, stretching is done\n");
3447                 break;
3448             }
3449
3450             /* Destination must be full surface or match the clipping rectangle */
3451             if (dst_surface->clipper && ((IWineD3DClipperImpl *)dst_surface->clipper)->hWnd)
3452             {
3453                 RECT cliprect;
3454                 POINT pos[2];
3455                 GetClientRect(((IWineD3DClipperImpl *)dst_surface->clipper)->hWnd, &cliprect);
3456                 pos[0].x = dst_rect.left;
3457                 pos[0].y = dst_rect.top;
3458                 pos[1].x = dst_rect.right;
3459                 pos[1].y = dst_rect.bottom;
3460                 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *)dst_surface->clipper)->hWnd, pos, 2);
3461
3462                 if(pos[0].x != cliprect.left  || pos[0].y != cliprect.top   ||
3463                    pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
3464                 {
3465                     TRACE("No, dest rectangle doesn't match(clipper)\n");
3466                     TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect));
3467                     TRACE("Blt dest: %s\n", wine_dbgstr_rect(&dst_rect));
3468                     break;
3469                 }
3470             }
3471             else if (dst_rect.left || dst_rect.top
3472                     || dst_rect.right != dst_surface->currentDesc.Width
3473                     || dst_rect.bottom != dst_surface->currentDesc.Height)
3474             {
3475                 TRACE("No, dest rectangle doesn't match(surface size)\n");
3476                 break;
3477             }
3478
3479             TRACE("Yes\n");
3480
3481             /* These flags are unimportant for the flag check, remove them */
3482             if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
3483                 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
3484
3485                 /* The idea behind this is that a glReadPixels and a glDrawPixels call
3486                     * take very long, while a flip is fast.
3487                     * This applies to Half-Life, which does such Blts every time it finished
3488                     * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
3489                     * menu. This is also used by all apps when they do windowed rendering
3490                     *
3491                     * The problem is that flipping is not really the same as copying. After a
3492                     * Blt the front buffer is a copy of the back buffer, and the back buffer is
3493                     * untouched. Therefore it's necessary to override the swap effect
3494                     * and to set it back after the flip.
3495                     *
3496                     * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
3497                     * testcases.
3498                     */
3499
3500                 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
3501                 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3502
3503                 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
3504                 IWineD3DSwapChain_Present((IWineD3DSwapChain *)dstSwapchain,
3505                         NULL, NULL, dstSwapchain->win_handle, NULL, 0);
3506
3507                 dstSwapchain->presentParms.SwapEffect = orig_swap;
3508
3509                 return WINED3D_OK;
3510             }
3511             break;
3512         }
3513
3514         TRACE("Unsupported blit between buffers on the same swapchain\n");
3515         return WINED3DERR_INVALIDCALL;
3516     } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
3517         FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3518         return WINED3DERR_INVALIDCALL;
3519     } else if(dstSwapchain && srcSwapchain) {
3520         FIXME("Implement hardware blit between two different swapchains\n");
3521         return WINED3DERR_INVALIDCALL;
3522     }
3523     else if (dstSwapchain)
3524     {
3525         /* Handled with regular texture -> swapchain blit */
3526         if (src_surface == device->render_targets[0])
3527             TRACE("Blit from active render target to a swapchain\n");
3528     }
3529     else if (srcSwapchain && dst_surface == device->render_targets[0])
3530     {
3531         FIXME("Implement blit from a swapchain to the active render target\n");
3532         return WINED3DERR_INVALIDCALL;
3533     }
3534
3535     if ((srcSwapchain || src_surface == device->render_targets[0]) && !dstSwapchain)
3536     {
3537         /* Blit from render target to texture */
3538         BOOL stretchx;
3539
3540         /* P8 read back is not implemented */
3541         if (src_surface->resource.format_desc->format == WINED3DFMT_P8_UINT
3542                 || dst_surface->resource.format_desc->format == WINED3DFMT_P8_UINT)
3543         {
3544             TRACE("P8 read back not supported by frame buffer to texture blit\n");
3545             return WINED3DERR_INVALIDCALL;
3546         }
3547
3548         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3549             TRACE("Color keying not supported by frame buffer to texture blit\n");
3550             return WINED3DERR_INVALIDCALL;
3551             /* Destination color key is checked above */
3552         }
3553
3554         if(dst_rect.right - dst_rect.left != src_rect.right - src_rect.left) {
3555             stretchx = TRUE;
3556         } else {
3557             stretchx = FALSE;
3558         }
3559
3560         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3561          * flip the image nor scale it.
3562          *
3563          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3564          * -> If the app wants a image width an unscaled width, copy it line per line
3565          * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3566          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3567          *    back buffer. This is slower than reading line per line, thus not used for flipping
3568          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3569          *    pixel by pixel
3570          *
3571          * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3572          * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3573          * backends.
3574          */
3575         if (fbo_blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
3576                 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format_desc,
3577                 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format_desc))
3578         {
3579             surface_blt_fbo(device, Filter,
3580                     src_surface, SFLAG_INDRAWABLE, &src_rect,
3581                     dst_surface, SFLAG_INDRAWABLE, &dst_rect);
3582             surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
3583         }
3584         else if (!stretchx || dst_rect.right - dst_rect.left > src_surface->currentDesc.Width
3585                 || dst_rect.bottom - dst_rect.top > src_surface->currentDesc.Height)
3586         {
3587             TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3588             fb_copy_to_texture_direct(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
3589         } else {
3590             TRACE("Using hardware stretching to flip / stretch the texture\n");
3591             fb_copy_to_texture_hwstretch(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
3592         }
3593
3594         if (!(dst_surface->Flags & SFLAG_DONOTFREE))
3595         {
3596             HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
3597             dst_surface->resource.allocatedMemory = NULL;
3598             dst_surface->resource.heapMemory = NULL;
3599         }
3600         else
3601         {
3602             dst_surface->Flags &= ~SFLAG_INSYSMEM;
3603         }
3604
3605         return WINED3D_OK;
3606     }
3607     else if (src_surface)
3608     {
3609         /* Blit from offscreen surface to render target */
3610         DWORD oldCKeyFlags = src_surface->CKeyFlags;
3611         WINEDDCOLORKEY oldBltCKey = src_surface->SrcBltCKey;
3612         struct wined3d_context *context;
3613
3614         TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3615
3616         if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3617                 && fbo_blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
3618                         &src_rect, src_surface->resource.usage, src_surface->resource.pool,
3619                         src_surface->resource.format_desc,
3620                         &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
3621                         dst_surface->resource.format_desc))
3622         {
3623             TRACE("Using surface_blt_fbo.\n");
3624             /* The source is always a texture, but never the currently active render target, and the texture
3625              * contents are never upside down. */
3626             surface_blt_fbo(device, Filter,
3627                     src_surface, SFLAG_INDRAWABLE, &src_rect,
3628                     dst_surface, SFLAG_INDRAWABLE, &dst_rect);
3629             surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
3630             return WINED3D_OK;
3631         }
3632
3633         if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3634                 && arbfp_blit.blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
3635                         &src_rect, src_surface->resource.usage, src_surface->resource.pool,
3636                         src_surface->resource.format_desc,
3637                         &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
3638                         dst_surface->resource.format_desc))
3639         {
3640             return arbfp_blit_surface(device, src_surface, &src_rect, dst_surface, &dst_rect, BLIT_OP_BLIT, Filter);
3641         }
3642
3643         /* Color keying: Check if we have to do a color keyed blt,
3644          * and if not check if a color key is activated.
3645          *
3646          * Just modify the color keying parameters in the surface and restore them afterwards
3647          * The surface keeps track of the color key last used to load the opengl surface.
3648          * PreLoad will catch the change to the flags and color key and reload if necessary.
3649          */
3650         if(Flags & WINEDDBLT_KEYSRC) {
3651             /* Use color key from surface */
3652         } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
3653             /* Use color key from DDBltFx */
3654             src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3655             src_surface->SrcBltCKey = DDBltFx->ddckSrcColorkey;
3656         } else {
3657             /* Do not use color key */
3658             src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3659         }
3660
3661         /* Now load the surface */
3662         surface_internal_preload(src_surface, SRGB_RGB);
3663
3664         /* Activate the destination context, set it up for blitting */
3665         context = context_acquire(device, dst_surface);
3666         context_apply_blit_state(context, device);
3667
3668         if (dstSwapchain && dst_surface == dstSwapchain->front_buffer)
3669             surface_translate_frontbuffer_coords(dst_surface, context->win_handle, &dst_rect);
3670
3671         if (!device->blitter->blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
3672                 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format_desc,
3673                 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format_desc))
3674         {
3675             FIXME("Unsupported blit operation falling back to software\n");
3676             return WINED3DERR_INVALIDCALL;
3677         }
3678
3679         device->blitter->set_shader((IWineD3DDevice *)device, src_surface);
3680
3681         ENTER_GL();
3682
3683         /* This is for color keying */
3684         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3685             glEnable(GL_ALPHA_TEST);
3686             checkGLcall("glEnable(GL_ALPHA_TEST)");
3687
3688             /* When the primary render target uses P8, the alpha component contains the palette index.
3689              * Which means that the colorkey is one of the palette entries. In other cases pixels that
3690              * should be masked away have alpha set to 0. */
3691             if (primary_render_target_is_p8(device))
3692                 glAlphaFunc(GL_NOTEQUAL, (float)src_surface->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
3693             else
3694                 glAlphaFunc(GL_NOTEQUAL, 0.0f);
3695             checkGLcall("glAlphaFunc");
3696         } else {
3697             glDisable(GL_ALPHA_TEST);
3698             checkGLcall("glDisable(GL_ALPHA_TEST)");
3699         }
3700
3701         /* Draw a textured quad
3702          */
3703         draw_textured_quad(src_surface, &src_rect, &dst_rect, Filter);
3704
3705         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3706             glDisable(GL_ALPHA_TEST);
3707             checkGLcall("glDisable(GL_ALPHA_TEST)");
3708         }
3709
3710         /* Restore the color key parameters */
3711         src_surface->CKeyFlags = oldCKeyFlags;
3712         src_surface->SrcBltCKey = oldBltCKey;
3713
3714         LEAVE_GL();
3715
3716         /* Leave the opengl state valid for blitting */
3717         device->blitter->unset_shader((IWineD3DDevice *)device);
3718
3719         if (wined3d_settings.strict_draw_ordering || (dstSwapchain
3720                 && (dst_surface == dstSwapchain->front_buffer
3721                 || dstSwapchain->num_contexts > 1)))
3722             wglFlush(); /* Flush to ensure ordering across contexts. */
3723
3724         context_release(context);
3725
3726         /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3727         /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3728          * is outdated now
3729          */
3730         surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
3731
3732         return WINED3D_OK;
3733     } else {
3734         /* Source-Less Blit to render target */
3735         if (Flags & WINEDDBLT_COLORFILL) {
3736             DWORD color;
3737
3738             TRACE("Colorfill\n");
3739
3740             /* The color as given in the Blt function is in the format of the frame-buffer...
3741              * 'clear' expect it in ARGB format => we need to do some conversion :-)
3742              */
3743             if (!surface_convert_color_to_argb(dst_surface, DDBltFx->u5.dwFillColor, &color))
3744             {
3745                 /* The color conversion function already prints an error, so need to do it here */
3746                 return WINED3DERR_INVALIDCALL;
3747             }
3748
3749             if (ffp_blit.blit_supported(&device->adapter->gl_info, BLIT_OP_COLOR_FILL,
3750                     NULL, 0, 0, NULL,
3751                     &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
3752                     dst_surface->resource.format_desc))
3753             {
3754                 return ffp_blit.color_fill(device, dst_surface, &dst_rect, color);
3755             }
3756             else if (cpu_blit.blit_supported(&device->adapter->gl_info, BLIT_OP_COLOR_FILL,
3757                     NULL, 0, 0, NULL,
3758                     &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
3759                     dst_surface->resource.format_desc))
3760             {
3761                 return cpu_blit.color_fill(device, dst_surface, &dst_rect, color);
3762             }
3763             return WINED3DERR_INVALIDCALL;
3764         }
3765     }
3766
3767     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3768     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3769     return WINED3DERR_INVALIDCALL;
3770 }
3771
3772 static HRESULT IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, const RECT *DestRect,
3773         IWineD3DSurface *src_surface, const RECT *src_rect, DWORD Flags, const WINEDDBLTFX *DDBltFx)
3774 {
3775     IWineD3DDeviceImpl *device = This->resource.device;
3776     float depth;
3777
3778     if (Flags & WINEDDBLT_DEPTHFILL) {
3779         switch(This->resource.format_desc->format)
3780         {
3781             case WINED3DFMT_D16_UNORM:
3782                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff;
3783                 break;
3784             case WINED3DFMT_S1_UINT_D15_UNORM:
3785                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00007fff;
3786                 break;
3787             case WINED3DFMT_D24_UNORM_S8_UINT:
3788             case WINED3DFMT_X8D24_UNORM:
3789                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff;
3790                 break;
3791             case WINED3DFMT_D32_UNORM:
3792                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff;
3793                 break;
3794             default:
3795                 depth = 0.0f;
3796                 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format_desc->format));
3797         }
3798
3799         return IWineD3DDevice_Clear((IWineD3DDevice *)device, DestRect ? 1 : 0, (const WINED3DRECT *)DestRect,
3800                 WINED3DCLEAR_ZBUFFER, 0x00000000, depth, 0x00000000);
3801     }
3802
3803     FIXME("(%p): Unsupp depthstencil blit\n", This);
3804     return WINED3DERR_INVALIDCALL;
3805 }
3806
3807 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect,
3808         IWineD3DSurface *src_surface, const RECT *SrcRect, DWORD Flags,
3809         const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
3810 {
3811     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3812     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
3813     IWineD3DDeviceImpl *device = This->resource.device;
3814
3815     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
3816             iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
3817             Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
3818     TRACE("Usage is %s.\n", debug_d3dusage(This->resource.usage));
3819
3820     if ((This->Flags & SFLAG_LOCKED) || (src && (src->Flags & SFLAG_LOCKED)))
3821     {
3822         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3823         return WINEDDERR_SURFACEBUSY;
3824     }
3825
3826     /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
3827      * except depth blits, which seem to work
3828      */
3829     if (This == device->depth_stencil || (src && src == device->depth_stencil))
3830     {
3831         if (device->inScene && !(Flags & WINEDDBLT_DEPTHFILL))
3832         {
3833             TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3834             return WINED3DERR_INVALIDCALL;
3835         }
3836         else if (SUCCEEDED(IWineD3DSurfaceImpl_BltZ(This, DestRect, src_surface, SrcRect, Flags, DDBltFx)))
3837         {
3838             TRACE("Z Blit override handled the blit\n");
3839             return WINED3D_OK;
3840         }
3841     }
3842
3843     /* Special cases for RenderTargets */
3844     if ((This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3845             || (src && (src->resource.usage & WINED3DUSAGE_RENDERTARGET)))
3846     {
3847         if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This, DestRect, src, SrcRect, Flags, DDBltFx, Filter)))
3848             return WINED3D_OK;
3849     }
3850
3851     /* For the rest call the X11 surface implementation.
3852      * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
3853      * other Blts are rather rare. */
3854     return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, src_surface, SrcRect, Flags, DDBltFx, Filter);
3855 }
3856
3857 static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
3858         IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
3859 {
3860     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3861     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
3862     IWineD3DDeviceImpl *device = This->resource.device;
3863
3864     TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
3865             iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
3866
3867     if ((This->Flags & SFLAG_LOCKED) || (src->Flags & SFLAG_LOCKED))
3868     {
3869         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3870         return WINEDDERR_SURFACEBUSY;
3871     }
3872
3873     if (device->inScene && (This == device->depth_stencil || src == device->depth_stencil))
3874     {
3875         TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3876         return WINED3DERR_INVALIDCALL;
3877     }
3878
3879     /* Special cases for RenderTargets */
3880     if ((This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3881             || (src->resource.usage & WINED3DUSAGE_RENDERTARGET))
3882     {
3883
3884         RECT SrcRect, DstRect;
3885         DWORD Flags=0;
3886
3887         surface_get_rect(src, rsrc, &SrcRect);
3888
3889         DstRect.left = dstx;
3890         DstRect.top=dsty;
3891         DstRect.right = dstx + SrcRect.right - SrcRect.left;
3892         DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
3893
3894         /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
3895         if(trans & WINEDDBLTFAST_SRCCOLORKEY)
3896             Flags |= WINEDDBLT_KEYSRC;
3897         if(trans & WINEDDBLTFAST_DESTCOLORKEY)
3898             Flags |= WINEDDBLT_KEYDEST;
3899         if(trans & WINEDDBLTFAST_WAIT)
3900             Flags |= WINEDDBLT_WAIT;
3901         if(trans & WINEDDBLTFAST_DONOTWAIT)
3902             Flags |= WINEDDBLT_DONOTWAIT;
3903
3904         if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This,
3905                 &DstRect, src, &SrcRect, Flags, NULL, WINED3DTEXF_POINT)))
3906             return WINED3D_OK;
3907     }
3908
3909     return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, src_surface, rsrc, trans);
3910 }
3911
3912 static HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface)
3913 {
3914     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3915     RGBQUAD col[256];
3916     IWineD3DPaletteImpl *pal = This->palette;
3917     unsigned int n;
3918     TRACE("(%p)\n", This);
3919
3920     if (!pal) return WINED3D_OK;
3921
3922     if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
3923             || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
3924     {
3925         if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3926         {
3927             /* Make sure the texture is up to date. This call doesn't do
3928              * anything if the texture is already up to date. */
3929             surface_load_location(This, SFLAG_INTEXTURE, NULL);
3930
3931             /* We want to force a palette refresh, so mark the drawable as not being up to date */
3932             surface_modify_location(This, SFLAG_INDRAWABLE, FALSE);
3933         }
3934         else
3935         {
3936             if (!(This->Flags & SFLAG_INSYSMEM))
3937             {
3938                 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
3939                 surface_load_location(This, SFLAG_INSYSMEM, NULL);
3940             }
3941             TRACE("Dirtifying surface\n");
3942             surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
3943         }
3944     }
3945
3946     if(This->Flags & SFLAG_DIBSECTION) {
3947         TRACE("(%p): Updating the hdc's palette\n", This);
3948         for (n=0; n<256; n++) {
3949             col[n].rgbRed   = pal->palents[n].peRed;
3950             col[n].rgbGreen = pal->palents[n].peGreen;
3951             col[n].rgbBlue  = pal->palents[n].peBlue;
3952             col[n].rgbReserved = 0;
3953         }
3954         SetDIBColorTable(This->hDC, 0, 256, col);
3955     }
3956
3957     /* Propagate the changes to the drawable when we have a palette. */
3958     if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3959         surface_load_location(This, SFLAG_INDRAWABLE, NULL);
3960
3961     return WINED3D_OK;
3962 }
3963
3964 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3965     /** Check against the maximum texture sizes supported by the video card **/
3966     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3967     const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
3968     unsigned int pow2Width, pow2Height;
3969
3970     This->texture_name = 0;
3971     This->texture_target = GL_TEXTURE_2D;
3972
3973     /* Non-power2 support */
3974     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3975     {
3976         pow2Width = This->currentDesc.Width;
3977         pow2Height = This->currentDesc.Height;
3978     }
3979     else
3980     {
3981         /* Find the nearest pow2 match */
3982         pow2Width = pow2Height = 1;
3983         while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
3984         while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
3985     }
3986     This->pow2Width  = pow2Width;
3987     This->pow2Height = pow2Height;
3988
3989     if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
3990         /** TODO: add support for non power two compressed textures **/
3991         if (This->resource.format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
3992         {
3993             FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
3994                   This, This->currentDesc.Width, This->currentDesc.Height);
3995             return WINED3DERR_NOTAVAILABLE;
3996         }
3997     }
3998
3999     if(pow2Width != This->currentDesc.Width ||
4000        pow2Height != This->currentDesc.Height) {
4001         This->Flags |= SFLAG_NONPOW2;
4002     }
4003
4004     TRACE("%p\n", This);
4005     if ((This->pow2Width > gl_info->limits.texture_size || This->pow2Height > gl_info->limits.texture_size)
4006             && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4007     {
4008         /* one of three options
4009         1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
4010         2: Set the texture to the maximum size (bad idea)
4011         3:    WARN and return WINED3DERR_NOTAVAILABLE;
4012         4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target.
4013         */
4014         if(This->resource.pool == WINED3DPOOL_DEFAULT || This->resource.pool == WINED3DPOOL_MANAGED)
4015         {
4016             WARN("(%p) Unable to allocate a surface which exceeds the maximum OpenGL texture size\n", This);
4017             return WINED3DERR_NOTAVAILABLE;
4018         }
4019
4020         /* We should never use this surface in combination with OpenGL! */
4021         TRACE("(%p) Creating an oversized surface: %ux%u\n", This, This->pow2Width, This->pow2Height);
4022     }
4023     else
4024     {
4025         /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
4026            is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
4027            doesn't work in combination with ARB_TEXTURE_RECTANGLE.
4028         */
4029         if (This->Flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
4030                 && !(This->resource.format_desc->format == WINED3DFMT_P8_UINT
4031                 && gl_info->supported[EXT_PALETTED_TEXTURE]
4032                 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
4033         {
4034             This->texture_target = GL_TEXTURE_RECTANGLE_ARB;
4035             This->pow2Width  = This->currentDesc.Width;
4036             This->pow2Height = This->currentDesc.Height;
4037             This->Flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
4038         }
4039     }
4040
4041     switch (wined3d_settings.offscreen_rendering_mode)
4042     {
4043         case ORM_FBO:
4044             This->get_drawable_size = get_drawable_size_fbo;
4045             break;
4046
4047         case ORM_BACKBUFFER:
4048             This->get_drawable_size = get_drawable_size_backbuffer;
4049             break;
4050
4051         default:
4052             ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
4053             return WINED3DERR_INVALIDCALL;
4054     }
4055
4056     This->Flags |= SFLAG_INSYSMEM;
4057
4058     return WINED3D_OK;
4059 }
4060
4061 /* GL locking is done by the caller */
4062 static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
4063         GLuint texture, GLsizei w, GLsizei h, GLenum target)
4064 {
4065     IWineD3DDeviceImpl *device = This->resource.device;
4066     GLint compare_mode = GL_NONE;
4067     struct blt_info info;
4068     GLint old_binding = 0;
4069
4070     glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
4071
4072     glDisable(GL_CULL_FACE);
4073     glDisable(GL_BLEND);
4074     glDisable(GL_ALPHA_TEST);
4075     glDisable(GL_SCISSOR_TEST);
4076     glDisable(GL_STENCIL_TEST);
4077     glEnable(GL_DEPTH_TEST);
4078     glDepthFunc(GL_ALWAYS);
4079     glDepthMask(GL_TRUE);
4080     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
4081     glViewport(0, 0, w, h);
4082
4083     surface_get_blt_info(target, NULL, w, h, &info);
4084     GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4085     glGetIntegerv(info.binding, &old_binding);
4086     glBindTexture(info.bind_target, texture);
4087     if (gl_info->supported[ARB_SHADOW])
4088     {
4089         glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
4090         if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
4091     }
4092
4093     device->shader_backend->shader_select_depth_blt((IWineD3DDevice *)device,
4094             info.tex_type, &This->ds_current_size);
4095
4096     glBegin(GL_TRIANGLE_STRIP);
4097     glTexCoord3fv(info.coords[0]);
4098     glVertex2f(-1.0f, -1.0f);
4099     glTexCoord3fv(info.coords[1]);
4100     glVertex2f(1.0f, -1.0f);
4101     glTexCoord3fv(info.coords[2]);
4102     glVertex2f(-1.0f, 1.0f);
4103     glTexCoord3fv(info.coords[3]);
4104     glVertex2f(1.0f, 1.0f);
4105     glEnd();
4106
4107     if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
4108     glBindTexture(info.bind_target, old_binding);
4109
4110     glPopAttrib();
4111
4112     device->shader_backend->shader_deselect_depth_blt((IWineD3DDevice *)device);
4113 }
4114
4115 void surface_modify_ds_location(IWineD3DSurfaceImpl *surface,
4116         DWORD location, UINT w, UINT h)
4117 {
4118     TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
4119
4120     if (location & ~SFLAG_DS_LOCATIONS)
4121         FIXME("Invalid location (%#x) specified.\n", location);
4122
4123     surface->ds_current_size.cx = w;
4124     surface->ds_current_size.cy = h;
4125     surface->Flags &= ~SFLAG_DS_LOCATIONS;
4126     surface->Flags |= location;
4127 }
4128
4129 /* Context activation is done by the caller. */
4130 void surface_load_ds_location(IWineD3DSurfaceImpl *surface, struct wined3d_context *context, DWORD location)
4131 {
4132     IWineD3DDeviceImpl *device = surface->resource.device;
4133     const struct wined3d_gl_info *gl_info = context->gl_info;
4134
4135     TRACE("surface %p, new location %#x.\n", surface, location);
4136
4137     /* TODO: Make this work for modes other than FBO */
4138     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
4139
4140     if (!(surface->Flags & location))
4141     {
4142         surface->ds_current_size.cx = 0;
4143         surface->ds_current_size.cy = 0;
4144     }
4145
4146     if (surface->ds_current_size.cx == surface->currentDesc.Width
4147             && surface->ds_current_size.cy == surface->currentDesc.Height)
4148     {
4149         TRACE("Location (%#x) is already up to date.\n", location);
4150         return;
4151     }
4152
4153     if (surface->current_renderbuffer)
4154     {
4155         FIXME("Not supported with fixed up depth stencil.\n");
4156         return;
4157     }
4158
4159     if (!(surface->Flags & SFLAG_LOCATIONS))
4160     {
4161         FIXME("No up to date depth stencil location.\n");
4162         surface->Flags |= location;
4163         return;
4164     }
4165
4166     if (location == SFLAG_DS_OFFSCREEN)
4167     {
4168         GLint old_binding = 0;
4169         GLenum bind_target;
4170
4171         TRACE("Copying onscreen depth buffer to depth texture.\n");
4172
4173         ENTER_GL();
4174
4175         if (!device->depth_blt_texture)
4176         {
4177             glGenTextures(1, &device->depth_blt_texture);
4178         }
4179
4180         /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4181          * directly on the FBO texture. That's because we need to flip. */
4182         context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4183         if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
4184         {
4185             glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
4186             bind_target = GL_TEXTURE_RECTANGLE_ARB;
4187         }
4188         else
4189         {
4190             glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
4191             bind_target = GL_TEXTURE_2D;
4192         }
4193         glBindTexture(bind_target, device->depth_blt_texture);
4194         glCopyTexImage2D(bind_target, surface->texture_level, surface->resource.format_desc->glInternal,
4195                 0, 0, surface->currentDesc.Width, surface->currentDesc.Height, 0);
4196         glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4197         glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4198         glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4199         glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4200         glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
4201         glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
4202         glBindTexture(bind_target, old_binding);
4203
4204         /* Setup the destination */
4205         if (!device->depth_blt_rb)
4206         {
4207             gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
4208             checkGLcall("glGenRenderbuffersEXT");
4209         }
4210         if (device->depth_blt_rb_w != surface->currentDesc.Width
4211                 || device->depth_blt_rb_h != surface->currentDesc.Height)
4212         {
4213             gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
4214             checkGLcall("glBindRenderbufferEXT");
4215             gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
4216                     surface->currentDesc.Width, surface->currentDesc.Height);
4217             checkGLcall("glRenderbufferStorageEXT");
4218             device->depth_blt_rb_w = surface->currentDesc.Width;
4219             device->depth_blt_rb_h = surface->currentDesc.Height;
4220         }
4221
4222         context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4223         gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
4224                 GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
4225         checkGLcall("glFramebufferRenderbufferEXT");
4226         context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, surface, FALSE);
4227
4228         /* Do the actual blit */
4229         surface_depth_blt(surface, gl_info, device->depth_blt_texture,
4230                 surface->currentDesc.Width, surface->currentDesc.Height, bind_target);
4231         checkGLcall("depth_blt");
4232
4233         if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4234         else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4235
4236         LEAVE_GL();
4237
4238         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4239     }
4240     else if (location == SFLAG_DS_ONSCREEN)
4241     {
4242         TRACE("Copying depth texture to onscreen depth buffer.\n");
4243
4244         ENTER_GL();
4245
4246         context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4247         surface_depth_blt(surface, gl_info, surface->texture_name,
4248                 surface->currentDesc.Width, surface->currentDesc.Height, surface->texture_target);
4249         checkGLcall("depth_blt");
4250
4251         if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4252
4253         LEAVE_GL();
4254
4255         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4256     }
4257     else
4258     {
4259         ERR("Invalid location (%#x) specified.\n", location);
4260     }
4261
4262     surface->Flags |= location;
4263     surface->ds_current_size.cx = surface->currentDesc.Width;
4264     surface->ds_current_size.cy = surface->currentDesc.Height;
4265 }
4266
4267 void surface_modify_location(IWineD3DSurfaceImpl *surface, DWORD flag, BOOL persistent)
4268 {
4269     IWineD3DBaseTexture *texture;
4270     IWineD3DSurfaceImpl *overlay;
4271
4272     TRACE("surface %p, location %s, persistent %#x.\n",
4273             surface, debug_surflocation(flag), persistent);
4274
4275     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4276     {
4277         if (surface_is_offscreen(surface))
4278         {
4279             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4280             if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4281         }
4282         else
4283         {
4284             TRACE("Surface %p is an onscreen surface.\n", surface);
4285         }
4286     }
4287
4288     if (persistent)
4289     {
4290         if (((surface->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE))
4291                 || ((surface->Flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX)))
4292         {
4293             if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)surface,
4294                     &IID_IWineD3DBaseTexture, (void **)&texture)))
4295             {
4296                 TRACE("Passing to container.\n");
4297                 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4298                 IWineD3DBaseTexture_Release(texture);
4299             }
4300         }
4301         surface->Flags &= ~SFLAG_LOCATIONS;
4302         surface->Flags |= flag;
4303
4304         /* Redraw emulated overlays, if any */
4305         if (flag & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
4306         {
4307             LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, IWineD3DSurfaceImpl, overlay_entry)
4308             {
4309                 IWineD3DSurface_DrawOverlay((IWineD3DSurface *)overlay);
4310             }
4311         }
4312     }
4313     else
4314     {
4315         if ((surface->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
4316         {
4317             if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)surface,
4318                     &IID_IWineD3DBaseTexture, (void **)&texture)))
4319             {
4320                 TRACE("Passing to container\n");
4321                 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4322                 IWineD3DBaseTexture_Release(texture);
4323             }
4324         }
4325         surface->Flags &= ~flag;
4326     }
4327
4328     if (!(surface->Flags & SFLAG_LOCATIONS))
4329     {
4330         ERR("Surface %p does not have any up to date location.\n", surface);
4331     }
4332 }
4333
4334 static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT *rect_in)
4335 {
4336     IWineD3DDeviceImpl *device = This->resource.device;
4337     IWineD3DSwapChainImpl *swapchain;
4338     struct wined3d_context *context;
4339     RECT src_rect, dst_rect;
4340
4341     surface_get_rect(This, rect_in, &src_rect);
4342
4343     context = context_acquire(device, This);
4344     context_apply_blit_state(context, device);
4345     if (context->render_offscreen)
4346     {
4347         dst_rect.left = src_rect.left;
4348         dst_rect.right = src_rect.right;
4349         dst_rect.top = src_rect.bottom;
4350         dst_rect.bottom = src_rect.top;
4351     }
4352     else
4353     {
4354         dst_rect = src_rect;
4355     }
4356
4357     swapchain = This->container.type == WINED3D_CONTAINER_SWAPCHAIN ? This->container.u.swapchain : NULL;
4358     if (swapchain && This == swapchain->front_buffer)
4359         surface_translate_frontbuffer_coords(This, context->win_handle, &dst_rect);
4360
4361     device->blitter->set_shader((IWineD3DDevice *) device, This);
4362
4363     ENTER_GL();
4364     draw_textured_quad(This, &src_rect, &dst_rect, WINED3DTEXF_POINT);
4365     LEAVE_GL();
4366
4367     device->blitter->unset_shader((IWineD3DDevice *) device);
4368
4369     if (wined3d_settings.strict_draw_ordering || (swapchain
4370             && (This == swapchain->front_buffer || swapchain->num_contexts > 1)))
4371         wglFlush(); /* Flush to ensure ordering across contexts. */
4372
4373     context_release(context);
4374 }
4375
4376 HRESULT surface_load_location(IWineD3DSurfaceImpl *surface, DWORD flag, const RECT *rect)
4377 {
4378     IWineD3DDeviceImpl *device = surface->resource.device;
4379     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4380     BOOL drawable_read_ok = surface_is_offscreen(surface);
4381     struct wined3d_format_desc desc;
4382     CONVERT_TYPES convert;
4383     int width, pitch, outpitch;
4384     BYTE *mem;
4385     BOOL in_fbo = FALSE;
4386
4387     TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(flag), wine_dbgstr_rect(rect));
4388
4389     if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4390     {
4391         if (flag == SFLAG_INTEXTURE)
4392         {
4393             struct wined3d_context *context = context_acquire(device, NULL);
4394             surface_load_ds_location(surface, context, SFLAG_DS_OFFSCREEN);
4395             context_release(context);
4396             return WINED3D_OK;
4397         }
4398         else
4399         {
4400             FIXME("Unimplemented location %#x for depth/stencil buffers.\n", flag);
4401             return WINED3DERR_INVALIDCALL;
4402         }
4403     }
4404
4405     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4406     {
4407         if (surface_is_offscreen(surface))
4408         {
4409             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
4410              * Prefer SFLAG_INTEXTURE. */
4411             if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
4412             drawable_read_ok = FALSE;
4413             in_fbo = TRUE;
4414         }
4415         else
4416         {
4417             TRACE("Surface %p is an onscreen surface.\n", surface);
4418         }
4419     }
4420
4421     if (surface->Flags & flag)
4422     {
4423         TRACE("Location already up to date\n");
4424         return WINED3D_OK;
4425     }
4426
4427     if (!(surface->Flags & SFLAG_LOCATIONS))
4428     {
4429         ERR("Surface %p does not have any up to date location.\n", surface);
4430         surface->Flags |= SFLAG_LOST;
4431         return WINED3DERR_DEVICELOST;
4432     }
4433
4434     if (flag == SFLAG_INSYSMEM)
4435     {
4436         surface_prepare_system_memory(surface);
4437
4438         /* Download the surface to system memory */
4439         if (surface->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
4440         {
4441             struct wined3d_context *context = NULL;
4442
4443             if (!device->isInDraw) context = context_acquire(device, NULL);
4444
4445             surface_bind_and_dirtify(surface, !(surface->Flags & SFLAG_INTEXTURE));
4446             surface_download_data(surface, gl_info);
4447
4448             if (context) context_release(context);
4449         }
4450         else
4451         {
4452             /* Note: It might be faster to download into a texture first. */
4453             read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
4454                     IWineD3DSurface_GetPitch((IWineD3DSurface *)surface));
4455         }
4456     }
4457     else if (flag == SFLAG_INDRAWABLE)
4458     {
4459         if (surface->Flags & SFLAG_INTEXTURE)
4460         {
4461             surface_blt_to_drawable(surface, rect);
4462         }
4463         else
4464         {
4465             int byte_count;
4466             if ((surface->Flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
4467             {
4468                 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
4469                  * values, otherwise we get incorrect values in the target. For now go the slow way
4470                  * via a system memory copy
4471                  */
4472                 surface_load_location(surface, SFLAG_INSYSMEM, rect);
4473             }
4474
4475             d3dfmt_get_conv(surface, FALSE /* We need color keying */,
4476                     FALSE /* We won't use textures */, &desc, &convert);
4477
4478             /* The width is in 'length' not in bytes */
4479             width = surface->currentDesc.Width;
4480             pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
4481
4482             /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4483              * but it isn't set (yet) in all cases it is getting called. */
4484             if ((convert != NO_CONVERSION) && (surface->Flags & SFLAG_PBO))
4485             {
4486                 struct wined3d_context *context = NULL;
4487
4488                 TRACE("Removing the pbo attached to surface %p.\n", surface);
4489
4490                 if (!device->isInDraw) context = context_acquire(device, NULL);
4491                 surface_remove_pbo(surface, gl_info);
4492                 if (context) context_release(context);
4493             }
4494
4495             if ((convert != NO_CONVERSION) && surface->resource.allocatedMemory)
4496             {
4497                 int height = surface->currentDesc.Height;
4498                 byte_count = desc.conv_byte_count;
4499
4500                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4501                 outpitch = width * byte_count;
4502                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4503
4504                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4505                 if(!mem) {
4506                     ERR("Out of memory %d, %d!\n", outpitch, height);
4507                     return WINED3DERR_OUTOFVIDEOMEMORY;
4508                 }
4509                 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, pitch,
4510                         width, height, outpitch, convert, surface);
4511
4512                 surface->Flags |= SFLAG_CONVERTED;
4513             }
4514             else
4515             {
4516                 surface->Flags &= ~SFLAG_CONVERTED;
4517                 mem = surface->resource.allocatedMemory;
4518                 byte_count = desc.byte_count;
4519             }
4520
4521             flush_to_framebuffer_drawpixels(surface, desc.glFormat, desc.glType, byte_count, mem);
4522
4523             /* Don't delete PBO memory */
4524             if ((mem != surface->resource.allocatedMemory) && !(surface->Flags & SFLAG_PBO))
4525                 HeapFree(GetProcessHeap(), 0, mem);
4526         }
4527     }
4528     else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */
4529     {
4530         const DWORD attach_flags = WINED3DFMT_FLAG_FBO_ATTACHABLE | WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB;
4531
4532         if (drawable_read_ok && (surface->Flags & SFLAG_INDRAWABLE))
4533         {
4534             read_from_framebuffer_texture(surface, flag == SFLAG_INSRGBTEX);
4535         }
4536         else if (surface->Flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
4537                 && (surface->resource.format_desc->Flags & attach_flags) == attach_flags
4538                 && fbo_blit_supported(gl_info, BLIT_OP_BLIT,
4539                         NULL, surface->resource.usage, surface->resource.pool, surface->resource.format_desc,
4540                         NULL, surface->resource.usage, surface->resource.pool, surface->resource.format_desc))
4541         {
4542             DWORD src_location = flag == SFLAG_INSRGBTEX ? SFLAG_INTEXTURE : SFLAG_INSRGBTEX;
4543             RECT rect = {0, 0, surface->currentDesc.Width, surface->currentDesc.Height};
4544
4545             surface_blt_fbo(surface->resource.device, WINED3DTEXF_POINT,
4546                     surface, src_location, &rect, surface, flag, &rect);
4547         }
4548         else
4549         {
4550             /* Upload from system memory */
4551             BOOL srgb = flag == SFLAG_INSRGBTEX;
4552             struct wined3d_context *context = NULL;
4553
4554             d3dfmt_get_conv(surface, TRUE /* We need color keying */,
4555                     TRUE /* We will use textures */, &desc, &convert);
4556
4557             if (srgb)
4558             {
4559                 if ((surface->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
4560                 {
4561                     /* Performance warning... */
4562                     FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
4563                     surface_load_location(surface, SFLAG_INSYSMEM, rect);
4564                 }
4565             }
4566             else
4567             {
4568                 if ((surface->Flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
4569                 {
4570                     /* Performance warning... */
4571                     FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
4572                     surface_load_location(surface, SFLAG_INSYSMEM, rect);
4573                 }
4574             }
4575             if (!(surface->Flags & SFLAG_INSYSMEM))
4576             {
4577                 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
4578                 /* Lets hope we get it from somewhere... */
4579                 surface_load_location(surface, SFLAG_INSYSMEM, rect);
4580             }
4581
4582             if (!device->isInDraw) context = context_acquire(device, NULL);
4583
4584             surface_prepare_texture(surface, gl_info, srgb);
4585             surface_bind_and_dirtify(surface, srgb);
4586
4587             if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
4588             {
4589                 surface->Flags |= SFLAG_GLCKEY;
4590                 surface->glCKey = surface->SrcBltCKey;
4591             }
4592             else surface->Flags &= ~SFLAG_GLCKEY;
4593
4594             /* The width is in 'length' not in bytes */
4595             width = surface->currentDesc.Width;
4596             pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
4597
4598             /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4599              * but it isn't set (yet) in all cases it is getting called. */
4600             if ((convert != NO_CONVERSION || desc.convert) && (surface->Flags & SFLAG_PBO))
4601             {
4602                 TRACE("Removing the pbo attached to surface %p.\n", surface);
4603                 surface_remove_pbo(surface, gl_info);
4604             }
4605
4606             if (desc.convert)
4607             {
4608                 /* This code is entered for texture formats which need a fixup. */
4609                 int height = surface->currentDesc.Height;
4610
4611                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4612                 outpitch = width * desc.conv_byte_count;
4613                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4614
4615                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4616                 if(!mem) {
4617                     ERR("Out of memory %d, %d!\n", outpitch, height);
4618                     if (context) context_release(context);
4619                     return WINED3DERR_OUTOFVIDEOMEMORY;
4620                 }
4621                 desc.convert(surface->resource.allocatedMemory, mem, pitch, width, height);
4622             }
4623             else if (convert != NO_CONVERSION && surface->resource.allocatedMemory)
4624             {
4625                 /* This code is only entered for color keying fixups */
4626                 int height = surface->currentDesc.Height;
4627
4628                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4629                 outpitch = width * desc.conv_byte_count;
4630                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4631
4632                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4633                 if(!mem) {
4634                     ERR("Out of memory %d, %d!\n", outpitch, height);
4635                     if (context) context_release(context);
4636                     return WINED3DERR_OUTOFVIDEOMEMORY;
4637                 }
4638                 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, pitch,
4639                         width, height, outpitch, convert, surface);
4640             }
4641             else
4642             {
4643                 mem = surface->resource.allocatedMemory;
4644             }
4645
4646             /* Make sure the correct pitch is used */
4647             ENTER_GL();
4648             glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
4649             LEAVE_GL();
4650
4651             if (mem || (surface->Flags & SFLAG_PBO))
4652                 surface_upload_data(surface, gl_info, &desc, srgb, mem);
4653
4654             /* Restore the default pitch */
4655             ENTER_GL();
4656             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4657             LEAVE_GL();
4658
4659             if (context) context_release(context);
4660
4661             /* Don't delete PBO memory */
4662             if ((mem != surface->resource.allocatedMemory) && !(surface->Flags & SFLAG_PBO))
4663                 HeapFree(GetProcessHeap(), 0, mem);
4664         }
4665     }
4666
4667     if (!rect) surface->Flags |= flag;
4668
4669     if (in_fbo && (surface->Flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)))
4670     {
4671         /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4672         surface->Flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4673     }
4674
4675     return WINED3D_OK;
4676 }
4677
4678 static WINED3DSURFTYPE WINAPI IWineD3DSurfaceImpl_GetImplType(IWineD3DSurface *iface) {
4679     return SURFACE_OPENGL;
4680 }
4681
4682 static HRESULT WINAPI IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
4683     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4684     HRESULT hr;
4685
4686     /* If there's no destination surface there is nothing to do */
4687     if(!This->overlay_dest) return WINED3D_OK;
4688
4689     /* Blt calls ModifyLocation on the dest surface, which in turn calls DrawOverlay to
4690      * update the overlay. Prevent an endless recursion
4691      */
4692     if(This->overlay_dest->Flags & SFLAG_INOVERLAYDRAW) {
4693         return WINED3D_OK;
4694     }
4695     This->overlay_dest->Flags |= SFLAG_INOVERLAYDRAW;
4696     hr = IWineD3DSurfaceImpl_Blt((IWineD3DSurface *) This->overlay_dest, &This->overlay_destrect,
4697                                  iface, &This->overlay_srcrect, WINEDDBLT_WAIT,
4698                                  NULL, WINED3DTEXF_LINEAR);
4699     This->overlay_dest->Flags &= ~SFLAG_INOVERLAYDRAW;
4700
4701     return hr;
4702 }
4703
4704 BOOL surface_is_offscreen(IWineD3DSurfaceImpl *surface)
4705 {
4706     IWineD3DSwapChainImpl *swapchain = surface->container.u.swapchain;
4707
4708     /* Not on a swapchain - must be offscreen */
4709     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
4710
4711     /* The front buffer is always onscreen */
4712     if (surface == swapchain->front_buffer) return FALSE;
4713
4714     /* If the swapchain is rendered to an FBO, the backbuffer is
4715      * offscreen, otherwise onscreen */
4716     return swapchain->render_to_fbo;
4717 }
4718
4719 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
4720 {
4721     /* IUnknown */
4722     IWineD3DBaseSurfaceImpl_QueryInterface,
4723     IWineD3DBaseSurfaceImpl_AddRef,
4724     IWineD3DSurfaceImpl_Release,
4725     /* IWineD3DResource */
4726     IWineD3DBaseSurfaceImpl_GetParent,
4727     IWineD3DBaseSurfaceImpl_SetPrivateData,
4728     IWineD3DBaseSurfaceImpl_GetPrivateData,
4729     IWineD3DBaseSurfaceImpl_FreePrivateData,
4730     IWineD3DBaseSurfaceImpl_SetPriority,
4731     IWineD3DBaseSurfaceImpl_GetPriority,
4732     IWineD3DSurfaceImpl_PreLoad,
4733     IWineD3DSurfaceImpl_UnLoad,
4734     IWineD3DBaseSurfaceImpl_GetType,
4735     /* IWineD3DSurface */
4736     IWineD3DBaseSurfaceImpl_GetContainer,
4737     IWineD3DBaseSurfaceImpl_GetDesc,
4738     IWineD3DSurfaceImpl_LockRect,
4739     IWineD3DSurfaceImpl_UnlockRect,
4740     IWineD3DSurfaceImpl_GetDC,
4741     IWineD3DSurfaceImpl_ReleaseDC,
4742     IWineD3DSurfaceImpl_Flip,
4743     IWineD3DSurfaceImpl_Blt,
4744     IWineD3DBaseSurfaceImpl_GetBltStatus,
4745     IWineD3DBaseSurfaceImpl_GetFlipStatus,
4746     IWineD3DBaseSurfaceImpl_IsLost,
4747     IWineD3DBaseSurfaceImpl_Restore,
4748     IWineD3DSurfaceImpl_BltFast,
4749     IWineD3DBaseSurfaceImpl_GetPalette,
4750     IWineD3DBaseSurfaceImpl_SetPalette,
4751     IWineD3DSurfaceImpl_RealizePalette,
4752     IWineD3DBaseSurfaceImpl_SetColorKey,
4753     IWineD3DBaseSurfaceImpl_GetPitch,
4754     IWineD3DSurfaceImpl_SetMem,
4755     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
4756     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
4757     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
4758     IWineD3DBaseSurfaceImpl_UpdateOverlay,
4759     IWineD3DBaseSurfaceImpl_SetClipper,
4760     IWineD3DBaseSurfaceImpl_GetClipper,
4761     /* Internal use: */
4762     IWineD3DSurfaceImpl_LoadTexture,
4763     IWineD3DSurfaceImpl_BindTexture,
4764     IWineD3DBaseSurfaceImpl_GetData,
4765     IWineD3DSurfaceImpl_SetFormat,
4766     IWineD3DSurfaceImpl_PrivateSetup,
4767     IWineD3DSurfaceImpl_GetImplType,
4768     IWineD3DSurfaceImpl_DrawOverlay
4769 };
4770
4771 static HRESULT ffp_blit_alloc(IWineD3DDevice *iface) { return WINED3D_OK; }
4772 /* Context activation is done by the caller. */
4773 static void ffp_blit_free(IWineD3DDevice *iface) { }
4774
4775 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
4776 /* Context activation is done by the caller. */
4777 static void ffp_blit_p8_upload_palette(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
4778 {
4779     BYTE table[256][4];
4780     BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
4781
4782     d3dfmt_p8_init_palette(surface, table, colorkey_active);
4783
4784     TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
4785     ENTER_GL();
4786     GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
4787     LEAVE_GL();
4788 }
4789
4790 /* Context activation is done by the caller. */
4791 static HRESULT ffp_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
4792 {
4793     IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
4794     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4795     enum complex_fixup fixup = get_complex_fixup(surface->resource.format_desc->color_fixup);
4796
4797     /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
4798      * else the surface is converted in software at upload time in LoadLocation.
4799      */
4800     if(fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
4801         ffp_blit_p8_upload_palette(surface, gl_info);
4802
4803     ENTER_GL();
4804     glEnable(surface->texture_target);
4805     checkGLcall("glEnable(surface->texture_target)");
4806     LEAVE_GL();
4807     return WINED3D_OK;
4808 }
4809
4810 /* Context activation is done by the caller. */
4811 static void ffp_blit_unset(IWineD3DDevice *iface)
4812 {
4813     IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
4814     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4815
4816     ENTER_GL();
4817     glDisable(GL_TEXTURE_2D);
4818     checkGLcall("glDisable(GL_TEXTURE_2D)");
4819     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
4820     {
4821         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
4822         checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4823     }
4824     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
4825     {
4826         glDisable(GL_TEXTURE_RECTANGLE_ARB);
4827         checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4828     }
4829     LEAVE_GL();
4830 }
4831
4832 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4833                                const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4834                                const struct wined3d_format_desc *src_format_desc,
4835                                const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4836                                const struct wined3d_format_desc *dst_format_desc)
4837 {
4838     enum complex_fixup src_fixup;
4839
4840     if (blit_op == BLIT_OP_COLOR_FILL)
4841     {
4842         if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
4843         {
4844             TRACE("Color fill not supported\n");
4845             return FALSE;
4846         }
4847
4848         return TRUE;
4849     }
4850
4851     src_fixup = get_complex_fixup(src_format_desc->color_fixup);
4852     if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
4853     {
4854         TRACE("Checking support for fixup:\n");
4855         dump_color_fixup_desc(src_format_desc->color_fixup);
4856     }
4857
4858     if (blit_op != BLIT_OP_BLIT)
4859     {
4860         TRACE("Unsupported blit_op=%d\n", blit_op);
4861         return FALSE;
4862      }
4863
4864     if (!is_identity_fixup(dst_format_desc->color_fixup))
4865     {
4866         TRACE("Destination fixups are not supported\n");
4867         return FALSE;
4868     }
4869
4870     if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
4871     {
4872         TRACE("P8 fixup supported\n");
4873         return TRUE;
4874     }
4875
4876     /* We only support identity conversions. */
4877     if (is_identity_fixup(src_format_desc->color_fixup))
4878     {
4879         TRACE("[OK]\n");
4880         return TRUE;
4881     }
4882
4883     TRACE("[FAILED]\n");
4884     return FALSE;
4885 }
4886
4887 static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device,
4888         IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD color)
4889 {
4890     const float c[] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4891
4892     return device_clear_render_targets(device, 1 /* rt_count */, &dst_surface, 1 /* rect_count */,
4893             (const WINED3DRECT *)dst_rect, WINED3DCLEAR_TARGET, c, 0.0f /* depth */, 0 /* stencil */);
4894 }
4895
4896 const struct blit_shader ffp_blit =  {
4897     ffp_blit_alloc,
4898     ffp_blit_free,
4899     ffp_blit_set,
4900     ffp_blit_unset,
4901     ffp_blit_supported,
4902     ffp_blit_color_fill
4903 };
4904
4905 static HRESULT cpu_blit_alloc(IWineD3DDevice *iface)
4906 {
4907     return WINED3D_OK;
4908 }
4909
4910 /* Context activation is done by the caller. */
4911 static void cpu_blit_free(IWineD3DDevice *iface)
4912 {
4913 }
4914
4915 /* Context activation is done by the caller. */
4916 static HRESULT cpu_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
4917 {
4918     return WINED3D_OK;
4919 }
4920
4921 /* Context activation is done by the caller. */
4922 static void cpu_blit_unset(IWineD3DDevice *iface)
4923 {
4924 }
4925
4926 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4927                                const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4928                                const struct wined3d_format_desc *src_format_desc,
4929                                const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4930                                const struct wined3d_format_desc *dst_format_desc)
4931 {
4932     if (blit_op == BLIT_OP_COLOR_FILL)
4933     {
4934         return TRUE;
4935     }
4936
4937     return FALSE;
4938 }
4939
4940 static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
4941 {
4942     WINEDDBLTFX BltFx;
4943     memset(&BltFx, 0, sizeof(BltFx));
4944     BltFx.dwSize = sizeof(BltFx);
4945     BltFx.u5.dwFillColor = color_convert_argb_to_fmt(fill_color, dst_surface->resource.format_desc->format);
4946     return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
4947 }
4948
4949 const struct blit_shader cpu_blit =  {
4950     cpu_blit_alloc,
4951     cpu_blit_free,
4952     cpu_blit_set,
4953     cpu_blit_unset,
4954     cpu_blit_supported,
4955     cpu_blit_color_fill
4956 };
4957
4958 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4959                                const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4960                                const struct wined3d_format_desc *src_format_desc,
4961                                const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4962                                const struct wined3d_format_desc *dst_format_desc)
4963 {
4964     if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
4965         return FALSE;
4966
4967     /* We only support blitting. Things like color keying / color fill should
4968      * be handled by other blitters.
4969      */
4970     if (blit_op != BLIT_OP_BLIT)
4971         return FALSE;
4972
4973     /* Source and/or destination need to be on the GL side */
4974     if (src_pool == WINED3DPOOL_SYSTEMMEM || dst_pool == WINED3DPOOL_SYSTEMMEM)
4975         return FALSE;
4976
4977     if(!((src_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET))
4978         && ((dst_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
4979         return FALSE;
4980
4981     if (!is_identity_fixup(src_format_desc->color_fixup) ||
4982         !is_identity_fixup(dst_format_desc->color_fixup))
4983         return FALSE;
4984
4985     if (!(src_format_desc->format == dst_format_desc->format
4986         || (is_identity_fixup(src_format_desc->color_fixup)
4987         && is_identity_fixup(dst_format_desc->color_fixup))))
4988         return FALSE;
4989
4990     return TRUE;
4991 }