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