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