Added a few more Unicode digits from Unicode version 4.1.
[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         Thease 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 fro the sufrace*/
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-systemmemory surfaces */
328
329             /*Surface has no memory currently allocate 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, laoding the surface again won't free THis->resource.allocatedMemory */
335                 /* TODO: make activeLock a bit more intelegent, 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_R5G6B5:
756                 {
757                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
758                                  GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
759                     vcheckGLcall("glDrawPixels");
760                 }
761                 break;
762             case WINED3DFMT_X1R5G5B5:
763                 {
764                     int size;
765                     unsigned short *data;
766                     data = (unsigned short *)This->resource.allocatedMemory;
767                     size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
768                     while(size > 0) {
769                             *data |= 0x8000;
770                             data++;
771                             size--;
772                     }
773                 }
774             case WINED3DFMT_A1R5G5B5:
775                 {
776                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
777                                  GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, This->resource.allocatedMemory);
778                     vcheckGLcall("glDrawPixels");
779                 }
780                 break;
781             case WINED3DFMT_R8G8B8:
782                 {
783                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
784                                  GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
785                     vcheckGLcall("glDrawPixels");
786                 }
787                 break;
788             case WINED3DFMT_X8R8G8B8: /* make sure the X byte is set to alpha on, since it 
789                                         could be any random value this fixes the intro move in Pirates! */
790                 {
791                     int size;
792                     unsigned int *data;
793                     data = (unsigned int *)This->resource.allocatedMemory;
794                     size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
795                     while(size > 0) {
796                             *data |= 0xFF000000;
797                             data++;
798                             size--;
799                     }
800                 }
801             case WINED3DFMT_A8R8G8B8:
802                 {
803                     glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
804                     vcheckGLcall("glPixelStorei");
805                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
806                                  GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
807                     vcheckGLcall("glDrawPixels");
808                     glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
809                     vcheckGLcall("glPixelStorei");
810                 }
811                 break;
812             case WINED3DFMT_A2R10G10B10:
813                 {
814                     glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
815                     vcheckGLcall("glPixelStorei");
816                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
817                                  GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, This->resource.allocatedMemory);
818                     vcheckGLcall("glDrawPixels");
819                     glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
820                     vcheckGLcall("glPixelStorei");
821                 }
822                 break;
823             default:
824                 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
825             }
826
827             glPixelZoom(1.0,1.0);
828             vcheckGLcall("glPixelZoom");
829             glDrawBuffer(prev_draw);
830             vcheckGLcall("glDrawBuffer");
831             glRasterPos3iv(&prev_rasterpos[0]);
832             vcheckGLcall("glRasterPos3iv");
833
834             /* Reset to previous pack row length / blending state */
835             glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
836             if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
837
838             LEAVE_GL();
839
840             /** restore clean dirty state */
841             IWineD3DSurface_CleanDirtyRect(iface);
842
843         } else {
844             FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
845         }
846         IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
847
848     } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
849
850         if (iface == myDevice->depthStencilBuffer) {
851             FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
852         } else {
853             FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
854         }
855
856     } else {
857         FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
858     }
859
860     unlock_end:
861     This->locked = FALSE;
862     memset(&This->lockedRect, 0, sizeof(RECT));
863     return D3D_OK;
864 }
865
866 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
867     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
868     FIXME("No support for GetDC yet for surface %p\n", This);
869     return D3DERR_INVALIDCALL;
870 }
871
872 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
873     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
874     FIXME("No support for ReleaseDC yet for surface %p\n", This);
875     return D3DERR_INVALIDCALL;
876 }
877
878 /* ******************************************************
879    IWineD3DSurface Internal (No mapping to directx api) parts follow
880    ****************************************************** */
881 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
882     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
883
884     if (This->inTexture) {
885         TRACE("Surface already in texture\n");
886         return D3D_OK;
887     }
888     if (This->Dirty == FALSE) {
889         TRACE("surface isn't dirty\n");
890         return D3D_OK;
891     }
892
893     This->Dirty = FALSE;
894
895     /* 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. */
896     if (This->resource.pool == D3DPOOL_SCRATCH || This->resource.pool == D3DPOOL_SYSTEMMEM) /*never store scratch or system mem textures in the video ram*/
897     {
898         FIXME("(%p) Opperation not supported for scratch or SYSTEMMEM textures\n",This);
899         return D3DERR_INVALIDCALL;
900     }
901
902     if (This->inPBuffer) {
903         ENTER_GL();
904
905         if (This->glDescription.level != 0)
906             FIXME("Surface in texture is only supported for level 0\n");
907         else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
908                  This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
909                  This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
910                  This->resource.format == WINED3DFMT_DXT5)
911             FIXME("Format %d not supported\n", This->resource.format);
912         else {
913             GLint prevRead;
914             glGetIntegerv(GL_READ_BUFFER, &prevRead);
915             vcheckGLcall("glGetIntegerv");
916             glReadBuffer(GL_BACK);
917             vcheckGLcall("glReadBuffer");
918
919             glCopyTexImage2D(This->glDescription.target,
920                              This->glDescription.level,
921                              This->glDescription.glFormatInternal,
922                              0,
923                              0,
924                              This->currentDesc.Width,
925                              This->currentDesc.Height,
926                              0);
927
928             checkGLcall("glCopyTexImage2D");
929             glReadBuffer(prevRead);
930             vcheckGLcall("glReadBuffer");
931             TRACE("Updating target %d\n", This->glDescription.target);
932             This->inTexture = TRUE;
933         }
934         LEAVE_GL();
935         return D3D_OK;
936     }
937
938     if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
939         !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
940         /**
941          * wanted a paletted texture and not really support it in HW
942          * so software emulation code begin
943          */
944         UINT i;
945         PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
946         VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
947         BYTE* dst = (BYTE*) surface;
948         BYTE* src = (BYTE*) This->resource.allocatedMemory;
949
950         for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
951             BYTE color = *src++;
952             *dst++ = pal[color].peRed;
953             *dst++ = pal[color].peGreen;
954             *dst++ = pal[color].peBlue;
955             if (This->resource.format == WINED3DFMT_A8P8)
956                 *dst++ = pal[color].peFlags;
957             else
958                 *dst++ = 0xFF;
959         }
960
961         ENTER_GL();
962
963         TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
964               This->glDescription.target,
965               This->glDescription.level,
966               GL_RGBA,
967               This->currentDesc.Width,
968               This->currentDesc.Height,
969               0,
970               GL_RGBA,
971               GL_UNSIGNED_BYTE,
972               surface);
973         glTexImage2D(This->glDescription.target,
974                      This->glDescription.level,
975                      GL_RGBA,
976                      This->currentDesc.Width,
977                      This->currentDesc.Height,
978                      0,
979                      GL_RGBA,
980                      GL_UNSIGNED_BYTE,
981                      surface);
982         checkGLcall("glTexImage2D");
983         HeapFree(GetProcessHeap(), 0, surface);
984
985         LEAVE_GL();
986
987         return D3D_OK;
988     }
989
990     /* TODO: Compressed non-power 2 support */
991
992     if (This->resource.format == WINED3DFMT_DXT1 ||
993         This->resource.format == WINED3DFMT_DXT2 ||
994         This->resource.format == WINED3DFMT_DXT3 ||
995         This->resource.format == WINED3DFMT_DXT4 ||
996         This->resource.format == WINED3DFMT_DXT5) {
997         if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
998             TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
999                   This->glDescription.target,
1000                   This->glDescription.level,
1001                   This->glDescription.glFormatInternal,
1002                   This->currentDesc.Width,
1003                   This->currentDesc.Height,
1004                   0,
1005                   This->resource.size,
1006                   This->resource.allocatedMemory);
1007
1008             ENTER_GL();
1009
1010             GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1011                                                   This->glDescription.level,
1012                                                   This->glDescription.glFormatInternal,
1013                                                   This->currentDesc.Width,
1014                                                   This->currentDesc.Height,
1015                                                   0,
1016                                                   This->resource.size,
1017                                                   This->resource.allocatedMemory);
1018             checkGLcall("glCommpressedTexTexImage2D");
1019
1020             LEAVE_GL();
1021
1022             if(This->activeLock == FALSE){
1023                 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1024                 This->resource.allocatedMemory = NULL;
1025             }
1026
1027         } else {
1028             FIXME("Using DXT1/3/5 without advertized support\n");
1029         }
1030     } else {
1031
1032        /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1033         if (NP2_REPACK == wined3d_settings.nonpower2_mode && This->nonpow2 == TRUE) {
1034
1035
1036             TRACE("non power of two support\n");
1037             ENTER_GL();
1038             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,
1039                 This->glDescription.target,
1040                 This->glDescription.level,
1041                 debug_d3dformat(This->resource.format),
1042                 This->glDescription.glFormatInternal,
1043                 This->pow2Width,
1044                 This->pow2Height,
1045                 0,
1046                 This->glDescription.glFormat,
1047                 This->glDescription.glType,
1048                 NULL);
1049
1050             glTexImage2D(This->glDescription.target,
1051                          This->glDescription.level,
1052                          This->glDescription.glFormatInternal,
1053                          This->pow2Width,
1054                          This->pow2Height,
1055                          0/*border*/,
1056                          This->glDescription.glFormat,
1057                          This->glDescription.glType,
1058                          NULL);
1059
1060             checkGLcall("glTexImage2D");
1061             if (This->resource.allocatedMemory != NULL) {
1062                 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1063                 /* And map the non-power two data into the top left corner */
1064                 glTexSubImage2D(
1065                     This->glDescription.target,
1066                     This->glDescription.level,
1067                     0 /* xoffset */,
1068                     0 /* ysoffset */ ,
1069                     This->currentDesc.Width,
1070                     This->currentDesc.Height,
1071                     This->glDescription.glFormat,
1072                     This->glDescription.glType,
1073                     This->resource.allocatedMemory
1074                 );
1075                 checkGLcall("glTexSubImage2D");
1076             }
1077             LEAVE_GL();
1078
1079         } else {
1080
1081             TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1082                 This->glDescription.target,
1083                 This->glDescription.level,
1084                 debug_d3dformat(This->resource.format),
1085                 This->glDescription.glFormatInternal,
1086                 This->pow2Width,
1087                 This->pow2Height,
1088                 0,
1089                 This->glDescription.glFormat,
1090                 This->glDescription.glType,
1091                 This->resource.allocatedMemory);
1092
1093             ENTER_GL();
1094             glTexImage2D(This->glDescription.target,
1095                         This->glDescription.level,
1096                         This->glDescription.glFormatInternal,
1097                         This->pow2Width,
1098                         This->pow2Height,
1099                         0 /* border */,
1100                         This->glDescription.glFormat,
1101                         This->glDescription.glType,
1102                         This->resource.allocatedMemory);
1103             checkGLcall("glTexImage2D");
1104             LEAVE_GL();
1105         }
1106
1107 #if 0
1108         {
1109             static unsigned int gen = 0;
1110             char buffer[4096];
1111             ++gen;
1112             if ((gen % 10) == 0) {
1113                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1114                 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1115             }
1116             /*
1117              * debugging crash code
1118             if (gen == 250) {
1119               void** test = NULL;
1120               *test = 0;
1121             }
1122             */
1123         }
1124 #endif
1125         if(This->activeLock == FALSE){
1126             HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1127             This->resource.allocatedMemory = NULL;
1128         }
1129
1130     }
1131
1132     return D3D_OK;
1133 }
1134
1135 #include <errno.h>
1136 #include <stdio.h>
1137 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1138     FILE* f = NULL;
1139     UINT i, y;
1140     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1141     char *allocatedMemory;
1142     char *textureRow;
1143     IWineD3DSwapChain *swapChain = NULL;
1144     int width, height;
1145     GLuint tmpTexture;
1146     DWORD color;
1147     /*FIXME:
1148     Textures my not be stored in ->allocatedgMemory and a GlTexture
1149     so we should lock the surface before saving a snapshot, or at least check that
1150     */
1151     /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1152     by calling GetTexImage and in compressed form by calling
1153     GetCompressedTexImageARB.  Queried compressed images can be saved and
1154     later reused by calling CompressedTexImage[123]DARB.  Pre-compressed
1155     texture images do not need to be processed by the GL and should
1156     significantly improve texture loading performance relative to uncompressed
1157     images. */
1158
1159 /* Setup the width and height to be the internal texture width and height. */
1160     width  = This->pow2Width;
1161     height = This->pow2Height;
1162 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1163     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1164
1165     if (swapChain || This->inPBuffer) { /* if were not a real texture then read the back buffer into a real texture*/
1166 /* 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 */
1167         GLint prevRead;
1168         ENTER_GL();
1169         FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1170         glEnable(GL_TEXTURE_2D);
1171
1172         glGenTextures(1, &tmpTexture);
1173         glBindTexture(GL_TEXTURE_2D, tmpTexture);
1174
1175         glTexImage2D(GL_TEXTURE_2D,
1176                         0,
1177                         GL_RGBA,
1178                         width,
1179                         height,
1180                         0/*border*/,
1181                         GL_RGBA,
1182                         GL_UNSIGNED_INT_8_8_8_8_REV,
1183                         NULL);
1184
1185         glGetIntegerv(GL_READ_BUFFER, &prevRead);
1186         vcheckGLcall("glGetIntegerv");
1187         glReadBuffer(GL_BACK);
1188         vcheckGLcall("glReadBuffer");
1189         glCopyTexImage2D(GL_TEXTURE_2D,
1190                             0,
1191                             GL_RGBA,
1192                             0,
1193                             0,
1194                             width,
1195                             height,
1196                             0);
1197
1198         checkGLcall("glCopyTexImage2D");
1199         glReadBuffer(prevRead);
1200         LEAVE_GL();
1201
1202     } else { /* bind the real texture */
1203         IWineD3DSurface_PreLoad(iface);
1204     }
1205     allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width  * height * 4);
1206     ENTER_GL();
1207     FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1208     glGetTexImage(GL_TEXTURE_2D,
1209                 This->glDescription.level,
1210                 GL_RGBA,
1211                 GL_UNSIGNED_INT_8_8_8_8_REV,
1212                 allocatedMemory);
1213     checkGLcall("glTexImage2D");
1214     if (tmpTexture) {
1215         glBindTexture(GL_TEXTURE_2D, 0);
1216         glDeleteTextures(1, &tmpTexture);
1217     }
1218     LEAVE_GL();
1219
1220     f = fopen(filename, "w+");
1221     if (NULL == f) {
1222         ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1223         return D3DERR_INVALIDCALL;
1224     }
1225 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1226     TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1227 /* TGA header */
1228     fputc(0,f);
1229     fputc(0,f);
1230     fputc(2,f);
1231     fputc(0,f);
1232     fputc(0,f);
1233     fputc(0,f);
1234     fputc(0,f);
1235     fputc(0,f);
1236     fputc(0,f);
1237     fputc(0,f);
1238     fputc(0,f);
1239     fputc(0,f);
1240 /* short width*/
1241     fwrite(&width,2,1,f);
1242 /* short height */
1243     fwrite(&height,2,1,f);
1244 /* format rgba */
1245     fputc(0x20,f);
1246     fputc(0x28,f);
1247 /* raw data */
1248     /* 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*/
1249     if(swapChain)
1250         textureRow = allocatedMemory + (width * (height - 1) *4);
1251     else
1252         textureRow = allocatedMemory;
1253     for (y = 0 ; y < height; y++) {
1254         for (i = 0; i < width;  i++) {
1255             color = *((DWORD*)textureRow);
1256             fputc((color >> 16) & 0xFF, f); /* B */
1257             fputc((color >>  8) & 0xFF, f); /* G */
1258             fputc((color >>  0) & 0xFF, f); /* R */
1259             fputc((color >> 24) & 0xFF, f); /* A */
1260             textureRow += 4;
1261         }
1262         /* take two rows of the pointer to the texture memory */
1263         if(swapChain)
1264             (textureRow-= width << 3);
1265
1266     }
1267     TRACE("Closing file\n");
1268     fclose(f);
1269
1270     if(swapChain) {
1271         IWineD3DSwapChain_Release(swapChain);
1272     }
1273     HeapFree(GetProcessHeap(), 0, allocatedMemory);
1274     return D3D_OK;
1275 }
1276
1277 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1278     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1279     This->Dirty = FALSE;
1280     This->dirtyRect.left   = This->currentDesc.Width;
1281     This->dirtyRect.top    = This->currentDesc.Height;
1282     This->dirtyRect.right  = 0;
1283     This->dirtyRect.bottom = 0;
1284     TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1285           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1286     return D3D_OK;
1287 }
1288
1289 /**
1290  *   Slightly inefficient way to handle multiple dirty rects but it works :)
1291  */
1292 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
1293     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1294     IWineD3DBaseTexture *baseTexture = NULL;
1295     This->Dirty = TRUE;
1296     if (NULL != pDirtyRect) {
1297         This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
1298         This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
1299         This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
1300         This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
1301     } else {
1302         This->dirtyRect.left   = 0;
1303         This->dirtyRect.top    = 0;
1304         This->dirtyRect.right  = This->currentDesc.Width;
1305         This->dirtyRect.bottom = This->currentDesc.Height;
1306     }
1307     TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left,
1308           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1309     /* if the container is a basetexture then mark it dirty. */
1310     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
1311         TRACE("Passing to conatiner\n");
1312         IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1313         IWineD3DBaseTexture_Release(baseTexture);
1314     }
1315     return D3D_OK;
1316 }
1317
1318 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IUnknown *container) {
1319     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1320     TRACE("Setting container to %p from %p\n", container, This->container);
1321     This->container = container;
1322     return D3D_OK;
1323 }
1324
1325 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
1326     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1327
1328     if (This->resource.format != WINED3DFMT_UNKNOWN) {
1329         FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
1330         return D3DERR_INVALIDCALL;
1331     }
1332
1333     TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
1334     if (format == WINED3DFMT_UNKNOWN) {
1335         This->resource.size = 0;
1336     } else if (format == WINED3DFMT_DXT1) {
1337         /* DXT1 is half byte per pixel */
1338         This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4)) >> 1;
1339
1340     } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
1341                format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
1342         This->resource.size = ((max(This->pow2Width, 4) * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * max(This->pow2Height, 4));
1343     } else {
1344         This->resource.size = (This->pow2Width * D3DFmtGetBpp(This->resource.wineD3DDevice, format)) * This->pow2Height;
1345     }
1346
1347
1348     /* Setup some glformat defaults */
1349     if (format != WINED3DFMT_UNKNOWN) {
1350         This->glDescription.glFormat         = D3DFmt2GLFmt(This->resource.wineD3DDevice, format);
1351         This->glDescription.glFormatInternal = D3DFmt2GLIntFmt(This->resource.wineD3DDevice, format);
1352         This->glDescription.glType           = D3DFmt2GLType(This->resource.wineD3DDevice, format);
1353     } else {
1354         This->glDescription.glFormat         = 0;
1355         This->glDescription.glFormatInternal = 0;
1356         This->glDescription.glType           = 0;
1357     }
1358
1359     if (format != WINED3DFMT_UNKNOWN) {
1360         This->bytesPerPixel = D3DFmtGetBpp(This->resource.wineD3DDevice, format);
1361         This->pow2Size      = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
1362     } else {
1363         This->bytesPerPixel = 0;
1364         This->pow2Size      = 0;
1365     }
1366
1367     This->lockable = (WINED3DFMT_D16_LOCKABLE == format) ? TRUE : This->lockable;
1368
1369     This->resource.format = format;
1370
1371     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);
1372
1373     return D3D_OK;
1374 }
1375
1376 /* TODO: replace this function with context management routines */
1377 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL  inTexture) {
1378     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1379
1380     This->inPBuffer = inPBuffer;
1381     This->inTexture = inTexture;
1382     return D3D_OK;
1383 }
1384
1385 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
1386 {
1387     /* IUnknown */
1388     IWineD3DSurfaceImpl_QueryInterface,
1389     IWineD3DSurfaceImpl_AddRef,
1390     IWineD3DSurfaceImpl_Release,
1391     /* IWineD3DResource */
1392     IWineD3DSurfaceImpl_GetParent,
1393     IWineD3DSurfaceImpl_GetDevice,
1394     IWineD3DSurfaceImpl_SetPrivateData,
1395     IWineD3DSurfaceImpl_GetPrivateData,
1396     IWineD3DSurfaceImpl_FreePrivateData,
1397     IWineD3DSurfaceImpl_SetPriority,
1398     IWineD3DSurfaceImpl_GetPriority,
1399     IWineD3DSurfaceImpl_PreLoad,
1400     IWineD3DSurfaceImpl_GetType,
1401     /* IWineD3DSurface */
1402     IWineD3DSurfaceImpl_GetContainer,
1403     IWineD3DSurfaceImpl_GetDesc,
1404     IWineD3DSurfaceImpl_LockRect,
1405     IWineD3DSurfaceImpl_UnlockRect,
1406     IWineD3DSurfaceImpl_GetDC,
1407     IWineD3DSurfaceImpl_ReleaseDC,
1408     /* Internal use: */
1409     IWineD3DSurfaceImpl_CleanDirtyRect,
1410     IWineD3DSurfaceImpl_AddDirtyRect,
1411     IWineD3DSurfaceImpl_LoadTexture,
1412     IWineD3DSurfaceImpl_SaveSnapshot,
1413     IWineD3DSurfaceImpl_SetContainer,
1414     IWineD3DSurfaceImpl_SetPBufferState,
1415     IWineD3DSurfaceImpl_SetGlTextureDesc,
1416     IWineD3DSurfaceImpl_GetGlDesc,
1417     IWineD3DSurfaceImpl_GetData,
1418     IWineD3DSurfaceImpl_SetFormat
1419 };