wintrust: Add a helper function to initialize chain creation parameters.
[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 Stefan Dösinger for CodeWeavers
11  * Copyright 2007 Henri Verbeet
12  * Copyright 2006-2007 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 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
35
36 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
37
38 static void surface_download_data(IWineD3DSurfaceImpl *This) {
39     if (!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO)) This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, This->resource.size + 4);
40     if (This->resource.format == WINED3DFMT_DXT1 ||
41             This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
42             This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
43         if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */
44             FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
45         } else {
46             TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
47                 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
48
49             GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
50             checkGLcall("glGetCompressedTexImageARB()");
51         }
52     } else {
53         void *mem;
54         int src_pitch = 0;
55         int dst_pitch = 0;
56
57          if(This->Flags & SFLAG_CONVERTED) {
58              FIXME("Read back converted textures unsupported\n");
59              return;
60          }
61
62         if (This->Flags & SFLAG_NONPOW2) {
63             unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
64             src_pitch = This->bytesPerPixel * This->pow2Width;
65             dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
66             src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
67             mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
68         } else {
69             mem = This->resource.allocatedMemory;
70         }
71
72         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
73                 This->glDescription.glFormat, This->glDescription.glType, mem);
74
75         if(This->Flags & SFLAG_PBO) {
76             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
77             checkGLcall("glBindBufferARB");
78
79             glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
80                           This->glDescription.glType, NULL);
81             checkGLcall("glGetTexImage()");
82
83             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
84             checkGLcall("glBindBufferARB");
85         } else {
86             glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
87                           This->glDescription.glType, mem);
88             checkGLcall("glGetTexImage()");
89         }
90
91         if (This->Flags & SFLAG_NONPOW2) {
92             LPBYTE src_data, dst_data;
93             int y;
94             /*
95              * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
96              * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
97              * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
98              *
99              * We're doing this...
100              *
101              * instead of boxing the texture :
102              * |<-texture width ->|  -->pow2width|   /\
103              * |111111111111111111|              |   |
104              * |222 Texture 222222| boxed empty  | texture height
105              * |3333 Data 33333333|              |   |
106              * |444444444444444444|              |   \/
107              * -----------------------------------   |
108              * |     boxed  empty | boxed empty  | pow2height
109              * |                  |              |   \/
110              * -----------------------------------
111              *
112              *
113              * we're repacking the data to the expected texture width
114              *
115              * |<-texture width ->|  -->pow2width|   /\
116              * |111111111111111111222222222222222|   |
117              * |222333333333333333333444444444444| texture height
118              * |444444                           |   |
119              * |                                 |   \/
120              * |                                 |   |
121              * |            empty                | pow2height
122              * |                                 |   \/
123              * -----------------------------------
124              *
125              * == is the same as
126              *
127              * |<-texture width ->|    /\
128              * |111111111111111111|
129              * |222222222222222222|texture height
130              * |333333333333333333|
131              * |444444444444444444|    \/
132              * --------------------
133              *
134              * this also means that any references to allocatedMemory should work with the data as if were a
135              * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
136              *
137              * internally the texture is still stored in a boxed format so any references to textureName will
138              * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
139              *
140              * Performance should not be an issue, because applications normally do not lock the surfaces when
141              * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
142              * and doesn't have to be re-read.
143              */
144             src_data = mem;
145             dst_data = This->resource.allocatedMemory;
146             TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
147             for (y = 1 ; y < This->currentDesc.Height; y++) {
148                 /* skip the first row */
149                 src_data += src_pitch;
150                 dst_data += dst_pitch;
151                 memcpy(dst_data, src_data, dst_pitch);
152             }
153
154             HeapFree(GetProcessHeap(), 0, mem);
155         }
156     }
157     /* Surface has now been downloaded */
158     This->Flags |= SFLAG_INSYSMEM;
159 }
160
161 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
162     if (This->resource.format == WINED3DFMT_DXT1 ||
163             This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
164             This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
165         if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
166             FIXME("Using DXT1/3/5 without advertized support\n");
167         } else {
168             if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
169                 /* Neither NONPOW2, DIBSECTION nor OVERSIZE flags can be set on compressed textures */
170                 This->Flags |= SFLAG_CLIENT;
171             }
172
173             /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver)
174              * glCompressedTexImage2D does not accept NULL pointers. So for compressed textures surface_allocate_surface does nothing, and this
175              * function uses glCompressedTexImage2D instead of the SubImage call
176              */
177             TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
178             ENTER_GL();
179
180             if(This->Flags & SFLAG_PBO) {
181                 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
182                 checkGLcall("glBindBufferARB");
183                 TRACE("(%p) pbo: %#x, data: %p\n", This, This->pbo, data);
184
185                 GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal,
186                         width, height, 0 /* border */, This->resource.size, NULL));
187                 checkGLcall("glCompressedTexSubImage2D");
188
189                 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
190                 checkGLcall("glBindBufferARB");
191             } else {
192                 GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal,
193                         width, height, 0 /* border */, This->resource.size, data));
194                 checkGLcall("glCompressedTexSubImage2D");
195             }
196             LEAVE_GL();
197         }
198     } else {
199         TRACE("(%p) : Calling glTexSubImage2D w %d,  h %d, data, %p\n", This, width, height, data);
200         ENTER_GL();
201
202         if(This->Flags & SFLAG_PBO) {
203             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
204             checkGLcall("glBindBufferARB");
205             TRACE("(%p) pbo: %#x, data: %p\n", This, This->pbo, data);
206
207             glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, NULL);
208             checkGLcall("glTexSubImage2D");
209
210             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
211             checkGLcall("glBindBufferARB");
212         }
213         else {
214             glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
215             checkGLcall("glTexSubImage2D");
216         }
217
218         LEAVE_GL();
219     }
220 }
221
222 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
223     BOOL enable_client_storage = FALSE;
224
225     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", This,
226             This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type);
227
228     if (This->resource.format == WINED3DFMT_DXT1 ||
229             This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
230             This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
231         /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */
232         TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n");
233         return;
234     }
235
236     ENTER_GL();
237
238     if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
239         if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_OVERSIZE | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) {
240             /* In some cases we want to disable client storage.
241              * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
242              * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
243              * SFLAG_OVERSIZE: The gl texture is smaller than the allocated memory
244              * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
245              * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
246              */
247             glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
248             checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
249             This->Flags &= ~SFLAG_CLIENT;
250             enable_client_storage = TRUE;
251         } else {
252             This->Flags |= SFLAG_CLIENT;
253             /* Below point opengl to our allocated texture memory */
254         }
255     }
256     glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type,
257                  This->Flags & SFLAG_CLIENT ? This->resource.allocatedMemory : NULL);
258     checkGLcall("glTexImage2D");
259
260     if(enable_client_storage) {
261         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
262         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
263     }
264     LEAVE_GL();
265
266     This->Flags |= SFLAG_ALLOCATED;
267 }
268
269 /* In D3D the depth stencil dimensions have to be greater than or equal to the
270  * render target dimensions. With FBOs, the dimensions have to be an exact match. */
271 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
272 void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) {
273     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
274     renderbuffer_entry_t *entry;
275     GLuint renderbuffer = 0;
276     unsigned int src_width, src_height;
277
278     src_width = This->pow2Width;
279     src_height = This->pow2Height;
280
281     /* A depth stencil smaller than the render target is not valid */
282     if (width > src_width || height > src_height) return;
283
284     /* Remove any renderbuffer set if the sizes match */
285     if (width == src_width && height == src_height) {
286         This->current_renderbuffer = NULL;
287         return;
288     }
289
290     /* Look if we've already got a renderbuffer of the correct dimensions */
291     LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) {
292         if (entry->width == width && entry->height == height) {
293             renderbuffer = entry->id;
294             This->current_renderbuffer = entry;
295             break;
296         }
297     }
298
299     if (!renderbuffer) {
300         const GlPixelFormatDesc *glDesc;
301         getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
302
303         GL_EXTCALL(glGenRenderbuffersEXT(1, &renderbuffer));
304         GL_EXTCALL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer));
305         GL_EXTCALL(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, glDesc->glFormat, width, height));
306
307         entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
308         entry->width = width;
309         entry->height = height;
310         entry->id = renderbuffer;
311         list_add_head(&This->renderbuffers, &entry->entry);
312
313         This->current_renderbuffer = entry;
314     }
315
316     checkGLcall("set_compatible_renderbuffer");
317 }
318
319 GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchain) {
320     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
321     IWineD3DSwapChainImpl *swapchain_impl = (IWineD3DSwapChainImpl *)swapchain;
322
323     TRACE("(%p) : swapchain %p\n", This, swapchain);
324
325     if (swapchain_impl->backBuffer && swapchain_impl->backBuffer[0] == iface) {
326         TRACE("Returning GL_BACK\n");
327         return GL_BACK;
328     } else if (swapchain_impl->frontBuffer == iface) {
329         TRACE("Returning GL_FRONT\n");
330         return GL_FRONT;
331     }
332
333     FIXME("Higher back buffer, returning GL_BACK\n");
334     return GL_BACK;
335 }
336
337 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
338     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
339     ULONG ref = InterlockedDecrement(&This->resource.ref);
340     TRACE("(%p) : Releasing from %d\n", This, ref + 1);
341     if (ref == 0) {
342         IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
343         renderbuffer_entry_t *entry, *entry2;
344         TRACE("(%p) : cleaning up\n", This);
345
346         if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
347
348             /* Need a context to destroy the texture. Use the currently active render target, but only if
349              * the primary render target exists. Otherwise lastActiveRenderTarget is garbage, see above.
350              * When destroying the primary rt, Uninit3D will activate a context before doing anything
351              */
352             if(device->render_targets && device->render_targets[0]) {
353                 ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
354             }
355
356             TRACE("Deleting texture %d\n", This->glDescription.textureName);
357             ENTER_GL();
358             glDeleteTextures(1, &This->glDescription.textureName);
359             LEAVE_GL();
360         }
361
362         if(This->Flags & SFLAG_PBO) {
363             /* Delete the PBO */
364             GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
365         }
366
367         if(This->Flags & SFLAG_DIBSECTION) {
368             /* Release the DC */
369             SelectObject(This->hDC, This->dib.holdbitmap);
370             DeleteDC(This->hDC);
371             /* Release the DIB section */
372             DeleteObject(This->dib.DIBsection);
373             This->dib.bitmap_data = NULL;
374             This->resource.allocatedMemory = NULL;
375         }
376         if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
377
378         HeapFree(GetProcessHeap(), 0, This->palette9);
379
380         IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
381         if(iface == device->ddraw_primary)
382             device->ddraw_primary = NULL;
383
384         LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
385             GL_EXTCALL(glDeleteRenderbuffersEXT(1, &entry->id));
386             HeapFree(GetProcessHeap(), 0, entry);
387         }
388
389         TRACE("(%p) Released\n", This);
390         HeapFree(GetProcessHeap(), 0, This);
391
392     }
393     return ref;
394 }
395
396 /* ****************************************************
397    IWineD3DSurface IWineD3DResource parts follow
398    **************************************************** */
399
400 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
401     /* TODO: check for locks */
402     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
403     IWineD3DBaseTexture *baseTexture = NULL;
404     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
405
406     TRACE("(%p)Checking to see if the container is a base texture\n", This);
407     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
408         TRACE("Passing to container\n");
409         IWineD3DBaseTexture_PreLoad(baseTexture);
410         IWineD3DBaseTexture_Release(baseTexture);
411     } else {
412     TRACE("(%p) : About to load surface\n", This);
413
414     if(!device->isInDraw) {
415         ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
416     }
417
418     ENTER_GL();
419     glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
420     if (!This->glDescription.level) {
421         if (!This->glDescription.textureName) {
422             glGenTextures(1, &This->glDescription.textureName);
423             checkGLcall("glGenTextures");
424             TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
425         }
426         glBindTexture(This->glDescription.target, This->glDescription.textureName);
427         checkGLcall("glBindTexture");
428         IWineD3DSurface_LoadTexture(iface, FALSE);
429         /* This is where we should be reducing the amount of GLMemoryUsed */
430     } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
431         /* assume this is a coding error not a real error for now */
432         FIXME("Mipmap surface has a glTexture bound to it!\n");
433     }
434     if (This->resource.pool == WINED3DPOOL_DEFAULT) {
435        /* Tell opengl to try and keep this texture in video ram (well mostly) */
436        GLclampf tmp;
437        tmp = 0.9f;
438         glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
439     }
440     LEAVE_GL();
441     }
442     return;
443 }
444
445 /* ******************************************************
446    IWineD3DSurface IWineD3DSurface parts follow
447    ****************************************************** */
448
449 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
450     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
451     TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
452     if (This->glDescription.textureName == 0 && textureName != 0) {
453         This->Flags &= ~SFLAG_INTEXTURE;
454         IWineD3DSurface_AddDirtyRect(iface, NULL);
455     }
456     This->glDescription.textureName = textureName;
457     This->glDescription.target      = target;
458     This->Flags &= ~SFLAG_ALLOCATED;
459 }
460
461 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
462     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
463     TRACE("(%p) : returning %p\n", This, &This->glDescription);
464     *glDescription = &This->glDescription;
465 }
466
467 /* TODO: think about moving this down to resource? */
468 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
469     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
470     /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the future  */
471     if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
472         FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
473     }
474     return (CONST void*)(This->resource.allocatedMemory);
475 }
476
477 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch, BOOL srcUpsideDown) {
478     BYTE *mem;
479     GLint fmt;
480     GLint type;
481     BYTE *row, *top, *bottom;
482     int i;
483     BOOL bpp;
484
485     switch(This->resource.format)
486     {
487         case WINED3DFMT_P8:
488         {
489             /* GL can't return palettized data, so read ARGB pixels into a
490              * separate block of memory and convert them into palettized format
491              * in software. Slow, but if the app means to use palettized render
492              * targets and locks it...
493              *
494              * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
495              * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
496              * for the color channels when palettizing the colors.
497              */
498             fmt = GL_RGB;
499             type = GL_UNSIGNED_BYTE;
500             pitch *= 3;
501             mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
502             if(!mem) {
503                 ERR("Out of memory\n");
504                 return;
505             }
506             bpp = This->bytesPerPixel * 3;
507         }
508         break;
509
510         default:
511             mem = dest;
512             fmt = This->glDescription.glFormat;
513             type = This->glDescription.glType;
514             bpp = This->bytesPerPixel;
515     }
516
517     if(This->Flags & SFLAG_PBO) {
518         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
519         checkGLcall("glBindBufferARB");
520     }
521
522     glReadPixels(rect->left, rect->top,
523                  rect->right - rect->left,
524                  rect->bottom - rect->top,
525                  fmt, type, mem);
526     vcheckGLcall("glReadPixels");
527
528     if(This->Flags & SFLAG_PBO) {
529         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
530         checkGLcall("glBindBufferARB");
531
532         /* Check if we need to flip the image. If we need to flip use glMapBufferARB
533          * to get a pointer to it and perform the flipping in software. This is a lot
534          * faster than calling glReadPixels for each line. In case we want more speed
535          * we should rerender it flipped in a FBO and read the data back from the FBO. */
536         if(!srcUpsideDown) {
537             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
538             checkGLcall("glBindBufferARB");
539
540             mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
541             checkGLcall("glMapBufferARB");
542         }
543     }
544
545     /* TODO: Merge this with the palettization loop below for P8 targets */
546     if(!srcUpsideDown) {
547         UINT len, off;
548         /* glReadPixels returns the image upside down, and there is no way to prevent this.
549             Flip the lines in software */
550         len = (rect->right - rect->left) * bpp;
551         off = rect->left * bpp;
552
553         row = HeapAlloc(GetProcessHeap(), 0, len);
554         if(!row) {
555             ERR("Out of memory\n");
556             if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem);
557             return;
558         }
559
560         top = mem + pitch * rect->top;
561         bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
562         for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
563             memcpy(row, top + off, len);
564             memcpy(top + off, bottom + off, len);
565             memcpy(bottom + off, row, len);
566             top += pitch;
567             bottom -= pitch;
568         }
569         HeapFree(GetProcessHeap(), 0, row);
570
571         /* Unmap the temp PBO buffer */
572         if(This->Flags & SFLAG_PBO) {
573             GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
574             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
575         }
576     }
577
578     if(This->resource.format == WINED3DFMT_P8) {
579         PALETTEENTRY *pal;
580         DWORD width = pitch / 3;
581         int x, y, c;
582         if(This->palette) {
583             pal = This->palette->palents;
584         } else {
585             pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
586         }
587
588         for(y = rect->top; y < rect->bottom; y++) {
589             for(x = rect->left; x < rect->right; x++) {
590                 /*                      start              lines            pixels      */
591                 BYTE *blue =  (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
592                 BYTE *green = blue  + 1;
593                 BYTE *red =   green + 1;
594
595                 for(c = 0; c < 256; c++) {
596                     if(*red   == pal[c].peRed   &&
597                        *green == pal[c].peGreen &&
598                        *blue  == pal[c].peBlue)
599                     {
600                         *((BYTE *) dest + y * width + x) = c;
601                         break;
602                     }
603                 }
604             }
605         }
606         HeapFree(GetProcessHeap(), 0, mem);
607     }
608 }
609
610 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
611     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
612     IWineD3DDeviceImpl  *myDevice = This->resource.wineD3DDevice;
613     IWineD3DSwapChainImpl *swapchain = NULL;
614
615     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
616
617     if (This->Flags & SFLAG_LOCKED) {
618         WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
619         return WINED3DERR_INVALIDCALL;
620     }
621     if (!(This->Flags & SFLAG_LOCKABLE)) {
622         /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
623               texture regions, and since the destination is an unlockable region we need
624               to tolerate this                                                           */
625         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
626         /*return WINED3DERR_INVALIDCALL; */
627     }
628
629     pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
630
631     /* Mark the surface locked */
632     This->Flags |= SFLAG_LOCKED;
633
634     /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
635      * or a pbo to map
636      */
637     if(!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO)) {
638         This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + 4);
639         This->Flags &= ~SFLAG_INSYSMEM; /* This is the marker that surface data has to be downloaded */
640     }
641
642     /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
643      * Also don't create a PBO for systemmem surfaces. */
644     if(GL_SUPPORT(ARB_PIXEL_BUFFER_OBJECT) && (This->Flags & SFLAG_DYNLOCK) && !(This->Flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2)) && (This->resource.pool != WINED3DPOOL_SYSTEMMEM)) {
645         GLenum error;
646         ENTER_GL();
647
648         GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
649         error = glGetError();
650         if(This->pbo == 0 || error != GL_NO_ERROR) {
651             ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
652         }
653
654         TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
655
656         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
657         checkGLcall("glBindBufferARB");
658
659         GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
660         checkGLcall("glBufferDataARB");
661
662         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
663         checkGLcall("glBindBufferARB");
664
665         /* We don't need the system memory anymore and we can't even use it for PBOs */
666         HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
667         This->resource.allocatedMemory = NULL;
668         This->Flags |= SFLAG_PBO;
669         LEAVE_GL();
670     }
671
672     /* Calculate the correct start address to report */
673     if (NULL == pRect) {
674         This->lockedRect.left   = 0;
675         This->lockedRect.top    = 0;
676         This->lockedRect.right  = This->currentDesc.Width;
677         This->lockedRect.bottom = This->currentDesc.Height;
678         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
679     } else {
680         This->lockedRect.left   = pRect->left;
681         This->lockedRect.top    = pRect->top;
682         This->lockedRect.right  = pRect->right;
683         This->lockedRect.bottom = pRect->bottom;
684         TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
685     }
686
687     if (This->Flags & SFLAG_NONPOW2) {
688         TRACE("Locking non-power 2 texture\n");
689     }
690
691     /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
692      * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
693      * changed
694      */
695     if(!(This->Flags & SFLAG_DYNLOCK)) {
696         This->lockCount++;
697         /* MAXLOCKCOUNT is defined in wined3d_private.h */
698         if(This->lockCount > MAXLOCKCOUNT) {
699             TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
700             This->Flags |= SFLAG_DYNLOCK;
701         }
702     }
703
704     if (Flags & WINED3DLOCK_DISCARD) {
705         /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
706         TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
707         This->Flags |= SFLAG_INSYSMEM;
708     }
709
710     if (This->Flags & SFLAG_INSYSMEM) {
711         TRACE("Local copy is up to date, not downloading data\n");
712         goto lock_end;
713     }
714
715     /* Now download the surface content from opengl
716      * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
717      * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
718      */
719     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
720     if(swapchain || iface == myDevice->render_targets[0]) {
721         BOOL srcIsUpsideDown;
722
723         if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
724             static BOOL warned = FALSE;
725             if(!warned) {
726                 ERR("The application tries to lock the render target, but render target locking is disabled\n");
727                 warned = TRUE;
728             }
729             if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
730             return WINED3D_OK;
731         }
732
733         /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
734          * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
735          * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
736          * context->last_was_blit set on the unlock.
737          */
738         ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
739         ENTER_GL();
740
741         /* Select the correct read buffer, and give some debug output.
742          * There is no need to keep track of the current read buffer or reset it, every part of the code
743          * that reads sets the read buffer as desired.
744          */
745         if(!swapchain) {
746             /* Locking the primary render target which is not on a swapchain(=offscreen render target).
747              * Read from the back buffer
748              */
749             TRACE("Locking offscreen render target\n");
750             glReadBuffer(myDevice->offscreenBuffer);
751             srcIsUpsideDown = TRUE;
752         } else {
753             GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain);
754             TRACE("Locking %#x buffer\n", buffer);
755             glReadBuffer(buffer);
756             checkGLcall("glReadBuffer");
757
758             IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
759             srcIsUpsideDown = FALSE;
760         }
761
762         switch(wined3d_settings.rendertargetlock_mode) {
763             case RTL_AUTO:
764             case RTL_READDRAW:
765             case RTL_READTEX:
766                 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
767                 break;
768
769             case RTL_TEXDRAW:
770             case RTL_TEXTEX:
771                 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
772                 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
773                 break;
774         }
775
776         LEAVE_GL();
777
778         /* Mark the local copy up to date if a full download was done */
779         if(This->lockedRect.left == 0 &&
780            This->lockedRect.top == 0 &&
781            This->lockedRect.right == This->currentDesc.Width &&
782            This->lockedRect.bottom == This->currentDesc.Height) {
783             This->Flags |= SFLAG_INSYSMEM;
784         }
785     } else if(iface == myDevice->stencilBufferTarget) {
786         /** the depth stencil in openGL has a format of GL_FLOAT
787          * which should be good for WINED3DFMT_D16_LOCKABLE
788          * and WINED3DFMT_D16
789          * it is unclear what format the stencil buffer is in except.
790          * 'Each index is converted to fixed point...
791          * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
792          * mappings in the table GL_PIXEL_MAP_S_TO_S.
793          * glReadPixels(This->lockedRect.left,
794          *             This->lockedRect.bottom - j - 1,
795          *             This->lockedRect.right - This->lockedRect.left,
796          *             1,
797          *             GL_DEPTH_COMPONENT,
798          *             type,
799          *             (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
800          *
801          * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
802          * gl texture(next path), or in local memory(early return because of set SFLAG_INSYSMEM above). If
803          * none of that is the case the problem is not in this function :-)
804          ********************************************/
805         FIXME("Depth stencil locking not supported yet\n");
806     } else {
807         /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
808         TRACE("locking an ordinary surface\n");
809
810         if (0 != This->glDescription.textureName) {
811             /* Now I have to copy thing bits back */
812
813             if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
814                 ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
815             }
816
817             ENTER_GL();
818             /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
819             if (GL_SUPPORT(ARB_MULTITEXTURE)) {
820                 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
821                 checkGLcall("glActiveTextureARB");
822             }
823             IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
824             IWineD3DSurface_PreLoad(iface);
825
826             surface_download_data(This);
827             LEAVE_GL();
828         }
829     }
830
831 lock_end:
832     if(This->Flags & SFLAG_PBO) {
833         ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
834         ENTER_GL();
835         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
836         checkGLcall("glBindBufferARB");
837
838         /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
839         if(This->resource.allocatedMemory) {
840             ERR("The surface already has PBO memory allocated!\n");
841         }
842
843         This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
844         checkGLcall("glMapBufferARB");
845
846         /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
847         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
848         checkGLcall("glBindBufferARB");
849
850         LEAVE_GL();
851     }
852
853     /* Calculate the correct start address to report */
854     if (NULL == pRect) {
855         pLockedRect->pBits = This->resource.allocatedMemory;
856     } else {
857         /* DXTn textures are based on compressed blocks of 4x4 pixels, each
858          * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
859          * slightly different meaning compared to regular textures. For DXTn
860          * textures Pitch is the size of a row of blocks, 4 high and "width"
861          * long. The x offset is calculated differently as well, since moving 4
862          * pixels to the right actually moves an entire 4x4 block to right, ie
863          * 16 bytes (8 in case of DXT1). */
864         if (This->resource.format == WINED3DFMT_DXT1) {
865             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
866         } else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3
867                 || This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
868             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
869         } else {
870             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
871         }
872     }
873
874     if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
875         /* Don't dirtify */
876     } else {
877         IWineD3DBaseTexture *pBaseTexture;
878         /**
879          * Dirtify on lock
880          * as seen in msdn docs
881          */
882         IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
883
884         /** Dirtify Container if needed */
885         if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
886             TRACE("Making container dirty\n");
887             IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
888             IWineD3DBaseTexture_Release(pBaseTexture);
889         } else {
890             TRACE("Surface is standalone, no need to dirty the container\n");
891         }
892     }
893
894     TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch,
895           This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
896     return WINED3D_OK;
897 }
898
899 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
900     GLint  prev_store;
901     GLint  prev_rasterpos[4];
902     GLint skipBytes = 0;
903     BOOL storechanged = FALSE, memory_allocated = FALSE;
904     GLint fmt, type;
905     BYTE *mem;
906     UINT bpp;
907     UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);    /* target is argb, 4 byte */
908
909     glDisable(GL_TEXTURE_2D);
910     vcheckGLcall("glDisable(GL_TEXTURE_2D)");
911
912     glFlush();
913     vcheckGLcall("glFlush");
914     glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
915     vcheckGLcall("glIntegerv");
916     glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
917     vcheckGLcall("glIntegerv");
918     glPixelZoom(1.0, -1.0);
919     vcheckGLcall("glPixelZoom");
920
921     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
922     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
923     glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
924
925     glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
926     vcheckGLcall("glRasterPos2f");
927
928     /* Some drivers(radeon dri, others?) don't like exceptions during
929      * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
930      * after ReleaseDC. Reading it will cause an exception, which x11drv will
931      * catch to put the dib section in InSync mode, which leads to a crash
932      * and a blocked x server on my radeon card.
933      *
934      * The following lines read the dib section so it is put in inSync mode
935      * before glDrawPixels is called and the crash is prevented. There won't
936      * be any interfering gdi accesses, because UnlockRect is called from
937      * ReleaseDC, and the app won't use the dc any more afterwards.
938      */
939     if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) {
940         volatile BYTE read;
941         read = This->resource.allocatedMemory[0];
942     }
943
944     switch (This->resource.format) {
945         /* No special care needed */
946         case WINED3DFMT_A4R4G4B4:
947         case WINED3DFMT_R5G6B5:
948         case WINED3DFMT_A1R5G5B5:
949         case WINED3DFMT_R8G8B8:
950             type = This->glDescription.glType;
951             fmt = This->glDescription.glFormat;
952             mem = This->resource.allocatedMemory;
953             bpp = This->bytesPerPixel;
954             break;
955
956         case WINED3DFMT_X4R4G4B4:
957         {
958             int size;
959             unsigned short *data;
960             data = (unsigned short *)This->resource.allocatedMemory;
961             size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
962             while(size > 0) {
963                 *data |= 0xF000;
964                 data++;
965                 size--;
966             }
967             type = This->glDescription.glType;
968             fmt = This->glDescription.glFormat;
969             mem = This->resource.allocatedMemory;
970             bpp = This->bytesPerPixel;
971         }
972         break;
973
974         case WINED3DFMT_X1R5G5B5:
975         {
976             int size;
977             unsigned short *data;
978             data = (unsigned short *)This->resource.allocatedMemory;
979             size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
980             while(size > 0) {
981                 *data |= 0x8000;
982                 data++;
983                 size--;
984             }
985             type = This->glDescription.glType;
986             fmt = This->glDescription.glFormat;
987             mem = This->resource.allocatedMemory;
988             bpp = This->bytesPerPixel;
989         }
990         break;
991
992         case WINED3DFMT_X8R8G8B8:
993         {
994             /* make sure the X byte is set to alpha on, since it 
995                could be any random value. This fixes the intro movie in Pirates! */
996             int size;
997             unsigned int *data;
998             data = (unsigned int *)This->resource.allocatedMemory;
999             size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
1000             while(size > 0) {
1001                 *data |= 0xFF000000;
1002                 data++;
1003                 size--;
1004             }
1005         }
1006         /* Fall through */
1007
1008         case WINED3DFMT_A8R8G8B8:
1009         {
1010             glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
1011             vcheckGLcall("glPixelStorei");
1012             storechanged = TRUE;
1013             type = This->glDescription.glType;
1014             fmt = This->glDescription.glFormat;
1015             mem = This->resource.allocatedMemory;
1016             bpp = This->bytesPerPixel;
1017         }
1018         break;
1019
1020         case WINED3DFMT_A2R10G10B10:
1021         {
1022             glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
1023             vcheckGLcall("glPixelStorei");
1024             storechanged = TRUE;
1025             type = This->glDescription.glType;
1026             fmt = This->glDescription.glFormat;
1027             mem = This->resource.allocatedMemory;
1028             bpp = This->bytesPerPixel;
1029         }
1030         break;
1031
1032         case WINED3DFMT_P8:
1033         {
1034             int height = This->glRect.bottom - This->glRect.top;
1035             type = GL_UNSIGNED_BYTE;
1036             fmt = GL_RGBA;
1037
1038             mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
1039             if(!mem) {
1040                 ERR("Out of memory\n");
1041                 return;
1042             }
1043             memory_allocated = TRUE;
1044             d3dfmt_convert_surface(This->resource.allocatedMemory,
1045                                    mem,
1046                                    pitch,
1047                                    pitch,
1048                                    height,
1049                                    pitch * 4,
1050                                    CONVERT_PALETTED,
1051                                    This);
1052             bpp = This->bytesPerPixel * 4;
1053             pitch *= 4;
1054         }
1055         break;
1056
1057         default:
1058             FIXME("Unsupported Format %u in locking func\n", This->resource.format);
1059
1060             /* Give it a try */
1061             type = This->glDescription.glType;
1062             fmt = This->glDescription.glFormat;
1063             mem = This->resource.allocatedMemory;
1064             bpp = This->bytesPerPixel;
1065     }
1066
1067     if(This->Flags & SFLAG_PBO) {
1068         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1069         checkGLcall("glBindBufferARB");
1070     }
1071
1072     glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1073                  (This->lockedRect.bottom - This->lockedRect.top)-1,
1074                  fmt, type,
1075                  mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1076     checkGLcall("glDrawPixels");
1077
1078     if(This->Flags & SFLAG_PBO) {
1079         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1080         checkGLcall("glBindBufferARB");
1081     }
1082
1083     glPixelZoom(1.0,1.0);
1084     vcheckGLcall("glPixelZoom");
1085
1086     glRasterPos3iv(&prev_rasterpos[0]);
1087     vcheckGLcall("glRasterPos3iv");
1088
1089     /* Reset to previous pack row length */
1090     glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1091     vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1092     if(storechanged) {
1093         glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1094         vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1095     }
1096
1097     /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
1098      * turn it on again
1099      */
1100     glEnable(GL_TEXTURE_2D);
1101     checkGLcall("glEnable(GL_TEXTURE_2D)");
1102
1103     if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
1104     return;
1105 }
1106
1107 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
1108     float glTexCoord[4];
1109
1110     glTexCoord[0] = (float) This->lockedRect.left   / (float) This->pow2Width; /* left */
1111     glTexCoord[1] = (float) This->lockedRect.right  / (float) This->pow2Width; /* right */
1112     glTexCoord[2] = (float) This->lockedRect.top    / (float) This->pow2Height; /* top */
1113     glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
1114
1115     IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
1116
1117     ENTER_GL();
1118
1119     glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1120     checkGLcall("glEnable glBindTexture");
1121
1122     /* No filtering for blts */
1123     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1124     checkGLcall("glTexParameteri");
1125     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1126     checkGLcall("glTexParameteri");
1127
1128     /* Start drawing a quad */
1129     glBegin(GL_QUADS);
1130
1131     glColor3d(1.0f, 1.0f, 1.0f);
1132     glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1133     glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
1134
1135     glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1136     glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1137
1138     glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1139     glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1140
1141     glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1142     glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1143
1144     glEnd();
1145     checkGLcall("glEnd");
1146
1147     /* Unbind the texture */
1148     glBindTexture(GL_TEXTURE_2D, 0);
1149     checkGLcall("glEnable glBindTexture");
1150
1151     LEAVE_GL();
1152 }
1153
1154 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1155     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1156     IWineD3DDeviceImpl  *myDevice = This->resource.wineD3DDevice;
1157     IWineD3DSwapChainImpl *swapchain = NULL;
1158
1159     if (!(This->Flags & SFLAG_LOCKED)) {
1160         WARN("trying to Unlock an unlocked surf@%p\n", This);
1161         return WINED3DERR_INVALIDCALL;
1162     }
1163
1164     if (This->Flags & SFLAG_PBO) {
1165         TRACE("Freeing PBO memory\n");
1166         ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1167         ENTER_GL();
1168         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1169         GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1170         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1171         checkGLcall("glUnmapBufferARB");
1172         LEAVE_GL();
1173         This->resource.allocatedMemory = NULL;
1174     }
1175
1176     TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1177
1178     if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1179         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1180         goto unlock_end;
1181     }
1182
1183     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1184     if(swapchain || (myDevice->render_targets && iface == myDevice->render_targets[0])) {
1185         if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1186             static BOOL warned = FALSE;
1187             if(!warned) {
1188                 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1189                 warned = TRUE;
1190             }
1191             if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1192             goto unlock_end;
1193         }
1194
1195         /* Activate the correct context for the render target */
1196         ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1197         ENTER_GL();
1198
1199         if(!swapchain) {
1200             /* Primary offscreen render target */
1201             TRACE("Offscreen render target\n");
1202             glDrawBuffer(myDevice->offscreenBuffer);
1203             checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1204         } else {
1205             GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain);
1206             TRACE("Unlocking %#x buffer\n", buffer);
1207             glDrawBuffer(buffer);
1208             checkGLcall("glDrawBuffer");
1209
1210             IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1211         }
1212
1213         switch(wined3d_settings.rendertargetlock_mode) {
1214             case RTL_AUTO:
1215             case RTL_READDRAW:
1216             case RTL_TEXDRAW:
1217                 flush_to_framebuffer_drawpixels(This);
1218                 break;
1219
1220             case RTL_READTEX:
1221             case RTL_TEXTEX:
1222                 flush_to_framebuffer_texture(This);
1223                 break;
1224         }
1225         if(!swapchain) {
1226             glDrawBuffer(myDevice->offscreenBuffer);
1227             checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1228         } else if(swapchain->backBuffer) {
1229             glDrawBuffer(GL_BACK);
1230             checkGLcall("glDrawBuffer(GL_BACK)");
1231         } else {
1232             glDrawBuffer(GL_FRONT);
1233             checkGLcall("glDrawBuffer(GL_FRONT)");
1234         }
1235         LEAVE_GL();
1236
1237         This->dirtyRect.left   = This->currentDesc.Width;
1238         This->dirtyRect.top    = This->currentDesc.Height;
1239         This->dirtyRect.right  = 0;
1240         This->dirtyRect.bottom = 0;
1241         This->Flags |= SFLAG_INDRAWABLE;
1242     } else if(iface == myDevice->stencilBufferTarget) {
1243         FIXME("Depth Stencil buffer locking is not implemented\n");
1244     } else {
1245         /* The rest should be a normal texture */
1246         IWineD3DBaseTextureImpl *impl;
1247         /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1248          * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1249          * states need resetting
1250          */
1251         if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1252             if(impl->baseTexture.bindCount) {
1253                 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1254             }
1255             IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1256         }
1257     }
1258
1259     unlock_end:
1260     This->Flags &= ~SFLAG_LOCKED;
1261     memset(&This->lockedRect, 0, sizeof(RECT));
1262     return WINED3D_OK;
1263 }
1264
1265 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1266     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1267     WINED3DLOCKED_RECT lock;
1268     HRESULT hr;
1269     RGBQUAD col[256];
1270
1271     TRACE("(%p)->(%p)\n",This,pHDC);
1272
1273     if(This->Flags & SFLAG_USERPTR) {
1274         ERR("Not supported on surfaces with an application-provided surfaces\n");
1275         return WINEDDERR_NODC;
1276     }
1277
1278     /* Give more detailed info for ddraw */
1279     if (This->Flags & SFLAG_DCINUSE)
1280         return WINEDDERR_DCALREADYCREATED;
1281
1282     /* Can't GetDC if the surface is locked */
1283     if (This->Flags & SFLAG_LOCKED)
1284         return WINED3DERR_INVALIDCALL;
1285
1286     memset(&lock, 0, sizeof(lock)); /* To be sure */
1287
1288     /* Create a DIB section if there isn't a hdc yet */
1289     if(!This->hDC) {
1290         IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
1291         if(This->Flags & SFLAG_CLIENT) {
1292             IWineD3DSurface_PreLoad(iface);
1293         }
1294
1295         /* Use the dib section from now on if we are not using a PBO */
1296         if(!(This->Flags & SFLAG_PBO))
1297             This->resource.allocatedMemory = This->dib.bitmap_data;
1298     }
1299
1300     /* Lock the surface */
1301     hr = IWineD3DSurface_LockRect(iface,
1302                                   &lock,
1303                                   NULL,
1304                                   0);
1305
1306     if(This->Flags & SFLAG_PBO) {
1307         /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
1308         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
1309     }
1310
1311     if(FAILED(hr)) {
1312         ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1313         /* keep the dib section */
1314         return hr;
1315     }
1316
1317     if(This->resource.format == WINED3DFMT_P8 ||
1318         This->resource.format == WINED3DFMT_A8P8) {
1319         unsigned int n;
1320         if(This->palette) {
1321             PALETTEENTRY ent[256];
1322
1323             GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1324             for (n=0; n<256; n++) {
1325                 col[n].rgbRed   = ent[n].peRed;
1326                 col[n].rgbGreen = ent[n].peGreen;
1327                 col[n].rgbBlue  = ent[n].peBlue;
1328                 col[n].rgbReserved = 0;
1329             }
1330         } else {
1331             IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1332
1333             for (n=0; n<256; n++) {
1334                 col[n].rgbRed   = device->palettes[device->currentPalette][n].peRed;
1335                 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1336                 col[n].rgbBlue  = device->palettes[device->currentPalette][n].peBlue;
1337                 col[n].rgbReserved = 0;
1338             }
1339
1340         }
1341         SetDIBColorTable(This->hDC, 0, 256, col);
1342     }
1343
1344     *pHDC = This->hDC;
1345     TRACE("returning %p\n",*pHDC);
1346     This->Flags |= SFLAG_DCINUSE;
1347
1348     return WINED3D_OK;
1349 }
1350
1351 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1352     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1353
1354     TRACE("(%p)->(%p)\n",This,hDC);
1355
1356     if (!(This->Flags & SFLAG_DCINUSE))
1357         return WINED3DERR_INVALIDCALL;
1358
1359     if (This->hDC !=hDC) {
1360         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
1361         return WINED3DERR_INVALIDCALL;
1362     }
1363
1364     if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) {
1365         /* Copy the contents of the DIB over to the PBO */
1366         memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
1367     }
1368
1369     /* we locked first, so unlock now */
1370     IWineD3DSurface_UnlockRect(iface);
1371
1372     This->Flags &= ~SFLAG_DCINUSE;
1373
1374     return WINED3D_OK;
1375 }
1376
1377 /* ******************************************************
1378    IWineD3DSurface Internal (No mapping to directx api) parts follow
1379    ****************************************************** */
1380
1381 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) {
1382     BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
1383     const GlPixelFormatDesc *glDesc;
1384     getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
1385
1386     /* Default values: From the surface */
1387     *format = glDesc->glFormat;
1388     *internal = srgb_mode?glDesc->glGammaInternal:glDesc->glInternal;
1389     *type = glDesc->glType;
1390     *convert = NO_CONVERSION;
1391     *target_bpp = This->bytesPerPixel;
1392
1393     /* Ok, now look if we have to do any conversion */
1394     switch(This->resource.format) {
1395         case WINED3DFMT_P8:
1396             /* ****************
1397                 Paletted Texture
1398                 **************** */
1399             /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1400              * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1401              */
1402             if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1403                 *format = GL_RGBA;
1404                 *internal = GL_RGBA;
1405                 *type = GL_UNSIGNED_BYTE;
1406                 *target_bpp = 4;
1407                 if(colorkey_active) {
1408                     *convert = CONVERT_PALETTED_CK;
1409                 } else {
1410                     *convert = CONVERT_PALETTED;
1411                 }
1412             }
1413
1414             break;
1415
1416         case WINED3DFMT_R3G3B2:
1417             /* **********************
1418                 GL_UNSIGNED_BYTE_3_3_2
1419                 ********************** */
1420             if (colorkey_active) {
1421                 /* This texture format will never be used.. So do not care about color keying
1422                     up until the point in time it will be needed :-) */
1423                 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1424             }
1425             break;
1426
1427         case WINED3DFMT_R5G6B5:
1428             if (colorkey_active) {
1429                 *convert = CONVERT_CK_565;
1430                 *format = GL_RGBA;
1431                 *internal = GL_RGBA;
1432                 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1433             }
1434             break;
1435
1436         case WINED3DFMT_X1R5G5B5:
1437             if (colorkey_active) {
1438                 *convert = CONVERT_CK_5551;
1439                 *format = GL_BGRA;
1440                 *internal = GL_RGBA;
1441                 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
1442             }
1443             break;
1444
1445         case WINED3DFMT_R8G8B8:
1446             if (colorkey_active) {
1447                 *convert = CONVERT_CK_RGB24;
1448                 *format = GL_RGBA;
1449                 *internal = GL_RGBA;
1450                 *type = GL_UNSIGNED_INT_8_8_8_8;
1451                 *target_bpp = 4;
1452             }
1453             break;
1454
1455         case WINED3DFMT_X8R8G8B8:
1456             if (colorkey_active) {
1457                 *convert = CONVERT_RGB32_888;
1458                 *format = GL_RGBA;
1459                 *internal = GL_RGBA;
1460                 *type = GL_UNSIGNED_INT_8_8_8_8;
1461             }
1462             break;
1463
1464         case WINED3DFMT_V8U8:
1465             if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1466             else if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) {
1467                 *format = GL_DUDV_ATI;
1468                 *internal = GL_DU8DV8_ATI;
1469                 *type = GL_BYTE;
1470                 /* No conversion - Just change the gl type */
1471                 break;
1472             }
1473             *convert = CONVERT_V8U8;
1474             *format = GL_BGR;
1475             *internal = GL_RGB8;
1476             *type = GL_UNSIGNED_BYTE;
1477             *target_bpp = 3;
1478             break;
1479
1480         case WINED3DFMT_L6V5U5:
1481             *convert = CONVERT_L6V5U5;
1482             if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
1483                 *target_bpp = 3;
1484                 /* Use format and types from table */
1485             } else {
1486                 /* Load it into unsigned R5G6B5, swap L and V channels, and revert that in the shader */
1487                 *target_bpp = 2;
1488                 *format = GL_RGB;
1489                 *internal = GL_RGB5;
1490                 *type = GL_UNSIGNED_SHORT_5_6_5;
1491             }
1492             break;
1493
1494         case WINED3DFMT_X8L8V8U8:
1495             *convert = CONVERT_X8L8V8U8;
1496             *target_bpp = 4;
1497             if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
1498                 /* Use formats from gl table. It is a bit unfortunate, but the conversion
1499                  * is needed to set the X format to 255 to get 1.0 for alpha when sampling
1500                  * the texture. OpenGL can't use GL_DSDT8_MAG8_NV as internal format with
1501                  * the needed type and format parameter, so the internal format contains a
1502                  * 4th component, which is returned as alpha
1503                  */
1504             } else {
1505                 /* Not supported by GL_ATI_envmap_bumpmap */
1506                 *format = GL_BGRA;
1507                 *internal = GL_RGB8;
1508                 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
1509             }
1510             break;
1511
1512         case WINED3DFMT_Q8W8V8U8:
1513             if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1514             *convert = CONVERT_Q8W8V8U8;
1515             *format = GL_BGRA;
1516             *internal = GL_RGBA8;
1517             *type = GL_UNSIGNED_BYTE;
1518             *target_bpp = 4;
1519             /* Not supported by GL_ATI_envmap_bumpmap */
1520             break;
1521
1522         case WINED3DFMT_V16U16:
1523             if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1524             *convert = CONVERT_V16U16;
1525             *format = GL_BGR;
1526             *internal = GL_RGB16_EXT;
1527             *type = GL_UNSIGNED_SHORT;
1528             *target_bpp = 6;
1529             /* What should I do here about GL_ATI_envmap_bumpmap?
1530              * Convert it or allow data loss by loading it into a 8 bit / channel texture?
1531              */
1532             break;
1533
1534         case WINED3DFMT_A4L4:
1535             /* A4L4 exists as an internal gl format, but for some reason there is not
1536              * format+type combination to load it. Thus convert it to A8L8, then load it
1537              * with A4L4 internal, but A8L8 format+type
1538              */
1539             *convert = CONVERT_A4L4;
1540             *format = GL_LUMINANCE_ALPHA;
1541             *internal = GL_LUMINANCE4_ALPHA4;
1542             *type = GL_UNSIGNED_BYTE;
1543             *target_bpp = 2;
1544             break;
1545
1546         case WINED3DFMT_R32F:
1547             /* Can be loaded in theory with fmt=GL_RED, type=GL_FLOAT, but this fails. The reason
1548              * is that D3D expects the undefined green, blue and alpha channels to return 1.0
1549              * when sampling, but OpenGL sets green and blue to 0.0 instead. Thus we have to inject
1550              * 1.0 instead.
1551              *
1552              * The alpha channel defaults to 1.0 in opengl, so nothing has to be done about it.
1553              */
1554             *convert = CONVERT_R32F;
1555             *format = GL_RGB;
1556             *internal = GL_RGB32F_ARB;
1557             *type = GL_FLOAT;
1558             *target_bpp = 12;
1559             break;
1560
1561         case WINED3DFMT_R16F:
1562             /* Similar to R32F */
1563             *convert = CONVERT_R16F;
1564             *format = GL_RGB;
1565             *internal = GL_RGB16F_ARB;
1566             *type = GL_HALF_FLOAT_ARB;
1567             *target_bpp = 6;
1568             break;
1569
1570         default:
1571             break;
1572     }
1573
1574     return WINED3D_OK;
1575 }
1576
1577 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This) {
1578     BYTE *source, *dest;
1579     TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
1580
1581     switch (convert) {
1582         case NO_CONVERSION:
1583         {
1584             memcpy(dst, src, pitch * height);
1585             break;
1586         }
1587         case CONVERT_PALETTED:
1588         case CONVERT_PALETTED_CK:
1589         {
1590             IWineD3DPaletteImpl* pal = This->palette;
1591             BYTE table[256][4];
1592             unsigned int i;
1593             unsigned int x, y;
1594
1595             if( pal == NULL) {
1596                 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1597             }
1598
1599             if (pal == NULL) {
1600                 /* Still no palette? Use the device's palette */
1601                 /* Get the surface's palette */
1602                 for (i = 0; i < 256; i++) {
1603                     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1604
1605                     table[i][0] = device->palettes[device->currentPalette][i].peRed;
1606                     table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1607                     table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1608                     if ((convert == CONVERT_PALETTED_CK) &&
1609                         (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1610                         (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1611                         /* We should maybe here put a more 'neutral' color than the standard bright purple
1612                           one often used by application to prevent the nice purple borders when bi-linear
1613                           filtering is on */
1614                         table[i][3] = 0x00;
1615                     } else {
1616                         table[i][3] = 0xFF;
1617                     }
1618                 }
1619             } else {
1620                 TRACE("Using surface palette %p\n", pal);
1621                 /* Get the surface's palette */
1622                 for (i = 0; i < 256; i++) {
1623                     table[i][0] = pal->palents[i].peRed;
1624                     table[i][1] = pal->palents[i].peGreen;
1625                     table[i][2] = pal->palents[i].peBlue;
1626                     if ((convert == CONVERT_PALETTED_CK) &&
1627                         (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1628                         (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1629                         /* We should maybe here put a more 'neutral' color than the standard bright purple
1630                           one often used by application to prevent the nice purple borders when bi-linear
1631                           filtering is on */
1632                         table[i][3] = 0x00;
1633                     } else if(pal->Flags & WINEDDPCAPS_ALPHA) {
1634                         table[i][3] = pal->palents[i].peFlags;
1635                     } else {
1636                         table[i][3] = 0xFF;
1637                     }
1638                 }
1639             }
1640
1641             for (y = 0; y < height; y++)
1642             {
1643                 source = src + pitch * y;
1644                 dest = dst + outpitch * y;
1645                 /* This is an 1 bpp format, using the width here is fine */
1646                 for (x = 0; x < width; x++) {
1647                     BYTE color = *source++;
1648                     *dest++ = table[color][0];
1649                     *dest++ = table[color][1];
1650                     *dest++ = table[color][2];
1651                     *dest++ = table[color][3];
1652                 }
1653             }
1654         }
1655         break;
1656
1657         case CONVERT_CK_565:
1658         {
1659             /* Converting the 565 format in 5551 packed to emulate color-keying.
1660
1661               Note : in all these conversion, it would be best to average the averaging
1662                       pixels to get the color of the pixel that will be color-keyed to
1663                       prevent 'color bleeding'. This will be done later on if ever it is
1664                       too visible.
1665
1666               Note2: Nvidia documents say that their driver does not support alpha + color keying
1667                      on the same surface and disables color keying in such a case
1668             */
1669             unsigned int x, y;
1670             WORD *Source;
1671             WORD *Dest;
1672
1673             TRACE("Color keyed 565\n");
1674
1675             for (y = 0; y < height; y++) {
1676                 Source = (WORD *) (src + y * pitch);
1677                 Dest = (WORD *) (dst + y * outpitch);
1678                 for (x = 0; x < width; x++ ) {
1679                     WORD color = *Source++;
1680                     *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1681                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
1682                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
1683                         *Dest |= 0x0001;
1684                     }
1685                     Dest++;
1686                 }
1687             }
1688         }
1689         break;
1690
1691         case CONVERT_CK_5551:
1692         {
1693             /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
1694             unsigned int x, y;
1695             WORD *Source;
1696             WORD *Dest;
1697             TRACE("Color keyed 5551\n");
1698             for (y = 0; y < height; y++) {
1699                 Source = (WORD *) (src + y * pitch);
1700                 Dest = (WORD *) (dst + y * outpitch);
1701                 for (x = 0; x < width; x++ ) {
1702                     WORD color = *Source++;
1703                     *Dest = color;
1704                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
1705                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
1706                         *Dest |= (1 << 15);
1707                     }
1708                     else {
1709                         *Dest &= ~(1 << 15);
1710                     }
1711                     Dest++;
1712                 }
1713             }
1714         }
1715         break;
1716
1717         case CONVERT_V8U8:
1718         {
1719             unsigned int x, y;
1720             short *Source;
1721             unsigned char *Dest;
1722             for(y = 0; y < height; y++) {
1723                 Source = (short *) (src + y * pitch);
1724                 Dest = (unsigned char *) (dst + y * outpitch);
1725                 for (x = 0; x < width; x++ ) {
1726                     long color = (*Source++);
1727                     /* B */ Dest[0] = 0xff;
1728                     /* G */ Dest[1] = (color >> 8) + 128; /* V */
1729                     /* R */ Dest[2] = (color) + 128;      /* U */
1730                     Dest += 3;
1731                 }
1732             }
1733             break;
1734         }
1735
1736         case CONVERT_V16U16:
1737         {
1738             unsigned int x, y;
1739             DWORD *Source;
1740             unsigned short *Dest;
1741             for(y = 0; y < height; y++) {
1742                 Source = (DWORD *) (src + y * pitch);
1743                 Dest = (unsigned short *) (dst + y * outpitch);
1744                 for (x = 0; x < width; x++ ) {
1745                     DWORD color = (*Source++);
1746                     /* B */ Dest[0] = 0xffff;
1747                     /* G */ Dest[1] = (color >> 16) + 32768; /* V */
1748                     /* R */ Dest[2] = (color      ) + 32768; /* U */
1749                     Dest += 3;
1750                 }
1751             }
1752             break;
1753         }
1754
1755         case CONVERT_Q8W8V8U8:
1756         {
1757             unsigned int x, y;
1758             DWORD *Source;
1759             unsigned char *Dest;
1760             for(y = 0; y < height; y++) {
1761                 Source = (DWORD *) (src + y * pitch);
1762                 Dest = (unsigned char *) (dst + y * outpitch);
1763                 for (x = 0; x < width; x++ ) {
1764                     long color = (*Source++);
1765                     /* B */ Dest[0] = ((color >> 16) & 0xff) + 128; /* W */
1766                     /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */
1767                     /* R */ Dest[2] = (color         & 0xff) + 128; /* U */
1768                     /* A */ Dest[3] = ((color >> 24) & 0xff) + 128; /* Q */
1769                     Dest += 4;
1770                 }
1771             }
1772             break;
1773         }
1774
1775         case CONVERT_L6V5U5:
1776         {
1777             unsigned int x, y;
1778             WORD *Source;
1779             unsigned char *Dest;
1780
1781             if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
1782                 /* This makes the gl surface bigger(24 bit instead of 16), but it works with
1783                  * fixed function and shaders without further conversion once the surface is
1784                  * loaded
1785                  */
1786                 for(y = 0; y < height; y++) {
1787                     Source = (WORD *) (src + y * pitch);
1788                     Dest = (unsigned char *) (dst + y * outpitch);
1789                     for (x = 0; x < width; x++ ) {
1790                         short color = (*Source++);
1791                         unsigned char l = ((color >> 10) & 0xfc);
1792                                   char v = ((color >>  5) & 0x3e);
1793                                   char u = ((color      ) & 0x1f);
1794
1795                         /* 8 bits destination, 6 bits source, 8th bit is the sign. gl ignores the sign
1796                          * and doubles the positive range. Thus shift left only once, gl does the 2nd
1797                          * shift. GL reads a signed value and converts it into an unsigned value.
1798                          */
1799                         /* M */ Dest[2] = l << 1;
1800
1801                         /* Those are read as signed, but kept signed. Just left-shift 3 times to scale
1802                          * from 5 bit values to 8 bit values.
1803                          */
1804                         /* V */ Dest[1] = v << 3;
1805                         /* U */ Dest[0] = u << 3;
1806                         Dest += 3;
1807                     }
1808                 }
1809             } else {
1810                 for(y = 0; y < height; y++) {
1811                     unsigned short *Dest_s = (unsigned short *) (dst + y * outpitch);
1812                     Source = (WORD *) (src + y * pitch);
1813                     for (x = 0; x < width; x++ ) {
1814                         short color = (*Source++);
1815                         unsigned char l = ((color >> 10) & 0xfc);
1816                                  short v = ((color >>  5) & 0x3e);
1817                                  short u = ((color      ) & 0x1f);
1818                         short v_conv = v + 16;
1819                         short u_conv = u + 16;
1820
1821                         *Dest_s = ((v_conv << 11) & 0xf800) | ((l << 5) & 0x7e0) | (u_conv & 0x1f);
1822                         Dest_s += 1;
1823                     }
1824                 }
1825             }
1826             break;
1827         }
1828
1829         case CONVERT_X8L8V8U8:
1830         {
1831             unsigned int x, y;
1832             DWORD *Source;
1833             unsigned char *Dest;
1834
1835             if(GL_SUPPORT(NV_TEXTURE_SHADER)) {
1836                 /* This implementation works with the fixed function pipeline and shaders
1837                  * without further modification after converting the surface.
1838                  */
1839                 for(y = 0; y < height; y++) {
1840                     Source = (DWORD *) (src + y * pitch);
1841                     Dest = (unsigned char *) (dst + y * outpitch);
1842                     for (x = 0; x < width; x++ ) {
1843                         long color = (*Source++);
1844                         /* L */ Dest[2] = ((color >> 16) & 0xff);   /* L */
1845                         /* V */ Dest[1] = ((color >> 8 ) & 0xff);   /* V */
1846                         /* U */ Dest[0] = (color         & 0xff);   /* U */
1847                         /* I */ Dest[3] = 255;                      /* X */
1848                         Dest += 4;
1849                     }
1850                 }
1851             } else {
1852                 /* Doesn't work correctly with the fixed function pipeline, but can work in
1853                  * shaders if the shader is adjusted. (There's no use for this format in gl's
1854                  * standard fixed function pipeline anyway).
1855                  */
1856                 for(y = 0; y < height; y++) {
1857                     Source = (DWORD *) (src + y * pitch);
1858                     Dest = (unsigned char *) (dst + y * outpitch);
1859                     for (x = 0; x < width; x++ ) {
1860                         long color = (*Source++);
1861                         /* B */ Dest[0] = ((color >> 16) & 0xff);       /* L */
1862                         /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */
1863                         /* R */ Dest[2] = (color         & 0xff) + 128;  /* U */
1864                         Dest += 4;
1865                     }
1866                 }
1867             }
1868             break;
1869         }
1870
1871         case CONVERT_A4L4:
1872         {
1873             unsigned int x, y;
1874             unsigned char *Source;
1875             unsigned char *Dest;
1876             for(y = 0; y < height; y++) {
1877                 Source = (unsigned char *) (src + y * pitch);
1878                 Dest = (unsigned char *) (dst + y * outpitch);
1879                 for (x = 0; x < width; x++ ) {
1880                     unsigned char color = (*Source++);
1881                     /* A */ Dest[1] = (color & 0xf0) << 0;
1882                     /* L */ Dest[0] = (color & 0x0f) << 4;
1883                     Dest += 2;
1884                 }
1885             }
1886             break;
1887         }
1888
1889         case CONVERT_R32F:
1890         {
1891             unsigned int x, y;
1892             float *Source;
1893             float *Dest;
1894             for(y = 0; y < height; y++) {
1895                 Source = (float *) (src + y * pitch);
1896                 Dest = (float *) (dst + y * outpitch);
1897                 for (x = 0; x < width; x++ ) {
1898                     float color = (*Source++);
1899                     Dest[0] = color;
1900                     Dest[1] = 1.0;
1901                     Dest[2] = 1.0;
1902                     Dest += 3;
1903                 }
1904             }
1905             break;
1906         }
1907
1908         case CONVERT_R16F:
1909         {
1910             unsigned int x, y;
1911             WORD *Source;
1912             WORD *Dest;
1913             WORD one = 0x3c00;
1914             for(y = 0; y < height; y++) {
1915                 Source = (WORD *) (src + y * pitch);
1916                 Dest = (WORD *) (dst + y * outpitch);
1917                 for (x = 0; x < width; x++ ) {
1918                     WORD color = (*Source++);
1919                     Dest[0] = color;
1920                     Dest[1] = one;
1921                     Dest[2] = one;
1922                     Dest += 3;
1923                 }
1924             }
1925             break;
1926         }
1927         default:
1928             ERR("Unsupported conversation type %d\n", convert);
1929     }
1930     return WINED3D_OK;
1931 }
1932
1933 /* This function is used in case of 8bit paletted textures to upload the palette.
1934    For now it only supports GL_EXT_paletted_texture extension but support for other
1935    extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1936 */
1937 static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1938     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1939     IWineD3DPaletteImpl* pal = This->palette;
1940     BYTE table[256][4];
1941     int i;
1942
1943     if (pal == NULL) {
1944         /* Still no palette? Use the device's palette */
1945         /* Get the surface's palette */
1946         for (i = 0; i < 256; i++) {
1947             IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1948
1949             table[i][0] = device->palettes[device->currentPalette][i].peRed;
1950             table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1951             table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1952             if ((convert == CONVERT_PALETTED_CK) &&
1953                 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1954                 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1955                 /* We should maybe here put a more 'neutral' color than the standard bright purple
1956                    one often used by application to prevent the nice purple borders when bi-linear
1957                    filtering is on */
1958                 table[i][3] = 0x00;
1959             } else {
1960                 table[i][3] = 0xFF;
1961             }
1962         }
1963     } else {
1964         TRACE("Using surface palette %p\n", pal);
1965         /* Get the surface's palette */
1966         for (i = 0; i < 256; i++) {
1967             table[i][0] = pal->palents[i].peRed;
1968             table[i][1] = pal->palents[i].peGreen;
1969             table[i][2] = pal->palents[i].peBlue;
1970             if ((convert == CONVERT_PALETTED_CK) &&
1971                 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1972                 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1973                 /* We should maybe here put a more 'neutral' color than the standard bright purple
1974                    one often used by application to prevent the nice purple borders when bi-linear
1975                    filtering is on */
1976                 table[i][3] = 0x00;
1977             } else if(pal->Flags & WINEDDPCAPS_ALPHA) {
1978                 table[i][3] = pal->palents[i].peFlags;
1979             } else {
1980                 table[i][3] = 0xFF;
1981             }
1982         }
1983     }
1984     GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1985 }
1986
1987 static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
1988     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1989
1990     if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) {
1991         /* If a ddraw-style palette is attached assume no d3d9 palette change.
1992          * Also the palette isn't interesting if the surface format isn't P8 or A8P8
1993          */
1994         return FALSE;
1995     }
1996
1997     if(This->palette9) {
1998         if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) {
1999             return FALSE;
2000         }
2001     } else {
2002         This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2003     }
2004     memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
2005     return TRUE;
2006 }
2007
2008 static inline void clear_unused_channels(IWineD3DSurfaceImpl *This) {
2009     GLboolean oldwrite[4];
2010
2011     /* Some formats have only some color channels, and the others are 1.0.
2012      * since our rendering renders to all channels, and those pixel formats
2013      * are emulated by using a full texture with the other channels set to 1.0
2014      * manually, clear the unused channels.
2015      *
2016      * This could be done with hacking colorwriteenable to mask the colors,
2017      * but before drawing the buffer would have to be cleared too, so there's
2018      * no gain in that
2019      */
2020     switch(This->resource.format) {
2021         case WINED3DFMT_R16F:
2022         case WINED3DFMT_R32F:
2023             TRACE("R16F or R32F format, clearing green, blue and alpha to 1.0\n");
2024             /* Do not activate a context, the correct drawable is active already
2025              * though just the read buffer is set, make sure to have the correct draw
2026              * buffer too
2027              */
2028             glDrawBuffer(This->resource.wineD3DDevice->offscreenBuffer);
2029             glDisable(GL_SCISSOR_TEST);
2030             glGetBooleanv(GL_COLOR_WRITEMASK, oldwrite);
2031             glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE);
2032             glClearColor(0.0, 1.0, 1.0, 1.0);
2033             glClear(GL_COLOR_BUFFER_BIT);
2034             glColorMask(oldwrite[0], oldwrite[1], oldwrite[2], oldwrite[3]);
2035             if(!This->resource.wineD3DDevice->render_offscreen) glDrawBuffer(GL_BACK);
2036             checkGLcall("Unused channel clear\n");
2037             break;
2038
2039         default: break;
2040     }
2041 }
2042
2043 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
2044     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2045     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2046     GLenum format, internal, type;
2047     CONVERT_TYPES convert;
2048     int bpp;
2049     int width, pitch, outpitch;
2050     BYTE *mem;
2051
2052     if (!(This->Flags & SFLAG_INTEXTURE)) {
2053         TRACE("Reloading because surface is dirty\n");
2054     } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2055               ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
2056               /* Reload: vice versa  OR */
2057               ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
2058               /* Also reload: Color key is active AND the color key has changed */
2059               ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
2060                 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
2061                 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
2062         TRACE("Reloading because of color keying\n");
2063     } else if(palette9_changed(This)) {
2064         TRACE("Reloading surface because the d3d8/9 palette was changed\n");
2065     } else {
2066         TRACE("surface is already in texture\n");
2067         return WINED3D_OK;
2068     }
2069
2070     This->Flags |= SFLAG_INTEXTURE;
2071
2072     /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2073     *  These resources are not bound by device size or format restrictions. Because of this,
2074     *  these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2075     *  However, these resources can always be created, locked, and copied.
2076     */
2077     if (This->resource.pool == WINED3DPOOL_SCRATCH )
2078     {
2079         FIXME("(%p) Operation not supported for scratch textures\n",This);
2080         return WINED3DERR_INVALIDCALL;
2081     }
2082
2083     d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, srgb_mode);
2084
2085     if (This->Flags & SFLAG_INDRAWABLE) {
2086         if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
2087                  This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
2088                  This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
2089                  This->resource.format == WINED3DFMT_DXT5)
2090             FIXME("Format %d not supported\n", This->resource.format);
2091         else {
2092             GLint prevRead;
2093
2094             ENTER_GL();
2095             glGetIntegerv(GL_READ_BUFFER, &prevRead);
2096             vcheckGLcall("glGetIntegerv");
2097             glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer);
2098             vcheckGLcall("glReadBuffer");
2099
2100             if(!(This->Flags & SFLAG_ALLOCATED)) {
2101                 surface_allocate_surface(This, internal, This->pow2Width,
2102                                          This->pow2Height, format, type);
2103             }
2104
2105             clear_unused_channels(This);
2106
2107             glCopyTexSubImage2D(This->glDescription.target,
2108                                 This->glDescription.level,
2109                                 0, 0, 0, 0,
2110                                 This->currentDesc.Width,
2111                                 This->currentDesc.Height);
2112             checkGLcall("glCopyTexSubImage2D");
2113
2114             glReadBuffer(prevRead);
2115             vcheckGLcall("glReadBuffer");
2116
2117             LEAVE_GL();
2118
2119             TRACE("Updated target %d\n", This->glDescription.target);
2120         }
2121         return WINED3D_OK;
2122     } else
2123         /* The only place where LoadTexture() might get called when isInDraw=1
2124          * is ActivateContext where lastActiveRenderTarget is preloaded.
2125          */
2126         if(iface == device->lastActiveRenderTarget && device->isInDraw)
2127             ERR("Reading back render target but SFLAG_INDRAWABLE not set\n");
2128
2129     /* Otherwise: System memory copy must be most up to date */
2130
2131     if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
2132         This->Flags |= SFLAG_GLCKEY;
2133         This->glCKey = This->SrcBltCKey;
2134     }
2135     else This->Flags &= ~SFLAG_GLCKEY;
2136
2137     /* The width is in 'length' not in bytes */
2138     width = This->currentDesc.Width;
2139     pitch = IWineD3DSurface_GetPitch(iface);
2140
2141     if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
2142         int height = This->currentDesc.Height;
2143
2144         /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
2145         outpitch = width * bpp;
2146         outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
2147
2148         mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
2149         if(!mem) {
2150             ERR("Out of memory %d, %d!\n", outpitch, height);
2151             return WINED3DERR_OUTOFVIDEOMEMORY;
2152         }
2153         d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
2154
2155         This->Flags |= SFLAG_CONVERTED;
2156     } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
2157         d3dfmt_p8_upload_palette(iface, convert);
2158         This->Flags &= ~SFLAG_CONVERTED;
2159         mem = This->resource.allocatedMemory;
2160     } else {
2161         This->Flags &= ~SFLAG_CONVERTED;
2162         mem = This->resource.allocatedMemory;
2163     }
2164
2165     /* Make sure the correct pitch is used */
2166     glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
2167
2168     if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
2169         TRACE("non power of two support\n");
2170         if(!(This->Flags & SFLAG_ALLOCATED)) {
2171             surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
2172         }
2173         if (mem || (This->Flags & SFLAG_PBO)) {
2174             surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
2175         }
2176     } else {
2177         /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory
2178          * changed. So also keep track of memory changes. In this case the texture has to be reallocated
2179          */
2180         if(!(This->Flags & SFLAG_ALLOCATED)) {
2181             surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
2182         }
2183         if (mem || (This->Flags & SFLAG_PBO)) {
2184             surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
2185         }
2186     }
2187
2188     /* Restore the default pitch */
2189     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2190
2191     /* Don't delete PBO memory */
2192     if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
2193         HeapFree(GetProcessHeap(), 0, mem);
2194
2195 #if 0
2196     {
2197         static unsigned int gen = 0;
2198         char buffer[4096];
2199         ++gen;
2200         if ((gen % 10) == 0) {
2201             snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
2202             IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2203         }
2204         /*
2205          * debugging crash code
2206          if (gen == 250) {
2207          void** test = NULL;
2208          *test = 0;
2209          }
2210          */
2211     }
2212 #endif
2213
2214     if (!(This->Flags & SFLAG_DONOTFREE)) {
2215         HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2216         This->resource.allocatedMemory = NULL;
2217         This->Flags &= ~SFLAG_INSYSMEM;
2218     }
2219
2220     return WINED3D_OK;
2221 }
2222
2223 #include <errno.h>
2224 #include <stdio.h>
2225 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
2226     FILE* f = NULL;
2227     UINT i, y;
2228     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2229     char *allocatedMemory;
2230     char *textureRow;
2231     IWineD3DSwapChain *swapChain = NULL;
2232     int width, height;
2233     GLuint tmpTexture = 0;
2234     DWORD color;
2235     /*FIXME:
2236     Textures may not be stored in ->allocatedgMemory and a GlTexture
2237     so we should lock the surface before saving a snapshot, or at least check that
2238     */
2239     /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2240     by calling GetTexImage and in compressed form by calling
2241     GetCompressedTexImageARB.  Queried compressed images can be saved and
2242     later reused by calling CompressedTexImage[123]DARB.  Pre-compressed
2243     texture images do not need to be processed by the GL and should
2244     significantly improve texture loading performance relative to uncompressed
2245     images. */
2246
2247 /* Setup the width and height to be the internal texture width and height. */
2248     width  = This->pow2Width;
2249     height = This->pow2Height;
2250 /* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2251     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2252
2253     if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2254         /* if were not a real texture then read the back buffer into a real texture */
2255         /* we don't want to interfere with the back buffer so read the data into a temporary
2256          * texture and then save the data out of the temporary texture
2257          */
2258         GLint prevRead;
2259         ENTER_GL();
2260         TRACE("(%p) Reading render target into texture\n", This);
2261         glEnable(GL_TEXTURE_2D);
2262
2263         glGenTextures(1, &tmpTexture);
2264         glBindTexture(GL_TEXTURE_2D, tmpTexture);
2265
2266         glTexImage2D(GL_TEXTURE_2D,
2267                         0,
2268                         GL_RGBA,
2269                         width,
2270                         height,
2271                         0/*border*/,
2272                         GL_RGBA,
2273                         GL_UNSIGNED_INT_8_8_8_8_REV,
2274                         NULL);
2275
2276         glGetIntegerv(GL_READ_BUFFER, &prevRead);
2277         vcheckGLcall("glGetIntegerv");
2278         glReadBuffer(swapChain ? GL_BACK : This->resource.wineD3DDevice->offscreenBuffer);
2279         vcheckGLcall("glReadBuffer");
2280         glCopyTexImage2D(GL_TEXTURE_2D,
2281                             0,
2282                             GL_RGBA,
2283                             0,
2284                             0,
2285                             width,
2286                             height,
2287                             0);
2288
2289         checkGLcall("glCopyTexImage2D");
2290         glReadBuffer(prevRead);
2291         LEAVE_GL();
2292
2293     } else { /* bind the real texture, and make sure it up to date */
2294         IWineD3DSurface_PreLoad(iface);
2295     }
2296     allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width  * height * 4);
2297     ENTER_GL();
2298     FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
2299     glGetTexImage(GL_TEXTURE_2D,
2300                 This->glDescription.level,
2301                 GL_RGBA,
2302                 GL_UNSIGNED_INT_8_8_8_8_REV,
2303                 allocatedMemory);
2304     checkGLcall("glTexImage2D");
2305     if (tmpTexture) {
2306         glBindTexture(GL_TEXTURE_2D, 0);
2307         glDeleteTextures(1, &tmpTexture);
2308     }
2309     LEAVE_GL();
2310
2311     f = fopen(filename, "w+");
2312     if (NULL == f) {
2313         ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2314         return WINED3DERR_INVALIDCALL;
2315     }
2316 /* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
2317     TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2318 /* TGA header */
2319     fputc(0,f);
2320     fputc(0,f);
2321     fputc(2,f);
2322     fputc(0,f);
2323     fputc(0,f);
2324     fputc(0,f);
2325     fputc(0,f);
2326     fputc(0,f);
2327     fputc(0,f);
2328     fputc(0,f);
2329     fputc(0,f);
2330     fputc(0,f);
2331 /* short width*/
2332     fwrite(&width,2,1,f);
2333 /* short height */
2334     fwrite(&height,2,1,f);
2335 /* format rgba */
2336     fputc(0x20,f);
2337     fputc(0x28,f);
2338 /* raw data */
2339     /* 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 */
2340     if(swapChain)
2341         textureRow = allocatedMemory + (width * (height - 1) *4);
2342     else
2343         textureRow = allocatedMemory;
2344     for (y = 0 ; y < height; y++) {
2345         for (i = 0; i < width;  i++) {
2346             color = *((DWORD*)textureRow);
2347             fputc((color >> 16) & 0xFF, f); /* B */
2348             fputc((color >>  8) & 0xFF, f); /* G */
2349             fputc((color >>  0) & 0xFF, f); /* R */
2350             fputc((color >> 24) & 0xFF, f); /* A */
2351             textureRow += 4;
2352         }
2353         /* take two rows of the pointer to the texture memory */
2354         if(swapChain)
2355             (textureRow-= width << 3);
2356
2357     }
2358     TRACE("Closing file\n");
2359     fclose(f);
2360
2361     if(swapChain) {
2362         IWineD3DSwapChain_Release(swapChain);
2363     }
2364     HeapFree(GetProcessHeap(), 0, allocatedMemory);
2365     return WINED3D_OK;
2366 }
2367
2368 /**
2369  *   Slightly inefficient way to handle multiple dirty rects but it works :)
2370  */
2371 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2372     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2373     IWineD3DBaseTexture *baseTexture = NULL;
2374     if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE))
2375         surface_download_data(This);
2376
2377     This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
2378     if (NULL != pDirtyRect) {
2379         This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
2380         This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
2381         This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
2382         This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2383     } else {
2384         This->dirtyRect.left   = 0;
2385         This->dirtyRect.top    = 0;
2386         This->dirtyRect.right  = This->currentDesc.Width;
2387         This->dirtyRect.bottom = This->currentDesc.Height;
2388     }
2389     TRACE("(%p) : Dirty: yes, Rect:(%d,%d,%d,%d)\n", This, This->dirtyRect.left,
2390           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2391     /* if the container is a basetexture then mark it dirty. */
2392     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2393         TRACE("Passing to container\n");
2394         IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2395         IWineD3DBaseTexture_Release(baseTexture);
2396     }
2397     return WINED3D_OK;
2398 }
2399
2400 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2401     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2402     HRESULT hr;
2403     const GlPixelFormatDesc *glDesc;
2404     getFormatDescEntry(format, &GLINFO_LOCATION, &glDesc);
2405
2406     TRACE("(%p) : Calling base function first\n", This);
2407     hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
2408     if(SUCCEEDED(hr)) {
2409         /* Setup some glformat defaults */
2410         This->glDescription.glFormat         = glDesc->glFormat;
2411         This->glDescription.glFormatInternal = glDesc->glInternal;
2412         This->glDescription.glType           = glDesc->glType;
2413
2414         This->Flags &= ~SFLAG_ALLOCATED;
2415         TRACE("(%p) : glFormat %d, glFotmatInternal %d, glType %d\n", This,
2416               This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2417     }
2418     return hr;
2419 }
2420
2421 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2422     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2423
2424     if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2425         WARN("Surface is locked or the HDC is in use\n");
2426         return WINED3DERR_INVALIDCALL;
2427     }
2428
2429     if(Mem && Mem != This->resource.allocatedMemory) {
2430         void *release = NULL;
2431
2432         /* Do I have to copy the old surface content? */
2433         if(This->Flags & SFLAG_DIBSECTION) {
2434                 /* Release the DC. No need to hold the critical section for the update
2435                  * Thread because this thread runs only on front buffers, but this method
2436                  * fails for render targets in the check above.
2437                  */
2438                 SelectObject(This->hDC, This->dib.holdbitmap);
2439                 DeleteDC(This->hDC);
2440                 /* Release the DIB section */
2441                 DeleteObject(This->dib.DIBsection);
2442                 This->dib.bitmap_data = NULL;
2443                 This->resource.allocatedMemory = NULL;
2444                 This->hDC = NULL;
2445                 This->Flags &= ~SFLAG_DIBSECTION;
2446         } else if(!(This->Flags & SFLAG_USERPTR)) {
2447             release = This->resource.allocatedMemory;
2448         }
2449         This->resource.allocatedMemory = Mem;
2450         This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
2451
2452         /* Now the surface memory is most up do date. Invalidate drawable and texture */
2453         This->Flags &= ~(SFLAG_INDRAWABLE | SFLAG_INTEXTURE);
2454
2455         /* For client textures opengl has to be notified */
2456         if(This->Flags & SFLAG_CLIENT) {
2457             This->Flags &= ~SFLAG_ALLOCATED;
2458             IWineD3DSurface_PreLoad(iface);
2459             /* And hope that the app behaves correctly and did not free the old surface memory before setting a new pointer */
2460         }
2461
2462         /* Now free the old memory if any */
2463         HeapFree(GetProcessHeap(), 0, release);
2464     } else if(This->Flags & SFLAG_USERPTR) {
2465         /* Lockrect and GetDC will re-create the dib section and allocated memory */
2466         This->resource.allocatedMemory = NULL;
2467         This->Flags &= ~SFLAG_USERPTR;
2468
2469         if(This->Flags & SFLAG_CLIENT) {
2470             This->Flags &= ~SFLAG_ALLOCATED;
2471             /* This respecifies an empty texture and opengl knows that the old memory is gone */
2472             IWineD3DSurface_PreLoad(iface);
2473         }
2474     }
2475     return WINED3D_OK;
2476 }
2477
2478 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2479     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2480     IWineD3DSwapChainImpl *swapchain = NULL;
2481     HRESULT hr;
2482     TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2483
2484     /* Flipping is only supported on RenderTargets */
2485     if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return WINEDDERR_NOTFLIPPABLE;
2486
2487     if(override) {
2488         /* DDraw sets this for the X11 surfaces, so don't confuse the user 
2489          * FIXME("(%p) Target override is not supported by now\n", This);
2490          * Additionally, it isn't really possible to support triple-buffering
2491          * properly on opengl at all
2492          */
2493     }
2494
2495     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
2496     if(!swapchain) {
2497         ERR("Flipped surface is not on a swapchain\n");
2498         return WINEDDERR_NOTFLIPPABLE;
2499     }
2500
2501     /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
2502      * and only d3d8 and d3d9 apps specify the presentation interval
2503      */
2504     if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
2505         /* Most common case first to avoid wasting time on all the other cases */
2506         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
2507     } else if(Flags & WINEDDFLIP_NOVSYNC) {
2508         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2509     } else if(Flags & WINEDDFLIP_INTERVAL2) {
2510         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
2511     } else if(Flags & WINEDDFLIP_INTERVAL3) {
2512         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
2513     } else {
2514         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
2515     }
2516
2517     /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2518     hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *) swapchain, NULL, NULL, 0, NULL, 0);
2519     IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2520     return hr;
2521 }
2522
2523 /* Does a direct frame buffer -> texture copy. Stretching is done
2524  * with single pixel copy calls
2525  */
2526 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) {
2527     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2528     float xrel, yrel;
2529     UINT row;
2530     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2531
2532
2533     ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2534     ENTER_GL();
2535     IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2536
2537     /* Bind the target texture */
2538     glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2539     checkGLcall("glBindTexture");
2540     if(!swapchain) {
2541         glReadBuffer(myDevice->offscreenBuffer);
2542     } else {
2543         GLenum buffer = surface_get_gl_buffer(SrcSurface, (IWineD3DSwapChain *)swapchain);
2544         glReadBuffer(buffer);
2545     }
2546     checkGLcall("glReadBuffer");
2547
2548     xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2549     yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2550
2551     if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2552         FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2553
2554         if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
2555             ERR("Texture filtering not supported in direct blit\n");
2556         }
2557     } else if((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) && ((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2558         ERR("Texture filtering not supported in direct blit\n");
2559     }
2560
2561     if(upsidedown &&
2562        !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2563        !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2564         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2565
2566         glCopyTexSubImage2D(This->glDescription.target,
2567                             This->glDescription.level,
2568                             drect->x1, drect->y1, /* xoffset, yoffset */
2569                             srect->x1, Src->currentDesc.Height - srect->y2,
2570                             drect->x2 - drect->x1, drect->y2 - drect->y1);
2571     } else {
2572         UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2573         /* I have to process this row by row to swap the image,
2574          * otherwise it would be upside down, so stretching in y direction
2575          * doesn't cost extra time
2576          *
2577          * However, stretching in x direction can be avoided if not necessary
2578          */
2579         for(row = drect->y1; row < drect->y2; row++) {
2580             if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2581                 /* Well, that stuff works, but it's very slow.
2582                  * find a better way instead
2583                  */
2584                 UINT col;
2585
2586                 for(col = drect->x1; col < drect->x2; col++) {
2587                     glCopyTexSubImage2D(This->glDescription.target,
2588                                         This->glDescription.level,
2589                                         drect->x1 + col, row, /* xoffset, yoffset */
2590                                         srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2591                                         1, 1);
2592                 }
2593             } else {
2594                 glCopyTexSubImage2D(This->glDescription.target,
2595                                     This->glDescription.level,
2596                                     drect->x1, row, /* xoffset, yoffset */
2597                                     srect->x1, yoffset - (int) (row * yrel),
2598                                     drect->x2-drect->x1, 1);
2599             }
2600         }
2601     }
2602
2603     vcheckGLcall("glCopyTexSubImage2D");
2604     LEAVE_GL();
2605 }
2606
2607 /* Uses the hardware to stretch and flip the image */
2608 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) {
2609     GLuint src, backup = 0;
2610     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2611     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2612     float left, right, top, bottom; /* Texture coordinates */
2613     UINT fbwidth = Src->currentDesc.Width;
2614     UINT fbheight = Src->currentDesc.Height;
2615     GLenum drawBuffer = GL_BACK;
2616
2617     TRACE("Using hwstretch blit\n");
2618     /* Activate the Proper context for reading from the source surface, set it up for blitting */
2619     ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2620     ENTER_GL();
2621     IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2622
2623     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2624      * This way we don't have to wait for the 2nd readback to finish to leave this function.
2625      */
2626     if(GL_LIMITS(aux_buffers) >= 2) {
2627         /* Got more than one aux buffer? Use the 2nd aux buffer */
2628         drawBuffer = GL_AUX1;
2629     } else if((swapchain || myDevice->offscreenBuffer == GL_BACK) && GL_LIMITS(aux_buffers) >= 1) {
2630         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2631         drawBuffer = GL_AUX0;
2632     }
2633
2634     if(!swapchain && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2635         glGenTextures(1, &backup);
2636         checkGLcall("glGenTextures\n");
2637         glBindTexture(GL_TEXTURE_2D, backup);
2638         checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2639     } else {
2640         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2641          * we are reading from the back buffer, the backup can be used as source texture
2642          */
2643         if(Src->glDescription.textureName == 0) {
2644             /* Get it a description */
2645             IWineD3DSurface_PreLoad(SrcSurface);
2646         }
2647         glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2648         checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2649
2650         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2651         Src->Flags &= ~SFLAG_INTEXTURE;
2652     }
2653
2654     glReadBuffer(GL_BACK);
2655     checkGLcall("glReadBuffer(GL_BACK)");
2656
2657     /* TODO: Only back up the part that will be overwritten */
2658     glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2659                         0, 0 /* read offsets */,
2660                         0, 0,
2661                         fbwidth,
2662                         fbheight);
2663
2664     checkGLcall("glCopyTexSubImage2D");
2665
2666     /* No issue with overriding these - the sampler is dirty due to blit usage */
2667     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2668                     stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]);
2669     checkGLcall("glTexParameteri");
2670     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2671                     minMipLookup[Filter][WINED3DTEXF_NONE]);
2672     checkGLcall("glTexParameteri");
2673
2674     if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) {
2675         src = backup ? backup : Src->glDescription.textureName;
2676     } else {
2677         glReadBuffer(GL_FRONT);
2678         checkGLcall("glReadBuffer(GL_FRONT)");
2679
2680         glGenTextures(1, &src);
2681         checkGLcall("glGenTextures(1, &src)");
2682         glBindTexture(GL_TEXTURE_2D, src);
2683         checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2684
2685         /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2686          * out for power of 2 sizes
2687          */
2688         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2689                     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2690         checkGLcall("glTexImage2D");
2691         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2692                             0, 0 /* read offsets */,
2693                             0, 0,
2694                             fbwidth,
2695                             fbheight);
2696
2697         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2698         checkGLcall("glTexParameteri");
2699         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2700         checkGLcall("glTexParameteri");
2701
2702         glReadBuffer(GL_BACK);
2703         checkGLcall("glReadBuffer(GL_BACK)");
2704     }
2705     checkGLcall("glEnd and previous");
2706
2707     left = (float) srect->x1 / (float) Src->pow2Width;
2708     right = (float) srect->x2 / (float) Src->pow2Width;
2709
2710     if(upsidedown) {
2711         top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2712         bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2713     } else {
2714         top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2715         bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2716     }
2717
2718     /* draw the source texture stretched and upside down. The correct surface is bound already */
2719     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2720     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2721
2722     glDrawBuffer(drawBuffer);
2723     glReadBuffer(drawBuffer);
2724
2725     glBegin(GL_QUADS);
2726         /* bottom left */
2727         glTexCoord2f(left, bottom);
2728         glVertex2i(0, fbheight);
2729
2730         /* top left */
2731         glTexCoord2f(left, top);
2732         glVertex2i(0, fbheight - drect->y2 - drect->y1);
2733
2734         /* top right */
2735         glTexCoord2f(right, top);
2736         glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2737
2738         /* bottom right */
2739         glTexCoord2f(right, bottom);
2740         glVertex2i(drect->x2 - drect->x1, fbheight);
2741     glEnd();
2742     checkGLcall("glEnd and previous");
2743
2744     /* Now read the stretched and upside down image into the destination texture */
2745     glBindTexture(This->glDescription.target, This->glDescription.textureName);
2746     checkGLcall("glBindTexture");
2747     glCopyTexSubImage2D(This->glDescription.target,
2748                         0,
2749                         drect->x1, drect->y1, /* xoffset, yoffset */
2750                         0, 0, /* We blitted the image to the origin */
2751                         drect->x2 - drect->x1, drect->y2 - drect->y1);
2752     checkGLcall("glCopyTexSubImage2D");
2753
2754     /* Write the back buffer backup back */
2755     glBindTexture(GL_TEXTURE_2D, backup ? backup : Src->glDescription.textureName);
2756     checkGLcall("glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName)");
2757
2758     if(drawBuffer == GL_BACK) {
2759         glBegin(GL_QUADS);
2760             /* top left */
2761             glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2762             glVertex2i(0, 0);
2763
2764             /* bottom left */
2765             glTexCoord2f(0.0, 0.0);
2766             glVertex2i(0, fbheight);
2767
2768             /* bottom right */
2769             glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2770             glVertex2i(fbwidth, Src->currentDesc.Height);
2771
2772             /* top right */
2773             glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2774             glVertex2i(fbwidth, 0);
2775         glEnd();
2776     } else {
2777         /* Restore the old draw buffer */
2778         glDrawBuffer(GL_BACK);
2779     }
2780
2781     /* Cleanup */
2782     if(src != Src->glDescription.textureName && src != backup) {
2783         glDeleteTextures(1, &src);
2784         checkGLcall("glDeleteTextures(1, &src)");
2785     }
2786     if(backup) {
2787         glDeleteTextures(1, &backup);
2788         checkGLcall("glDeleteTextures(1, &backup)");
2789     }
2790     LEAVE_GL();
2791 }
2792
2793 /* Not called from the VTable */
2794 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
2795     WINED3DRECT rect;
2796     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2797     IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2798     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2799
2800     TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2801
2802     /* Get the swapchain. One of the surfaces has to be a primary surface */
2803     if(This->resource.pool == WINED3DPOOL_SYSTEMMEM) {
2804         WARN("Destination is in sysmem, rejecting gl blt\n");
2805         return WINED3DERR_INVALIDCALL;
2806     }
2807     IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2808     if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2809     if(Src) {
2810         if(Src->resource.pool == WINED3DPOOL_SYSTEMMEM) {
2811             WARN("Src is in sysmem, rejecting gl blt\n");
2812             return WINED3DERR_INVALIDCALL;
2813         }
2814         IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2815         if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2816     }
2817
2818     /* Early sort out of cases where no render target is used */
2819     if(!dstSwapchain && !srcSwapchain &&
2820         SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2821         TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2822         return WINED3DERR_INVALIDCALL;
2823     }
2824
2825     /* No destination color keying supported */
2826     if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
2827         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2828         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2829         return WINED3DERR_INVALIDCALL;
2830     }
2831
2832     if (DestRect) {
2833         rect.x1 = DestRect->left;
2834         rect.y1 = DestRect->top;
2835         rect.x2 = DestRect->right;
2836         rect.y2 = DestRect->bottom;
2837     } else {
2838         rect.x1 = 0;
2839         rect.y1 = 0;
2840         rect.x2 = This->currentDesc.Width;
2841         rect.y2 = This->currentDesc.Height;
2842     }
2843
2844     /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2845     if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer &&
2846        ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) {
2847         /* Half-life does a Blt from the back buffer to the front buffer,
2848          * Full surface size, no flags... Use present instead
2849          *
2850          * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
2851          */
2852
2853         /* Check rects - IWineD3DDevice_Present doesn't handle them */
2854         while(1)
2855         {
2856             RECT mySrcRect;
2857             TRACE("Looking if a Present can be done...\n");
2858             /* Source Rectangle must be full surface */
2859             if( SrcRect ) {
2860                 if(SrcRect->left != 0 || SrcRect->top != 0 ||
2861                    SrcRect->right != Src->currentDesc.Width || SrcRect->bottom != Src->currentDesc.Height) {
2862                     TRACE("No, Source rectangle doesn't match\n");
2863                     break;
2864                 }
2865             }
2866             mySrcRect.left = 0;
2867             mySrcRect.top = 0;
2868             mySrcRect.right = Src->currentDesc.Width;
2869             mySrcRect.bottom = Src->currentDesc.Height;
2870
2871             /* No stretching may occur */
2872             if(mySrcRect.right != rect.x2 - rect.x1 ||
2873                mySrcRect.bottom != rect.y2 - rect.y1) {
2874                 TRACE("No, stretching is done\n");
2875                 break;
2876             }
2877
2878             /* Destination must be full surface or match the clipping rectangle */
2879             if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd)
2880             {
2881                 RECT cliprect;
2882                 POINT pos[2];
2883                 GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect);
2884                 pos[0].x = rect.x1;
2885                 pos[0].y = rect.y1;
2886                 pos[1].x = rect.x2;
2887                 pos[1].y = rect.y2;
2888                 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd,
2889                                 pos, 2);
2890
2891                 if(pos[0].x != cliprect.left  || pos[0].y != cliprect.top   ||
2892                    pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
2893                 {
2894                     TRACE("No, dest rectangle doesn't match(clipper)\n");
2895                     TRACE("Clip rect at (%d,%d)-(%d,%d)\n", cliprect.left, cliprect.top, cliprect.right, cliprect.bottom);
2896                     TRACE("Blt dest: (%d,%d)-(%d,%d)\n", rect.x1, rect.y1, rect.x2, rect.y2);
2897                     break;
2898                 }
2899             }
2900             else
2901             {
2902                 if(rect.x1 != 0 || rect.y1 != 0 ||
2903                    rect.x2 != This->currentDesc.Width || rect.y2 != This->currentDesc.Height) {
2904                     TRACE("No, dest rectangle doesn't match(surface size)\n");
2905                     break;
2906                 }
2907             }
2908
2909             TRACE("Yes\n");
2910
2911             /* These flags are unimportant for the flag check, remove them */
2912             if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
2913                 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2914
2915                 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2916                     * take very long, while a flip is fast.
2917                     * This applies to Half-Life, which does such Blts every time it finished
2918                     * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2919                     * menu. This is also used by all apps when they do windowed rendering
2920                     *
2921                     * The problem is that flipping is not really the same as copying. After a
2922                     * Blt the front buffer is a copy of the back buffer, and the back buffer is
2923                     * untouched. Therefore it's necessary to override the swap effect
2924                     * and to set it back after the flip.
2925                     *
2926                     * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
2927                     * testcases.
2928                     */
2929
2930                 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2931                 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2932
2933                 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2934                 IWineD3DSwapChain_Present((IWineD3DSwapChain *) dstSwapchain, NULL, NULL, 0, NULL, 0);
2935
2936                 dstSwapchain->presentParms.SwapEffect = orig_swap;
2937
2938                 return WINED3D_OK;
2939             }
2940             break;
2941         }
2942
2943         TRACE("Unsupported blit between buffers on the same swapchain\n");
2944         return WINED3DERR_INVALIDCALL;
2945     } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2946               (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2947         ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2948         return WINED3DERR_INVALIDCALL;
2949     }
2950
2951     if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2952         /* Blit from render target to texture */
2953         WINED3DRECT srect;
2954         BOOL upsideDown, stretchx;
2955
2956         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
2957             TRACE("Color keying not supported by frame buffer to texture blit\n");
2958             return WINED3DERR_INVALIDCALL;
2959             /* Destination color key is checked above */
2960         }
2961
2962         /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2963          * glCopyTexSubImage is a bit picky about the parameters we pass to it
2964          */
2965         if(SrcRect) {
2966             if(SrcRect->top < SrcRect->bottom) {
2967                 srect.y1 = SrcRect->top;
2968                 srect.y2 = SrcRect->bottom;
2969                 upsideDown = FALSE;
2970             } else {
2971                 srect.y1 = SrcRect->bottom;
2972                 srect.y2 = SrcRect->top;
2973                 upsideDown = TRUE;
2974             }
2975             srect.x1 = SrcRect->left;
2976             srect.x2 = SrcRect->right;
2977         } else {
2978             srect.x1 = 0;
2979             srect.y1 = 0;
2980             srect.x2 = Src->currentDesc.Width;
2981             srect.y2 = Src->currentDesc.Height;
2982             upsideDown = FALSE;
2983         }
2984         if(rect.x1 > rect.x2) {
2985             UINT tmp = rect.x2;
2986             rect.x2 = rect.x1;
2987             rect.x1 = tmp;
2988             upsideDown = !upsideDown;
2989         }
2990         if(!srcSwapchain) {
2991             TRACE("Reading from an offscreen target\n");
2992             upsideDown = !upsideDown;
2993         }
2994
2995         if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2996             stretchx = TRUE;
2997         } else {
2998             stretchx = FALSE;
2999         }
3000
3001         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3002          * flip the image nor scale it.
3003          *
3004          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3005          * -> If the app wants a image width an unscaled width, copy it line per line
3006          * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3007          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3008          *    back buffer. This is slower than reading line per line, thus not used for flipping
3009          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3010          *    pixel by pixel
3011          *
3012          * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3013          * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3014          * backends.
3015          */
3016         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && GL_SUPPORT(EXT_FRAMEBUFFER_BLIT)) {
3017             stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &srect,
3018                     (IWineD3DSurface *)This, &rect, Filter, upsideDown);
3019         } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
3020                                     rect.y2 - rect.y1 > Src->currentDesc.Height) {
3021             TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3022             fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
3023         } else {
3024             TRACE("Using hardware stretching to flip / stretch the texture\n");
3025             fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
3026         }
3027
3028         if(!(This->Flags & SFLAG_DONOTFREE)) {
3029             HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
3030             This->resource.allocatedMemory = NULL;
3031         } else {
3032             This->Flags &= ~SFLAG_INSYSMEM;
3033         }
3034         /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3035          * path is never entered
3036          */
3037         This->Flags |= SFLAG_INTEXTURE;
3038
3039         return WINED3D_OK;
3040     } else if(Src) {
3041         /* Blit from offscreen surface to render target */
3042         float glTexCoord[4];
3043         DWORD oldCKeyFlags = Src->CKeyFlags;
3044         WINEDDCOLORKEY oldBltCKey = This->SrcBltCKey;
3045         RECT SourceRectangle;
3046
3047         TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
3048
3049         if(SrcRect) {
3050             SourceRectangle.left = SrcRect->left;
3051             SourceRectangle.right = SrcRect->right;
3052             SourceRectangle.top = SrcRect->top;
3053             SourceRectangle.bottom = SrcRect->bottom;
3054         } else {
3055             SourceRectangle.left = 0;
3056             SourceRectangle.right = Src->currentDesc.Width;
3057             SourceRectangle.top = 0;
3058             SourceRectangle.bottom = Src->currentDesc.Height;
3059         }
3060
3061         if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
3062             /* Fall back to software */
3063             WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
3064                     SourceRectangle.left, SourceRectangle.top,
3065                     SourceRectangle.right, SourceRectangle.bottom);
3066             return WINED3DERR_INVALIDCALL;
3067         }
3068
3069         /* Color keying: Check if we have to do a color keyed blt,
3070          * and if not check if a color key is activated.
3071          *
3072          * Just modify the color keying parameters in the surface and restore them afterwards
3073          * The surface keeps track of the color key last used to load the opengl surface.
3074          * PreLoad will catch the change to the flags and color key and reload if necessary.
3075          */
3076         if(Flags & WINEDDBLT_KEYSRC) {
3077             /* Use color key from surface */
3078         } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
3079             /* Use color key from DDBltFx */
3080             Src->CKeyFlags |= WINEDDSD_CKSRCBLT;
3081             This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
3082         } else {
3083             /* Do not use color key */
3084             Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3085         }
3086
3087         /* Now load the surface */
3088         IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
3089
3090
3091         /* Activate the destination context, set it up for blitting */
3092         ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
3093         ENTER_GL();
3094
3095         if(!dstSwapchain) {
3096             TRACE("Drawing to offscreen buffer\n");
3097             glDrawBuffer(myDevice->offscreenBuffer);
3098             checkGLcall("glDrawBuffer");
3099         } else {
3100             GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This, (IWineD3DSwapChain *)dstSwapchain);
3101             TRACE("Drawing to %#x buffer\n", buffer);
3102             glDrawBuffer(buffer);
3103             checkGLcall("glDrawBuffer");
3104         }
3105
3106         /* Bind the texture */
3107         glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
3108         checkGLcall("glBindTexture");
3109
3110         /* Filtering for StretchRect */
3111         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
3112                         stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]);
3113         checkGLcall("glTexParameteri");
3114         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
3115                         minMipLookup[Filter][WINED3DTEXF_NONE]);
3116         checkGLcall("glTexParameteri");
3117         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
3118         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
3119         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3120         checkGLcall("glTexEnvi");
3121
3122         /* This is for color keying */
3123         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3124             glEnable(GL_ALPHA_TEST);
3125             checkGLcall("glEnable GL_ALPHA_TEST");
3126             glAlphaFunc(GL_NOTEQUAL, 0.0);
3127             checkGLcall("glAlphaFunc\n");
3128         } else {
3129             glDisable(GL_ALPHA_TEST);
3130             checkGLcall("glDisable GL_ALPHA_TEST");
3131         }
3132
3133         /* Draw a textured quad
3134          */
3135         glBegin(GL_QUADS);
3136
3137         glColor3d(1.0f, 1.0f, 1.0f);
3138         glTexCoord2f(glTexCoord[0], glTexCoord[2]);
3139         glVertex3f(rect.x1,
3140                     rect.y1,
3141                     0.0);
3142
3143         glTexCoord2f(glTexCoord[0], glTexCoord[3]);
3144         glVertex3f(rect.x1, rect.y2, 0.0);
3145
3146         glTexCoord2f(glTexCoord[1], glTexCoord[3]);
3147         glVertex3f(rect.x2,
3148                     rect.y2,
3149                     0.0);
3150
3151         glTexCoord2f(glTexCoord[1], glTexCoord[2]);
3152         glVertex3f(rect.x2,
3153                     rect.y1,
3154                     0.0);
3155         glEnd();
3156         checkGLcall("glEnd");
3157
3158         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3159             glDisable(GL_ALPHA_TEST);
3160             checkGLcall("glDisable(GL_ALPHA_TEST)");
3161         }
3162
3163         /* Unbind the texture */
3164         glBindTexture(GL_TEXTURE_2D, 0);
3165         checkGLcall("glEnable glBindTexture");
3166
3167         /* The draw buffer should only need to be restored if we were drawing to the front buffer, and there is a back buffer.
3168          * otherwise the context manager should choose between GL_BACK / offscreenDrawBuffer
3169          */
3170         if(dstSwapchain && This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && dstSwapchain->backBuffer) {
3171             glDrawBuffer(GL_BACK);
3172             checkGLcall("glDrawBuffer");
3173         }
3174         /* Restore the color key parameters */
3175         Src->CKeyFlags = oldCKeyFlags;
3176         This->SrcBltCKey = oldBltCKey;
3177
3178         LEAVE_GL();
3179
3180         /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3181         This->Flags &= ~SFLAG_INSYSMEM;
3182         /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3183          * is outdated now
3184          */
3185         if(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO) {
3186             This->Flags |= SFLAG_INDRAWABLE;
3187             This->Flags &= ~SFLAG_INTEXTURE;
3188         } else {
3189             This->Flags |= SFLAG_INTEXTURE;
3190         }
3191
3192         return WINED3D_OK;
3193     } else {
3194         /* Source-Less Blit to render target */
3195         if (Flags & WINEDDBLT_COLORFILL) {
3196             /* This is easy to handle for the D3D Device... */
3197             DWORD color;
3198
3199             TRACE("Colorfill\n");
3200
3201             /* The color as given in the Blt function is in the format of the frame-buffer...
3202              * 'clear' expect it in ARGB format => we need to do some conversion :-)
3203              */
3204             if (This->resource.format == WINED3DFMT_P8) {
3205                 if (This->palette) {
3206                     color = ((0xFF000000) |
3207                             (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
3208                             (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
3209                             (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
3210                 } else {
3211                     color = 0xFF000000;
3212                 }
3213             }
3214             else if (This->resource.format == WINED3DFMT_R5G6B5) {
3215                 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
3216                     color = 0xFFFFFFFF;
3217                 } else {
3218                     color = ((0xFF000000) |
3219                             ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
3220                             ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
3221                             ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
3222                 }
3223             }
3224             else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
3225                     (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
3226                 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
3227             }
3228             else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
3229                 color = DDBltFx->u5.dwFillColor;
3230             }
3231             else {
3232                 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
3233                 return WINED3DERR_INVALIDCALL;
3234             }
3235
3236             TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
3237             if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
3238                 glDrawBuffer(GL_BACK);
3239                 checkGLcall("glDrawBuffer(GL_BACK)");
3240             } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
3241                 glDrawBuffer(GL_FRONT);
3242                 checkGLcall("glDrawBuffer(GL_FRONT)");
3243             } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3244                 glDrawBuffer(myDevice->offscreenBuffer);
3245                 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)");
3246             } else {
3247                 TRACE("Surface is higher back buffer, falling back to software\n");
3248                 return WINED3DERR_INVALIDCALL;
3249             }
3250
3251             TRACE("(%p) executing Render Target override, color = %x\n", This, color);
3252
3253             IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
3254                                 1 /* Number of rectangles */,
3255                                 &rect,
3256                                 WINED3DCLEAR_TARGET,
3257                                 color,
3258                                 0.0 /* Z */,
3259                                 0 /* Stencil */);
3260
3261             /* Restore the original draw buffer */
3262             if(!dstSwapchain) {
3263                 glDrawBuffer(myDevice->offscreenBuffer);
3264             } else if(dstSwapchain->backBuffer && dstSwapchain->backBuffer[0]) {
3265                 glDrawBuffer(GL_BACK);
3266             }
3267             vcheckGLcall("glDrawBuffer");
3268
3269             return WINED3D_OK;
3270         }
3271     }
3272
3273     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3274     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3275     return WINED3DERR_INVALIDCALL;
3276 }
3277
3278 static HRESULT WINAPI IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx)
3279 {
3280     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3281     float depth;
3282
3283     if (Flags & WINEDDBLT_DEPTHFILL) {
3284         switch(This->resource.format) {
3285             case WINED3DFMT_D16:
3286                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff;
3287                 break;
3288             case WINED3DFMT_D15S1:
3289                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000fffe;
3290                 break;
3291             case WINED3DFMT_D24S8:
3292             case WINED3DFMT_D24X8:
3293                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff;
3294                 break;
3295             case WINED3DFMT_D32:
3296                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff;
3297                 break;
3298             default:
3299                 depth = 0.0;
3300                 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format));
3301         }
3302
3303         return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice,
3304                                     DestRect == NULL ? 0 : 1,
3305                                     (WINED3DRECT *) DestRect,
3306                                     WINED3DCLEAR_ZBUFFER,
3307                                     0x00000000,
3308                                     depth,
3309                                     0x00000000);
3310     }
3311
3312     FIXME("(%p): Unsupp depthstencil blit\n", This);
3313     return WINED3DERR_INVALIDCALL;
3314 }
3315
3316 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
3317     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3318     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3319     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3320     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3321     TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
3322
3323     /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
3324      * except depth blits, which seem to work
3325      */
3326     if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) {
3327         if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) {
3328             TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3329             return WINED3DERR_INVALIDCALL;
3330         } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
3331             TRACE("Z Blit override handled the blit\n");
3332             return WINED3D_OK;
3333         }
3334     }
3335
3336     /* Special cases for RenderTargets */
3337     if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3338         ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3339         if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK) return WINED3D_OK;
3340     }
3341
3342     /* For the rest call the X11 surface implementation.
3343      * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
3344      * other Blts are rather rare
3345      */
3346     return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
3347 }
3348
3349 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
3350     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3351     IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
3352     IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3353     TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
3354
3355     if(myDevice->inScene &&
3356        (iface == myDevice->stencilBufferTarget ||
3357        (Source && Source == myDevice->stencilBufferTarget))) {
3358         TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3359         return WINED3DERR_INVALIDCALL;
3360     }
3361
3362     /* Special cases for RenderTargets */
3363     if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3364         ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3365
3366         RECT SrcRect, DstRect;
3367         DWORD Flags=0;
3368
3369         if(rsrc) {
3370             SrcRect.left = rsrc->left;
3371             SrcRect.top= rsrc->top;
3372             SrcRect.bottom = rsrc->bottom;
3373             SrcRect.right = rsrc->right;
3374         } else {
3375             SrcRect.left = 0;
3376             SrcRect.top = 0;
3377             SrcRect.right = srcImpl->currentDesc.Width;
3378             SrcRect.bottom = srcImpl->currentDesc.Height;
3379         }
3380
3381         DstRect.left = dstx;
3382         DstRect.top=dsty;
3383         DstRect.right = dstx + SrcRect.right - SrcRect.left;
3384         DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
3385
3386         /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
3387         if(trans & WINEDDBLTFAST_SRCCOLORKEY)
3388             Flags |= WINEDDBLT_KEYSRC;
3389         if(trans & WINEDDBLTFAST_DESTCOLORKEY)
3390             Flags |= WINEDDBLT_KEYDEST;
3391         if(trans & WINEDDBLTFAST_WAIT)
3392             Flags |= WINEDDBLT_WAIT;
3393         if(trans & WINEDDBLTFAST_DONOTWAIT)
3394             Flags |= WINEDDBLT_DONOTWAIT;
3395
3396         if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK) return WINED3D_OK;
3397     }
3398
3399
3400     return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
3401 }
3402
3403 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3404     /** Check against the maximum texture sizes supported by the video card **/
3405     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3406     unsigned int pow2Width, pow2Height;
3407     const GlPixelFormatDesc *glDesc;
3408
3409     getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
3410     /* Setup some glformat defaults */
3411     This->glDescription.glFormat         = glDesc->glFormat;
3412     This->glDescription.glFormatInternal = glDesc->glInternal;
3413     This->glDescription.glType           = glDesc->glType;
3414
3415     This->glDescription.textureName      = 0;
3416     This->glDescription.target           = GL_TEXTURE_2D;
3417
3418     /* Non-power2 support */
3419     if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
3420         pow2Width = This->currentDesc.Width;
3421         pow2Height = This->currentDesc.Height;
3422     } else {
3423         /* Find the nearest pow2 match */
3424         pow2Width = pow2Height = 1;
3425         while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
3426         while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
3427     }
3428     This->pow2Width  = pow2Width;
3429     This->pow2Height = pow2Height;
3430
3431     if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
3432         WINED3DFORMAT Format = This->resource.format;
3433         /** TODO: add support for non power two compressed textures **/
3434         if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
3435             || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
3436             FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
3437                   This, This->currentDesc.Width, This->currentDesc.Height);
3438             return WINED3DERR_NOTAVAILABLE;
3439         }
3440     }
3441
3442     if(pow2Width != This->currentDesc.Width ||
3443        pow2Height != This->currentDesc.Height) {
3444         This->Flags |= SFLAG_NONPOW2;
3445     }
3446
3447     TRACE("%p\n", This);
3448     if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3449         /* one of three options
3450         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)
3451         2: Set the texture to the maximum size (bad idea)
3452         3:    WARN and return WINED3DERR_NOTAVAILABLE;
3453         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.
3454         */
3455         WARN("(%p) Creating an oversized surface\n", This);
3456         This->Flags |= SFLAG_OVERSIZE;
3457
3458         /* This will be initialized on the first blt */
3459         This->glRect.left = 0;
3460         This->glRect.top = 0;
3461         This->glRect.right = 0;
3462         This->glRect.bottom = 0;
3463     } else {
3464         /* No oversize, gl rect is the full texture size */
3465         This->Flags &= ~SFLAG_OVERSIZE;
3466         This->glRect.left = 0;
3467         This->glRect.top = 0;
3468         This->glRect.right = This->pow2Width;
3469         This->glRect.bottom = This->pow2Height;
3470     }
3471
3472     if(This->resource.allocatedMemory == NULL) {
3473         /* Make sure memory exists from the start, and it is initialized properly. D3D initializes surfaces,
3474          * gl does not, so we need to upload zeroes to init the gl texture.
3475          */
3476         This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + 4);
3477     }
3478     This->Flags |= SFLAG_INSYSMEM;
3479
3480     return WINED3D_OK;
3481 }
3482
3483 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3484 {
3485     /* IUnknown */
3486     IWineD3DBaseSurfaceImpl_QueryInterface,
3487     IWineD3DBaseSurfaceImpl_AddRef,
3488     IWineD3DSurfaceImpl_Release,
3489     /* IWineD3DResource */
3490     IWineD3DBaseSurfaceImpl_GetParent,
3491     IWineD3DBaseSurfaceImpl_GetDevice,
3492     IWineD3DBaseSurfaceImpl_SetPrivateData,
3493     IWineD3DBaseSurfaceImpl_GetPrivateData,
3494     IWineD3DBaseSurfaceImpl_FreePrivateData,
3495     IWineD3DBaseSurfaceImpl_SetPriority,
3496     IWineD3DBaseSurfaceImpl_GetPriority,
3497     IWineD3DSurfaceImpl_PreLoad,
3498     IWineD3DBaseSurfaceImpl_GetType,
3499     /* IWineD3DSurface */
3500     IWineD3DBaseSurfaceImpl_GetContainer,
3501     IWineD3DBaseSurfaceImpl_GetDesc,
3502     IWineD3DSurfaceImpl_LockRect,
3503     IWineD3DSurfaceImpl_UnlockRect,
3504     IWineD3DSurfaceImpl_GetDC,
3505     IWineD3DSurfaceImpl_ReleaseDC,
3506     IWineD3DSurfaceImpl_Flip,
3507     IWineD3DSurfaceImpl_Blt,
3508     IWineD3DBaseSurfaceImpl_GetBltStatus,
3509     IWineD3DBaseSurfaceImpl_GetFlipStatus,
3510     IWineD3DBaseSurfaceImpl_IsLost,
3511     IWineD3DBaseSurfaceImpl_Restore,
3512     IWineD3DSurfaceImpl_BltFast,
3513     IWineD3DBaseSurfaceImpl_GetPalette,
3514     IWineD3DBaseSurfaceImpl_SetPalette,
3515     IWineD3DBaseSurfaceImpl_RealizePalette,
3516     IWineD3DBaseSurfaceImpl_SetColorKey,
3517     IWineD3DBaseSurfaceImpl_GetPitch,
3518     IWineD3DSurfaceImpl_SetMem,
3519     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
3520     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
3521     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
3522     IWineD3DBaseSurfaceImpl_UpdateOverlay,
3523     IWineD3DBaseSurfaceImpl_SetClipper,
3524     IWineD3DBaseSurfaceImpl_GetClipper,
3525     /* Internal use: */
3526     IWineD3DSurfaceImpl_AddDirtyRect,
3527     IWineD3DSurfaceImpl_LoadTexture,
3528     IWineD3DSurfaceImpl_SaveSnapshot,
3529     IWineD3DBaseSurfaceImpl_SetContainer,
3530     IWineD3DSurfaceImpl_SetGlTextureDesc,
3531     IWineD3DSurfaceImpl_GetGlDesc,
3532     IWineD3DSurfaceImpl_GetData,
3533     IWineD3DSurfaceImpl_SetFormat,
3534     IWineD3DSurfaceImpl_PrivateSetup
3535 };