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