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