Allow the WINED3DSBT_IMPL to be applied so that states can be synced
[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 (dxt3/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_DXT3 || This->resource.format == WINED3DFMT_DXT5) /* DXT3/5 is 16 bytes per block */
285         pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 4;
286     else
287         pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width;  /* Bytes / row */
288
289     if (NULL == pRect) {
290         pLockedRect->pBits = This->resource.allocatedMemory;
291         This->lockedRect.left   = 0;
292         This->lockedRect.top    = 0;
293         This->lockedRect.right  = This->currentDesc.Width;
294         This->lockedRect.bottom = This->currentDesc.Height;
295         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);
296     } else {
297         TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
298
299         if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
300             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel/2));
301         } else {
302             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
303         }
304         This->lockedRect.left   = pRect->left;
305         This->lockedRect.top    = pRect->top;
306         This->lockedRect.right  = pRect->right;
307         This->lockedRect.bottom = pRect->bottom;
308     }
309
310     if (This->nonpow2) {
311         TRACE("Locking non-power 2 texture\n");
312     }
313
314     if (0 == This->resource.usage || This->resource.usage & D3DUSAGE_DYNAMIC) {
315         /* classic surface  TODO: non 2d surfaces?
316         Thease resources may be POOL_SYSTEMMEM, so they must not access the device */
317         TRACE("locking an ordinarary surface\n");
318         /* Check to see if memory has already been allocated fro the sufrace*/
319         if (NULL == This->resource.allocatedMemory) { /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
320             /* Non-systemmemory surfaces */
321
322             /*Surface has no memory currently allocate to it!*/
323             TRACE("(%p) Locking rect\n" , This);
324             This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
325
326             /*Now I have to copy thing bits back*/  
327             This->activeLock = TRUE; /* When this flag is set to true, laoding the surface again won't free THis->resource.allocatedMemory */
328             /* TODO: make activeLock a bit more intelegent, maybe implement a method to purge the texture memory. */
329             ENTER_GL();
330
331             /* Make sure that the texture is loaded */
332             IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
333
334             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);
335             /* TODO: DXT2 and DXT4 formats */
336             if (This->resource.format == WINED3DFMT_DXT1 ||
337                 This->resource.format == WINED3DFMT_DXT3 ||
338                 This->resource.format == WINED3DFMT_DXT5) {
339                 TRACE("Locking a compressed texture\n");
340                 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
341                     GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
342                                                         This->glDescription.level,
343                                                         This->resource.allocatedMemory);
344
345                 } else {
346                     FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
347                 }
348             } else {
349                 glGetTexImage(This->glDescription.target,
350                             This->glDescription.level,
351                             This->glDescription.glFormat,
352                             This->glDescription.glType,
353                             This->resource.allocatedMemory);
354                 vcheckGLcall("glGetTexImage");
355             }
356             LEAVE_GL();
357         } else { /* Nothing to do */
358             TRACE("Memory %p already allocted for texture\n",  This->resource.allocatedMemory);
359         }
360
361         if (NULL == pRect) {
362             pLockedRect->pBits = This->resource.allocatedMemory;
363         }  else{
364             if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
365                 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel/2));
366             } else {
367                 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
368             }
369         }
370
371     } else if (D3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
372
373         GLint  prev_store;
374         GLint  prev_read;
375         BOOL notInContext = FALSE;
376         IWineD3DSwapChainImpl *targetSwapChain = NULL;
377
378
379         ENTER_GL();
380
381             /**
382              * for render->surface copy begin to begin of allocatedMemory
383              * unlock can be more easy
384              */
385
386         TRACE("locking a render target\n");
387
388         if (This->resource.allocatedMemory == NULL)
389                 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
390
391         This->activeLock = TRUE; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
392         pLockedRect->pBits = This->resource.allocatedMemory;
393
394         glFlush();
395         vcheckGLcall("glFlush");
396         glGetIntegerv(GL_READ_BUFFER, &prev_read);
397         vcheckGLcall("glIntegerv");
398         glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
399         vcheckGLcall("glIntegerv");
400
401  /* Here's what we have to do:
402             See if the swapchain has the same context as the renderTarget or the surface is the render target.
403             Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
404             and use the front back buffer as required.
405             if not, we need to switch contexts and then switchback at the end.
406          */
407         IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
408         IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
409
410         /* 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! */
411         if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
412                 if (iface == myDevice->renderTarget || iface == swapchain->backBuffer) {
413                     TRACE("locking back buffer\n");
414                    glReadBuffer(GL_BACK);
415                 } else if (iface == swapchain->frontBuffer) {
416                    TRACE("locking front\n");
417                    glReadBuffer(GL_FRONT);
418                 } else if (iface == myDevice->depthStencilBuffer) {
419                     FIXME("Stencil Buffer lock unsupported for now\n");
420                 } else {
421                    FIXME("(%p) Shouldn't have got here!\n", This);
422                    glReadBuffer(GL_BACK);
423                 }
424         } else if (swapchain != NULL) {
425             IWineD3DSwapChainImpl *implSwapChain;
426             IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
427             if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
428                     /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
429                     if (iface == swapchain->backBuffer) {
430                         glReadBuffer(GL_BACK);
431                     } else if (iface == swapchain->frontBuffer) {
432                         glReadBuffer(GL_FRONT);
433                     } else if (iface == myDevice->depthStencilBuffer) {
434                         FIXME("Stencil Buffer lock unsupported for now\n");
435                     } else {
436                         FIXME("Should have got here!\n");
437                         glReadBuffer(GL_BACK);
438                     }
439             } else {
440                 /* We need to switch contexts to be able to read the buffer!!! */
441                 FIXME("The buffer requested isn't in the current openGL context\n");
442                 notInContext = TRUE;
443                 /* TODO: check the contexts, to see if were shared with the current context */
444             }
445             IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
446         }
447         if (swapchain != NULL)       IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
448         if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
449
450
451         /** the depth stencil in openGL has a format of GL_FLOAT
452         * which should be good for WINED3DFMT_D16_LOCKABLE
453         * and WINED3DFMT_D16
454         * it is unclear what format the stencil buffer is in except.
455         * 'Each index is converted to fixed point...
456         * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
457         * mappings in the table GL_PIXEL_MAP_S_TO_S.
458         * glReadPixels(This->lockedRect.left,
459         *             This->lockedRect.bottom - j - 1,
460         *             This->lockedRect.right - This->lockedRect.left,
461         *             1,
462         *             GL_DEPTH_COMPONENT,
463         *             type,
464         *             (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
465             *****************************************/
466         if (!notInContext) { /* Only read the buffer if it's in the current context */
467             long j;
468 #if 0
469             /* 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,
470             *  This is on an ATI9600, and may be format dependent, anyhow this hack makes this demo dx9_2d_demo_game
471             *  run ten times faster!
472             * ************************************/
473             BOOL ati_performance_hack = FALSE;
474             ati_performance_hack = (This->lockedRect.bottom - This->lockedRect.top > 10) || (This->lockedRect.right - This->lockedRect.left > 10)? TRUE: FALSE;
475 #endif
476             if ((This->lockedRect.left == 0 &&  This->lockedRect.top == 0 &&
477                 This->lockedRect.right == This->currentDesc.Width
478                 && This->lockedRect.bottom ==  This->currentDesc.Height)) {
479                     glReadPixels(0, 0,
480                     This->currentDesc.Width,
481                     This->currentDesc.Height,
482                     This->glDescription.glFormat,
483                     This->glDescription.glType,
484                     (char *)pLockedRect->pBits);
485             } else if (This->lockedRect.left == 0 &&  This->lockedRect.right == This->currentDesc.Width) {
486                     glReadPixels(0,
487                     This->lockedRect.top,
488                     This->currentDesc.Width,
489                     This->currentDesc.Height,
490                     This->glDescription.glFormat,
491                     This->glDescription.glType,
492                     (char *)pLockedRect->pBits);
493             } else{
494
495                 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
496                     glReadPixels(This->lockedRect.left, 
497                                  This->lockedRect.bottom - j - 1, 
498                                  This->lockedRect.right - This->lockedRect.left, 
499                                  1,
500                                  This->glDescription.glFormat,
501                                  This->glDescription.glType,
502                                  (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
503
504                 }
505             }
506             vcheckGLcall("glReadPixels");
507             TRACE("Resetting buffer\n");
508             glReadBuffer(prev_read);
509             vcheckGLcall("glReadBuffer");
510         }
511         LEAVE_GL();
512
513     } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
514
515         if (!messages & 1) {
516             FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
517             /*
518
519             glReadPixels(This->lockedRect.left,
520             This->lockedRect.bottom - j - 1,
521             This->lockedRect.right - This->lockedRect.left,
522             1,
523             GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
524
525             )
526             */
527             messages |= 1;
528         }
529     } else {
530         FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
531     }
532
533     if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
534         /* Don't dirtify */
535     } else {
536         IWineD3DBaseTexture *pBaseTexture;
537         /**
538          * Dirtify on lock
539          * as seen in msdn docs
540          */
541         IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
542
543         /** Dirtify Container if needed */
544         if (D3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
545             TRACE("Making container dirty\n");
546             IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
547             IWineD3DBaseTexture_Release(pBaseTexture);
548         } else {
549             TRACE("Surface is standalone, no need to dirty the container\n");
550         }
551     }
552
553     TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
554
555     This->locked = TRUE;
556     return D3D_OK;
557 }
558
559 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
560     GLint skipBytes = 0;
561     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
562     IWineD3DDeviceImpl  *myDevice = This->resource.wineD3DDevice;
563     const char *buffername = "";
564     IWineD3DSwapChainImpl *swapchain = NULL;
565
566     if (FALSE == This->locked) {
567         WARN("trying to Unlock an unlocked surf@%p\n", This);
568         return D3DERR_INVALIDCALL;
569     }
570
571     if (D3DUSAGE_RENDERTARGET & This->resource.usage) {
572         IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
573
574         if ((swapchain != NULL) &&  iface ==  swapchain->backBuffer) {
575                 buffername = "backBuffer";
576         } else if ((swapchain != NULL) && iface ==  swapchain->frontBuffer) {
577                 buffername = "frontBuffer";
578         } else if (iface == myDevice->depthStencilBuffer) {
579                 buffername = "depthStencilBuffer";
580         } else if (iface == myDevice->renderTarget) {
581                 buffername = "renderTarget";
582         }
583     }
584
585     if (swapchain != NULL) {
586         IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
587     }
588
589     TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Dirty);
590
591     if (FALSE == This->Dirty) {
592         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
593         goto unlock_end;
594     }
595
596     if (0 == This->resource.usage) { /* classic surface */
597         /**
598          * nothing to do
599          * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
600          */
601     } else if (D3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
602
603         /****************************
604         * TODO: Render targets are 'special' and
605         * ?some? locking needs to be passed onto the context manager
606         * so that it becomes possible to use auxilary buffers, pbuffers
607         * render-to-texture, shared, cached contexts etc...
608         * ****************************/
609         IWineD3DSwapChainImpl *implSwapChain;
610         IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
611
612         if (iface ==  implSwapChain->backBuffer || iface ==  implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
613             GLint  prev_store;
614             GLint  prev_draw;
615             GLint  prev_rasterpos[4];
616
617             ENTER_GL();
618
619             glFlush();
620             vcheckGLcall("glFlush");
621             glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
622             vcheckGLcall("glIntegerv");
623             glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
624             vcheckGLcall("glIntegerv");
625             glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
626             vcheckGLcall("glIntegerv");
627             glPixelZoom(1.0, -1.0);
628             vcheckGLcall("glPixelZoom");
629
630             /* glDrawPixels transforms the raster position as though it was a vertex -
631                we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
632                per drawprim (and leave set - it will sort itself out due to last_was_rhw */
633             if (!myDevice->last_was_rhw) {
634
635                 double X, Y, height, width, minZ, maxZ;
636                 myDevice->last_was_rhw = TRUE;
637
638                 /* Transformed already into viewport coordinates, so we do not need transform
639                    matrices. Reset all matrices to identity and leave the default matrix in world
640                    mode.                                                                         */
641                 glMatrixMode(GL_MODELVIEW);
642                 checkGLcall("glMatrixMode");
643                 glLoadIdentity();
644                 checkGLcall("glLoadIdentity");
645
646                 glMatrixMode(GL_PROJECTION);
647                 checkGLcall("glMatrixMode");
648                 glLoadIdentity();
649                 checkGLcall("glLoadIdentity");
650
651                 /* Set up the viewport to be full viewport */
652                 X      = myDevice->stateBlock->viewport.X;
653                 Y      = myDevice->stateBlock->viewport.Y;
654                 height = myDevice->stateBlock->viewport.Height;
655                 width  = myDevice->stateBlock->viewport.Width;
656                 minZ   = myDevice->stateBlock->viewport.MinZ;
657                 maxZ   = myDevice->stateBlock->viewport.MaxZ;
658                 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
659                 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
660                 checkGLcall("glOrtho");
661
662                 /* Window Coord 0 is the middle of the first pixel, so translate by half
663                    a pixel (See comment above glTranslate below)                         */
664                 glTranslatef(0.5, 0.5, 0);
665                 checkGLcall("glTranslatef(0.5, 0.5, 0)");
666             }
667
668             if (iface ==  implSwapChain->backBuffer || iface == myDevice->renderTarget) {
669                 glDrawBuffer(GL_BACK);
670             } else if (iface ==  implSwapChain->frontBuffer) {
671                 glDrawBuffer(GL_FRONT);
672             }
673
674             vcheckGLcall("glDrawBuffer");
675
676             /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
677             glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
678             glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
679
680             /* And back buffers are not blended */
681             glDisable(GL_BLEND);
682
683             glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
684             vcheckGLcall("glRasterPos2f");
685             switch (This->resource.format) {
686             case WINED3DFMT_R5G6B5:
687                 {
688                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
689                                  GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
690                     vcheckGLcall("glDrawPixels");
691                 }
692                 break;
693             case WINED3DFMT_R8G8B8:
694                 {
695                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
696                                  GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
697                     vcheckGLcall("glDrawPixels");
698                 }
699                 break;
700             case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it 
701                                         could be any random value this fixes the intro move in Pirates! */
702                 {
703                     int size;
704                     unsigned int *data;
705                     data = (unsigned int *)This->resource.allocatedMemory;
706                     size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
707                     while(size > 0) {
708                             *data |= 0xFF000000;
709                             data++;
710                             size--;
711                     }
712                 }
713             case WINED3DFMT_A8R8G8B8:
714                 {
715                     glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
716                     vcheckGLcall("glPixelStorei");
717                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
718                                  GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
719                     vcheckGLcall("glDrawPixels");
720                     glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
721                     vcheckGLcall("glPixelStorei");
722                 }
723                 break;
724             default:
725                 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
726             }
727
728             glPixelZoom(1.0,1.0);
729             vcheckGLcall("glPixelZoom");
730             glDrawBuffer(prev_draw);
731             vcheckGLcall("glDrawBuffer");
732             glRasterPos3iv(&prev_rasterpos[0]);
733             vcheckGLcall("glRasterPos3iv");
734
735             /* Reset to previous pack row length / blending state */
736             glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
737             if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
738
739             LEAVE_GL();
740
741             /** restore clean dirty state */
742             IWineD3DSurface_CleanDirtyRect(iface);
743
744         } else {
745             FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
746         }
747         IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
748
749     } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
750
751         if (iface == myDevice->depthStencilBuffer) {
752             FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
753         } else {
754             FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
755         }
756
757     } else {
758         FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
759     }
760
761     unlock_end:
762     This->locked = FALSE;
763     memset(&This->lockedRect, 0, sizeof(RECT));
764     return D3D_OK;
765 }
766
767 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
768     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
769     FIXME("No support for GetDC yet for surface %p\n", This);
770     return D3DERR_INVALIDCALL;
771 }
772
773 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
774     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
775     FIXME("No support for ReleaseDC yet for surface %p\n", This);
776     return D3DERR_INVALIDCALL;
777 }
778
779 /* ******************************************************
780    IWineD3DSurface Internal (No mapping to directx api) parts follow
781    ****************************************************** */
782 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
783     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
784
785     if (This->inTexture) {
786         TRACE("Surface already in texture\n");
787         return D3D_OK;
788     }
789     if (This->Dirty == FALSE) {
790         TRACE("surface isn't dirty\n");
791         return D3D_OK;
792     }
793
794     This->Dirty = FALSE;
795
796     /* 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. */
797     if (This->resource.pool == D3DPOOL_SCRATCH || This->resource.pool == D3DPOOL_SYSTEMMEM) /*never store scratch or system mem textures in the video ram*/
798     {
799         FIXME("(%p) Opperation not supported for scratch or SYSTEMMEM textures\n",This);
800         return D3DERR_INVALIDCALL;
801     }
802
803     if (This->inPBuffer) {
804         ENTER_GL();
805
806         if (This->glDescription.level != 0)
807             FIXME("Surface in texture is only supported for level 0\n");
808         else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
809                  This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT3 ||
810                  This->resource.format == WINED3DFMT_DXT5)
811             FIXME("Format %d not supported\n", This->resource.format);
812         else {
813             GLint prevRead;
814             glGetIntegerv(GL_READ_BUFFER, &prevRead);
815             vcheckGLcall("glGetIntegerv");
816             glReadBuffer(GL_BACK);
817             vcheckGLcall("glReadBuffer");
818
819             glCopyTexImage2D(This->glDescription.target,
820                              This->glDescription.level,
821                              This->glDescription.glFormatInternal,
822                              0,
823                              0,
824                              This->currentDesc.Width,
825                              This->currentDesc.Height,
826                              0);
827
828             checkGLcall("glCopyTexImage2D");
829             glReadBuffer(prevRead);
830             vcheckGLcall("glReadBuffer");
831             TRACE("Updating target %d\n", This->glDescription.target);
832             This->inTexture = TRUE;
833         }
834         LEAVE_GL();
835         return D3D_OK;
836     }
837
838     if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
839         !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
840         /**
841          * wanted a paletted texture and not really support it in HW
842          * so software emulation code begin
843          */
844         UINT i;
845         PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
846         VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
847         BYTE* dst = (BYTE*) surface;
848         BYTE* src = (BYTE*) This->resource.allocatedMemory;
849
850         for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
851             BYTE color = *src++;
852             *dst++ = pal[color].peRed;
853             *dst++ = pal[color].peGreen;
854             *dst++ = pal[color].peBlue;
855             if (This->resource.format == WINED3DFMT_A8P8)
856                 *dst++ = pal[color].peFlags;
857             else
858                 *dst++ = 0xFF;
859         }
860
861         ENTER_GL();
862
863         TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
864               This->glDescription.target,
865               This->glDescription.level,
866               GL_RGBA,
867               This->currentDesc.Width,
868               This->currentDesc.Height,
869               0,
870               GL_RGBA,
871               GL_UNSIGNED_BYTE,
872               surface);
873         glTexImage2D(This->glDescription.target,
874                      This->glDescription.level,
875                      GL_RGBA,
876                      This->currentDesc.Width,
877                      This->currentDesc.Height,
878                      0,
879                      GL_RGBA,
880                      GL_UNSIGNED_BYTE,
881                      surface);
882         checkGLcall("glTexImage2D");
883         HeapFree(GetProcessHeap(), 0, surface);
884
885         LEAVE_GL();
886
887         return D3D_OK;
888     }
889
890     /* TODO: Compressed non-power 2 support */
891     /* TODO: DXT2 DXT4 support */
892     if (This->resource.format == WINED3DFMT_DXT1 ||
893         This->resource.format == WINED3DFMT_DXT3 ||
894         This->resource.format == WINED3DFMT_DXT5) {
895         if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
896             TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
897                   This->glDescription.target,
898                   This->glDescription.level,
899                   This->glDescription.glFormatInternal,
900                   This->currentDesc.Width,
901                   This->currentDesc.Height,
902                   0,
903                   This->resource.size,
904                   This->resource.allocatedMemory);
905
906             ENTER_GL();
907
908             GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
909                                                   This->glDescription.level,
910                                                   This->glDescription.glFormatInternal,
911                                                   This->currentDesc.Width,
912                                                   This->currentDesc.Height,
913                                                   0,
914                                                   This->resource.size,
915                                                   This->resource.allocatedMemory);
916             checkGLcall("glCommpressedTexTexImage2D");
917
918             LEAVE_GL();
919
920             if(This->activeLock == FALSE){
921                 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
922                 This->resource.allocatedMemory = NULL;
923             }
924
925         } else {
926             FIXME("Using DXT1/3/5 without advertized support\n");
927         }
928     } else {
929
930        /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
931         if (This->nonpow2 == TRUE) {
932
933             TRACE("non power of two support\n");
934             ENTER_GL();
935             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,
936                 This->glDescription.target,
937                 This->glDescription.level,
938                 debug_d3dformat(This->resource.format),
939                 This->glDescription.glFormatInternal,
940                 This->pow2Width,
941                 This->pow2Height,
942                 0,
943                 This->glDescription.glFormat,
944                 This->glDescription.glType,
945                 NULL);
946
947             glTexImage2D(This->glDescription.target,
948                          This->glDescription.level,
949                          This->glDescription.glFormatInternal,
950                          This->pow2Width,
951                          This->pow2Height,
952                          0/*border*/,
953                          This->glDescription.glFormat,
954                          This->glDescription.glType,
955                          NULL);
956
957             checkGLcall("glTexImage2D");
958             if (This->resource.allocatedMemory != NULL) {
959                 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
960                 /* And map the non-power two data into the top left corner */
961                 glTexSubImage2D(
962                     This->glDescription.target,
963                     This->glDescription.level,
964                     0 /* xoffset */,
965                     0 /* ysoffset */ ,
966                     This->currentDesc.Width,
967                     This->currentDesc.Height,
968                     This->glDescription.glFormat,
969                     This->glDescription.glType,
970                     This->resource.allocatedMemory
971                 );
972                 checkGLcall("glTexSubImage2D");
973             }
974             LEAVE_GL();
975
976         } else {
977
978             TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
979                 This->glDescription.target,
980                 This->glDescription.level,
981                 debug_d3dformat(This->resource.format),
982                 This->glDescription.glFormatInternal,
983                 This->currentDesc.Width,
984                 This->currentDesc.Height,
985                 0,
986                 This->glDescription.glFormat,
987                 This->glDescription.glType,
988                 This->resource.allocatedMemory);
989
990             ENTER_GL();
991             glTexImage2D(This->glDescription.target,
992                         This->glDescription.level,
993                         This->glDescription.glFormatInternal,
994                         This->currentDesc.Width,
995                         This->currentDesc.Height,
996                         0 /* border */,
997                         This->glDescription.glFormat,
998                         This->glDescription.glType,
999                         This->resource.allocatedMemory);
1000             checkGLcall("glTexImage2D");
1001             LEAVE_GL();
1002         }
1003
1004 #if 0
1005         {
1006             static unsigned int gen = 0;
1007             char buffer[4096];
1008             ++gen;
1009             if ((gen % 10) == 0) {
1010                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1011                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1012             }
1013             /*
1014              * debugging crash code
1015             if (gen == 250) {
1016               void** test = NULL;
1017               *test = 0;
1018             }
1019             */
1020         }
1021 #endif
1022         if(This->activeLock == FALSE){
1023             HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1024             This->resource.allocatedMemory = NULL;
1025         }
1026
1027     }
1028
1029     return D3D_OK;
1030 }
1031
1032 #include <errno.h>
1033 #include <stdio.h>
1034 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1035     FILE* f = NULL;
1036     ULONG i;
1037     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1038
1039     f = fopen(filename, "w+");
1040     if (NULL == f) {
1041         ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1042         return D3DERR_INVALIDCALL;
1043     }
1044
1045     TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->resource.format));
1046
1047     fprintf(f, "P6\n%u %u\n255\n", This->currentDesc.Width, This->currentDesc.Height);
1048     switch (This->resource.format) {
1049     case WINED3DFMT_X8R8G8B8:
1050     case WINED3DFMT_A8R8G8B8:
1051         {
1052             DWORD color;
1053             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1054                 color = ((DWORD*) This->resource.allocatedMemory)[i];
1055                 fputc((color >> 16) & 0xFF, f);
1056                 fputc((color >>  8) & 0xFF, f);
1057                 fputc((color >>  0) & 0xFF, f);
1058             }
1059         }
1060         break;
1061     case WINED3DFMT_R8G8B8:
1062         {
1063             BYTE* color;
1064             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1065                 color = ((BYTE*) This->resource.allocatedMemory) + (3 * i);
1066                 fputc((color[0]) & 0xFF, f);
1067                 fputc((color[1]) & 0xFF, f);
1068                 fputc((color[2]) & 0xFF, f);
1069             }
1070         }
1071         break;
1072     case WINED3DFMT_A1R5G5B5:
1073         {
1074             WORD color;
1075             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1076                 color = ((WORD*) This->resource.allocatedMemory)[i];
1077                 fputc(((color >> 10) & 0x1F) * 255 / 31, f);
1078                 fputc(((color >>  5) & 0x1F) * 255 / 31, f);
1079                 fputc(((color >>  0) & 0x1F) * 255 / 31, f);
1080             }
1081         }
1082         break;
1083     case WINED3DFMT_A4R4G4B4:
1084         {
1085             WORD color;
1086             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1087                 color = ((WORD*) This->resource.allocatedMemory)[i];
1088                 fputc(((color >>  8) & 0x0F) * 255 / 15, f);
1089                 fputc(((color >>  4) & 0x0F) * 255 / 15, f);
1090                 fputc(((color >>  0) & 0x0F) * 255 / 15, f);
1091             }
1092         }
1093         break;
1094
1095     case WINED3DFMT_R5G6B5:
1096         {
1097             WORD color;
1098             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
1099                 color = ((WORD*) This->resource.allocatedMemory)[i];
1100                 fputc(((color >> 11) & 0x1F) * 255 / 31, f);
1101                 fputc(((color >>  5) & 0x3F) * 255 / 63, f);
1102                 fputc(((color >>  0) & 0x1F) * 255 / 31, f);
1103             }
1104         }
1105         break;
1106     default:
1107         FIXME("Unimplemented dump mode format(%u,%s)\n", This->resource.format, debug_d3dformat(This->resource.format));
1108     }
1109     fclose(f);
1110     return D3D_OK;
1111 }
1112
1113 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1114     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1115     This->Dirty = FALSE;
1116     This->dirtyRect.left   = This->currentDesc.Width;
1117     This->dirtyRect.top    = This->currentDesc.Height;
1118     This->dirtyRect.right  = 0;
1119     This->dirtyRect.bottom = 0;
1120     TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1121           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1122     return D3D_OK;
1123 }
1124
1125 /**
1126  *   Slightly inefficient way to handle multiple dirty rects but it works :)
1127  */
1128 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1129     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1130     IWineD3DBaseTexture *baseTexture = NULL;
1131     This->Dirty = TRUE;
1132     if (NULL != pDirtyRect) {
1133         This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
1134         This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
1135         This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
1136         This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1137     } else {
1138         This->dirtyRect.left   = 0;
1139         This->dirtyRect.top    = 0;
1140         This->dirtyRect.right  = This->currentDesc.Width;
1141         This->dirtyRect.bottom = This->currentDesc.Height;
1142     }
1143     TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1144           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1145     /* if the container is a basetexture then mark it dirty. */
1146     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
1147         TRACE("Passing to conatiner\n");
1148         IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1149         IWineD3DBaseTexture_Release(baseTexture);
1150     }
1151     return D3D_OK;
1152 }
1153
1154 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IUnknown *container) {
1155     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1156     TRACE("Setting container to %p from %p\n", container, This->container);
1157     This->container = container;
1158     return D3D_OK;
1159 }
1160
1161 /* TODO: replace this function with context management routines */
1162 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL  inTexture) {
1163     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1164
1165     This->inPBuffer = inPBuffer;
1166     This->inTexture = inTexture;
1167     return D3D_OK;
1168 }
1169
1170 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1171 {
1172     /* IUnknown */
1173     IWineD3DSurfaceImpl_QueryInterface,
1174     IWineD3DSurfaceImpl_AddRef,
1175     IWineD3DSurfaceImpl_Release,
1176     /* IWineD3DResource */
1177     IWineD3DSurfaceImpl_GetParent,
1178     IWineD3DSurfaceImpl_GetDevice,
1179     IWineD3DSurfaceImpl_SetPrivateData,
1180     IWineD3DSurfaceImpl_GetPrivateData,
1181     IWineD3DSurfaceImpl_FreePrivateData,
1182     IWineD3DSurfaceImpl_SetPriority,
1183     IWineD3DSurfaceImpl_GetPriority,
1184     IWineD3DSurfaceImpl_PreLoad,
1185     IWineD3DSurfaceImpl_GetType,
1186     /* IWineD3DSurface */
1187     IWineD3DSurfaceImpl_GetContainer,
1188     IWineD3DSurfaceImpl_GetDesc,
1189     IWineD3DSurfaceImpl_LockRect,
1190     IWineD3DSurfaceImpl_UnlockRect,
1191     IWineD3DSurfaceImpl_GetDC,
1192     IWineD3DSurfaceImpl_ReleaseDC,
1193     /* Internal use: */
1194     IWineD3DSurfaceImpl_CleanDirtyRect,
1195     IWineD3DSurfaceImpl_AddDirtyRect,
1196     IWineD3DSurfaceImpl_LoadTexture,
1197     IWineD3DSurfaceImpl_SaveSnapshot,
1198     IWineD3DSurfaceImpl_SetContainer,
1199     IWineD3DSurfaceImpl_SetPBufferState,
1200     IWineD3DSurfaceImpl_SetGlTextureDesc,
1201     IWineD3DSurfaceImpl_GetGlDesc,
1202     IWineD3DSurfaceImpl_GetData
1203 };