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