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