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