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