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