kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / wined3d / surface.c
1 /*
2  * IWineD3DSurface Implementation
3  *
4  * Copyright 2002-2005 Jason Edmeades
5  * Copyright 2002-2003 Raphael Junqueira
6  * Copyright 2004 Christian Costa
7  * Copyright 2005 Oliver Stieber
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26 #include "wined3d_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
29 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
30
31 /* *******************************************
32    IWineD3DSurface IUnknown parts follow
33    ******************************************* */
34 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
35 {
36     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
37     /* Warn ,but be nice about things */
38     TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
39     if (riid == NULL) {
40         ERR("Probably FIXME: Calling query interface with NULL riid\n");
41     }
42     if (IsEqualGUID(riid, &IID_IUnknown)
43         || IsEqualGUID(riid, &IID_IWineD3DResource)
44         || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
45         IUnknown_AddRef((IUnknown*)iface);
46         *ppobj = This;
47         return D3D_OK;
48     }
49     return E_NOINTERFACE;
50 }
51
52 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
53     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
54     ULONG ref = InterlockedIncrement(&This->resource.ref);
55     TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
56     return ref;
57 }
58
59 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
60     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
61     ULONG ref = InterlockedDecrement(&This->resource.ref);
62     TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
63     if (ref == 0) {
64         TRACE("(%p) : cleaning up\n", This);
65         if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
66             ENTER_GL();
67             TRACE("Deleting texture %d\n", This->glDescription.textureName);
68             glDeleteTextures(1, &This->glDescription.textureName);
69             LEAVE_GL();
70         }
71         IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
72
73         TRACE("(%p) Released\n", This);
74         HeapFree(GetProcessHeap(), 0, This);
75
76     }
77     return ref;
78 }
79
80 /* ****************************************************
81    IWineD3DSurface IWineD3DResource parts follow
82    **************************************************** */
83 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
84     return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
85 }
86
87 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
88     return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
89 }
90
91 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
92     return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
93 }
94
95 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
96     return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
97 }
98
99 DWORD   WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
100     return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
101 }
102
103 DWORD   WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
104     return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
105 }
106
107 void    WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
108     /* TODO: re-write the way textures and managed,
109     *  use a 'opengl context manager' to manage RenderTarget surfaces
110     ** *********************************************************/
111
112     /* TODO: check for locks */
113     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
114     IWineD3DBaseTexture *baseTexture = NULL;
115     TRACE("(%p)Checking to see if the container is a base texture\n", This);
116     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
117         TRACE("Passing to conatiner\n");
118         IWineD3DBaseTexture_PreLoad(baseTexture);
119         IWineD3DBaseTexture_Release(baseTexture);
120     } else {
121     TRACE("(%p) : About to load surface\n", This);
122     ENTER_GL();
123 #if 0 /* TODO: context manager support */
124      IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
125 #endif
126     glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
127     if (This->glDescription.level == 0 &&  This->glDescription.textureName == 0) {
128           glGenTextures(1, &This->glDescription.textureName);
129           checkGLcall("glGenTextures");
130           TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
131           glBindTexture(This->glDescription.target, This->glDescription.textureName);
132           checkGLcall("glBindTexture");
133           IWineD3DSurface_LoadTexture(iface);
134           /* This is where we should be reducing the amount of GLMemoryUsed */
135     } else {
136         if (This->glDescription.level == 0) {
137           glBindTexture(This->glDescription.target, This->glDescription.textureName);
138           checkGLcall("glBindTexture");
139           IWineD3DSurface_LoadTexture(iface);
140         } else  if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
141             /* assume this is a coding error not a real error for now */
142             FIXME("Mipmap surface has a glTexture bound to it!\n");
143         }
144     }
145     if (This->resource.pool == D3DPOOL_DEFAULT) {
146        /* Tell opengl to try and keep this texture in video ram (well mostly) */
147        GLclampf tmp;
148        tmp = 0.9f;
149         glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
150     }
151     /* TODO: disable texture support, if it wastn't enabled when we entered. */
152 #if 0 /* TODO: context manager support */
153      IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
154               /* we don't care when the state is disabled(if atall) */);
155 #endif
156     LEAVE_GL();
157     }
158     return;
159 }
160
161 D3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
162     TRACE("(%p) : calling resourceimpl_GetType\n", iface);
163     return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
164 }
165
166 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
167     TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
168     return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
169 }
170
171 /* ******************************************************
172    IWineD3DSurface IWineD3DSurface parts follow
173    ****************************************************** */
174
175 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
176     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
177     HRESULT hr;
178     if (ppContainer == NULL) {
179             ERR("Get container called witout a null ppContainer\n");
180         return E_NOINTERFACE;
181     }
182     TRACE("(%p) : Relaying to queryInterface %p %p\n", This, ppContainer, *ppContainer);
183     /** From MSDN:
184      * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
185      * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
186      * GetContainer will return the Direct3D device used to create the surface.
187      */
188     hr = IUnknown_QueryInterface(This->container, riid, ppContainer);
189     return hr;
190 }
191
192 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
193     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
194
195     TRACE("(%p) : copying into %p\n", This, pDesc);
196     if(pDesc->Format != NULL)             *(pDesc->Format) = This->resource.format;
197     if(pDesc->Type != NULL)               *(pDesc->Type)   = This->resource.resourceType;
198     if(pDesc->Usage != NULL)              *(pDesc->Usage)              = This->resource.usage;
199     if(pDesc->Pool != NULL)               *(pDesc->Pool)               = This->resource.pool;
200     if(pDesc->Size != NULL)               *(pDesc->Size)               = This->resource.size;   /* dx8 only */
201     if(pDesc->MultiSampleType != NULL)    *(pDesc->MultiSampleType)    = This->currentDesc.MultiSampleType;
202     if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
203     if(pDesc->Width != NULL)              *(pDesc->Width)              = This->currentDesc.Width;
204     if(pDesc->Height != NULL)             *(pDesc->Height)             = This->currentDesc.Height;
205     return D3D_OK;
206 }
207
208 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
209     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
210     TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
211     if (This->glDescription.textureName == 0 && textureName != 0) {
212         This->Dirty = TRUE;
213         IWineD3DSurface_AddDirtyRect(iface, NULL);
214     }
215     This->glDescription.textureName = textureName;
216     This->glDescription.target      = target;
217 }
218
219 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
220     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
221     TRACE("(%p) : returning %p\n", This, &This->glDescription);
222     *glDescription = &This->glDescription;
223 }
224
225 /* TODO: think about moving this down to resource? */
226 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
227     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
228     /* 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  */
229     if (This->resource.pool != D3DPOOL_SYSTEMMEM) {
230         FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
231     }
232     return (CONST void*)(This->resource.allocatedMemory);
233 }
234
235 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
236     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
237     IWineD3DDeviceImpl  *myDevice = This->resource.wineD3DDevice;
238     IWineD3DSwapChainImpl *swapchain = NULL;
239     static UINT messages = 0; /* holds flags to disable fixme messages */
240
241     /* fixme: should we really lock as such? */
242     if (This->inTexture && This->inPBuffer) {
243         FIXME("Warning: Surface is in texture memory or pbuffer\n");
244         This->inTexture = 0;
245         This->inPBuffer = 0;
246     }
247
248     if (FALSE == This->lockable) {
249         /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
250               texture regions, and since the destination is an unlockable region we need
251               to tolerate this                                                           */
252         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
253         /*return D3DERR_INVALIDCALL; */
254     }
255
256     if (This->resource.usage & D3DUSAGE_RENDERTARGET) {
257         IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
258
259         if (swapchain != NULL ||  iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
260             if (swapchain != NULL && iface ==  swapchain->backBuffer) {
261                 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
262             } else if (swapchain != NULL && iface ==  swapchain->frontBuffer) {
263                 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
264             } else if (iface == myDevice->renderTarget) {
265                 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
266             } else if (iface == myDevice->depthStencilBuffer) {
267                 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
268             }
269
270             if (NULL != swapchain) {
271                 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
272             }
273             swapchain = NULL;
274         }
275     } else {
276         TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
277     }
278
279     /* DXTn formats don't have exact pitches as they are to the new row of blocks,
280          where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
281           ie pitch = (width/4) * bytes per block                                  */
282     if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
283         pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 3;
284     else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
285              This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
286         pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 4;
287     else {
288         if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & D3DUSAGE_RENDERTARGET) {
289             /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
290             pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width;  /* Bytes / row */
291         } else {
292             pLockedRect->Pitch = This->bytesPerPixel * This->pow2Width;
293         }
294     }
295
296     if (NULL == pRect) {
297         pLockedRect->pBits = This->resource.allocatedMemory;
298         This->lockedRect.left   = 0;
299         This->lockedRect.top    = 0;
300         This->lockedRect.right  = This->currentDesc.Width;
301         This->lockedRect.bottom = This->currentDesc.Height;
302         TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
303     } else {
304         TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
305
306         if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
307             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
308         } else {
309             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
310         }
311         This->lockedRect.left   = pRect->left;
312         This->lockedRect.top    = pRect->top;
313         This->lockedRect.right  = pRect->right;
314         This->lockedRect.bottom = pRect->bottom;
315     }
316
317     if (This->nonpow2) {
318         TRACE("Locking non-power 2 texture\n");
319     }
320
321     if (0 == This->resource.usage || This->resource.usage & D3DUSAGE_DYNAMIC) {
322         /* classic surface  TODO: non 2d surfaces?
323         These resources may be POOL_SYSTEMMEM, so they must not access the device */
324         TRACE("locking an ordinarary surface\n");
325         /* Check to see if memory has already been allocated from the surface*/
326         if (NULL == This->resource.allocatedMemory) { /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
327             /* Non-system memory surfaces */
328
329             /*Surface has no memory currently allocated to it!*/
330             TRACE("(%p) Locking rect\n" , This);
331             This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
332             if (0 != This->glDescription.textureName) {
333                 /* Now I have to copy thing bits back */
334                 This->activeLock = TRUE; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
335                 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
336                 ENTER_GL();
337     
338                 /* Make sure that the texture is loaded */
339                 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
340     
341                 TRACE("(%p) glGetTexImage level(%d), fmt(%d), typ(%d), mem(%p)\n" , This, This->glDescription.level,  This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
342     
343                 if (This->resource.format == WINED3DFMT_DXT1 ||
344                     This->resource.format == WINED3DFMT_DXT2 ||
345                     This->resource.format == WINED3DFMT_DXT3 ||
346                     This->resource.format == WINED3DFMT_DXT4 ||
347                     This->resource.format == WINED3DFMT_DXT5) {
348                     TRACE("Locking a compressed texture\n");
349                     if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
350                         GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
351                                                             This->glDescription.level,
352                                                             This->resource.allocatedMemory);
353     
354                     } else {
355                         FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
356                     }
357                 } else {
358                     glGetTexImage(This->glDescription.target,
359                                 This->glDescription.level,
360                                 This->glDescription.glFormat,
361                                 This->glDescription.glType,
362                                 This->resource.allocatedMemory);
363                     vcheckGLcall("glGetTexImage");
364                     if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
365                         /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
366                         the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
367                         repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
368         
369                         Were doing this...
370         
371                         instead of boxing the texture :
372                         |<-texture width ->|  -->pow2width|   /\
373                         |111111111111111111|              |   |
374                         |222 Texture 222222| boxed empty  | texture height
375                         |3333 Data 33333333|              |   |
376                         |444444444444444444|              |   \/
377                         -----------------------------------   |
378                         |     boxed  empty | boxed empty  | pow2height
379                         |                  |              |   \/
380                         -----------------------------------
381         
382         
383                         were repacking the data to the expected texture width
384         
385                         |<-texture width ->|  -->pow2width|   /\
386                         |111111111111111111222222222222222|   |
387                         |222333333333333333333444444444444| texture height
388                         |444444                           |   |
389                         |                                 |   \/
390                         |                                 |   |
391                         |            empty                | pow2height
392                         |                                 |   \/
393                         -----------------------------------
394         
395                         == is the same as
396         
397                         |<-texture width ->|    /\
398                         |111111111111111111|
399                         |222222222222222222|texture height
400                         |333333333333333333|
401                         |444444444444444444|    \/
402                         --------------------
403         
404                         this also means that any references to allocatedMemory should work with the data as if were a standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
405         
406                         internally the texture is still stored in a boxed format so any references to textureName will get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
407                         */
408                         if (This->nonpow2) {
409                             BYTE* dataa, *datab;
410                             int pitcha = 0, pitchb = 0;
411                             int y;
412                             pitcha = This->bytesPerPixel * This->currentDesc.Width;
413                             pitchb = This->bytesPerPixel * This->pow2Width;
414                             datab = dataa = This->resource.allocatedMemory;
415                             FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
416                             for (y = 1 ; y < This->currentDesc.Height; y++) {
417                                 dataa += pitcha; /* skip the first row */
418                                 datab += pitchb;
419                                 memcpy(dataa, datab, pitcha);
420                             }
421                         }
422                     }
423                 }
424                 LEAVE_GL();
425             }
426         } else { /* Nothing to do */
427             TRACE("Memory %p already allocted for texture\n",  This->resource.allocatedMemory);
428         }
429
430         if (NULL == pRect) {
431             pLockedRect->pBits = This->resource.allocatedMemory;
432         }  else{
433             if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
434                 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
435             } else {
436                 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
437             }
438         }
439
440     } else if (D3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
441
442         GLint  prev_store;
443         GLint  prev_read;
444         BOOL notInContext = FALSE;
445         IWineD3DSwapChainImpl *targetSwapChain = NULL;
446
447
448         ENTER_GL();
449
450             /**
451              * for render->surface copy begin to begin of allocatedMemory
452              * unlock can be more easy
453              */
454
455         TRACE("locking a render target\n");
456
457         if (This->resource.allocatedMemory == NULL)
458                 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
459
460         This->activeLock = TRUE; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
461         pLockedRect->pBits = This->resource.allocatedMemory;
462
463         glFlush();
464         vcheckGLcall("glFlush");
465         glGetIntegerv(GL_READ_BUFFER, &prev_read);
466         vcheckGLcall("glIntegerv");
467         glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
468         vcheckGLcall("glIntegerv");
469
470  /* Here's what we have to do:
471             See if the swapchain has the same context as the renderTarget or the surface is the render target.
472             Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
473             and use the front back buffer as required.
474             if not, we need to switch contexts and then switchback at the end.
475          */
476         IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
477         IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
478
479         /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
480         if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
481                 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
482                     TRACE("locking back buffer\n");
483                    glReadBuffer(GL_BACK);
484                 } else if (iface == swapchain->frontBuffer) {
485                    TRACE("locking front\n");
486                    glReadBuffer(GL_FRONT);
487                 } else if (iface == myDevice->depthStencilBuffer) {
488                     FIXME("Stencil Buffer lock unsupported for now\n");
489                 } else {
490                    FIXME("(%p) Shouldn't have got here!\n", This);
491                    glReadBuffer(GL_BACK);
492                 }
493         } else if (swapchain != NULL) {
494             IWineD3DSwapChainImpl *implSwapChain;
495             IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
496             if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
497                     /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
498                     if (iface == swapchain->backBuffer) {
499                         glReadBuffer(GL_BACK);
500                     } else if (iface == swapchain->frontBuffer) {
501                         glReadBuffer(GL_FRONT);
502                     } else if (iface == myDevice->depthStencilBuffer) {
503                         FIXME("Stencil Buffer lock unsupported for now\n");
504                     } else {
505                         FIXME("Should have got here!\n");
506                         glReadBuffer(GL_BACK);
507                     }
508             } else {
509                 /* We need to switch contexts to be able to read the buffer!!! */
510                 FIXME("The buffer requested isn't in the current openGL context\n");
511                 notInContext = TRUE;
512                 /* TODO: check the contexts, to see if were shared with the current context */
513             }
514             IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
515         }
516         if (swapchain != NULL)       IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
517         if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
518
519
520         /** the depth stencil in openGL has a format of GL_FLOAT
521         * which should be good for WINED3DFMT_D16_LOCKABLE
522         * and WINED3DFMT_D16
523         * it is unclear what format the stencil buffer is in except.
524         * 'Each index is converted to fixed point...
525         * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
526         * mappings in the table GL_PIXEL_MAP_S_TO_S.
527         * glReadPixels(This->lockedRect.left,
528         *             This->lockedRect.bottom - j - 1,
529         *             This->lockedRect.right - This->lockedRect.left,
530         *             1,
531         *             GL_DEPTH_COMPONENT,
532         *             type,
533         *             (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
534             *****************************************/
535         if (!notInContext) { /* Only read the buffer if it's in the current context */
536             long j;
537 #if 0
538             /* Bizarly it takes 120 millseconds to get an 800x600 region a line at a time, but only 10 to get the whole lot every time,
539             *  This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
540             *  run ten times faster!
541             * ************************************/
542             BOOL ati_performance_hack = FALSE;
543             ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
544 #endif
545             if ((This->lockedRect.left == 0 &&  This->lockedRect.top == 0 &&
546                 This->lockedRect.right == This->currentDesc.Width
547                 && This->lockedRect.bottom ==  This->currentDesc.Height)) {
548                     glReadPixels(0, 0,
549                     This->currentDesc.Width,
550                     This->currentDesc.Height,
551                     This->glDescription.glFormat,
552                     This->glDescription.glType,
553                     (char *)pLockedRect->pBits);
554             } else if (This->lockedRect.left == 0 &&  This->lockedRect.right == This->currentDesc.Width) {
555                     glReadPixels(0,
556                     This->lockedRect.top,
557                     This->currentDesc.Width,
558                     This->currentDesc.Height,
559                     This->glDescription.glFormat,
560                     This->glDescription.glType,
561                     (char *)pLockedRect->pBits);
562             } else{
563
564                 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
565                     glReadPixels(This->lockedRect.left, 
566                                  This->lockedRect.bottom - j - 1, 
567                                  This->lockedRect.right - This->lockedRect.left, 
568                                  1,
569                                  This->glDescription.glFormat,
570                                  This->glDescription.glType,
571                                  (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
572
573                 }
574             }
575             vcheckGLcall("glReadPixels");
576             TRACE("Resetting buffer\n");
577             glReadBuffer(prev_read);
578             vcheckGLcall("glReadBuffer");
579         }
580         LEAVE_GL();
581
582     } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
583
584         if (!messages & 1) {
585             FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
586             /*
587
588             glReadPixels(This->lockedRect.left,
589             This->lockedRect.bottom - j - 1,
590             This->lockedRect.right - This->lockedRect.left,
591             1,
592             GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
593
594             )
595             */
596             messages |= 1;
597         }
598     } else {
599         FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
600     }
601
602     if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
603         /* Don't dirtify */
604     } else {
605         IWineD3DBaseTexture *pBaseTexture;
606         /**
607          * Dirtify on lock
608          * as seen in msdn docs
609          */
610         IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
611
612         /** Dirtify Container if needed */
613         if (D3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
614             TRACE("Making container dirty\n");
615             IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
616             IWineD3DBaseTexture_Release(pBaseTexture);
617         } else {
618             TRACE("Surface is standalone, no need to dirty the container\n");
619         }
620     }
621
622     TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
623
624     This->locked = TRUE;
625     return D3D_OK;
626 }
627
628 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
629     GLint skipBytes = 0;
630     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
631     IWineD3DDeviceImpl  *myDevice = This->resource.wineD3DDevice;
632     const char *buffername = "";
633     IWineD3DSwapChainImpl *swapchain = NULL;
634
635     if (FALSE == This->locked) {
636         WARN("trying to Unlock an unlocked surf@%p\n", This);
637         return D3DERR_INVALIDCALL;
638     }
639
640     if (D3DUSAGE_RENDERTARGET & This->resource.usage) {
641         IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
642
643         if ((swapchain != NULL) &&  iface ==  swapchain->backBuffer) {
644                 buffername = "backBuffer";
645         } else if ((swapchain != NULL) && iface ==  swapchain->frontBuffer) {
646                 buffername = "frontBuffer";
647         } else if (iface == myDevice->depthStencilBuffer) {
648                 buffername = "depthStencilBuffer";
649         } else if (iface == myDevice->renderTarget) {
650                 buffername = "renderTarget";
651         }
652     }
653
654     if (swapchain != NULL) {
655         IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
656     }
657
658     TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Dirty);
659
660     if (FALSE == This->Dirty) {
661         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
662         goto unlock_end;
663     }
664
665     if (0 == This->resource.usage) { /* classic surface */
666         /**
667          * nothing to do
668          * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
669          */
670     } else if (D3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
671
672         /****************************
673         * TODO: Render targets are 'special' and
674         * ?some? locking needs to be passed onto the context manager
675         * so that it becomes possible to use auxiliary buffers, pbuffers
676         * render-to-texture, shared, cached contexts etc...
677         * ****************************/
678         IWineD3DSwapChainImpl *implSwapChain;
679         IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
680
681         if (iface ==  implSwapChain->backBuffer || iface ==  implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
682             GLint  prev_store;
683             GLint  prev_draw;
684             GLint  prev_rasterpos[4];
685
686             ENTER_GL();
687
688             glFlush();
689             vcheckGLcall("glFlush");
690             glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
691             vcheckGLcall("glIntegerv");
692             glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
693             vcheckGLcall("glIntegerv");
694             glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
695             vcheckGLcall("glIntegerv");
696             glPixelZoom(1.0, -1.0);
697             vcheckGLcall("glPixelZoom");
698
699             /* glDrawPixels transforms the raster position as though it was a vertex -
700                we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
701                per drawprim (and leave set - it will sort itself out due to last_was_rhw */
702             if (!myDevice->last_was_rhw) {
703
704                 double X, Y, height, width, minZ, maxZ;
705                 myDevice->last_was_rhw = TRUE;
706
707                 /* Transformed already into viewport coordinates, so we do not need transform
708                    matrices. Reset all matrices to identity and leave the default matrix in world
709                    mode.                                                                         */
710                 glMatrixMode(GL_MODELVIEW);
711                 checkGLcall("glMatrixMode");
712                 glLoadIdentity();
713                 checkGLcall("glLoadIdentity");
714
715                 glMatrixMode(GL_PROJECTION);
716                 checkGLcall("glMatrixMode");
717                 glLoadIdentity();
718                 checkGLcall("glLoadIdentity");
719
720                 /* Set up the viewport to be full viewport */
721                 X      = myDevice->stateBlock->viewport.X;
722                 Y      = myDevice->stateBlock->viewport.Y;
723                 height = myDevice->stateBlock->viewport.Height;
724                 width  = myDevice->stateBlock->viewport.Width;
725                 minZ   = myDevice->stateBlock->viewport.MinZ;
726                 maxZ   = myDevice->stateBlock->viewport.MaxZ;
727                 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
728                 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
729                 checkGLcall("glOrtho");
730
731                 /* Window Coord 0 is the middle of the first pixel, so translate by half
732                    a pixel (See comment above glTranslate below)                         */
733                 glTranslatef(0.5, 0.5, 0);
734                 checkGLcall("glTranslatef(0.5, 0.5, 0)");
735             }
736
737             if (iface ==  implSwapChain->backBuffer || iface == myDevice->renderTarget) {
738                 glDrawBuffer(GL_BACK);
739             } else if (iface ==  implSwapChain->frontBuffer) {
740                 glDrawBuffer(GL_FRONT);
741             }
742
743             vcheckGLcall("glDrawBuffer");
744
745             /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
746             glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
747             glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
748
749             /* And back buffers are not blended */
750             glDisable(GL_BLEND);
751
752             glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
753             vcheckGLcall("glRasterPos2f");
754             switch (This->resource.format) {
755             case WINED3DFMT_X4R4G4B4:
756                 {
757                     int size;
758                     unsigned short *data;
759                     data = (unsigned short *)This->resource.allocatedMemory;
760                     size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
761                     while(size > 0) {
762                             *data |= 0xF000;
763                             data++;
764                             size--;
765                     }
766                 }
767             case WINED3DFMT_A4R4G4B4:
768                 {
769                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
770                                  GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, This->resource.allocatedMemory);
771                     vcheckGLcall("glDrawPixels");
772                 }
773                 break;
774             case WINED3DFMT_R5G6B5:
775                 {
776                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
777                                  GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
778                     vcheckGLcall("glDrawPixels");
779                 }
780                 break;
781             case WINED3DFMT_X1R5G5B5:
782                 {
783                     int size;
784                     unsigned short *data;
785                     data = (unsigned short *)This->resource.allocatedMemory;
786                     size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
787                     while(size > 0) {
788                             *data |= 0x8000;
789                             data++;
790                             size--;
791                     }
792                 }
793             case WINED3DFMT_A1R5G5B5:
794                 {
795                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
796                                  GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
797                     vcheckGLcall("glDrawPixels");
798                 }
799                 break;
800             case WINED3DFMT_R8G8B8:
801                 {
802                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
803                                  GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
804                     vcheckGLcall("glDrawPixels");
805                 }
806                 break;
807             case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it 
808                                         could be any random value this fixes the intro move in Pirates! */
809                 {
810                     int size;
811                     unsigned int *data;
812                     data = (unsigned int *)This->resource.allocatedMemory;
813                     size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
814                     while(size > 0) {
815                             *data |= 0xFF000000;
816                             data++;
817                             size--;
818                     }
819                 }
820             case WINED3DFMT_A8R8G8B8:
821                 {
822                     glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
823                     vcheckGLcall("glPixelStorei");
824                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
825                                  GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
826                     vcheckGLcall("glDrawPixels");
827                     glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
828                     vcheckGLcall("glPixelStorei");
829                 }
830                 break;
831             case WINED3DFMT_A2R10G10B10:
832                 {
833                     glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
834                     vcheckGLcall("glPixelStorei");
835                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
836                                  GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
837                     vcheckGLcall("glDrawPixels");
838                     glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
839                     vcheckGLcall("glPixelStorei");
840                 }
841                 break;
842             default:
843                 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
844             }
845
846             glPixelZoom(1.0,1.0);
847             vcheckGLcall("glPixelZoom");
848             glDrawBuffer(prev_draw);
849             vcheckGLcall("glDrawBuffer");
850             glRasterPos3iv(&prev_rasterpos[0]);
851             vcheckGLcall("glRasterPos3iv");
852
853             /* Reset to previous pack row length / blending state */
854             glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
855             if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
856
857             LEAVE_GL();
858
859             /** restore clean dirty state */
860             IWineD3DSurface_CleanDirtyRect(iface);
861
862         } else {
863             FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
864         }
865         IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
866
867     } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
868
869         if (iface == myDevice->depthStencilBuffer) {
870             FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
871         } else {
872             FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
873         }
874
875     } else {
876         FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
877     }
878
879     unlock_end:
880     This->locked = FALSE;
881     memset(&This->lockedRect, 0, sizeof(RECT));
882     return D3D_OK;
883 }
884
885 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
886     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
887     FIXME("No support for GetDC yet for surface %p\n", This);
888     return D3DERR_INVALIDCALL;
889 }
890
891 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
892     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
893     FIXME("No support for ReleaseDC yet for surface %p\n", This);
894     return D3DERR_INVALIDCALL;
895 }
896
897 /* ******************************************************
898    IWineD3DSurface Internal (No mapping to directx api) parts follow
899    ****************************************************** */
900 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
901     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
902
903     if (This->inTexture) {
904         TRACE("Surface already in texture\n");
905         return D3D_OK;
906     }
907     if (This->Dirty == FALSE) {
908         TRACE("surface isn't dirty\n");
909         return D3D_OK;
910     }
911
912     This->Dirty = FALSE;
913
914     /* Resources are placed in system RAM and do not need to be recreated when a device is lost. These resources are not bound by device size or format restrictions. Because of this, these resources cannot be accessed by the Direct3D device nor set as textures or render targets. However, these resources can always be created, locked, and copied. */
915     if (This->resource.pool == D3DPOOL_SCRATCH || This->resource.pool == D3DPOOL_SYSTEMMEM) /*never store scratch or system mem textures in the video ram*/
916     {
917         FIXME("(%p) Operation not supported for scratch or SYSTEMMEM textures\n",This);
918         return D3DERR_INVALIDCALL;
919     }
920
921     if (This->inPBuffer) {
922         ENTER_GL();
923
924         if (This->glDescription.level != 0)
925             FIXME("Surface in texture is only supported for level 0\n");
926         else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
927                  This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
928                  This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
929                  This->resource.format == WINED3DFMT_DXT5)
930             FIXME("Format %d not supported\n", This->resource.format);
931         else {
932             GLint prevRead;
933             glGetIntegerv(GL_READ_BUFFER, &prevRead);
934             vcheckGLcall("glGetIntegerv");
935             glReadBuffer(GL_BACK);
936             vcheckGLcall("glReadBuffer");
937
938             glCopyTexImage2D(This->glDescription.target,
939                              This->glDescription.level,
940                              This->glDescription.glFormatInternal,
941                              0,
942                              0,
943                              This->currentDesc.Width,
944                              This->currentDesc.Height,
945                              0);
946
947             checkGLcall("glCopyTexImage2D");
948             glReadBuffer(prevRead);
949             vcheckGLcall("glReadBuffer");
950             TRACE("Updating target %d\n", This->glDescription.target);
951             This->inTexture = TRUE;
952         }
953         LEAVE_GL();
954         return D3D_OK;
955     }
956
957     if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
958         !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
959         /**
960          * wanted a paletted texture and not really support it in HW
961          * so software emulation code begin
962          */
963         UINT i;
964         PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
965         VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
966         BYTE* dst = (BYTE*) surface;
967         BYTE* src = (BYTE*) This->resource.allocatedMemory;
968
969         for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
970             BYTE color = *src++;
971             *dst++ = pal[color].peRed;
972             *dst++ = pal[color].peGreen;
973             *dst++ = pal[color].peBlue;
974             if (This->resource.format == WINED3DFMT_A8P8)
975                 *dst++ = pal[color].peFlags;
976             else
977                 *dst++ = 0xFF;
978         }
979
980         ENTER_GL();
981
982         TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
983               This->glDescription.target,
984               This->glDescription.level,
985               GL_RGBA,
986               This->currentDesc.Width,
987               This->currentDesc.Height,
988               0,
989               GL_RGBA,
990               GL_UNSIGNED_BYTE,
991               surface);
992         glTexImage2D(This->glDescription.target,
993                      This->glDescription.level,
994                      GL_RGBA,
995                      This->currentDesc.Width,
996                      This->currentDesc.Height,
997                      0,
998                      GL_RGBA,
999                      GL_UNSIGNED_BYTE,
1000                      surface);
1001         checkGLcall("glTexImage2D");
1002         HeapFree(GetProcessHeap(), 0, surface);
1003
1004         LEAVE_GL();
1005
1006         return D3D_OK;
1007     }
1008
1009     /* TODO: Compressed non-power 2 support */
1010
1011     if (This->resource.format == WINED3DFMT_DXT1 ||
1012         This->resource.format == WINED3DFMT_DXT2 ||
1013         This->resource.format == WINED3DFMT_DXT3 ||
1014         This->resource.format == WINED3DFMT_DXT4 ||
1015         This->resource.format == WINED3DFMT_DXT5) {
1016         if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1017             TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1018                   This->glDescription.target,
1019                   This->glDescription.level,
1020                   This->glDescription.glFormatInternal,
1021                   This->currentDesc.Width,
1022                   This->currentDesc.Height,
1023                   0,
1024                   This->resource.size,
1025                   This->resource.allocatedMemory);
1026
1027             ENTER_GL();
1028
1029             GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1030                                                   This->glDescription.level,
1031                                                   This->glDescription.glFormatInternal,
1032                                                   This->currentDesc.Width,
1033                                                   This->currentDesc.Height,
1034                                                   0,
1035                                                   This->resource.size,
1036                                                   This->resource.allocatedMemory);
1037             checkGLcall("glCommpressedTexTexImage2D");
1038
1039             LEAVE_GL();
1040
1041             if(This->activeLock == FALSE){
1042                 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1043                 This->resource.allocatedMemory = NULL;
1044             }
1045
1046         } else {
1047             FIXME("Using DXT1/3/5 without advertized support\n");
1048         }
1049     } else {
1050
1051        /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1052         if (NP2_REPACK == wined3d_settings.nonpower2_mode && This->nonpow2 == TRUE) {
1053
1054
1055             TRACE("non power of two support\n");
1056             ENTER_GL();
1057             TRACE("(%p) Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n", This,
1058                 This->glDescription.target,
1059                 This->glDescription.level,
1060                 debug_d3dformat(This->resource.format),
1061                 This->glDescription.glFormatInternal,
1062                 This->pow2Width,
1063                 This->pow2Height,
1064                 0,
1065                 This->glDescription.glFormat,
1066                 This->glDescription.glType,
1067                 NULL);
1068
1069             glTexImage2D(This->glDescription.target,
1070                          This->glDescription.level,
1071                          This->glDescription.glFormatInternal,
1072                          This->pow2Width,
1073                          This->pow2Height,
1074                          0/*border*/,
1075                          This->glDescription.glFormat,
1076                          This->glDescription.glType,
1077                          NULL);
1078
1079             checkGLcall("glTexImage2D");
1080             if (This->resource.allocatedMemory != NULL) {
1081                 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1082                 /* And map the non-power two data into the top left corner */
1083                 glTexSubImage2D(
1084                     This->glDescription.target,
1085                     This->glDescription.level,
1086                     0 /* xoffset */,
1087                     0 /* ysoffset */ ,
1088                     This->currentDesc.Width,
1089                     This->currentDesc.Height,
1090                     This->glDescription.glFormat,
1091                     This->glDescription.glType,
1092                     This->resource.allocatedMemory
1093                 );
1094                 checkGLcall("glTexSubImage2D");
1095             }
1096             LEAVE_GL();
1097
1098         } else {
1099
1100             TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1101                 This->glDescription.target,
1102                 This->glDescription.level,
1103                 debug_d3dformat(This->resource.format),
1104                 This->glDescription.glFormatInternal,
1105                 This->pow2Width,
1106                 This->pow2Height,
1107                 0,
1108                 This->glDescription.glFormat,
1109                 This->glDescription.glType,
1110                 This->resource.allocatedMemory);
1111
1112             ENTER_GL();
1113             glTexImage2D(This->glDescription.target,
1114                         This->glDescription.level,
1115                         This->glDescription.glFormatInternal,
1116                         This->pow2Width,
1117                         This->pow2Height,
1118                         0 /* border */,
1119                         This->glDescription.glFormat,
1120                         This->glDescription.glType,
1121                         This->resource.allocatedMemory);
1122             checkGLcall("glTexImage2D");
1123             LEAVE_GL();
1124         }
1125
1126 #if 0
1127         {
1128             static unsigned int gen = 0;
1129             char buffer[4096];
1130             ++gen;
1131             if ((gen % 10) == 0) {
1132                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1133                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1134             }
1135             /*
1136              * debugging crash code
1137             if (gen == 250) {
1138               void** test = NULL;
1139               *test = 0;
1140             }
1141             */
1142         }
1143 #endif
1144         if(This->activeLock == FALSE){
1145             HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1146             This->resource.allocatedMemory = NULL;
1147         }
1148
1149     }
1150
1151     return D3D_OK;
1152 }
1153
1154 #include <errno.h>
1155 #include <stdio.h>
1156 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1157     FILE* f = NULL;
1158     UINT i, y;
1159     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1160     char *allocatedMemory;
1161     char *textureRow;
1162     IWineD3DSwapChain *swapChain = NULL;
1163     int width, height;
1164     GLuint tmpTexture;
1165     DWORD color;
1166     /*FIXME:
1167     Textures my not be stored in ->allocatedgMemory and a GlTexture
1168     so we should lock the surface before saving a snapshot, or at least check that
1169     */
1170     /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1171     by calling GetTexImage and in compressed form by calling
1172     GetCompressedTexImageARB.  Queried compressed images can be saved and
1173     later reused by calling CompressedTexImage[123]DARB.  Pre-compressed
1174     texture images do not need to be processed by the GL and should
1175     significantly improve texture loading performance relative to uncompressed
1176     images. */
1177
1178 /* Setup the width and height to be the internal texture width and height. */
1179     width  = This->pow2Width;
1180     height = This->pow2Height;
1181 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1182     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1183
1184     if (swapChain || This->inPBuffer) { /* if were not a real texture then read the back buffer into a real texture*/
1185 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1186         GLint prevRead;
1187         ENTER_GL();
1188         FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1189         glEnable(GL_TEXTURE_2D);
1190
1191         glGenTextures(1, &tmpTexture);
1192         glBindTexture(GL_TEXTURE_2D, tmpTexture);
1193
1194         glTexImage2D(GL_TEXTURE_2D,
1195                         0,
1196                         GL_RGBA,
1197                         width,
1198                         height,
1199                         0/*border*/,
1200                         GL_RGBA,
1201                         GL_UNSIGNED_INT_8_8_8_8_REV,
1202                         NULL);
1203
1204         glGetIntegerv(GL_READ_BUFFER, &prevRead);
1205         vcheckGLcall("glGetIntegerv");
1206         glReadBuffer(GL_BACK);
1207         vcheckGLcall("glReadBuffer");
1208         glCopyTexImage2D(GL_TEXTURE_2D,
1209                             0,
1210                             GL_RGBA,
1211                             0,
1212                             0,
1213                             width,
1214                             height,
1215                             0);
1216
1217         checkGLcall("glCopyTexImage2D");
1218         glReadBuffer(prevRead);
1219         LEAVE_GL();
1220
1221     } else { /* bind the real texture */
1222         IWineD3DSurface_PreLoad(iface);
1223     }
1224     allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width  * height * 4);
1225     ENTER_GL();
1226     FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1227     glGetTexImage(GL_TEXTURE_2D,
1228                 This->glDescription.level,
1229                 GL_RGBA,
1230                 GL_UNSIGNED_INT_8_8_8_8_REV,
1231                 allocatedMemory);
1232     checkGLcall("glTexImage2D");
1233     if (tmpTexture) {
1234         glBindTexture(GL_TEXTURE_2D, 0);
1235         glDeleteTextures(1, &tmpTexture);
1236     }
1237     LEAVE_GL();
1238
1239     f = fopen(filename, "w+");
1240     if (NULL == f) {
1241         ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1242         return D3DERR_INVALIDCALL;
1243     }
1244 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1245     TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1246 /* TGA header */
1247     fputc(0,f);
1248     fputc(0,f);
1249     fputc(2,f);
1250     fputc(0,f);
1251     fputc(0,f);
1252     fputc(0,f);
1253     fputc(0,f);
1254     fputc(0,f);
1255     fputc(0,f);
1256     fputc(0,f);
1257     fputc(0,f);
1258     fputc(0,f);
1259 /* short width*/
1260     fwrite(&width,2,1,f);
1261 /* short height */
1262     fwrite(&height,2,1,f);
1263 /* format rgba */
1264     fputc(0x20,f);
1265     fputc(0x28,f);
1266 /* raw data */
1267     /* 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*/
1268     if(swapChain)
1269         textureRow = allocatedMemory + (width * (height - 1) *4);
1270     else
1271         textureRow = allocatedMemory;
1272     for (y = 0 ; y < height; y++) {
1273         for (i = 0; i < width;  i++) {
1274             color = *((DWORD*)textureRow);
1275             fputc((color >> 16) & 0xFF, f); /* B */
1276             fputc((color >>  8) & 0xFF, f); /* G */
1277             fputc((color >>  0) & 0xFF, f); /* R */
1278             fputc((color >> 24) & 0xFF, f); /* A */
1279             textureRow += 4;
1280         }
1281         /* take two rows of the pointer to the texture memory */
1282         if(swapChain)
1283             (textureRow-= width << 3);
1284
1285     }
1286     TRACE("Closing file\n");
1287     fclose(f);
1288
1289     if(swapChain) {
1290         IWineD3DSwapChain_Release(swapChain);
1291     }
1292     HeapFree(GetProcessHeap(), 0, allocatedMemory);
1293     return D3D_OK;
1294 }
1295
1296 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1297     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1298     This->Dirty = FALSE;
1299     This->dirtyRect.left   = This->currentDesc.Width;
1300     This->dirtyRect.top    = This->currentDesc.Height;
1301     This->dirtyRect.right  = 0;
1302     This->dirtyRect.bottom = 0;
1303     TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1304           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1305     return D3D_OK;
1306 }
1307
1308 /**
1309  *   Slightly inefficient way to handle multiple dirty rects but it works :)
1310  */
1311 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1312     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1313     IWineD3DBaseTexture *baseTexture = NULL;
1314     This->Dirty = TRUE;
1315     if (NULL != pDirtyRect) {
1316         This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
1317         This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
1318         This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
1319         This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1320     } else {
1321         This->dirtyRect.left   = 0;
1322         This->dirtyRect.top    = 0;
1323         This->dirtyRect.right  = This->currentDesc.Width;
1324         This->dirtyRect.bottom = This->currentDesc.Height;
1325     }
1326     TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1327           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1328     /* if the container is a basetexture then mark it dirty. */
1329     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
1330         TRACE("Passing to conatiner\n");
1331         IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1332         IWineD3DBaseTexture_Release(baseTexture);
1333     }
1334     return D3D_OK;
1335 }
1336
1337 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IUnknown *container) {
1338     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1339     TRACE("Setting container to %p from %p\n", container, This->container);
1340     This->container = container;
1341     return D3D_OK;
1342 }
1343
1344 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1345     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1346
1347     if (This->resource.format != WINED3DFMT_UNKNOWN) {
1348         FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1349         return D3DERR_INVALIDCALL;
1350     }
1351
1352     TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1353     if (format == WINED3DFMT_UNKNOWN) {
1354         This->resource.size = 0;
1355     } else if (format == WINED3DFMT_DXT1) {
1356         /* DXT1 is half byte per pixel */
1357         This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1358
1359     } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1360                format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1361         This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1362     } else {
1363         This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1364     }
1365
1366
1367     /* Setup some glformat defaults */
1368     if (format != WINED3DFMT_UNKNOWN) {
1369         This->glDescription.glFormat         = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1370         This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1371         This->glDescription.glType           = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1372     } else {
1373         This->glDescription.glFormat         = 0;
1374         This->glDescription.glFormatInternal = 0;
1375         This->glDescription.glType           = 0;
1376     }
1377
1378     if (format != WINED3DFMT_UNKNOWN) {
1379         This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1380         This->pow2Size      = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1381     } else {
1382         This->bytesPerPixel = 0;
1383         This->pow2Size      = 0;
1384     }
1385
1386     This->lockable = (WINED3DFMT_D16_LOCKABLE == format) ? TRUE : This->lockable;
1387
1388     This->resource.format = format;
1389
1390     TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->pow2Size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
1391
1392     return D3D_OK;
1393 }
1394
1395 /* TODO: replace this function with context management routines */
1396 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL  inTexture) {
1397     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1398
1399     This->inPBuffer = inPBuffer;
1400     This->inTexture = inTexture;
1401     return D3D_OK;
1402 }
1403
1404 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1405 {
1406     /* IUnknown */
1407     IWineD3DSurfaceImpl_QueryInterface,
1408     IWineD3DSurfaceImpl_AddRef,
1409     IWineD3DSurfaceImpl_Release,
1410     /* IWineD3DResource */
1411     IWineD3DSurfaceImpl_GetParent,
1412     IWineD3DSurfaceImpl_GetDevice,
1413     IWineD3DSurfaceImpl_SetPrivateData,
1414     IWineD3DSurfaceImpl_GetPrivateData,
1415     IWineD3DSurfaceImpl_FreePrivateData,
1416     IWineD3DSurfaceImpl_SetPriority,
1417     IWineD3DSurfaceImpl_GetPriority,
1418     IWineD3DSurfaceImpl_PreLoad,
1419     IWineD3DSurfaceImpl_GetType,
1420     /* IWineD3DSurface */
1421     IWineD3DSurfaceImpl_GetContainer,
1422     IWineD3DSurfaceImpl_GetDesc,
1423     IWineD3DSurfaceImpl_LockRect,
1424     IWineD3DSurfaceImpl_UnlockRect,
1425     IWineD3DSurfaceImpl_GetDC,
1426     IWineD3DSurfaceImpl_ReleaseDC,
1427     /* Internal use: */
1428     IWineD3DSurfaceImpl_CleanDirtyRect,
1429     IWineD3DSurfaceImpl_AddDirtyRect,
1430     IWineD3DSurfaceImpl_LoadTexture,
1431     IWineD3DSurfaceImpl_SaveSnapshot,
1432     IWineD3DSurfaceImpl_SetContainer,
1433     IWineD3DSurfaceImpl_SetPBufferState,
1434     IWineD3DSurfaceImpl_SetGlTextureDesc,
1435     IWineD3DSurfaceImpl_GetGlDesc,
1436     IWineD3DSurfaceImpl_GetData,
1437     IWineD3DSurfaceImpl_SetFormat
1438 };