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