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