d3d10: Add argument check to ID3D10Effect::GetTechniqueByName().
[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) 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("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1684
1685     /* This is also done in the base class, but we have to verify this before loading any data from
1686      * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
1687      * may interfere, and all other bad things may happen
1688      */
1689     if (This->Flags & SFLAG_LOCKED) {
1690         WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
1691         return WINED3DERR_INVALIDCALL;
1692     }
1693     This->Flags |= SFLAG_LOCKED;
1694
1695     if (!(This->Flags & SFLAG_LOCKABLE))
1696     {
1697         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
1698     }
1699
1700     if (Flags & WINED3DLOCK_DISCARD) {
1701         /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
1702         TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
1703         surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1704         This->Flags |= SFLAG_INSYSMEM;
1705         goto lock_end;
1706     }
1707
1708     if (This->Flags & SFLAG_INSYSMEM) {
1709         TRACE("Local copy is up to date, not downloading data\n");
1710         surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1711         goto lock_end;
1712     }
1713
1714     /* IWineD3DSurface_LoadLocation() does not check if the rectangle specifies
1715      * the full surface. Most callers don't need that, so do it here. */
1716     if (pRect && pRect->top == 0 && pRect->left == 0
1717             && pRect->right == This->currentDesc.Width
1718             && pRect->bottom == This->currentDesc.Height)
1719     {
1720         pass_rect = NULL;
1721     }
1722
1723     if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
1724             && ((This->Flags & SFLAG_SWAPCHAIN) || This == device->render_targets[0])))
1725     {
1726         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, pass_rect);
1727     }
1728
1729 lock_end:
1730     if (This->Flags & SFLAG_PBO)
1731     {
1732         const struct wined3d_gl_info *gl_info;
1733         struct wined3d_context *context;
1734
1735         context = context_acquire(device, NULL);
1736         gl_info = context->gl_info;
1737
1738         ENTER_GL();
1739         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1740         checkGLcall("glBindBufferARB");
1741
1742         /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
1743         if(This->resource.allocatedMemory) {
1744             ERR("The surface already has PBO memory allocated!\n");
1745         }
1746
1747         This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1748         checkGLcall("glMapBufferARB");
1749
1750         /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
1751         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1752         checkGLcall("glBindBufferARB");
1753
1754         LEAVE_GL();
1755         context_release(context);
1756     }
1757
1758     if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
1759         /* Don't dirtify */
1760     } else {
1761         IWineD3DBaseTexture *pBaseTexture;
1762         /**
1763          * Dirtify on lock
1764          * as seen in msdn docs
1765          */
1766         surface_add_dirty_rect(This, pRect);
1767
1768         /** Dirtify Container if needed */
1769         if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture))) {
1770             TRACE("Making container dirty\n");
1771             IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
1772             IWineD3DBaseTexture_Release(pBaseTexture);
1773         } else {
1774             TRACE("Surface is standalone, no need to dirty the container\n");
1775         }
1776     }
1777
1778     return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
1779 }
1780
1781 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem) {
1782     GLint  prev_store;
1783     GLint  prev_rasterpos[4];
1784     GLint skipBytes = 0;
1785     UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);    /* target is argb, 4 byte */
1786     IWineD3DDeviceImpl *device = This->resource.device;
1787     const struct wined3d_gl_info *gl_info;
1788     struct wined3d_context *context;
1789
1790     /* Activate the correct context for the render target */
1791     context = context_acquire(device, This);
1792     context_apply_blit_state(context, device);
1793     gl_info = context->gl_info;
1794
1795     ENTER_GL();
1796
1797     if (!surface_is_offscreen(This))
1798     {
1799         GLenum buffer = surface_get_gl_buffer(This);
1800         TRACE("Unlocking %#x buffer.\n", buffer);
1801         context_set_draw_buffer(context, buffer);
1802     }
1803     else
1804     {
1805         /* Primary offscreen render target */
1806         TRACE("Offscreen render target.\n");
1807         context_set_draw_buffer(context, device->offscreenBuffer);
1808     }
1809
1810     glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
1811     checkGLcall("glGetIntegerv");
1812     glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
1813     checkGLcall("glGetIntegerv");
1814     glPixelZoom(1.0f, -1.0f);
1815     checkGLcall("glPixelZoom");
1816
1817     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
1818     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
1819     glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
1820
1821     glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
1822     checkGLcall("glRasterPos3i");
1823
1824     /* Some drivers(radeon dri, others?) don't like exceptions during
1825      * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
1826      * after ReleaseDC. Reading it will cause an exception, which x11drv will
1827      * catch to put the dib section in InSync mode, which leads to a crash
1828      * and a blocked x server on my radeon card.
1829      *
1830      * The following lines read the dib section so it is put in InSync mode
1831      * before glDrawPixels is called and the crash is prevented. There won't
1832      * be any interfering gdi accesses, because UnlockRect is called from
1833      * ReleaseDC, and the app won't use the dc any more afterwards.
1834      */
1835     if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) {
1836         volatile BYTE read;
1837         read = This->resource.allocatedMemory[0];
1838     }
1839
1840     if(This->Flags & SFLAG_PBO) {
1841         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1842         checkGLcall("glBindBufferARB");
1843     }
1844
1845     /* When the surface is locked we only have to refresh the locked part else we need to update the whole image */
1846     if(This->Flags & SFLAG_LOCKED) {
1847         glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1848                      (This->lockedRect.bottom - This->lockedRect.top)-1,
1849                      fmt, type,
1850                      mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1851         checkGLcall("glDrawPixels");
1852     } else {
1853         glDrawPixels(This->currentDesc.Width,
1854                      This->currentDesc.Height,
1855                      fmt, type, mem);
1856         checkGLcall("glDrawPixels");
1857     }
1858
1859     if(This->Flags & SFLAG_PBO) {
1860         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1861         checkGLcall("glBindBufferARB");
1862     }
1863
1864     glPixelZoom(1.0f, 1.0f);
1865     checkGLcall("glPixelZoom");
1866
1867     glRasterPos3iv(&prev_rasterpos[0]);
1868     checkGLcall("glRasterPos3iv");
1869
1870     /* Reset to previous pack row length */
1871     glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1872     checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH)");
1873
1874     LEAVE_GL();
1875     context_release(context);
1876 }
1877
1878 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1879     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1880     IWineD3DDeviceImpl *device = This->resource.device;
1881     BOOL fullsurface;
1882
1883     if (!(This->Flags & SFLAG_LOCKED)) {
1884         WARN("trying to Unlock an unlocked surf@%p\n", This);
1885         return WINEDDERR_NOTLOCKED;
1886     }
1887
1888     if (This->Flags & SFLAG_PBO)
1889     {
1890         const struct wined3d_gl_info *gl_info;
1891         struct wined3d_context *context;
1892
1893         TRACE("Freeing PBO memory\n");
1894
1895         context = context_acquire(device, NULL);
1896         gl_info = context->gl_info;
1897
1898         ENTER_GL();
1899         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1900         GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1901         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1902         checkGLcall("glUnmapBufferARB");
1903         LEAVE_GL();
1904         context_release(context);
1905
1906         This->resource.allocatedMemory = NULL;
1907     }
1908
1909     TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1910
1911     if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1912         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1913         goto unlock_end;
1914     }
1915
1916     if ((This->Flags & SFLAG_SWAPCHAIN) || (device->render_targets && This == device->render_targets[0]))
1917     {
1918         if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1919             static BOOL warned = FALSE;
1920             if(!warned) {
1921                 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1922                 warned = TRUE;
1923             }
1924             goto unlock_end;
1925         }
1926
1927         if(This->dirtyRect.left   == 0 &&
1928            This->dirtyRect.top    == 0 &&
1929            This->dirtyRect.right  == This->currentDesc.Width &&
1930            This->dirtyRect.bottom == This->currentDesc.Height) {
1931             fullsurface = TRUE;
1932         } else {
1933             /* TODO: Proper partial rectangle tracking */
1934             fullsurface = FALSE;
1935             This->Flags |= SFLAG_INSYSMEM;
1936         }
1937
1938         switch(wined3d_settings.rendertargetlock_mode) {
1939             case RTL_READTEX:
1940                 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* partial texture loading not supported yet */);
1941                 /* drop through */
1942
1943             case RTL_READDRAW:
1944                 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
1945                 break;
1946         }
1947
1948         if(!fullsurface) {
1949             /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite
1950              * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where
1951              * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy
1952              * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is
1953              * not fully up to date because only a subrectangle was read in LockRect.
1954              */
1955             This->Flags &= ~SFLAG_INSYSMEM;
1956             This->Flags |= SFLAG_INDRAWABLE;
1957         }
1958
1959         This->dirtyRect.left   = This->currentDesc.Width;
1960         This->dirtyRect.top    = This->currentDesc.Height;
1961         This->dirtyRect.right  = 0;
1962         This->dirtyRect.bottom = 0;
1963     }
1964     else if (This == device->depth_stencil)
1965     {
1966         FIXME("Depth Stencil buffer locking is not implemented\n");
1967     } else {
1968         /* The rest should be a normal texture */
1969         IWineD3DBaseTextureImpl *impl;
1970         /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1971          * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1972          * states need resetting
1973          */
1974         if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1975             if (impl->baseTexture.bindCount)
1976                 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(impl->baseTexture.sampler));
1977             IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1978         }
1979     }
1980
1981     unlock_end:
1982     This->Flags &= ~SFLAG_LOCKED;
1983     memset(&This->lockedRect, 0, sizeof(RECT));
1984
1985     /* Overlays have to be redrawn manually after changes with the GL implementation */
1986     if(This->overlay_dest) {
1987         IWineD3DSurface_DrawOverlay(iface);
1988     }
1989     return WINED3D_OK;
1990 }
1991
1992 static void surface_release_client_storage(IWineD3DSurfaceImpl *surface)
1993 {
1994     struct wined3d_context *context;
1995
1996     context = context_acquire(surface->resource.device, NULL);
1997
1998     ENTER_GL();
1999     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2000     if (surface->texture_name)
2001     {
2002         surface_bind_and_dirtify(surface, FALSE);
2003         glTexImage2D(surface->texture_target, surface->texture_level,
2004                 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
2005     }
2006     if (surface->texture_name_srgb)
2007     {
2008         surface_bind_and_dirtify(surface, TRUE);
2009         glTexImage2D(surface->texture_target, surface->texture_level,
2010                 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
2011     }
2012     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2013
2014     LEAVE_GL();
2015     context_release(context);
2016
2017     IWineD3DSurface_ModifyLocation((IWineD3DSurface *)surface, SFLAG_INSRGBTEX, FALSE);
2018     IWineD3DSurface_ModifyLocation((IWineD3DSurface *)surface, SFLAG_INTEXTURE, FALSE);
2019     surface_force_reload(surface);
2020 }
2021
2022 static HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC)
2023 {
2024     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2025     WINED3DLOCKED_RECT lock;
2026     HRESULT hr;
2027     RGBQUAD col[256];
2028
2029     TRACE("(%p)->(%p)\n",This,pHDC);
2030
2031     if(This->Flags & SFLAG_USERPTR) {
2032         ERR("Not supported on surfaces with an application-provided surfaces\n");
2033         return WINEDDERR_NODC;
2034     }
2035
2036     /* Give more detailed info for ddraw */
2037     if (This->Flags & SFLAG_DCINUSE)
2038         return WINEDDERR_DCALREADYCREATED;
2039
2040     /* Can't GetDC if the surface is locked */
2041     if (This->Flags & SFLAG_LOCKED)
2042         return WINED3DERR_INVALIDCALL;
2043
2044     memset(&lock, 0, sizeof(lock)); /* To be sure */
2045
2046     /* Create a DIB section if there isn't a hdc yet */
2047     if(!This->hDC) {
2048         if(This->Flags & SFLAG_CLIENT) {
2049             IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2050             surface_release_client_storage(This);
2051         }
2052         hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
2053         if(FAILED(hr)) return WINED3DERR_INVALIDCALL;
2054
2055         /* Use the dib section from now on if we are not using a PBO */
2056         if(!(This->Flags & SFLAG_PBO))
2057             This->resource.allocatedMemory = This->dib.bitmap_data;
2058     }
2059
2060     /* Lock the surface */
2061     hr = IWineD3DSurface_LockRect(iface,
2062                                   &lock,
2063                                   NULL,
2064                                   0);
2065
2066     if(This->Flags & SFLAG_PBO) {
2067         /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
2068         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
2069     }
2070
2071     if(FAILED(hr)) {
2072         ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
2073         /* keep the dib section */
2074         return hr;
2075     }
2076
2077     if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
2078             || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
2079     {
2080         /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
2081             D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
2082         unsigned int n;
2083         const PALETTEENTRY *pal = NULL;
2084
2085         if(This->palette) {
2086             pal = This->palette->palents;
2087         } else {
2088             IWineD3DSurfaceImpl *dds_primary;
2089             IWineD3DSwapChainImpl *swapchain;
2090             swapchain = (IWineD3DSwapChainImpl *)This->resource.device->swapchains[0];
2091             dds_primary = swapchain->front_buffer;
2092             if (dds_primary && dds_primary->palette)
2093                 pal = dds_primary->palette->palents;
2094         }
2095
2096         if (pal) {
2097             for (n=0; n<256; n++) {
2098                 col[n].rgbRed   = pal[n].peRed;
2099                 col[n].rgbGreen = pal[n].peGreen;
2100                 col[n].rgbBlue  = pal[n].peBlue;
2101                 col[n].rgbReserved = 0;
2102             }
2103             SetDIBColorTable(This->hDC, 0, 256, col);
2104         }
2105     }
2106
2107     *pHDC = This->hDC;
2108     TRACE("returning %p\n",*pHDC);
2109     This->Flags |= SFLAG_DCINUSE;
2110
2111     return WINED3D_OK;
2112 }
2113
2114 static HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC)
2115 {
2116     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2117
2118     TRACE("(%p)->(%p)\n",This,hDC);
2119
2120     if (!(This->Flags & SFLAG_DCINUSE))
2121         return WINEDDERR_NODC;
2122
2123     if (This->hDC !=hDC) {
2124         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
2125         return WINEDDERR_NODC;
2126     }
2127
2128     if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) {
2129         /* Copy the contents of the DIB over to the PBO */
2130         memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
2131     }
2132
2133     /* we locked first, so unlock now */
2134     IWineD3DSurface_UnlockRect(iface);
2135
2136     This->Flags &= ~SFLAG_DCINUSE;
2137
2138     return WINED3D_OK;
2139 }
2140
2141 /* ******************************************************
2142    IWineD3DSurface Internal (No mapping to directx api) parts follow
2143    ****************************************************** */
2144
2145 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, struct wined3d_format_desc *desc, CONVERT_TYPES *convert)
2146 {
2147     BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
2148     IWineD3DDeviceImpl *device = This->resource.device;
2149     BOOL blit_supported = FALSE;
2150     RECT rect = {0, 0, This->pow2Width, This->pow2Height};
2151
2152     /* Copy the default values from the surface. Below we might perform fixups */
2153     /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2154     *desc = *This->resource.format_desc;
2155     *convert = NO_CONVERSION;
2156
2157     /* Ok, now look if we have to do any conversion */
2158     switch(This->resource.format_desc->format)
2159     {
2160         case WINED3DFMT_P8_UINT:
2161             /* ****************
2162                 Paletted Texture
2163                 **************** */
2164
2165             blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
2166                                                              &rect, This->resource.usage, This->resource.pool,
2167                                                              This->resource.format_desc, &rect, This->resource.usage,
2168                                                              This->resource.pool, This->resource.format_desc);
2169
2170             /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2171              * texturing. Further also use conversion in case of color keying.
2172              * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2173              * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2174              * conflicts with this.
2175              */
2176             if (!((blit_supported && device->render_targets && This == device->render_targets[0]))
2177                     || colorkey_active || !use_texturing)
2178             {
2179                 desc->glFormat = GL_RGBA;
2180                 desc->glInternal = GL_RGBA;
2181                 desc->glType = GL_UNSIGNED_BYTE;
2182                 desc->conv_byte_count = 4;
2183                 if(colorkey_active) {
2184                     *convert = CONVERT_PALETTED_CK;
2185                 } else {
2186                     *convert = CONVERT_PALETTED;
2187                 }
2188             }
2189             break;
2190
2191         case WINED3DFMT_B2G3R3_UNORM:
2192             /* **********************
2193                 GL_UNSIGNED_BYTE_3_3_2
2194                 ********************** */
2195             if (colorkey_active) {
2196                 /* This texture format will never be used.. So do not care about color keying
2197                     up until the point in time it will be needed :-) */
2198                 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2199             }
2200             break;
2201
2202         case WINED3DFMT_B5G6R5_UNORM:
2203             if (colorkey_active) {
2204                 *convert = CONVERT_CK_565;
2205                 desc->glFormat = GL_RGBA;
2206                 desc->glInternal = GL_RGB5_A1;
2207                 desc->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2208                 desc->conv_byte_count = 2;
2209             }
2210             break;
2211
2212         case WINED3DFMT_B5G5R5X1_UNORM:
2213             if (colorkey_active) {
2214                 *convert = CONVERT_CK_5551;
2215                 desc->glFormat = GL_BGRA;
2216                 desc->glInternal = GL_RGB5_A1;
2217                 desc->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2218                 desc->conv_byte_count = 2;
2219             }
2220             break;
2221
2222         case WINED3DFMT_B8G8R8_UNORM:
2223             if (colorkey_active) {
2224                 *convert = CONVERT_CK_RGB24;
2225                 desc->glFormat = GL_RGBA;
2226                 desc->glInternal = GL_RGBA8;
2227                 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2228                 desc->conv_byte_count = 4;
2229             }
2230             break;
2231
2232         case WINED3DFMT_B8G8R8X8_UNORM:
2233             if (colorkey_active) {
2234                 *convert = CONVERT_RGB32_888;
2235                 desc->glFormat = GL_RGBA;
2236                 desc->glInternal = GL_RGBA8;
2237                 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2238                 desc->conv_byte_count = 4;
2239             }
2240             break;
2241
2242         default:
2243             break;
2244     }
2245
2246     return WINED3D_OK;
2247 }
2248
2249 void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
2250 {
2251     IWineD3DDeviceImpl *device = This->resource.device;
2252     IWineD3DPaletteImpl *pal = This->palette;
2253     BOOL index_in_alpha = FALSE;
2254     unsigned int i;
2255
2256     /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
2257      * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
2258      * is slow. Further RGB->P8 conversion is not possible because palettes can have
2259      * duplicate entries. Store the color key in the unused alpha component to speed the
2260      * download up and to make conversion unneeded. */
2261     index_in_alpha = primary_render_target_is_p8(device);
2262
2263     if (!pal)
2264     {
2265         UINT dxVersion = ((IWineD3DImpl *)device->wined3d)->dxVersion;
2266
2267         /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
2268         if (dxVersion <= 7)
2269         {
2270             ERR("This code should never get entered for DirectDraw!, expect problems\n");
2271             if (index_in_alpha)
2272             {
2273                 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
2274                  * there's no palette at this time. */
2275                 for (i = 0; i < 256; i++) table[i][3] = i;
2276             }
2277         }
2278         else
2279         {
2280             /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
2281              * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
2282              * capability flag is present (wine does advertise this capability) */
2283             for (i = 0; i < 256; ++i)
2284             {
2285                 table[i][0] = device->palettes[device->currentPalette][i].peRed;
2286                 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
2287                 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
2288                 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
2289             }
2290         }
2291     }
2292     else
2293     {
2294         TRACE("Using surface palette %p\n", pal);
2295         /* Get the surface's palette */
2296         for (i = 0; i < 256; ++i)
2297         {
2298             table[i][0] = pal->palents[i].peRed;
2299             table[i][1] = pal->palents[i].peGreen;
2300             table[i][2] = pal->palents[i].peBlue;
2301
2302             /* When index_in_alpha is set the palette index is stored in the
2303              * alpha component. In case of a readback we can then read
2304              * GL_ALPHA. Color keying is handled in BltOverride using a
2305              * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
2306              * color key itself is passed to glAlphaFunc in other cases the
2307              * alpha component of pixels that should be masked away is set to 0. */
2308             if (index_in_alpha)
2309             {
2310                 table[i][3] = i;
2311             }
2312             else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
2313                     && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
2314             {
2315                 table[i][3] = 0x00;
2316             }
2317             else if(pal->Flags & WINEDDPCAPS_ALPHA)
2318             {
2319                 table[i][3] = pal->palents[i].peFlags;
2320             }
2321             else
2322             {
2323                 table[i][3] = 0xFF;
2324             }
2325         }
2326     }
2327 }
2328
2329 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
2330         UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
2331 {
2332     const BYTE *source;
2333     BYTE *dest;
2334     TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
2335
2336     switch (convert) {
2337         case NO_CONVERSION:
2338         {
2339             memcpy(dst, src, pitch * height);
2340             break;
2341         }
2342         case CONVERT_PALETTED:
2343         case CONVERT_PALETTED_CK:
2344         {
2345             IWineD3DPaletteImpl* pal = This->palette;
2346             BYTE table[256][4];
2347             unsigned int x, y;
2348
2349             if( pal == NULL) {
2350                 /* TODO: If we are a sublevel, try to get the palette from level 0 */
2351             }
2352
2353             d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
2354
2355             for (y = 0; y < height; y++)
2356             {
2357                 source = src + pitch * y;
2358                 dest = dst + outpitch * y;
2359                 /* This is an 1 bpp format, using the width here is fine */
2360                 for (x = 0; x < width; x++) {
2361                     BYTE color = *source++;
2362                     *dest++ = table[color][0];
2363                     *dest++ = table[color][1];
2364                     *dest++ = table[color][2];
2365                     *dest++ = table[color][3];
2366                 }
2367             }
2368         }
2369         break;
2370
2371         case CONVERT_CK_565:
2372         {
2373             /* Converting the 565 format in 5551 packed to emulate color-keying.
2374
2375               Note : in all these conversion, it would be best to average the averaging
2376                       pixels to get the color of the pixel that will be color-keyed to
2377                       prevent 'color bleeding'. This will be done later on if ever it is
2378                       too visible.
2379
2380               Note2: Nvidia documents say that their driver does not support alpha + color keying
2381                      on the same surface and disables color keying in such a case
2382             */
2383             unsigned int x, y;
2384             const WORD *Source;
2385             WORD *Dest;
2386
2387             TRACE("Color keyed 565\n");
2388
2389             for (y = 0; y < height; y++) {
2390                 Source = (const WORD *)(src + y * pitch);
2391                 Dest = (WORD *) (dst + y * outpitch);
2392                 for (x = 0; x < width; x++ ) {
2393                     WORD color = *Source++;
2394                     *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
2395                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2396                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2397                         *Dest |= 0x0001;
2398                     }
2399                     Dest++;
2400                 }
2401             }
2402         }
2403         break;
2404
2405         case CONVERT_CK_5551:
2406         {
2407             /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
2408             unsigned int x, y;
2409             const WORD *Source;
2410             WORD *Dest;
2411             TRACE("Color keyed 5551\n");
2412             for (y = 0; y < height; y++) {
2413                 Source = (const WORD *)(src + y * pitch);
2414                 Dest = (WORD *) (dst + y * outpitch);
2415                 for (x = 0; x < width; x++ ) {
2416                     WORD color = *Source++;
2417                     *Dest = color;
2418                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2419                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2420                         *Dest |= (1 << 15);
2421                     }
2422                     else {
2423                         *Dest &= ~(1 << 15);
2424                     }
2425                     Dest++;
2426                 }
2427             }
2428         }
2429         break;
2430
2431         case CONVERT_CK_RGB24:
2432         {
2433             /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
2434             unsigned int x, y;
2435             for (y = 0; y < height; y++)
2436             {
2437                 source = src + pitch * y;
2438                 dest = dst + outpitch * y;
2439                 for (x = 0; x < width; x++) {
2440                     DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
2441                     DWORD dstcolor = color << 8;
2442                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2443                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2444                         dstcolor |= 0xff;
2445                     }
2446                     *(DWORD*)dest = dstcolor;
2447                     source += 3;
2448                     dest += 4;
2449                 }
2450             }
2451         }
2452         break;
2453
2454         case CONVERT_RGB32_888:
2455         {
2456             /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
2457             unsigned int x, y;
2458             for (y = 0; y < height; y++)
2459             {
2460                 source = src + pitch * y;
2461                 dest = dst + outpitch * y;
2462                 for (x = 0; x < width; x++) {
2463                     DWORD color = 0xffffff & *(const DWORD*)source;
2464                     DWORD dstcolor = color << 8;
2465                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2466                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2467                         dstcolor |= 0xff;
2468                     }
2469                     *(DWORD*)dest = dstcolor;
2470                     source += 4;
2471                     dest += 4;
2472                 }
2473             }
2474         }
2475         break;
2476
2477         default:
2478             ERR("Unsupported conversion type %#x.\n", convert);
2479     }
2480     return WINED3D_OK;
2481 }
2482
2483 BOOL palette9_changed(IWineD3DSurfaceImpl *This)
2484 {
2485     IWineD3DDeviceImpl *device = This->resource.device;
2486
2487     if (This->palette || (This->resource.format_desc->format != WINED3DFMT_P8_UINT
2488             && This->resource.format_desc->format != WINED3DFMT_P8_UINT_A8_UNORM))
2489     {
2490         /* If a ddraw-style palette is attached assume no d3d9 palette change.
2491          * Also the palette isn't interesting if the surface format isn't P8 or A8P8
2492          */
2493         return FALSE;
2494     }
2495
2496     if (This->palette9)
2497     {
2498         if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
2499         {
2500             return FALSE;
2501         }
2502     } else {
2503         This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2504     }
2505     memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
2506     return TRUE;
2507 }
2508
2509 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
2510     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2511     DWORD flag = srgb_mode ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2512
2513     if (!(This->Flags & flag)) {
2514         TRACE("Reloading because surface is dirty\n");
2515     } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2516               ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
2517               /* Reload: vice versa  OR */
2518               ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
2519               /* Also reload: Color key is active AND the color key has changed */
2520               ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
2521                 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
2522                 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
2523         TRACE("Reloading because of color keying\n");
2524         /* To perform the color key conversion we need a sysmem copy of
2525          * the surface. Make sure we have it
2526          */
2527
2528         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2529         /* Make sure the texture is reloaded because of the color key change, this kills performance though :( */
2530         /* TODO: This is not necessarily needed with hw palettized texture support */
2531         IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2532     } else {
2533         TRACE("surface is already in texture\n");
2534         return WINED3D_OK;
2535     }
2536
2537     /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2538      *  These resources are not bound by device size or format restrictions. Because of this,
2539      *  these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2540      *  However, these resources can always be created, locked, and copied.
2541      */
2542     if (This->resource.pool == WINED3DPOOL_SCRATCH )
2543     {
2544         FIXME("(%p) Operation not supported for scratch textures\n",This);
2545         return WINED3DERR_INVALIDCALL;
2546     }
2547
2548     IWineD3DSurface_LoadLocation(iface, flag, NULL /* no partial locking for textures yet */);
2549
2550 #if 0
2551     {
2552         static unsigned int gen = 0;
2553         char buffer[4096];
2554         ++gen;
2555         if ((gen % 10) == 0) {
2556             snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm",
2557                     This, This->texture_target, This->texture_level, gen);
2558             IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2559         }
2560         /*
2561          * debugging crash code
2562          if (gen == 250) {
2563          void** test = NULL;
2564          *test = 0;
2565          }
2566          */
2567     }
2568 #endif
2569
2570     if (!(This->Flags & SFLAG_DONOTFREE)) {
2571         HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
2572         This->resource.allocatedMemory = NULL;
2573         This->resource.heapMemory = NULL;
2574         IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, FALSE);
2575     }
2576
2577     return WINED3D_OK;
2578 }
2579
2580 /* Context activation is done by the caller. */
2581 static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
2582     /* TODO: check for locks */
2583     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2584     IWineD3DBaseTexture *baseTexture = NULL;
2585
2586     TRACE("(%p)Checking to see if the container is a base texture\n", This);
2587     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2588         TRACE("Passing to container\n");
2589         IWineD3DBaseTexture_BindTexture(baseTexture, srgb);
2590         IWineD3DBaseTexture_Release(baseTexture);
2591     }
2592     else
2593     {
2594         GLuint *name;
2595
2596         TRACE("(%p) : Binding surface\n", This);
2597
2598         name = srgb ? &This->texture_name_srgb : &This->texture_name;
2599
2600         ENTER_GL();
2601
2602         if (!This->texture_level)
2603         {
2604             if (!*name) {
2605                 glGenTextures(1, name);
2606                 checkGLcall("glGenTextures");
2607                 TRACE("Surface %p given name %d\n", This, *name);
2608
2609                 glBindTexture(This->texture_target, *name);
2610                 checkGLcall("glBindTexture");
2611                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2612                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
2613                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2614                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
2615                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2616                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)");
2617                 glTexParameteri(This->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2618                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
2619                 glTexParameteri(This->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2620                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
2621             }
2622             /* This is where we should be reducing the amount of GLMemoryUsed */
2623         } else if (*name) {
2624             /* Mipmap surfaces should have a base texture container */
2625             ERR("Mipmap surface has a glTexture bound to it!\n");
2626         }
2627
2628         glBindTexture(This->texture_target, *name);
2629         checkGLcall("glBindTexture");
2630
2631         LEAVE_GL();
2632     }
2633 }
2634
2635 #include <errno.h>
2636 #include <stdio.h>
2637 static HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename)
2638 {
2639     FILE* f = NULL;
2640     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2641     char *allocatedMemory;
2642     const char *textureRow;
2643     IWineD3DSwapChain *swapChain = NULL;
2644     int width, height, i, y;
2645     GLuint tmpTexture = 0;
2646     DWORD color;
2647     /*FIXME:
2648     Textures may not be stored in ->allocatedgMemory and a GlTexture
2649     so we should lock the surface before saving a snapshot, or at least check that
2650     */
2651     /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2652     by calling GetTexImage and in compressed form by calling
2653     GetCompressedTexImageARB.  Queried compressed images can be saved and
2654     later reused by calling CompressedTexImage[123]DARB.  Pre-compressed
2655     texture images do not need to be processed by the GL and should
2656     significantly improve texture loading performance relative to uncompressed
2657     images. */
2658
2659 /* Setup the width and height to be the internal texture width and height. */
2660     width  = This->pow2Width;
2661     height = This->pow2Height;
2662 /* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2663     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2664
2665     if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2666         /* if were not a real texture then read the back buffer into a real texture */
2667         /* we don't want to interfere with the back buffer so read the data into a temporary
2668          * texture and then save the data out of the temporary texture
2669          */
2670         GLint prevRead;
2671         ENTER_GL();
2672         TRACE("(%p) Reading render target into texture\n", This);
2673
2674         glGenTextures(1, &tmpTexture);
2675         glBindTexture(GL_TEXTURE_2D, tmpTexture);
2676
2677         glTexImage2D(GL_TEXTURE_2D,
2678                         0,
2679                         GL_RGBA,
2680                         width,
2681                         height,
2682                         0/*border*/,
2683                         GL_RGBA,
2684                         GL_UNSIGNED_INT_8_8_8_8_REV,
2685                         NULL);
2686
2687         glGetIntegerv(GL_READ_BUFFER, &prevRead);
2688         checkGLcall("glGetIntegerv");
2689         glReadBuffer(swapChain ? GL_BACK : This->resource.device->offscreenBuffer);
2690         checkGLcall("glReadBuffer");
2691         glCopyTexImage2D(GL_TEXTURE_2D,
2692                             0,
2693                             GL_RGBA,
2694                             0,
2695                             0,
2696                             width,
2697                             height,
2698                             0);
2699
2700         checkGLcall("glCopyTexImage2D");
2701         glReadBuffer(prevRead);
2702         LEAVE_GL();
2703
2704     } else { /* bind the real texture, and make sure it up to date */
2705         surface_internal_preload(This, SRGB_RGB);
2706         surface_bind_and_dirtify(This, FALSE);
2707     }
2708     allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width  * height * 4);
2709     ENTER_GL();
2710     FIXME("Saving texture level %d width %d height %d\n", This->texture_level, width, height);
2711     glGetTexImage(GL_TEXTURE_2D, This->texture_level, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, allocatedMemory);
2712     checkGLcall("glGetTexImage");
2713     if (tmpTexture) {
2714         glBindTexture(GL_TEXTURE_2D, 0);
2715         glDeleteTextures(1, &tmpTexture);
2716     }
2717     LEAVE_GL();
2718
2719     f = fopen(filename, "w+");
2720     if (NULL == f) {
2721         ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2722         return WINED3DERR_INVALIDCALL;
2723     }
2724 /* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
2725     TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format_desc->format));
2726 /* TGA header */
2727     fputc(0,f);
2728     fputc(0,f);
2729     fputc(2,f);
2730     fputc(0,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 /* short width*/
2740     fwrite(&width,2,1,f);
2741 /* short height */
2742     fwrite(&height,2,1,f);
2743 /* format rgba */
2744     fputc(0x20,f);
2745     fputc(0x28,f);
2746 /* raw data */
2747     /* 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 */
2748     if(swapChain)
2749         textureRow = allocatedMemory + (width * (height - 1) *4);
2750     else
2751         textureRow = allocatedMemory;
2752     for (y = 0 ; y < height; y++) {
2753         for (i = 0; i < width;  i++) {
2754             color = *((const DWORD*)textureRow);
2755             fputc((color >> 16) & 0xFF, f); /* B */
2756             fputc((color >>  8) & 0xFF, f); /* G */
2757             fputc((color >>  0) & 0xFF, f); /* R */
2758             fputc((color >> 24) & 0xFF, f); /* A */
2759             textureRow += 4;
2760         }
2761         /* take two rows of the pointer to the texture memory */
2762         if(swapChain)
2763             (textureRow-= width << 3);
2764
2765     }
2766     TRACE("Closing file\n");
2767     fclose(f);
2768
2769     if(swapChain) {
2770         IWineD3DSwapChain_Release(swapChain);
2771     }
2772     HeapFree(GetProcessHeap(), 0, allocatedMemory);
2773     return WINED3D_OK;
2774 }
2775
2776 static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2777     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2778     HRESULT hr;
2779
2780     TRACE("(%p) : Calling base function first\n", This);
2781     hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
2782     if(SUCCEEDED(hr)) {
2783         This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
2784         TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This, This->resource.format_desc->glFormat,
2785                 This->resource.format_desc->glInternal, This->resource.format_desc->glType);
2786     }
2787     return hr;
2788 }
2789
2790 static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2791     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2792
2793     if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2794         WARN("Surface is locked or the HDC is in use\n");
2795         return WINED3DERR_INVALIDCALL;
2796     }
2797
2798     if(Mem && Mem != This->resource.allocatedMemory) {
2799         void *release = NULL;
2800
2801         /* Do I have to copy the old surface content? */
2802         if(This->Flags & SFLAG_DIBSECTION) {
2803                 /* Release the DC. No need to hold the critical section for the update
2804                  * Thread because this thread runs only on front buffers, but this method
2805                  * fails for render targets in the check above.
2806                  */
2807                 SelectObject(This->hDC, This->dib.holdbitmap);
2808                 DeleteDC(This->hDC);
2809                 /* Release the DIB section */
2810                 DeleteObject(This->dib.DIBsection);
2811                 This->dib.bitmap_data = NULL;
2812                 This->resource.allocatedMemory = NULL;
2813                 This->hDC = NULL;
2814                 This->Flags &= ~SFLAG_DIBSECTION;
2815         } else if(!(This->Flags & SFLAG_USERPTR)) {
2816             release = This->resource.heapMemory;
2817             This->resource.heapMemory = NULL;
2818         }
2819         This->resource.allocatedMemory = Mem;
2820         This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
2821
2822         /* Now the surface memory is most up do date. Invalidate drawable and texture */
2823         IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2824
2825         /* For client textures opengl has to be notified */
2826         if (This->Flags & SFLAG_CLIENT)
2827             surface_release_client_storage(This);
2828
2829         /* Now free the old memory if any */
2830         HeapFree(GetProcessHeap(), 0, release);
2831     } else if(This->Flags & SFLAG_USERPTR) {
2832         /* LockRect and GetDC will re-create the dib section and allocated memory */
2833         This->resource.allocatedMemory = NULL;
2834         /* HeapMemory should be NULL already */
2835         if(This->resource.heapMemory != NULL) ERR("User pointer surface has heap memory allocated\n");
2836         This->Flags &= ~SFLAG_USERPTR;
2837
2838         if (This->Flags & SFLAG_CLIENT)
2839             surface_release_client_storage(This);
2840     }
2841     return WINED3D_OK;
2842 }
2843
2844 void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
2845
2846     /* Flip the surface contents */
2847     /* Flip the DC */
2848     {
2849         HDC tmp;
2850         tmp = front->hDC;
2851         front->hDC = back->hDC;
2852         back->hDC = tmp;
2853     }
2854
2855     /* Flip the DIBsection */
2856     {
2857         HBITMAP tmp;
2858         BOOL hasDib = front->Flags & SFLAG_DIBSECTION;
2859         tmp = front->dib.DIBsection;
2860         front->dib.DIBsection = back->dib.DIBsection;
2861         back->dib.DIBsection = tmp;
2862
2863         if(back->Flags & SFLAG_DIBSECTION) front->Flags |= SFLAG_DIBSECTION;
2864         else front->Flags &= ~SFLAG_DIBSECTION;
2865         if(hasDib) back->Flags |= SFLAG_DIBSECTION;
2866         else back->Flags &= ~SFLAG_DIBSECTION;
2867     }
2868
2869     /* Flip the surface data */
2870     {
2871         void* tmp;
2872
2873         tmp = front->dib.bitmap_data;
2874         front->dib.bitmap_data = back->dib.bitmap_data;
2875         back->dib.bitmap_data = tmp;
2876
2877         tmp = front->resource.allocatedMemory;
2878         front->resource.allocatedMemory = back->resource.allocatedMemory;
2879         back->resource.allocatedMemory = tmp;
2880
2881         tmp = front->resource.heapMemory;
2882         front->resource.heapMemory = back->resource.heapMemory;
2883         back->resource.heapMemory = tmp;
2884     }
2885
2886     /* Flip the PBO */
2887     {
2888         GLuint tmp_pbo = front->pbo;
2889         front->pbo = back->pbo;
2890         back->pbo = tmp_pbo;
2891     }
2892
2893     /* client_memory should not be different, but just in case */
2894     {
2895         BOOL tmp;
2896         tmp = front->dib.client_memory;
2897         front->dib.client_memory = back->dib.client_memory;
2898         back->dib.client_memory = tmp;
2899     }
2900
2901     /* Flip the opengl texture */
2902     {
2903         GLuint tmp;
2904
2905         tmp = back->texture_name;
2906         back->texture_name = front->texture_name;
2907         front->texture_name = tmp;
2908
2909         tmp = back->texture_name_srgb;
2910         back->texture_name_srgb = front->texture_name_srgb;
2911         front->texture_name_srgb = tmp;
2912     }
2913
2914     {
2915         DWORD tmp_flags = back->Flags;
2916         back->Flags = front->Flags;
2917         front->Flags = tmp_flags;
2918     }
2919 }
2920
2921 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2922     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2923     IWineD3DSwapChainImpl *swapchain = NULL;
2924     HRESULT hr;
2925     TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2926
2927     /* Flipping is only supported on RenderTargets and overlays*/
2928     if( !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)) ) {
2929         WARN("Tried to flip a non-render target, non-overlay surface\n");
2930         return WINEDDERR_NOTFLIPPABLE;
2931     }
2932
2933     if(This->resource.usage & WINED3DUSAGE_OVERLAY) {
2934         flip_surface(This, (IWineD3DSurfaceImpl *) override);
2935
2936         /* Update the overlay if it is visible */
2937         if(This->overlay_dest) {
2938             return IWineD3DSurface_DrawOverlay((IWineD3DSurface *) This);
2939         } else {
2940             return WINED3D_OK;
2941         }
2942     }
2943
2944     if(override) {
2945         /* DDraw sets this for the X11 surfaces, so don't confuse the user
2946          * FIXME("(%p) Target override is not supported by now\n", This);
2947          * Additionally, it isn't really possible to support triple-buffering
2948          * properly on opengl at all
2949          */
2950     }
2951
2952     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
2953     if(!swapchain) {
2954         ERR("Flipped surface is not on a swapchain\n");
2955         return WINEDDERR_NOTFLIPPABLE;
2956     }
2957
2958     /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
2959      * and only d3d8 and d3d9 apps specify the presentation interval
2960      */
2961     if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
2962         /* Most common case first to avoid wasting time on all the other cases */
2963         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
2964     } else if(Flags & WINEDDFLIP_NOVSYNC) {
2965         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2966     } else if(Flags & WINEDDFLIP_INTERVAL2) {
2967         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
2968     } else if(Flags & WINEDDFLIP_INTERVAL3) {
2969         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
2970     } else {
2971         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
2972     }
2973
2974     /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2975     hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
2976             NULL, NULL, swapchain->win_handle, NULL, 0);
2977     IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2978     return hr;
2979 }
2980
2981 /* Does a direct frame buffer -> texture copy. Stretching is done
2982  * with single pixel copy calls
2983  */
2984 static void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
2985         const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
2986 {
2987     IWineD3DDeviceImpl *device = dst_surface->resource.device;
2988     float xrel, yrel;
2989     UINT row;
2990     struct wined3d_context *context;
2991     BOOL upsidedown = FALSE;
2992     RECT dst_rect = *dst_rect_in;
2993
2994     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2995      * glCopyTexSubImage is a bit picky about the parameters we pass to it
2996      */
2997     if(dst_rect.top > dst_rect.bottom) {
2998         UINT tmp = dst_rect.bottom;
2999         dst_rect.bottom = dst_rect.top;
3000         dst_rect.top = tmp;
3001         upsidedown = TRUE;
3002     }
3003
3004     context = context_acquire(device, src_surface);
3005     context_apply_blit_state(context, device);
3006     surface_internal_preload(dst_surface, SRGB_RGB);
3007     ENTER_GL();
3008
3009     /* Bind the target texture */
3010     glBindTexture(dst_surface->texture_target, dst_surface->texture_name);
3011     checkGLcall("glBindTexture");
3012     if (surface_is_offscreen(src_surface))
3013     {
3014         TRACE("Reading from an offscreen target\n");
3015         upsidedown = !upsidedown;
3016         glReadBuffer(device->offscreenBuffer);
3017     }
3018     else
3019     {
3020         glReadBuffer(surface_get_gl_buffer(src_surface));
3021     }
3022     checkGLcall("glReadBuffer");
3023
3024     xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
3025     yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
3026
3027     if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3028     {
3029         FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3030
3031         if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
3032             ERR("Texture filtering not supported in direct blit\n");
3033         }
3034     }
3035     else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
3036             && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3037     {
3038         ERR("Texture filtering not supported in direct blit\n");
3039     }
3040
3041     if (upsidedown
3042             && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3043             && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3044     {
3045         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
3046
3047         glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3048                 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
3049                 src_rect->left, src_surface->currentDesc.Height - src_rect->bottom,
3050                 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3051     } else {
3052         UINT yoffset = src_surface->currentDesc.Height - src_rect->top + dst_rect.top - 1;
3053         /* I have to process this row by row to swap the image,
3054          * otherwise it would be upside down, so stretching in y direction
3055          * doesn't cost extra time
3056          *
3057          * However, stretching in x direction can be avoided if not necessary
3058          */
3059         for(row = dst_rect.top; row < dst_rect.bottom; row++) {
3060             if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3061             {
3062                 /* Well, that stuff works, but it's very slow.
3063                  * find a better way instead
3064                  */
3065                 UINT col;
3066
3067                 for (col = dst_rect.left; col < dst_rect.right; ++col)
3068                 {
3069                     glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3070                             dst_rect.left + col /* x offset */, row /* y offset */,
3071                             src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
3072                 }
3073             }
3074             else
3075             {
3076                 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3077                         dst_rect.left /* x offset */, row /* y offset */,
3078                         src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
3079             }
3080         }
3081     }
3082     checkGLcall("glCopyTexSubImage2D");
3083
3084     LEAVE_GL();
3085     context_release(context);
3086
3087     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3088      * path is never entered
3089      */
3090     IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INTEXTURE, TRUE);
3091 }
3092
3093 /* Uses the hardware to stretch and flip the image */
3094 static void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
3095         const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
3096 {
3097     IWineD3DDeviceImpl *device = dst_surface->resource.device;
3098     GLuint src, backup = 0;
3099     IWineD3DSwapChainImpl *src_swapchain = NULL;
3100     float left, right, top, bottom; /* Texture coordinates */
3101     UINT fbwidth = src_surface->currentDesc.Width;
3102     UINT fbheight = src_surface->currentDesc.Height;
3103     struct wined3d_context *context;
3104     GLenum drawBuffer = GL_BACK;
3105     GLenum texture_target;
3106     BOOL noBackBufferBackup;
3107     BOOL src_offscreen;
3108     BOOL upsidedown = FALSE;
3109     RECT dst_rect = *dst_rect_in;
3110
3111     TRACE("Using hwstretch blit\n");
3112     /* Activate the Proper context for reading from the source surface, set it up for blitting */
3113     context = context_acquire(device, src_surface);
3114     context_apply_blit_state(context, device);
3115     surface_internal_preload(dst_surface, SRGB_RGB);
3116
3117     src_offscreen = surface_is_offscreen(src_surface);
3118     noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
3119     if (!noBackBufferBackup && !src_surface->texture_name)
3120     {
3121         /* Get it a description */
3122         surface_internal_preload(src_surface, SRGB_RGB);
3123     }
3124     ENTER_GL();
3125
3126     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3127      * This way we don't have to wait for the 2nd readback to finish to leave this function.
3128      */
3129     if (context->aux_buffers >= 2)
3130     {
3131         /* Got more than one aux buffer? Use the 2nd aux buffer */
3132         drawBuffer = GL_AUX1;
3133     }
3134     else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
3135     {
3136         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3137         drawBuffer = GL_AUX0;
3138     }
3139
3140     if(noBackBufferBackup) {
3141         glGenTextures(1, &backup);
3142         checkGLcall("glGenTextures");
3143         glBindTexture(GL_TEXTURE_2D, backup);
3144         checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3145         texture_target = GL_TEXTURE_2D;
3146     } else {
3147         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3148          * we are reading from the back buffer, the backup can be used as source texture
3149          */
3150         texture_target = src_surface->texture_target;
3151         glBindTexture(texture_target, src_surface->texture_name);
3152         checkGLcall("glBindTexture(texture_target, src_surface->texture_name)");
3153         glEnable(texture_target);
3154         checkGLcall("glEnable(texture_target)");
3155
3156         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3157         src_surface->Flags &= ~SFLAG_INTEXTURE;
3158     }
3159
3160     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3161      * glCopyTexSubImage is a bit picky about the parameters we pass to it
3162      */
3163     if(dst_rect.top > dst_rect.bottom) {
3164         UINT tmp = dst_rect.bottom;
3165         dst_rect.bottom = dst_rect.top;
3166         dst_rect.top = tmp;
3167         upsidedown = TRUE;
3168     }
3169
3170     if (src_offscreen)
3171     {
3172         TRACE("Reading from an offscreen target\n");
3173         upsidedown = !upsidedown;
3174         glReadBuffer(device->offscreenBuffer);
3175     }
3176     else
3177     {
3178         glReadBuffer(surface_get_gl_buffer(src_surface));
3179     }
3180
3181     /* TODO: Only back up the part that will be overwritten */
3182     glCopyTexSubImage2D(texture_target, 0,
3183                         0, 0 /* read offsets */,
3184                         0, 0,
3185                         fbwidth,
3186                         fbheight);
3187
3188     checkGLcall("glCopyTexSubImage2D");
3189
3190     /* No issue with overriding these - the sampler is dirty due to blit usage */
3191     glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
3192             wined3d_gl_mag_filter(magLookup, Filter));
3193     checkGLcall("glTexParameteri");
3194     glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
3195             wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
3196     checkGLcall("glTexParameteri");
3197
3198     IWineD3DSurface_GetContainer((IWineD3DSurface *)src_surface, &IID_IWineD3DSwapChain, (void **)&src_swapchain);
3199     if (src_swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)src_swapchain);
3200     if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
3201     {
3202         src = backup ? backup : src_surface->texture_name;
3203     }
3204     else
3205     {
3206         glReadBuffer(GL_FRONT);
3207         checkGLcall("glReadBuffer(GL_FRONT)");
3208
3209         glGenTextures(1, &src);
3210         checkGLcall("glGenTextures(1, &src)");
3211         glBindTexture(GL_TEXTURE_2D, src);
3212         checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
3213
3214         /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3215          * out for power of 2 sizes
3216          */
3217         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
3218                 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
3219         checkGLcall("glTexImage2D");
3220         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3221                             0, 0 /* read offsets */,
3222                             0, 0,
3223                             fbwidth,
3224                             fbheight);
3225
3226         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3227         checkGLcall("glTexParameteri");
3228         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3229         checkGLcall("glTexParameteri");
3230
3231         glReadBuffer(GL_BACK);
3232         checkGLcall("glReadBuffer(GL_BACK)");
3233
3234         if(texture_target != GL_TEXTURE_2D) {
3235             glDisable(texture_target);
3236             glEnable(GL_TEXTURE_2D);
3237             texture_target = GL_TEXTURE_2D;
3238         }
3239     }
3240     checkGLcall("glEnd and previous");
3241
3242     left = src_rect->left;
3243     right = src_rect->right;
3244
3245     if (upsidedown)
3246     {
3247         top = src_surface->currentDesc.Height - src_rect->top;
3248         bottom = src_surface->currentDesc.Height - src_rect->bottom;
3249     }
3250     else
3251     {
3252         top = src_surface->currentDesc.Height - src_rect->bottom;
3253         bottom = src_surface->currentDesc.Height - src_rect->top;
3254     }
3255
3256     if (src_surface->Flags & SFLAG_NORMCOORD)
3257     {
3258         left /= src_surface->pow2Width;
3259         right /= src_surface->pow2Width;
3260         top /= src_surface->pow2Height;
3261         bottom /= src_surface->pow2Height;
3262     }
3263
3264     /* draw the source texture stretched and upside down. The correct surface is bound already */
3265     glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
3266     glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
3267
3268     context_set_draw_buffer(context, drawBuffer);
3269     glReadBuffer(drawBuffer);
3270
3271     glBegin(GL_QUADS);
3272         /* bottom left */
3273         glTexCoord2f(left, bottom);
3274         glVertex2i(0, fbheight);
3275
3276         /* top left */
3277         glTexCoord2f(left, top);
3278         glVertex2i(0, fbheight - dst_rect.bottom - dst_rect.top);
3279
3280         /* top right */
3281         glTexCoord2f(right, top);
3282         glVertex2i(dst_rect.right - dst_rect.left, fbheight - dst_rect.bottom - dst_rect.top);
3283
3284         /* bottom right */
3285         glTexCoord2f(right, bottom);
3286         glVertex2i(dst_rect.right - dst_rect.left, fbheight);
3287     glEnd();
3288     checkGLcall("glEnd and previous");
3289
3290     if (texture_target != dst_surface->texture_target)
3291     {
3292         glDisable(texture_target);
3293         glEnable(dst_surface->texture_target);
3294         texture_target = dst_surface->texture_target;
3295     }
3296
3297     /* Now read the stretched and upside down image into the destination texture */
3298     glBindTexture(texture_target, dst_surface->texture_name);
3299     checkGLcall("glBindTexture");
3300     glCopyTexSubImage2D(texture_target,
3301                         0,
3302                         dst_rect.left, dst_rect.top, /* xoffset, yoffset */
3303                         0, 0, /* We blitted the image to the origin */
3304                         dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3305     checkGLcall("glCopyTexSubImage2D");
3306
3307     if(drawBuffer == GL_BACK) {
3308         /* Write the back buffer backup back */
3309         if(backup) {
3310             if(texture_target != GL_TEXTURE_2D) {
3311                 glDisable(texture_target);
3312                 glEnable(GL_TEXTURE_2D);
3313                 texture_target = GL_TEXTURE_2D;
3314             }
3315             glBindTexture(GL_TEXTURE_2D, backup);
3316             checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3317         }
3318         else
3319         {
3320             if (texture_target != src_surface->texture_target)
3321             {
3322                 glDisable(texture_target);
3323                 glEnable(src_surface->texture_target);
3324                 texture_target = src_surface->texture_target;
3325             }
3326             glBindTexture(src_surface->texture_target, src_surface->texture_name);
3327             checkGLcall("glBindTexture(src_surface->texture_target, src_surface->texture_name)");
3328         }
3329
3330         glBegin(GL_QUADS);
3331             /* top left */
3332             glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
3333             glVertex2i(0, 0);
3334
3335             /* bottom left */
3336             glTexCoord2f(0.0f, 0.0f);
3337             glVertex2i(0, fbheight);
3338
3339             /* bottom right */
3340             glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
3341             glVertex2i(fbwidth, src_surface->currentDesc.Height);
3342
3343             /* top right */
3344             glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
3345                     (float)fbheight / (float)src_surface->pow2Height);
3346             glVertex2i(fbwidth, 0);
3347         glEnd();
3348     }
3349     glDisable(texture_target);
3350     checkGLcall("glDisable(texture_target)");
3351
3352     /* Cleanup */
3353     if (src != src_surface->texture_name && src != backup)
3354     {
3355         glDeleteTextures(1, &src);
3356         checkGLcall("glDeleteTextures(1, &src)");
3357     }
3358     if(backup) {
3359         glDeleteTextures(1, &backup);
3360         checkGLcall("glDeleteTextures(1, &backup)");
3361     }
3362
3363     LEAVE_GL();
3364
3365     if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
3366
3367     context_release(context);
3368
3369     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3370      * path is never entered
3371      */
3372     IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INTEXTURE, TRUE);
3373 }
3374
3375 /* Until the blit_shader is ready, define some prototypes here. */
3376 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
3377                                const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
3378                                const struct wined3d_format_desc *src_format_desc,
3379                                const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
3380                                const struct wined3d_format_desc *dst_format_desc);
3381
3382 /* Not called from the VTable */
3383 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *DestRect,
3384         IWineD3DSurfaceImpl *src_surface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx,
3385         WINED3DTEXTUREFILTERTYPE Filter)
3386 {
3387     IWineD3DDeviceImpl *device = dst_surface->resource.device;
3388     IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
3389     RECT dst_rect, src_rect;
3390
3391     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
3392             dst_surface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
3393             Flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
3394
3395     /* Get the swapchain. One of the surfaces has to be a primary surface */
3396     if (dst_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
3397     {
3398         WARN("Destination is in sysmem, rejecting gl blt\n");
3399         return WINED3DERR_INVALIDCALL;
3400     }
3401     IWineD3DSurface_GetContainer((IWineD3DSurface *)dst_surface, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
3402     if (dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)dstSwapchain);
3403     if (src_surface)
3404     {
3405         if (src_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
3406         {
3407             WARN("Src is in sysmem, rejecting gl blt\n");
3408             return WINED3DERR_INVALIDCALL;
3409         }
3410         IWineD3DSurface_GetContainer((IWineD3DSurface *)src_surface, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
3411         if (srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)srcSwapchain);
3412     }
3413
3414     /* Early sort out of cases where no render target is used */
3415     if (!dstSwapchain && !srcSwapchain
3416             && src_surface != device->render_targets[0]
3417             && dst_surface != device->render_targets[0])
3418     {
3419         TRACE("No surface is render target, not using hardware blit.\n");
3420         return WINED3DERR_INVALIDCALL;
3421     }
3422
3423     /* No destination color keying supported */
3424     if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
3425         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3426         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3427         return WINED3DERR_INVALIDCALL;
3428     }
3429
3430     surface_get_rect(dst_surface, DestRect, &dst_rect);
3431     if (src_surface) surface_get_rect(src_surface, SrcRect, &src_rect);
3432
3433     /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
3434     if (dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->back_buffers
3435             && dst_surface == dstSwapchain->front_buffer
3436             && src_surface == dstSwapchain->back_buffers[0])
3437     {
3438         /* Half-life does a Blt from the back buffer to the front buffer,
3439          * Full surface size, no flags... Use present instead
3440          *
3441          * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
3442          */
3443
3444         /* Check rects - IWineD3DDevice_Present doesn't handle them */
3445         while(1)
3446         {
3447             TRACE("Looking if a Present can be done...\n");
3448             /* Source Rectangle must be full surface */
3449             if (src_rect.left || src_rect.top
3450                     || src_rect.right != src_surface->currentDesc.Width
3451                     || src_rect.bottom != src_surface->currentDesc.Height)
3452             {
3453                 TRACE("No, Source rectangle doesn't match\n");
3454                 break;
3455             }
3456
3457             /* No stretching may occur */
3458             if(src_rect.right != dst_rect.right - dst_rect.left ||
3459                src_rect.bottom != dst_rect.bottom - dst_rect.top) {
3460                 TRACE("No, stretching is done\n");
3461                 break;
3462             }
3463
3464             /* Destination must be full surface or match the clipping rectangle */
3465             if (dst_surface->clipper && ((IWineD3DClipperImpl *)dst_surface->clipper)->hWnd)
3466             {
3467                 RECT cliprect;
3468                 POINT pos[2];
3469                 GetClientRect(((IWineD3DClipperImpl *)dst_surface->clipper)->hWnd, &cliprect);
3470                 pos[0].x = dst_rect.left;
3471                 pos[0].y = dst_rect.top;
3472                 pos[1].x = dst_rect.right;
3473                 pos[1].y = dst_rect.bottom;
3474                 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *)dst_surface->clipper)->hWnd, pos, 2);
3475
3476                 if(pos[0].x != cliprect.left  || pos[0].y != cliprect.top   ||
3477                    pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
3478                 {
3479                     TRACE("No, dest rectangle doesn't match(clipper)\n");
3480                     TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect));
3481                     TRACE("Blt dest: %s\n", wine_dbgstr_rect(&dst_rect));
3482                     break;
3483                 }
3484             }
3485             else if (dst_rect.left || dst_rect.top
3486                     || dst_rect.right != dst_surface->currentDesc.Width
3487                     || dst_rect.bottom != dst_surface->currentDesc.Height)
3488             {
3489                 TRACE("No, dest rectangle doesn't match(surface size)\n");
3490                 break;
3491             }
3492
3493             TRACE("Yes\n");
3494
3495             /* These flags are unimportant for the flag check, remove them */
3496             if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
3497                 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
3498
3499                 /* The idea behind this is that a glReadPixels and a glDrawPixels call
3500                     * take very long, while a flip is fast.
3501                     * This applies to Half-Life, which does such Blts every time it finished
3502                     * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
3503                     * menu. This is also used by all apps when they do windowed rendering
3504                     *
3505                     * The problem is that flipping is not really the same as copying. After a
3506                     * Blt the front buffer is a copy of the back buffer, and the back buffer is
3507                     * untouched. Therefore it's necessary to override the swap effect
3508                     * and to set it back after the flip.
3509                     *
3510                     * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
3511                     * testcases.
3512                     */
3513
3514                 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
3515                 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3516
3517                 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
3518                 IWineD3DSwapChain_Present((IWineD3DSwapChain *)dstSwapchain,
3519                         NULL, NULL, dstSwapchain->win_handle, NULL, 0);
3520
3521                 dstSwapchain->presentParms.SwapEffect = orig_swap;
3522
3523                 return WINED3D_OK;
3524             }
3525             break;
3526         }
3527
3528         TRACE("Unsupported blit between buffers on the same swapchain\n");
3529         return WINED3DERR_INVALIDCALL;
3530     } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
3531         FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3532         return WINED3DERR_INVALIDCALL;
3533     } else if(dstSwapchain && srcSwapchain) {
3534         FIXME("Implement hardware blit between two different swapchains\n");
3535         return WINED3DERR_INVALIDCALL;
3536     }
3537     else if (dstSwapchain)
3538     {
3539         /* Handled with regular texture -> swapchain blit */
3540         if (src_surface == device->render_targets[0])
3541             TRACE("Blit from active render target to a swapchain\n");
3542     }
3543     else if (srcSwapchain && dst_surface == device->render_targets[0])
3544     {
3545         FIXME("Implement blit from a swapchain to the active render target\n");
3546         return WINED3DERR_INVALIDCALL;
3547     }
3548
3549     if ((srcSwapchain || src_surface == device->render_targets[0]) && !dstSwapchain)
3550     {
3551         /* Blit from render target to texture */
3552         BOOL stretchx;
3553
3554         /* P8 read back is not implemented */
3555         if (src_surface->resource.format_desc->format == WINED3DFMT_P8_UINT
3556                 || dst_surface->resource.format_desc->format == WINED3DFMT_P8_UINT)
3557         {
3558             TRACE("P8 read back not supported by frame buffer to texture blit\n");
3559             return WINED3DERR_INVALIDCALL;
3560         }
3561
3562         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3563             TRACE("Color keying not supported by frame buffer to texture blit\n");
3564             return WINED3DERR_INVALIDCALL;
3565             /* Destination color key is checked above */
3566         }
3567
3568         if(dst_rect.right - dst_rect.left != src_rect.right - src_rect.left) {
3569             stretchx = TRUE;
3570         } else {
3571             stretchx = FALSE;
3572         }
3573
3574         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3575          * flip the image nor scale it.
3576          *
3577          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3578          * -> If the app wants a image width an unscaled width, copy it line per line
3579          * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3580          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3581          *    back buffer. This is slower than reading line per line, thus not used for flipping
3582          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3583          *    pixel by pixel
3584          *
3585          * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3586          * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3587          * backends.
3588          */
3589         if (fbo_blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
3590                 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format_desc,
3591                 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format_desc))
3592         {
3593             stretch_rect_fbo(device, src_surface, &src_rect, dst_surface, &dst_rect, Filter);
3594         }
3595         else if (!stretchx || dst_rect.right - dst_rect.left > src_surface->currentDesc.Width
3596                 || dst_rect.bottom - dst_rect.top > src_surface->currentDesc.Height)
3597         {
3598             TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3599             fb_copy_to_texture_direct(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
3600         } else {
3601             TRACE("Using hardware stretching to flip / stretch the texture\n");
3602             fb_copy_to_texture_hwstretch(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
3603         }
3604
3605         if (!(dst_surface->Flags & SFLAG_DONOTFREE))
3606         {
3607             HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
3608             dst_surface->resource.allocatedMemory = NULL;
3609             dst_surface->resource.heapMemory = NULL;
3610         }
3611         else
3612         {
3613             dst_surface->Flags &= ~SFLAG_INSYSMEM;
3614         }
3615
3616         return WINED3D_OK;
3617     }
3618     else if (src_surface)
3619     {
3620         /* Blit from offscreen surface to render target */
3621         DWORD oldCKeyFlags = src_surface->CKeyFlags;
3622         WINEDDCOLORKEY oldBltCKey = src_surface->SrcBltCKey;
3623         struct wined3d_context *context;
3624
3625         TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3626
3627         if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3628                 && fbo_blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
3629                         &src_rect, src_surface->resource.usage, src_surface->resource.pool,
3630                         src_surface->resource.format_desc,
3631                         &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
3632                         dst_surface->resource.format_desc))
3633         {
3634             TRACE("Using stretch_rect_fbo\n");
3635             /* The source is always a texture, but never the currently active render target, and the texture
3636              * contents are never upside down. */
3637             stretch_rect_fbo(device, src_surface, &src_rect, dst_surface, &dst_rect, Filter);
3638             return WINED3D_OK;
3639         }
3640
3641         if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3642                 && arbfp_blit.blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
3643                         &src_rect, src_surface->resource.usage, src_surface->resource.pool,
3644                         src_surface->resource.format_desc,
3645                         &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
3646                         dst_surface->resource.format_desc))
3647         {
3648             return arbfp_blit_surface(device, src_surface, &src_rect, dst_surface, &dst_rect, BLIT_OP_BLIT, Filter);
3649         }
3650
3651         /* Color keying: Check if we have to do a color keyed blt,
3652          * and if not check if a color key is activated.
3653          *
3654          * Just modify the color keying parameters in the surface and restore them afterwards
3655          * The surface keeps track of the color key last used to load the opengl surface.
3656          * PreLoad will catch the change to the flags and color key and reload if necessary.
3657          */
3658         if(Flags & WINEDDBLT_KEYSRC) {
3659             /* Use color key from surface */
3660         } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
3661             /* Use color key from DDBltFx */
3662             src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3663             src_surface->SrcBltCKey = DDBltFx->ddckSrcColorkey;
3664         } else {
3665             /* Do not use color key */
3666             src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3667         }
3668
3669         /* Now load the surface */
3670         surface_internal_preload(src_surface, SRGB_RGB);
3671
3672         /* Activate the destination context, set it up for blitting */
3673         context = context_acquire(device, dst_surface);
3674         context_apply_blit_state(context, device);
3675
3676         /* The coordinates of the ddraw front buffer are always fullscreen ('screen coordinates',
3677          * while OpenGL coordinates are window relative.
3678          * Also beware of the origin difference(top left vs bottom left).
3679          * Also beware that the front buffer's surface size is screen width x screen height,
3680          * whereas the real gl drawable size is the size of the window.
3681          */
3682         if (dstSwapchain && dst_surface == dstSwapchain->front_buffer)
3683         {
3684             RECT windowsize;
3685             POINT offset = {0,0};
3686             UINT h;
3687             ClientToScreen(context->win_handle, &offset);
3688             GetClientRect(context->win_handle, &windowsize);
3689             h = windowsize.bottom - windowsize.top;
3690             dst_rect.left -= offset.x; dst_rect.right -=offset.x;
3691             dst_rect.top -= offset.y; dst_rect.bottom -=offset.y;
3692             dst_rect.top += dst_surface->currentDesc.Height - h;
3693             dst_rect.bottom += dst_surface->currentDesc.Height - h;
3694         }
3695
3696         if (!device->blitter->blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
3697                 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format_desc,
3698                 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format_desc))
3699         {
3700             FIXME("Unsupported blit operation falling back to software\n");
3701             return WINED3DERR_INVALIDCALL;
3702         }
3703
3704         device->blitter->set_shader((IWineD3DDevice *)device, src_surface);
3705
3706         ENTER_GL();
3707
3708         /* This is for color keying */
3709         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3710             glEnable(GL_ALPHA_TEST);
3711             checkGLcall("glEnable(GL_ALPHA_TEST)");
3712
3713             /* When the primary render target uses P8, the alpha component contains the palette index.
3714              * Which means that the colorkey is one of the palette entries. In other cases pixels that
3715              * should be masked away have alpha set to 0. */
3716             if (primary_render_target_is_p8(device))
3717                 glAlphaFunc(GL_NOTEQUAL, (float)src_surface->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
3718             else
3719                 glAlphaFunc(GL_NOTEQUAL, 0.0f);
3720             checkGLcall("glAlphaFunc");
3721         } else {
3722             glDisable(GL_ALPHA_TEST);
3723             checkGLcall("glDisable(GL_ALPHA_TEST)");
3724         }
3725
3726         /* Draw a textured quad
3727          */
3728         draw_textured_quad(src_surface, &src_rect, &dst_rect, Filter);
3729
3730         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3731             glDisable(GL_ALPHA_TEST);
3732             checkGLcall("glDisable(GL_ALPHA_TEST)");
3733         }
3734
3735         /* Restore the color key parameters */
3736         src_surface->CKeyFlags = oldCKeyFlags;
3737         src_surface->SrcBltCKey = oldBltCKey;
3738
3739         LEAVE_GL();
3740
3741         /* Leave the opengl state valid for blitting */
3742         device->blitter->unset_shader((IWineD3DDevice *)device);
3743
3744         if (wined3d_settings.strict_draw_ordering || (dstSwapchain
3745                 && (dst_surface == dstSwapchain->front_buffer
3746                 || dstSwapchain->num_contexts > 1)))
3747             wglFlush(); /* Flush to ensure ordering across contexts. */
3748
3749         context_release(context);
3750
3751         /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3752         /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3753          * is outdated now
3754          */
3755         IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, TRUE);
3756
3757         return WINED3D_OK;
3758     } else {
3759         /* Source-Less Blit to render target */
3760         if (Flags & WINEDDBLT_COLORFILL) {
3761             DWORD color;
3762
3763             TRACE("Colorfill\n");
3764
3765             /* The color as given in the Blt function is in the format of the frame-buffer...
3766              * 'clear' expect it in ARGB format => we need to do some conversion :-)
3767              */
3768             if (!surface_convert_color_to_argb(dst_surface, DDBltFx->u5.dwFillColor, &color))
3769             {
3770                 /* The color conversion function already prints an error, so need to do it here */
3771                 return WINED3DERR_INVALIDCALL;
3772             }
3773
3774             if (ffp_blit.blit_supported(&device->adapter->gl_info, BLIT_OP_COLOR_FILL,
3775                     NULL, 0, 0, NULL,
3776                     &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
3777                     dst_surface->resource.format_desc))
3778             {
3779                 return ffp_blit.color_fill(device, dst_surface, &dst_rect, color);
3780             }
3781             else if (cpu_blit.blit_supported(&device->adapter->gl_info, BLIT_OP_COLOR_FILL,
3782                     NULL, 0, 0, NULL,
3783                     &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
3784                     dst_surface->resource.format_desc))
3785             {
3786                 return cpu_blit.color_fill(device, dst_surface, &dst_rect, color);
3787             }
3788             return WINED3DERR_INVALIDCALL;
3789         }
3790     }
3791
3792     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3793     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3794     return WINED3DERR_INVALIDCALL;
3795 }
3796
3797 static HRESULT IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, const RECT *DestRect,
3798         IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx)
3799 {
3800     IWineD3DDeviceImpl *device = This->resource.device;
3801     float depth;
3802
3803     if (Flags & WINEDDBLT_DEPTHFILL) {
3804         switch(This->resource.format_desc->format)
3805         {
3806             case WINED3DFMT_D16_UNORM:
3807                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff;
3808                 break;
3809             case WINED3DFMT_S1_UINT_D15_UNORM:
3810                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000fffe;
3811                 break;
3812             case WINED3DFMT_D24_UNORM_S8_UINT:
3813             case WINED3DFMT_X8D24_UNORM:
3814                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff;
3815                 break;
3816             case WINED3DFMT_D32_UNORM:
3817                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff;
3818                 break;
3819             default:
3820                 depth = 0.0f;
3821                 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format_desc->format));
3822         }
3823
3824         return IWineD3DDevice_Clear((IWineD3DDevice *)device, DestRect ? 1 : 0, (const WINED3DRECT *)DestRect,
3825                 WINED3DCLEAR_ZBUFFER, 0x00000000, depth, 0x00000000);
3826     }
3827
3828     FIXME("(%p): Unsupp depthstencil blit\n", This);
3829     return WINED3DERR_INVALIDCALL;
3830 }
3831
3832 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
3833         const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
3834     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3835     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3836     IWineD3DDeviceImpl *device = This->resource.device;
3837
3838     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3839     TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
3840
3841     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
3842     {
3843         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3844         return WINEDDERR_SURFACEBUSY;
3845     }
3846
3847     /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
3848      * except depth blits, which seem to work
3849      */
3850     if (This == device->depth_stencil || (Src && Src == device->depth_stencil))
3851     {
3852         if (device->inScene && !(Flags & WINEDDBLT_DEPTHFILL))
3853         {
3854             TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3855             return WINED3DERR_INVALIDCALL;
3856         } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
3857             TRACE("Z Blit override handled the blit\n");
3858             return WINED3D_OK;
3859         }
3860     }
3861
3862     /* Special cases for RenderTargets */
3863     if ((This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3864             || (Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET)))
3865     {
3866         if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This, DestRect, Src, SrcRect, Flags, DDBltFx, Filter)))
3867             return WINED3D_OK;
3868     }
3869
3870     /* For the rest call the X11 surface implementation.
3871      * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
3872      * other Blts are rather rare
3873      */
3874     return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
3875 }
3876
3877 static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
3878         IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
3879 {
3880     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3881     IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
3882     IWineD3DDeviceImpl *device = This->resource.device;
3883
3884     TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
3885
3886     if ( (This->Flags & SFLAG_LOCKED) || (srcImpl->Flags & SFLAG_LOCKED))
3887     {
3888         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3889         return WINEDDERR_SURFACEBUSY;
3890     }
3891
3892     if (device->inScene && (This == device->depth_stencil || srcImpl == device->depth_stencil))
3893     {
3894         TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3895         return WINED3DERR_INVALIDCALL;
3896     }
3897
3898     /* Special cases for RenderTargets */
3899     if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3900         (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
3901
3902         RECT SrcRect, DstRect;
3903         DWORD Flags=0;
3904
3905         surface_get_rect(srcImpl, rsrc, &SrcRect);
3906
3907         DstRect.left = dstx;
3908         DstRect.top=dsty;
3909         DstRect.right = dstx + SrcRect.right - SrcRect.left;
3910         DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
3911
3912         /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
3913         if(trans & WINEDDBLTFAST_SRCCOLORKEY)
3914             Flags |= WINEDDBLT_KEYSRC;
3915         if(trans & WINEDDBLTFAST_DESTCOLORKEY)
3916             Flags |= WINEDDBLT_KEYDEST;
3917         if(trans & WINEDDBLTFAST_WAIT)
3918             Flags |= WINEDDBLT_WAIT;
3919         if(trans & WINEDDBLTFAST_DONOTWAIT)
3920             Flags |= WINEDDBLT_DONOTWAIT;
3921
3922         if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This,
3923                 &DstRect, srcImpl, &SrcRect, Flags, NULL, WINED3DTEXF_POINT)))
3924             return WINED3D_OK;
3925     }
3926
3927
3928     return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
3929 }
3930
3931 static HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface)
3932 {
3933     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3934     RGBQUAD col[256];
3935     IWineD3DPaletteImpl *pal = This->palette;
3936     unsigned int n;
3937     TRACE("(%p)\n", This);
3938
3939     if (!pal) return WINED3D_OK;
3940
3941     if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
3942             || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
3943     {
3944         if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3945         {
3946             /* Make sure the texture is up to date. This call doesn't do anything if the texture is already up to date. */
3947             IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL);
3948
3949             /* We want to force a palette refresh, so mark the drawable as not being up to date */
3950             IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
3951         } else {
3952             if(!(This->Flags & SFLAG_INSYSMEM)) {
3953                 TRACE("Palette changed with surface that does not have an up to date system memory copy\n");
3954                 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
3955             }
3956             TRACE("Dirtifying surface\n");
3957             IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
3958         }
3959     }
3960
3961     if(This->Flags & SFLAG_DIBSECTION) {
3962         TRACE("(%p): Updating the hdc's palette\n", This);
3963         for (n=0; n<256; n++) {
3964             col[n].rgbRed   = pal->palents[n].peRed;
3965             col[n].rgbGreen = pal->palents[n].peGreen;
3966             col[n].rgbBlue  = pal->palents[n].peBlue;
3967             col[n].rgbReserved = 0;
3968         }
3969         SetDIBColorTable(This->hDC, 0, 256, col);
3970     }
3971
3972     /* Propagate the changes to the drawable when we have a palette. */
3973     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3974         IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, NULL);
3975
3976     return WINED3D_OK;
3977 }
3978
3979 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3980     /** Check against the maximum texture sizes supported by the video card **/
3981     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3982     const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
3983     unsigned int pow2Width, pow2Height;
3984
3985     This->texture_name = 0;
3986     This->texture_target = GL_TEXTURE_2D;
3987
3988     /* Non-power2 support */
3989     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINE_NORMALIZED_TEXRECT])
3990     {
3991         pow2Width = This->currentDesc.Width;
3992         pow2Height = This->currentDesc.Height;
3993     }
3994     else
3995     {
3996         /* Find the nearest pow2 match */
3997         pow2Width = pow2Height = 1;
3998         while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
3999         while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
4000     }
4001     This->pow2Width  = pow2Width;
4002     This->pow2Height = pow2Height;
4003
4004     if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
4005         /** TODO: add support for non power two compressed textures **/
4006         if (This->resource.format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
4007         {
4008             FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
4009                   This, This->currentDesc.Width, This->currentDesc.Height);
4010             return WINED3DERR_NOTAVAILABLE;
4011         }
4012     }
4013
4014     if(pow2Width != This->currentDesc.Width ||
4015        pow2Height != This->currentDesc.Height) {
4016         This->Flags |= SFLAG_NONPOW2;
4017     }
4018
4019     TRACE("%p\n", This);
4020     if ((This->pow2Width > gl_info->limits.texture_size || This->pow2Height > gl_info->limits.texture_size)
4021             && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4022     {
4023         /* one of three options
4024         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)
4025         2: Set the texture to the maximum size (bad idea)
4026         3:    WARN and return WINED3DERR_NOTAVAILABLE;
4027         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.
4028         */
4029         if(This->resource.pool == WINED3DPOOL_DEFAULT || This->resource.pool == WINED3DPOOL_MANAGED)
4030         {
4031             WARN("(%p) Unable to allocate a surface which exceeds the maximum OpenGL texture size\n", This);
4032             return WINED3DERR_NOTAVAILABLE;
4033         }
4034
4035         /* We should never use this surface in combination with OpenGL! */
4036         TRACE("(%p) Creating an oversized surface: %ux%u\n", This, This->pow2Width, This->pow2Height);
4037     }
4038     else
4039     {
4040         /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
4041            is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
4042            doesn't work in combination with ARB_TEXTURE_RECTANGLE.
4043         */
4044         if (This->Flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
4045                 && !(This->resource.format_desc->format == WINED3DFMT_P8_UINT
4046                 && gl_info->supported[EXT_PALETTED_TEXTURE]
4047                 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
4048         {
4049             This->texture_target = GL_TEXTURE_RECTANGLE_ARB;
4050             This->pow2Width  = This->currentDesc.Width;
4051             This->pow2Height = This->currentDesc.Height;
4052             This->Flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
4053         }
4054     }
4055
4056     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
4057         switch(wined3d_settings.offscreen_rendering_mode) {
4058             case ORM_FBO:        This->get_drawable_size = get_drawable_size_fbo;        break;
4059             case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
4060         }
4061     }
4062
4063     This->Flags |= SFLAG_INSYSMEM;
4064
4065     return WINED3D_OK;
4066 }
4067
4068 /* GL locking is done by the caller */
4069 static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
4070         GLuint texture, GLsizei w, GLsizei h, GLenum target)
4071 {
4072     IWineD3DDeviceImpl *device = This->resource.device;
4073     struct blt_info info;
4074     GLint old_binding = 0;
4075
4076     glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
4077
4078     glDisable(GL_CULL_FACE);
4079     glDisable(GL_BLEND);
4080     glDisable(GL_ALPHA_TEST);
4081     glDisable(GL_SCISSOR_TEST);
4082     glDisable(GL_STENCIL_TEST);
4083     glEnable(GL_DEPTH_TEST);
4084     glDepthFunc(GL_ALWAYS);
4085     glDepthMask(GL_TRUE);
4086     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
4087     glViewport(0, 0, w, h);
4088
4089     surface_get_blt_info(target, NULL, w, h, &info);
4090     GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4091     glGetIntegerv(info.binding, &old_binding);
4092     glBindTexture(info.bind_target, texture);
4093
4094     device->shader_backend->shader_select_depth_blt((IWineD3DDevice *)device,
4095             info.tex_type, &This->ds_current_size);
4096
4097     glBegin(GL_TRIANGLE_STRIP);
4098     glTexCoord3fv(info.coords[0]);
4099     glVertex2f(-1.0f, -1.0f);
4100     glTexCoord3fv(info.coords[1]);
4101     glVertex2f(1.0f, -1.0f);
4102     glTexCoord3fv(info.coords[2]);
4103     glVertex2f(-1.0f, 1.0f);
4104     glTexCoord3fv(info.coords[3]);
4105     glVertex2f(1.0f, 1.0f);
4106     glEnd();
4107
4108     glBindTexture(info.bind_target, old_binding);
4109
4110     glPopAttrib();
4111
4112     device->shader_backend->shader_deselect_depth_blt((IWineD3DDevice *)device);
4113 }
4114
4115 void surface_modify_ds_location(IWineD3DSurfaceImpl *surface,
4116         DWORD location, UINT w, UINT h)
4117 {
4118     TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
4119
4120     if (location & ~SFLAG_DS_LOCATIONS)
4121         FIXME("Invalid location (%#x) specified.\n", location);
4122
4123     surface->ds_current_size.cx = w;
4124     surface->ds_current_size.cy = h;
4125     surface->Flags &= ~SFLAG_DS_LOCATIONS;
4126     surface->Flags |= location;
4127 }
4128
4129 /* Context activation is done by the caller. */
4130 void surface_load_ds_location(IWineD3DSurfaceImpl *surface, struct wined3d_context *context, DWORD location)
4131 {
4132     IWineD3DDeviceImpl *device = surface->resource.device;
4133     const struct wined3d_gl_info *gl_info = context->gl_info;
4134
4135     TRACE("surface %p, new location %#x.\n", surface, location);
4136
4137     /* TODO: Make this work for modes other than FBO */
4138     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
4139
4140     if (!(surface->Flags & location))
4141     {
4142         surface->ds_current_size.cx = 0;
4143         surface->ds_current_size.cy = 0;
4144     }
4145
4146     if (surface->ds_current_size.cx == surface->currentDesc.Width
4147             && surface->ds_current_size.cy == surface->currentDesc.Height)
4148     {
4149         TRACE("Location (%#x) is already up to date.\n", location);
4150         return;
4151     }
4152
4153     if (surface->current_renderbuffer)
4154     {
4155         FIXME("Not supported with fixed up depth stencil.\n");
4156         return;
4157     }
4158
4159     if (!(surface->Flags & SFLAG_LOCATIONS))
4160     {
4161         FIXME("No up to date depth stencil location.\n");
4162         surface->Flags |= location;
4163         return;
4164     }
4165
4166     if (location == SFLAG_DS_OFFSCREEN)
4167     {
4168         GLint old_binding = 0;
4169         GLenum bind_target;
4170
4171         TRACE("Copying onscreen depth buffer to depth texture.\n");
4172
4173         ENTER_GL();
4174
4175         if (!device->depth_blt_texture)
4176         {
4177             glGenTextures(1, &device->depth_blt_texture);
4178         }
4179
4180         /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4181          * directly on the FBO texture. That's because we need to flip. */
4182         context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4183         if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
4184         {
4185             glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
4186             bind_target = GL_TEXTURE_RECTANGLE_ARB;
4187         }
4188         else
4189         {
4190             glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
4191             bind_target = GL_TEXTURE_2D;
4192         }
4193         glBindTexture(bind_target, device->depth_blt_texture);
4194         glCopyTexImage2D(bind_target, surface->texture_level, surface->resource.format_desc->glInternal,
4195                 0, 0, surface->currentDesc.Width, surface->currentDesc.Height, 0);
4196         glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4197         glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4198         glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4199         glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4200         glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
4201         glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
4202         glBindTexture(bind_target, old_binding);
4203
4204         /* Setup the destination */
4205         if (!device->depth_blt_rb)
4206         {
4207             gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
4208             checkGLcall("glGenRenderbuffersEXT");
4209         }
4210         if (device->depth_blt_rb_w != surface->currentDesc.Width
4211                 || device->depth_blt_rb_h != surface->currentDesc.Height)
4212         {
4213             gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
4214             checkGLcall("glBindRenderbufferEXT");
4215             gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
4216                     surface->currentDesc.Width, surface->currentDesc.Height);
4217             checkGLcall("glRenderbufferStorageEXT");
4218             device->depth_blt_rb_w = surface->currentDesc.Width;
4219             device->depth_blt_rb_h = surface->currentDesc.Height;
4220         }
4221
4222         context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4223         gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
4224                 GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
4225         checkGLcall("glFramebufferRenderbufferEXT");
4226         context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, surface, FALSE);
4227
4228         /* Do the actual blit */
4229         surface_depth_blt(surface, gl_info, device->depth_blt_texture,
4230                 surface->currentDesc.Width, surface->currentDesc.Height, bind_target);
4231         checkGLcall("depth_blt");
4232
4233         if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4234         else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4235
4236         LEAVE_GL();
4237
4238         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4239     }
4240     else if (location == SFLAG_DS_ONSCREEN)
4241     {
4242         TRACE("Copying depth texture to onscreen depth buffer.\n");
4243
4244         ENTER_GL();
4245
4246         context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4247         surface_depth_blt(surface, gl_info, surface->texture_name,
4248                 surface->currentDesc.Width, surface->currentDesc.Height, surface->texture_target);
4249         checkGLcall("depth_blt");
4250
4251         if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4252
4253         LEAVE_GL();
4254
4255         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4256     }
4257     else
4258     {
4259         ERR("Invalid location (%#x) specified.\n", location);
4260     }
4261
4262     surface->Flags |= location;
4263     surface->ds_current_size.cx = surface->currentDesc.Width;
4264     surface->ds_current_size.cy = surface->currentDesc.Height;
4265 }
4266
4267 static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
4268     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4269     IWineD3DBaseTexture *texture;
4270     IWineD3DSurfaceImpl *overlay;
4271
4272     TRACE("(%p)->(%s, %s)\n", iface, debug_surflocation(flag),
4273           persistent ? "TRUE" : "FALSE");
4274
4275     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4276     {
4277         if (surface_is_offscreen(This))
4278         {
4279             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4280             if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4281         }
4282         else
4283         {
4284             TRACE("Surface %p is an onscreen surface\n", iface);
4285         }
4286     }
4287
4288     if(persistent) {
4289         if(((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) ||
4290            ((This->Flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX))) {
4291             if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4292                 TRACE("Passing to container\n");
4293                 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4294                 IWineD3DBaseTexture_Release(texture);
4295             }
4296         }
4297         This->Flags &= ~SFLAG_LOCATIONS;
4298         This->Flags |= flag;
4299
4300         /* Redraw emulated overlays, if any */
4301         if(flag & SFLAG_INDRAWABLE && !list_empty(&This->overlays)) {
4302             LIST_FOR_EACH_ENTRY(overlay, &This->overlays, IWineD3DSurfaceImpl, overlay_entry) {
4303                 IWineD3DSurface_DrawOverlay((IWineD3DSurface *) overlay);
4304             }
4305         }
4306     } else {
4307         if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))) {
4308             if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4309                 TRACE("Passing to container\n");
4310                 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4311                 IWineD3DBaseTexture_Release(texture);
4312             }
4313         }
4314         This->Flags &= ~flag;
4315     }
4316
4317     if(!(This->Flags & SFLAG_LOCATIONS)) {
4318         ERR("%p: Surface does not have any up to date location\n", This);
4319     }
4320 }
4321
4322 static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT *rect_in)
4323 {
4324     IWineD3DDeviceImpl *device = This->resource.device;
4325     IWineD3DSwapChainImpl *swapchain;
4326     struct wined3d_context *context;
4327     RECT src_rect, dst_rect;
4328
4329     surface_get_rect(This, rect_in, &src_rect);
4330
4331     context = context_acquire(device, This);
4332     context_apply_blit_state(context, device);
4333     if (context->render_offscreen)
4334     {
4335         dst_rect.left = src_rect.left;
4336         dst_rect.right = src_rect.right;
4337         dst_rect.top = src_rect.bottom;
4338         dst_rect.bottom = src_rect.top;
4339     }
4340     else
4341     {
4342         dst_rect = src_rect;
4343     }
4344
4345     device->blitter->set_shader((IWineD3DDevice *) device, This);
4346
4347     ENTER_GL();
4348     draw_textured_quad(This, &src_rect, &dst_rect, WINED3DTEXF_POINT);
4349     LEAVE_GL();
4350
4351     device->blitter->set_shader((IWineD3DDevice *) device, This);
4352
4353     swapchain = (This->Flags & SFLAG_SWAPCHAIN) ? (IWineD3DSwapChainImpl *)This->container : NULL;
4354     if (wined3d_settings.strict_draw_ordering || (swapchain
4355             && (This == swapchain->front_buffer || swapchain->num_contexts > 1)))
4356         wglFlush(); /* Flush to ensure ordering across contexts. */
4357
4358     context_release(context);
4359 }
4360
4361 /*****************************************************************************
4362  * IWineD3DSurface::LoadLocation
4363  *
4364  * Copies the current surface data from wherever it is to the requested
4365  * location. The location is one of the surface flags, SFLAG_INSYSMEM,
4366  * SFLAG_INTEXTURE and SFLAG_INDRAWABLE. When the surface is current in
4367  * multiple locations, the gl texture is preferred over the drawable, which is
4368  * preferred over system memory. The PBO counts as system memory. If rect is
4369  * not NULL, only the specified rectangle is copied (only supported for
4370  * sysmem<->drawable copies at the moment). If rect is NULL, the destination
4371  * location is marked up to date after the copy.
4372  *
4373  * Parameters:
4374  *  flag: Surface location flag to be updated
4375  *  rect: rectangle to be copied
4376  *
4377  * Returns:
4378  *  WINED3D_OK on success
4379  *  WINED3DERR_DEVICELOST on an internal error
4380  *
4381  *****************************************************************************/
4382 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) {
4383     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4384     IWineD3DDeviceImpl *device = This->resource.device;
4385     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4386     struct wined3d_format_desc desc;
4387     CONVERT_TYPES convert;
4388     int width, pitch, outpitch;
4389     BYTE *mem;
4390     BOOL drawable_read_ok = TRUE;
4391     BOOL in_fbo = FALSE;
4392
4393     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4394     {
4395         if (surface_is_offscreen(This))
4396         {
4397             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
4398              * Prefer SFLAG_INTEXTURE. */
4399             if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
4400             drawable_read_ok = FALSE;
4401             in_fbo = TRUE;
4402         }
4403         else
4404         {
4405             TRACE("Surface %p is an onscreen surface\n", iface);
4406         }
4407     }
4408
4409     TRACE("(%p)->(%s, %p)\n", iface, debug_surflocation(flag), rect);
4410     if(rect) {
4411         TRACE("Rectangle: (%d,%d)-(%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom);
4412     }
4413
4414     if(This->Flags & flag) {
4415         TRACE("Location already up to date\n");
4416         return WINED3D_OK;
4417     }
4418
4419     if(!(This->Flags & SFLAG_LOCATIONS)) {
4420         ERR("%p: Surface does not have any up to date location\n", This);
4421         This->Flags |= SFLAG_LOST;
4422         return WINED3DERR_DEVICELOST;
4423     }
4424
4425     if(flag == SFLAG_INSYSMEM) {
4426         surface_prepare_system_memory(This);
4427
4428         /* Download the surface to system memory */
4429         if (This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
4430         {
4431             struct wined3d_context *context = NULL;
4432
4433             if (!device->isInDraw) context = context_acquire(device, NULL);
4434
4435             surface_bind_and_dirtify(This, !(This->Flags & SFLAG_INTEXTURE));
4436             surface_download_data(This, gl_info);
4437
4438             if (context) context_release(context);
4439         }
4440         else
4441         {
4442             /* Note: It might be faster to download into a texture first. */
4443             read_from_framebuffer(This, rect,
4444                                   This->resource.allocatedMemory,
4445                                   IWineD3DSurface_GetPitch(iface));
4446         }
4447     } else if(flag == SFLAG_INDRAWABLE) {
4448         if(This->Flags & SFLAG_INTEXTURE) {
4449             surface_blt_to_drawable(This, rect);
4450         } else {
4451             int byte_count;
4452             if((This->Flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX) {
4453                 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
4454                  * values, otherwise we get incorrect values in the target. For now go the slow way
4455                  * via a system memory copy
4456                  */
4457                 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4458             }
4459
4460             d3dfmt_get_conv(This, FALSE /* We need color keying */, FALSE /* We won't use textures */, &desc, &convert);
4461
4462             /* The width is in 'length' not in bytes */
4463             width = This->currentDesc.Width;
4464             pitch = IWineD3DSurface_GetPitch(iface);
4465
4466             /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4467              * but it isn't set (yet) in all cases it is getting called. */
4468             if ((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO))
4469             {
4470                 struct wined3d_context *context = NULL;
4471
4472                 TRACE("Removing the pbo attached to surface %p\n", This);
4473
4474                 if (!device->isInDraw) context = context_acquire(device, NULL);
4475                 surface_remove_pbo(This, gl_info);
4476                 if (context) context_release(context);
4477             }
4478
4479             if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
4480                 int height = This->currentDesc.Height;
4481                 byte_count = desc.conv_byte_count;
4482
4483                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4484                 outpitch = width * byte_count;
4485                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4486
4487                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4488                 if(!mem) {
4489                     ERR("Out of memory %d, %d!\n", outpitch, height);
4490                     return WINED3DERR_OUTOFVIDEOMEMORY;
4491                 }
4492                 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
4493
4494                 This->Flags |= SFLAG_CONVERTED;
4495             } else {
4496                 This->Flags &= ~SFLAG_CONVERTED;
4497                 mem = This->resource.allocatedMemory;
4498                 byte_count = desc.byte_count;
4499             }
4500
4501             flush_to_framebuffer_drawpixels(This, desc.glFormat, desc.glType, byte_count, mem);
4502
4503             /* Don't delete PBO memory */
4504             if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
4505                 HeapFree(GetProcessHeap(), 0, mem);
4506         }
4507     } else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */ {
4508         if (drawable_read_ok && (This->Flags & SFLAG_INDRAWABLE)) {
4509             read_from_framebuffer_texture(This, flag == SFLAG_INSRGBTEX);
4510         }
4511         else
4512         {
4513             /* Upload from system memory */
4514             BOOL srgb = flag == SFLAG_INSRGBTEX;
4515             struct wined3d_context *context = NULL;
4516
4517             d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */,
4518                     &desc, &convert);
4519
4520             if(srgb) {
4521                 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE) {
4522                     /* Performance warning ... */
4523                     FIXME("%p: Downloading rgb texture to reload it as srgb\n", This);
4524                     IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4525                 }
4526             } else {
4527                 if((This->Flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX) {
4528                     /* Performance warning ... */
4529                     FIXME("%p: Downloading srgb texture to reload it as rgb\n", This);
4530                     IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4531                 }
4532             }
4533             if(!(This->Flags & SFLAG_INSYSMEM)) {
4534                 /* Should not happen */
4535                 ERR("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set\n");
4536                 /* Lets hope we get it from somewhere... */
4537                 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4538             }
4539
4540             if (!device->isInDraw) context = context_acquire(device, NULL);
4541
4542             surface_prepare_texture(This, gl_info, srgb);
4543             surface_bind_and_dirtify(This, srgb);
4544
4545             if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
4546                 This->Flags |= SFLAG_GLCKEY;
4547                 This->glCKey = This->SrcBltCKey;
4548             }
4549             else This->Flags &= ~SFLAG_GLCKEY;
4550
4551             /* The width is in 'length' not in bytes */
4552             width = This->currentDesc.Width;
4553             pitch = IWineD3DSurface_GetPitch(iface);
4554
4555             /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4556              * but it isn't set (yet) in all cases it is getting called. */
4557             if((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO)) {
4558                 TRACE("Removing the pbo attached to surface %p\n", This);
4559                 surface_remove_pbo(This, gl_info);
4560             }
4561
4562             if(desc.convert) {
4563                 /* This code is entered for texture formats which need a fixup. */
4564                 int height = This->currentDesc.Height;
4565
4566                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4567                 outpitch = width * desc.conv_byte_count;
4568                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4569
4570                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4571                 if(!mem) {
4572                     ERR("Out of memory %d, %d!\n", outpitch, height);
4573                     if (context) context_release(context);
4574                     return WINED3DERR_OUTOFVIDEOMEMORY;
4575                 }
4576                 desc.convert(This->resource.allocatedMemory, mem, pitch, width, height);
4577             } else if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
4578                 /* This code is only entered for color keying fixups */
4579                 int height = This->currentDesc.Height;
4580
4581                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4582                 outpitch = width * desc.conv_byte_count;
4583                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4584
4585                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4586                 if(!mem) {
4587                     ERR("Out of memory %d, %d!\n", outpitch, height);
4588                     if (context) context_release(context);
4589                     return WINED3DERR_OUTOFVIDEOMEMORY;
4590                 }
4591                 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
4592             } else {
4593                 mem = This->resource.allocatedMemory;
4594             }
4595
4596             /* Make sure the correct pitch is used */
4597             ENTER_GL();
4598             glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
4599             LEAVE_GL();
4600
4601             if (mem || (This->Flags & SFLAG_PBO))
4602                 surface_upload_data(This, gl_info, &desc, srgb, mem);
4603
4604             /* Restore the default pitch */
4605             ENTER_GL();
4606             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4607             LEAVE_GL();
4608
4609             if (context) context_release(context);
4610
4611             /* Don't delete PBO memory */
4612             if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
4613                 HeapFree(GetProcessHeap(), 0, mem);
4614         }
4615     }
4616
4617     if(rect == NULL) {
4618         This->Flags |= flag;
4619     }
4620
4621     if (in_fbo && (This->Flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE))) {
4622         /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4623         This->Flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4624     }
4625
4626     return WINED3D_OK;
4627 }
4628
4629 static HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container)
4630 {
4631     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4632     IWineD3DSwapChain *swapchain = NULL;
4633
4634     /* Update the drawable size method */
4635     if(container) {
4636         IWineD3DBase_QueryInterface(container, &IID_IWineD3DSwapChain, (void **) &swapchain);
4637     }
4638     if(swapchain) {
4639         This->get_drawable_size = get_drawable_size_swapchain;
4640         IWineD3DSwapChain_Release(swapchain);
4641     } else if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
4642         switch(wined3d_settings.offscreen_rendering_mode) {
4643             case ORM_FBO:        This->get_drawable_size = get_drawable_size_fbo;        break;
4644             case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
4645         }
4646     }
4647
4648     return IWineD3DBaseSurfaceImpl_SetContainer(iface, container);
4649 }
4650
4651 static WINED3DSURFTYPE WINAPI IWineD3DSurfaceImpl_GetImplType(IWineD3DSurface *iface) {
4652     return SURFACE_OPENGL;
4653 }
4654
4655 static HRESULT WINAPI IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
4656     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4657     HRESULT hr;
4658
4659     /* If there's no destination surface there is nothing to do */
4660     if(!This->overlay_dest) return WINED3D_OK;
4661
4662     /* Blt calls ModifyLocation on the dest surface, which in turn calls DrawOverlay to
4663      * update the overlay. Prevent an endless recursion
4664      */
4665     if(This->overlay_dest->Flags & SFLAG_INOVERLAYDRAW) {
4666         return WINED3D_OK;
4667     }
4668     This->overlay_dest->Flags |= SFLAG_INOVERLAYDRAW;
4669     hr = IWineD3DSurfaceImpl_Blt((IWineD3DSurface *) This->overlay_dest, &This->overlay_destrect,
4670                                  iface, &This->overlay_srcrect, WINEDDBLT_WAIT,
4671                                  NULL, WINED3DTEXF_LINEAR);
4672     This->overlay_dest->Flags &= ~SFLAG_INOVERLAYDRAW;
4673
4674     return hr;
4675 }
4676
4677 BOOL surface_is_offscreen(IWineD3DSurfaceImpl *surface)
4678 {
4679     IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *)surface->container;
4680
4681     /* Not on a swapchain - must be offscreen */
4682     if (!(surface->Flags & SFLAG_SWAPCHAIN)) return TRUE;
4683
4684     /* The front buffer is always onscreen */
4685     if (surface == swapchain->front_buffer) return FALSE;
4686
4687     /* If the swapchain is rendered to an FBO, the backbuffer is
4688      * offscreen, otherwise onscreen */
4689     return swapchain->render_to_fbo;
4690 }
4691
4692 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
4693 {
4694     /* IUnknown */
4695     IWineD3DBaseSurfaceImpl_QueryInterface,
4696     IWineD3DBaseSurfaceImpl_AddRef,
4697     IWineD3DSurfaceImpl_Release,
4698     /* IWineD3DResource */
4699     IWineD3DBaseSurfaceImpl_GetParent,
4700     IWineD3DBaseSurfaceImpl_SetPrivateData,
4701     IWineD3DBaseSurfaceImpl_GetPrivateData,
4702     IWineD3DBaseSurfaceImpl_FreePrivateData,
4703     IWineD3DBaseSurfaceImpl_SetPriority,
4704     IWineD3DBaseSurfaceImpl_GetPriority,
4705     IWineD3DSurfaceImpl_PreLoad,
4706     IWineD3DSurfaceImpl_UnLoad,
4707     IWineD3DBaseSurfaceImpl_GetType,
4708     /* IWineD3DSurface */
4709     IWineD3DBaseSurfaceImpl_GetContainer,
4710     IWineD3DBaseSurfaceImpl_GetDesc,
4711     IWineD3DSurfaceImpl_LockRect,
4712     IWineD3DSurfaceImpl_UnlockRect,
4713     IWineD3DSurfaceImpl_GetDC,
4714     IWineD3DSurfaceImpl_ReleaseDC,
4715     IWineD3DSurfaceImpl_Flip,
4716     IWineD3DSurfaceImpl_Blt,
4717     IWineD3DBaseSurfaceImpl_GetBltStatus,
4718     IWineD3DBaseSurfaceImpl_GetFlipStatus,
4719     IWineD3DBaseSurfaceImpl_IsLost,
4720     IWineD3DBaseSurfaceImpl_Restore,
4721     IWineD3DSurfaceImpl_BltFast,
4722     IWineD3DBaseSurfaceImpl_GetPalette,
4723     IWineD3DBaseSurfaceImpl_SetPalette,
4724     IWineD3DSurfaceImpl_RealizePalette,
4725     IWineD3DBaseSurfaceImpl_SetColorKey,
4726     IWineD3DBaseSurfaceImpl_GetPitch,
4727     IWineD3DSurfaceImpl_SetMem,
4728     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
4729     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
4730     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
4731     IWineD3DBaseSurfaceImpl_UpdateOverlay,
4732     IWineD3DBaseSurfaceImpl_SetClipper,
4733     IWineD3DBaseSurfaceImpl_GetClipper,
4734     /* Internal use: */
4735     IWineD3DSurfaceImpl_LoadTexture,
4736     IWineD3DSurfaceImpl_BindTexture,
4737     IWineD3DSurfaceImpl_SaveSnapshot,
4738     IWineD3DSurfaceImpl_SetContainer,
4739     IWineD3DBaseSurfaceImpl_GetData,
4740     IWineD3DSurfaceImpl_SetFormat,
4741     IWineD3DSurfaceImpl_PrivateSetup,
4742     IWineD3DSurfaceImpl_ModifyLocation,
4743     IWineD3DSurfaceImpl_LoadLocation,
4744     IWineD3DSurfaceImpl_GetImplType,
4745     IWineD3DSurfaceImpl_DrawOverlay
4746 };
4747
4748 static HRESULT ffp_blit_alloc(IWineD3DDevice *iface) { return WINED3D_OK; }
4749 /* Context activation is done by the caller. */
4750 static void ffp_blit_free(IWineD3DDevice *iface) { }
4751
4752 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
4753 /* Context activation is done by the caller. */
4754 static void ffp_blit_p8_upload_palette(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
4755 {
4756     BYTE table[256][4];
4757     BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
4758
4759     d3dfmt_p8_init_palette(surface, table, colorkey_active);
4760
4761     TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
4762     ENTER_GL();
4763     GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
4764     LEAVE_GL();
4765 }
4766
4767 /* Context activation is done by the caller. */
4768 static HRESULT ffp_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
4769 {
4770     IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
4771     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4772     enum complex_fixup fixup = get_complex_fixup(surface->resource.format_desc->color_fixup);
4773
4774     /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
4775      * else the surface is converted in software at upload time in LoadLocation.
4776      */
4777     if(fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
4778         ffp_blit_p8_upload_palette(surface, gl_info);
4779
4780     ENTER_GL();
4781     glEnable(surface->texture_target);
4782     checkGLcall("glEnable(surface->texture_target)");
4783     LEAVE_GL();
4784     return WINED3D_OK;
4785 }
4786
4787 /* Context activation is done by the caller. */
4788 static void ffp_blit_unset(IWineD3DDevice *iface)
4789 {
4790     IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
4791     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4792
4793     ENTER_GL();
4794     glDisable(GL_TEXTURE_2D);
4795     checkGLcall("glDisable(GL_TEXTURE_2D)");
4796     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
4797     {
4798         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
4799         checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4800     }
4801     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
4802     {
4803         glDisable(GL_TEXTURE_RECTANGLE_ARB);
4804         checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4805     }
4806     LEAVE_GL();
4807 }
4808
4809 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4810                                const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4811                                const struct wined3d_format_desc *src_format_desc,
4812                                const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4813                                const struct wined3d_format_desc *dst_format_desc)
4814 {
4815     enum complex_fixup src_fixup;
4816
4817     if (blit_op == BLIT_OP_COLOR_FILL)
4818     {
4819         if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
4820         {
4821             TRACE("Color fill not supported\n");
4822             return FALSE;
4823         }
4824
4825         return TRUE;
4826     }
4827
4828     src_fixup = get_complex_fixup(src_format_desc->color_fixup);
4829     if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
4830     {
4831         TRACE("Checking support for fixup:\n");
4832         dump_color_fixup_desc(src_format_desc->color_fixup);
4833     }
4834
4835     if (blit_op != BLIT_OP_BLIT)
4836     {
4837         TRACE("Unsupported blit_op=%d\n", blit_op);
4838         return FALSE;
4839      }
4840
4841     if (!is_identity_fixup(dst_format_desc->color_fixup))
4842     {
4843         TRACE("Destination fixups are not supported\n");
4844         return FALSE;
4845     }
4846
4847     if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
4848     {
4849         TRACE("P8 fixup supported\n");
4850         return TRUE;
4851     }
4852
4853     /* We only support identity conversions. */
4854     if (is_identity_fixup(src_format_desc->color_fixup))
4855     {
4856         TRACE("[OK]\n");
4857         return TRUE;
4858     }
4859
4860     TRACE("[FAILED]\n");
4861     return FALSE;
4862 }
4863
4864 static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
4865 {
4866     return IWineD3DDeviceImpl_ClearSurface(device, dst_surface, 1 /* Number of rectangles */,
4867                                            (const WINED3DRECT*)dst_rect, WINED3DCLEAR_TARGET, fill_color, 0.0f /* Z */, 0 /* Stencil */);
4868 }
4869
4870 const struct blit_shader ffp_blit =  {
4871     ffp_blit_alloc,
4872     ffp_blit_free,
4873     ffp_blit_set,
4874     ffp_blit_unset,
4875     ffp_blit_supported,
4876     ffp_blit_color_fill
4877 };
4878
4879 static HRESULT cpu_blit_alloc(IWineD3DDevice *iface)
4880 {
4881     return WINED3D_OK;
4882 }
4883
4884 /* Context activation is done by the caller. */
4885 static void cpu_blit_free(IWineD3DDevice *iface)
4886 {
4887 }
4888
4889 /* Context activation is done by the caller. */
4890 static HRESULT cpu_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
4891 {
4892     return WINED3D_OK;
4893 }
4894
4895 /* Context activation is done by the caller. */
4896 static void cpu_blit_unset(IWineD3DDevice *iface)
4897 {
4898 }
4899
4900 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4901                                const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4902                                const struct wined3d_format_desc *src_format_desc,
4903                                const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4904                                const struct wined3d_format_desc *dst_format_desc)
4905 {
4906     if (blit_op == BLIT_OP_COLOR_FILL)
4907     {
4908         return TRUE;
4909     }
4910
4911     return FALSE;
4912 }
4913
4914 static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
4915 {
4916     WINEDDBLTFX BltFx;
4917     memset(&BltFx, 0, sizeof(BltFx));
4918     BltFx.dwSize = sizeof(BltFx);
4919     BltFx.u5.dwFillColor = color_convert_argb_to_fmt(fill_color, dst_surface->resource.format_desc->format);
4920     return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
4921 }
4922
4923 const struct blit_shader cpu_blit =  {
4924     cpu_blit_alloc,
4925     cpu_blit_free,
4926     cpu_blit_set,
4927     cpu_blit_unset,
4928     cpu_blit_supported,
4929     cpu_blit_color_fill
4930 };
4931
4932 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4933                                const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4934                                const struct wined3d_format_desc *src_format_desc,
4935                                const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4936                                const struct wined3d_format_desc *dst_format_desc)
4937 {
4938     if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
4939         return FALSE;
4940
4941     /* We only support blitting. Things like color keying / color fill should
4942      * be handled by other blitters.
4943      */
4944     if (blit_op != BLIT_OP_BLIT)
4945         return FALSE;
4946
4947     /* Source and/or destination need to be on the GL side */
4948     if (src_pool == WINED3DPOOL_SYSTEMMEM || dst_pool == WINED3DPOOL_SYSTEMMEM)
4949         return FALSE;
4950
4951     if(!((src_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET))
4952         && ((dst_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
4953         return FALSE;
4954
4955     if (!is_identity_fixup(src_format_desc->color_fixup) ||
4956         !is_identity_fixup(dst_format_desc->color_fixup))
4957         return FALSE;
4958
4959     if (!(src_format_desc->format == dst_format_desc->format
4960         || (is_identity_fixup(src_format_desc->color_fixup)
4961         && is_identity_fixup(dst_format_desc->color_fixup))))
4962         return FALSE;
4963
4964     return TRUE;
4965 }