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