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