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