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