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