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