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