Break out all the file related actions and helper functions into
[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 "wined3d_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
28 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
29
30 /* *******************************************
31    IWineD3DSurface IUnknown parts follow
32    ******************************************* */
33 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
34 {
35     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
36     /* Warn ,but be nice about things */
37     TRACE("(%p)->(%s,%p) \n", This,debugstr_guid(riid),ppobj);
38     if (riid == NULL) {
39         ERR("Probably FIXME: Calling query interface with NULL riid\n");
40     }
41     if (IsEqualGUID(riid, &IID_IUnknown)
42         || IsEqualGUID(riid, &IID_IWineD3DResource)
43         || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
44         IUnknown_AddRef((IUnknown*)iface);
45         *ppobj = This;
46         return D3D_OK;
47     }
48     return E_NOINTERFACE;
49 }
50
51 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
52     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
53     ULONG ref = InterlockedIncrement(&This->resource.ref);
54     TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
55     return ref;
56 }
57
58 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
59     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
60     ULONG ref = InterlockedDecrement(&This->resource.ref);
61     TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
62     if (ref == 0) {
63         if (This->textureName != 0) { /* release the openGL texture.. */
64             ENTER_GL();
65             TRACE("Deleting texture %d\n", This->textureName);
66             glDeleteTextures(1, &This->textureName);
67             LEAVE_GL();
68         }
69         IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
70         HeapFree(GetProcessHeap(), 0, This);
71
72     }
73     return ref;
74 }
75
76 /* ****************************************************
77    IWineD3DSurface IWineD3DResource parts follow
78    **************************************************** */
79 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
80     return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
81 }
82
83 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
84     return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
85 }
86
87 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
88     return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
89 }
90
91 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
92     return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
93 }
94
95 DWORD   WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
96     return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
97 }
98
99 DWORD   WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
100     return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
101 }
102
103 void    WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
104     /* TODO: re-write the way textures and managed,
105     *  use a 'opengl context manager' to manage RenderTarget surfaces
106     ** *********************************************************/
107     
108     /* TODO: check for locks */
109     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
110     IWineD3DBaseTexture *baseTexture = NULL;
111     TRACE("(%p)Checking to see if the container is a base textuer\n", This);
112     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == D3D_OK) {
113         TRACE("Passing to conatiner\n");
114         IWineD3DBaseTexture_PreLoad(baseTexture);
115         IWineD3DBaseTexture_Release(baseTexture);
116     } else{
117     TRACE("(%p) : About to load surface\n", This);
118     ENTER_GL();
119 #if 0 /* TODO: context manager support */
120      IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
121 #endif
122     glEnable(GL_TEXTURE_2D); /* make sure texture support is enabled in this context */
123     if (This->currentDesc.Level == 0 &&  This->textureName == 0) {
124           glGenTextures(1, &This->textureName);
125           checkGLcall("glGenTextures");
126           TRACE("Surface %p given name %d\n", This, This->textureName);
127           glBindTexture(GL_TEXTURE_2D, This->textureName);
128           checkGLcall("glBindTexture");
129           IWineD3DSurface_LoadTexture((IWineD3DSurface *) This, GL_TEXTURE_2D, This->currentDesc.Level);
130           /* This is where we should be reducing the amount of GLMemoryUsed */
131     }else {
132         if (This->currentDesc.Level == 0) {
133           glBindTexture(GL_TEXTURE_2D, This->textureName);
134           checkGLcall("glBindTexture");
135           IWineD3DSurface_LoadTexture((IWineD3DSurface *) This, GL_TEXTURE_2D, This->currentDesc.Level);
136         } else  if (This->textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
137             /* assume this is a coding error not a real error for now */
138             FIXME("Mipmap surface has a glTexture bound to it!\n");
139         }
140     }
141     if (This->resource.pool == D3DPOOL_DEFAULT) {
142        /* Tell opengl to try and keep this texture in video ram (well mostly) */
143        GLclampf tmp;
144        tmp = 0.9f;
145         glPrioritizeTextures(1, &This->textureName, &tmp);
146     }
147     /* TODO: disable texture support, if it wastn't enabled when we entered. */
148 #if 0 /* TODO: context manager support */
149      IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
150               /* we don't care when the state is disabled(if atall) */);
151 #endif
152     LEAVE_GL();
153     }
154     return;
155 }
156
157 D3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
158     return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
159 }
160
161 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
162     return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
163 }
164
165 /* ******************************************************
166    IWineD3DSurface IWineD3DSurface parts follow
167    ****************************************************** */
168
169 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
170     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
171     HRESULT hr;
172     if (ppContainer == NULL) {
173             ERR("Get container called witout a null ppContainer\n");
174         return E_NOINTERFACE;
175     }
176     TRACE("(%p) : Relaying to queryInterface %p %p\n", This, ppContainer, *ppContainer);
177     /** From MSDN:
178      * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
179      * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
180      * GetContainer will return the Direct3D device used to create the surface.
181      */
182     hr = IUnknown_QueryInterface(This->container, riid, ppContainer);
183     return hr;
184 }
185
186 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
187     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
188
189     TRACE("(%p) : copying into %p\n", This, pDesc);
190     *(pDesc->Format)             = This->resource.format;
191     *(pDesc->Type)               = This->resource.resourceType;
192     *(pDesc->Usage)              = This->resource.usage;
193     *(pDesc->Pool)               = This->resource.pool;
194     *(pDesc->Size)               = This->resource.size;   /* dx8 only */
195     *(pDesc->MultiSampleType)    = This->currentDesc.MultiSampleType;
196     *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
197     *(pDesc->Width)              = This->currentDesc.Width;
198     *(pDesc->Height)             = This->currentDesc.Height;
199     return D3D_OK;
200 }
201
202 HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
203     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
204
205     /* fixme: should we really lock as such? */
206     if (This->inTexture && This->inPBuffer) {
207         FIXME("Warning: Surface is in texture memory or pbuffer\n");
208         This->inTexture = 0;
209         This->inPBuffer = 0;
210     }
211
212     if (FALSE == This->lockable) {
213         /* Note: UpdateTextures calls CopyRects which calls this routine to populate the 
214               texture regions, and since the destination is an unlockable region we need
215               to tolerate this                                                           */
216         TRACE("Warning: trying to lock unlockable surf@%p\n", This);  
217         /*return D3DERR_INVALIDCALL; */
218     }
219
220     if (iface == This->resource.wineD3DDevice->backBuffer || iface == This->resource.wineD3DDevice->renderTarget || 
221                     iface == This->resource.wineD3DDevice->frontBuffer || iface == This->resource.wineD3DDevice->depthStencilBuffer) {
222         if (iface == This->resource.wineD3DDevice->backBuffer) {
223             TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
224         } else if (iface == This->resource.wineD3DDevice->frontBuffer) {
225             TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
226         } else if (iface == This->resource.wineD3DDevice->renderTarget) {
227             TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
228         } else if (iface == This->resource.wineD3DDevice->depthStencilBuffer) {
229             TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
230         }
231     } else {
232         TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
233     }
234
235     /* DXTn formats don't have exact pitches as they are to the new row of blocks,
236          where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt3/5)      
237           ie pitch = (width/4) * bytes per block                                  */
238     if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
239         pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 3;
240     else if (This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT5) /* DXT3/5 is 16 bytes per block */
241         pLockedRect->Pitch = (This->currentDesc.Width >> 2) << 4;
242     else
243         pLockedRect->Pitch = This->bytesPerPixel * This->currentDesc.Width;  /* Bytes / row */    
244
245     if (NULL == pRect) {
246         pLockedRect->pBits = This->resource.allocatedMemory;
247         This->lockedRect.left   = 0;
248         This->lockedRect.top    = 0;
249         This->lockedRect.right  = This->currentDesc.Width;
250         This->lockedRect.bottom = This->currentDesc.Height;
251         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);
252     } else {
253         TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
254
255         if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
256             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel/2));
257         } else {
258             pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
259         }
260         This->lockedRect.left   = pRect->left;
261         This->lockedRect.top    = pRect->top;
262         This->lockedRect.right  = pRect->right;
263         This->lockedRect.bottom = pRect->bottom;
264     }
265
266
267     if (0 == This->resource.usage) { /* classic surface */
268
269         /* Nothing to do ;) */
270
271     } else if (D3DUSAGE_RENDERTARGET & This->resource.usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
272
273         if (iface == This->resource.wineD3DDevice->backBuffer || iface == This->resource.wineD3DDevice->renderTarget || iface == This->resource.wineD3DDevice->frontBuffer) {
274             GLint  prev_store;
275             GLenum prev_read;
276
277             ENTER_GL();
278
279             /**
280              * for render->surface copy begin to begin of allocatedMemory
281              * unlock can be more easy
282              */
283             pLockedRect->pBits = This->resource.allocatedMemory;
284
285             glFlush();
286             vcheckGLcall("glFlush");
287             glGetIntegerv(GL_READ_BUFFER, &prev_read);
288             vcheckGLcall("glIntegerv");
289             glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
290             vcheckGLcall("glIntegerv");
291
292             if (iface == This->resource.wineD3DDevice->backBuffer) {
293                 glReadBuffer(GL_BACK);
294             } else if (iface == This->resource.wineD3DDevice->frontBuffer || iface == This->resource.wineD3DDevice->renderTarget) {
295                 glReadBuffer(GL_FRONT);
296             } else if (iface == This->resource.wineD3DDevice->depthStencilBuffer) {
297                 ERR("Stencil Buffer lock unsupported for now\n");
298             }
299             vcheckGLcall("glReadBuffer");
300
301             {
302                 long j;
303                 GLenum format = D3DFmt2GLFmt(This->resource.wineD3DDevice, This->resource.format);
304                 GLenum type   = D3DFmt2GLType(This->resource.wineD3DDevice, This->resource.format);
305                 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
306                     glReadPixels(This->lockedRect.left, 
307                                  This->lockedRect.bottom - j - 1, 
308                                  This->lockedRect.right - This->lockedRect.left, 
309                                  1,
310                                  format, 
311                                  type, 
312                                  (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
313                     vcheckGLcall("glReadPixels");
314                 }
315             }
316
317             glReadBuffer(prev_read);
318             vcheckGLcall("glReadBuffer");
319
320             LEAVE_GL();
321
322         } else {
323             FIXME("unsupported locking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
324         }
325
326     } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
327
328         FIXME("TODO stencil depth surface locking surf@%p usage(%lu)\n", This, This->resource.usage);
329
330     } else {
331         FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
332     }
333
334     if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
335         /* Don't dirtify */
336     } else {
337         IWineD3DBaseTexture *pBaseTexture;
338         /**
339          * Dirtify on lock
340          * as seen in msdn docs
341          */
342         IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
343
344         /** Dirtify Container if needed */        
345         if (D3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
346             TRACE("Making container dirty\n");
347             IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);            
348             IWineD3DBaseTexture_Release(pBaseTexture);
349         }else{
350             TRACE("Surface is standalone, no need to dirty the container\n");
351         }
352     }
353
354     TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
355
356     This->locked = TRUE;
357     return D3D_OK;
358 }
359
360 HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
361     GLint skipBytes = 0;
362     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
363
364     if (FALSE == This->locked) {
365         ERR("trying to Unlock an unlocked surf@%p\n", This);  
366         return D3DERR_INVALIDCALL;
367     }
368
369     if (iface== This->resource.wineD3DDevice->backBuffer || iface == This->resource.wineD3DDevice->frontBuffer || 
370                     iface == This->resource.wineD3DDevice->depthStencilBuffer || iface == This->resource.wineD3DDevice->renderTarget) {
371         if (iface == This->resource.wineD3DDevice->backBuffer) {
372             TRACE("(%p, backBuffer) : dirtyfied(%d)\n", This, This->Dirty);
373         } else if (iface == This->resource.wineD3DDevice->frontBuffer) {
374             TRACE("(%p, frontBuffer) : dirtyfied(%d)\n", This, This->Dirty);
375         } else if (iface == This->resource.wineD3DDevice->depthStencilBuffer) {
376             TRACE("(%p, stencilBuffer) : dirtyfied(%d)\n", This, This->Dirty);
377         } else if (iface == This->resource.wineD3DDevice->renderTarget) {
378             TRACE("(%p, renderTarget) : dirtyfied(%d)\n", This, This->Dirty);
379         }
380     } else {
381         TRACE("(%p) : dirtyfied(%d)\n", This, This->Dirty);
382     }
383
384     if (FALSE == This->Dirty) {
385         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
386         goto unlock_end;
387     }
388
389     if (0 == This->resource.usage) { /* classic surface */
390         /**
391          * nothing to do
392          * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
393          */
394     } else if (D3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
395
396         if (iface == This->resource.wineD3DDevice->backBuffer || iface == This->resource.wineD3DDevice->frontBuffer || iface == This->resource.wineD3DDevice->renderTarget) {
397             GLint  prev_store;
398             GLenum prev_draw;
399             GLint  prev_rasterpos[4];
400
401             ENTER_GL();
402
403             glFlush();
404             vcheckGLcall("glFlush");
405             glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
406             vcheckGLcall("glIntegerv");
407             glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
408             vcheckGLcall("glIntegerv");
409             glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
410             vcheckGLcall("glIntegerv");
411             glPixelZoom(1.0, -1.0);
412             vcheckGLcall("glPixelZoom");
413
414             /* glDrawPixels transforms the raster position as though it was a vertex -
415                we want to draw at screen position 0,0 - Set up ortho (rhw) mode as   
416                per drawprim (and leave set - it will sort itself out due to last_was_rhw */
417             if (!This->resource.wineD3DDevice->last_was_rhw) {
418
419                 double X, Y, height, width, minZ, maxZ;
420                 This->resource.wineD3DDevice->last_was_rhw = TRUE;
421
422                 /* Transformed already into viewport coordinates, so we do not need transform
423                    matrices. Reset all matrices to identity and leave the default matrix in world 
424                    mode.                                                                         */
425                 glMatrixMode(GL_MODELVIEW);
426                 checkGLcall("glMatrixMode");
427                 glLoadIdentity();
428                 checkGLcall("glLoadIdentity");
429
430                 glMatrixMode(GL_PROJECTION);
431                 checkGLcall("glMatrixMode");
432                 glLoadIdentity();
433                 checkGLcall("glLoadIdentity");
434
435                 /* Set up the viewport to be full viewport */
436                 X      = This->resource.wineD3DDevice->stateBlock->viewport.X;
437                 Y      = This->resource.wineD3DDevice->stateBlock->viewport.Y;
438                 height = This->resource.wineD3DDevice->stateBlock->viewport.Height;
439                 width  = This->resource.wineD3DDevice->stateBlock->viewport.Width;
440                 minZ   = This->resource.wineD3DDevice->stateBlock->viewport.MinZ;
441                 maxZ   = This->resource.wineD3DDevice->stateBlock->viewport.MaxZ;
442                 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
443                 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
444                 checkGLcall("glOrtho");
445
446                 /* Window Coord 0 is the middle of the first pixel, so translate by half
447                    a pixel (See comment above glTranslate below)                         */
448                 glTranslatef(0.5, 0.5, 0);
449                 checkGLcall("glTranslatef(0.5, 0.5, 0)");
450             }
451
452             if (iface == This->resource.wineD3DDevice->backBuffer) {
453                 glDrawBuffer(GL_BACK);
454             } else if (iface == This->resource.wineD3DDevice->frontBuffer || iface == This->resource.wineD3DDevice->renderTarget) {
455                 glDrawBuffer(GL_FRONT);
456             }
457             vcheckGLcall("glDrawBuffer");
458
459             /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
460             glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
461             glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
462
463             /* And back buffers are not blended */
464             glDisable(GL_BLEND);
465
466             glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
467             vcheckGLcall("glRasterPos2f");
468             switch (This->resource.format) {
469             case WINED3DFMT_R5G6B5:
470                 {
471                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
472                                  GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->resource.allocatedMemory);
473                     vcheckGLcall("glDrawPixels");
474                 }
475                 break;
476             case WINED3DFMT_R8G8B8:
477                 {
478                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
479                                  GL_RGB, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
480                     vcheckGLcall("glDrawPixels");
481                 }
482                 break;
483             case WINED3DFMT_X8R8G8B8: /* FIXME: there's no alpha change with D3DFMT_X8R8G8B8 but were using GL_BGRA */
484             case WINED3DFMT_A8R8G8B8:
485                 {
486                     glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
487                     vcheckGLcall("glPixelStorei");
488                     glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
489                                  GL_BGRA, GL_UNSIGNED_BYTE, This->resource.allocatedMemory);
490                     vcheckGLcall("glDrawPixels");
491                     glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
492                     vcheckGLcall("glPixelStorei");
493                 }
494                 break;
495             default:
496                 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
497             }
498
499             glPixelZoom(1.0,1.0);
500             vcheckGLcall("glPixelZoom");
501             glDrawBuffer(prev_draw);
502             vcheckGLcall("glDrawBuffer");
503             glRasterPos3iv(&prev_rasterpos[0]);
504             vcheckGLcall("glRasterPos3iv");
505
506             /* Reset to previous pack row length / blending state */
507             glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
508             if (This->resource.wineD3DDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
509
510             LEAVE_GL();
511
512             /** restore clean dirty state */
513             IWineD3DSurface_CleanDirtyRect(iface);
514
515         } else {
516             FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->resource.usage);
517         }
518
519     } else if (D3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
520
521         if (iface == This->resource.wineD3DDevice->depthStencilBuffer) {
522             FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
523         } else {
524             FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
525         }
526
527     } else {
528         FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
529     }
530
531     unlock_end:
532     This->locked = FALSE;
533     memset(&This->lockedRect, 0, sizeof(RECT));
534     return D3D_OK;
535 }
536
537 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
538     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
539     FIXME("No support for GetDC yet for surface %p\n", This);
540     return D3DERR_INVALIDCALL;
541 }
542
543 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
544     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
545     FIXME("No support for ReleaseDC yet for surface %p\n", This);
546     return D3DERR_INVALIDCALL;
547 }
548
549 /* ******************************************************
550    IWineD3DSurface Internal (No mapping to directx api) parts follow
551    ****************************************************** */
552 HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, GLenum gl_target, GLenum gl_level) {
553     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
554
555     if (This->inTexture)
556         return D3D_OK;
557
558     if (This->inPBuffer) {
559         ENTER_GL();
560
561         if (gl_level != 0)
562             FIXME("Surface in texture is only supported for level 0\n");
563         else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
564                  This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT3 ||
565                  This->resource.format == WINED3DFMT_DXT5)
566             FIXME("Format %d not supported\n", This->resource.format);
567         else {
568             glCopyTexImage2D(gl_target,
569                              0,
570                              D3DFmt2GLIntFmt(This->resource.wineD3DDevice,
571                                              This->resource.format),
572                              0,
573                              0,
574                              This->currentDesc.Width,
575                              This->currentDesc.Height,
576                              0);
577             TRACE("Updating target %d\n", gl_target);
578             This->inTexture = TRUE;
579         }
580         LEAVE_GL();
581         return D3D_OK;
582     }
583
584     if ((This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) &&
585         !GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
586         /**
587          * wanted a paletted texture and not really support it in HW 
588          * so software emulation code begin
589          */
590         UINT i;
591         PALETTEENTRY* pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
592         VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->currentDesc.Width * This->currentDesc.Height * sizeof(DWORD));
593         BYTE* dst = (BYTE*) surface;
594         BYTE* src = (BYTE*) This->resource.allocatedMemory;
595
596         for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
597             BYTE color = *src++;
598             *dst++ = pal[color].peRed;
599             *dst++ = pal[color].peGreen;
600             *dst++ = pal[color].peBlue;
601             if (This->resource.format == WINED3DFMT_A8P8)
602                 *dst++ = pal[color].peFlags;
603             else
604                 *dst++ = 0xFF; 
605         }
606
607         ENTER_GL();
608
609         TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
610               gl_target,
611               gl_level, 
612               GL_RGBA,
613               This->currentDesc.Width, 
614               This->currentDesc.Height, 
615               0, 
616               GL_RGBA,
617               GL_UNSIGNED_BYTE,
618               surface);
619         glTexImage2D(gl_target,
620                      gl_level, 
621                      GL_RGBA,
622                      This->currentDesc.Width,
623                      This->currentDesc.Height,
624                      0,
625                      GL_RGBA,
626                      GL_UNSIGNED_BYTE,
627                      surface);
628         checkGLcall("glTexImage2D");
629         HeapFree(GetProcessHeap(), 0, surface);
630
631         LEAVE_GL();
632
633         return D3D_OK;    
634     }
635
636     if (This->resource.format == WINED3DFMT_DXT1 ||
637         This->resource.format == WINED3DFMT_DXT3 ||
638         This->resource.format == WINED3DFMT_DXT5) {
639         if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
640             TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
641                   gl_target, 
642                   gl_level, 
643                   D3DFmt2GLIntFmt(This->resource.wineD3DDevice, This->resource.format), 
644                   This->currentDesc.Width, 
645                   This->currentDesc.Height, 
646                   0, 
647                   This->resource.size,
648                   This->resource.allocatedMemory);
649
650             ENTER_GL();
651
652             GL_EXTCALL(glCompressedTexImage2DARB)(gl_target, 
653                                                   gl_level, 
654                                                   D3DFmt2GLIntFmt(This->resource.wineD3DDevice, This->resource.format),
655                                                   This->currentDesc.Width,
656                                                   This->currentDesc.Height,
657                                                   0,
658                                                   This->resource.size,
659                                                   This->resource.allocatedMemory);
660             checkGLcall("glCommpressedTexTexImage2D");
661
662             LEAVE_GL();
663         } else {
664             FIXME("Using DXT1/3/5 without advertized support\n");
665         }
666     } else {
667
668         TRACE("Calling glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
669               gl_target, 
670               gl_level, 
671               debug_d3dformat(This->resource.format),
672               D3DFmt2GLIntFmt(This->resource.wineD3DDevice, This->resource.format), 
673               This->currentDesc.Width, 
674               This->currentDesc.Height, 
675               0, 
676               D3DFmt2GLFmt(This->resource.wineD3DDevice, This->resource.format), 
677               D3DFmt2GLType(This->resource.wineD3DDevice, This->resource.format),
678               This->resource.allocatedMemory);
679
680         ENTER_GL();
681
682         glTexImage2D(gl_target, 
683                      gl_level,
684                      D3DFmt2GLIntFmt(This->resource.wineD3DDevice, This->resource.format),
685                      This->currentDesc.Width,
686                      This->currentDesc.Height,
687                      0,
688                      D3DFmt2GLFmt(This->resource.wineD3DDevice, This->resource.format),
689                      D3DFmt2GLType(This->resource.wineD3DDevice, This->resource.format),
690                      This->resource.allocatedMemory);
691         checkGLcall("glTexImage2D");
692
693         LEAVE_GL();
694
695 #if 0
696         {
697             static unsigned int gen = 0;
698             char buffer[4096];
699             ++gen;
700             if ((gen % 10) == 0) {
701                 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, gl_target, gl_level, gen);
702                 IWineD3DSurfaceImpl_SaveSnapshot((LPDIRECT3DSURFACE8) This, buffer);
703             }
704             /*
705              * debugging crash code
706             if (gen == 250) {
707               void** test = NULL;
708               *test = 0;
709             }
710             */
711         }
712 #endif
713     }
714
715     return D3D_OK;
716 }
717
718 #include <errno.h>
719 #include <stdio.h>
720 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
721     FILE* f = NULL;
722     ULONG i;
723     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
724
725     f = fopen(filename, "w+");
726     if (NULL == f) {
727         ERR("opening of %s failed with: %s\n", filename, strerror(errno));
728         return D3DERR_INVALIDCALL;
729     }
730
731     TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->resource.format));
732
733     fprintf(f, "P6\n%u %u\n255\n", This->currentDesc.Width, This->currentDesc.Height);
734     switch (This->resource.format) {
735     case WINED3DFMT_X8R8G8B8:
736     case WINED3DFMT_A8R8G8B8:
737         {
738             DWORD color;
739             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
740                 color = ((DWORD*) This->resource.allocatedMemory)[i];
741                 fputc((color >> 16) & 0xFF, f);
742                 fputc((color >>  8) & 0xFF, f);
743                 fputc((color >>  0) & 0xFF, f);
744             }
745         }
746         break;
747     case WINED3DFMT_R8G8B8:
748         {
749             BYTE* color;
750             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
751                 color = ((BYTE*) This->resource.allocatedMemory) + (3 * i);
752                 fputc((color[0]) & 0xFF, f);
753                 fputc((color[1]) & 0xFF, f);
754                 fputc((color[2]) & 0xFF, f);
755             }
756         }
757         break;
758     case WINED3DFMT_A1R5G5B5:
759         {
760             WORD color;
761             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
762                 color = ((WORD*) This->resource.allocatedMemory)[i];
763                 fputc(((color >> 10) & 0x1F) * 255 / 31, f);
764                 fputc(((color >>  5) & 0x1F) * 255 / 31, f);
765                 fputc(((color >>  0) & 0x1F) * 255 / 31, f);
766             }
767         }
768         break;
769     case WINED3DFMT_A4R4G4B4:
770         {
771             WORD color;
772             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
773                 color = ((WORD*) This->resource.allocatedMemory)[i];
774                 fputc(((color >>  8) & 0x0F) * 255 / 15, f);
775                 fputc(((color >>  4) & 0x0F) * 255 / 15, f);
776                 fputc(((color >>  0) & 0x0F) * 255 / 15, f);
777             }
778         }
779         break;
780
781     case WINED3DFMT_R5G6B5:
782         {
783             WORD color;
784             for (i = 0; i < This->currentDesc.Width * This->currentDesc.Height; i++) {
785                 color = ((WORD*) This->resource.allocatedMemory)[i];
786                 fputc(((color >> 11) & 0x1F) * 255 / 31, f);
787                 fputc(((color >>  5) & 0x3F) * 255 / 63, f);
788                 fputc(((color >>  0) & 0x1F) * 255 / 31, f);
789             }
790         }
791         break;
792     default: 
793         FIXME("Unimplemented dump mode format(%u,%s)\n", This->resource.format, debug_d3dformat(This->resource.format));
794     }
795     fclose(f);
796     return D3D_OK;
797 }
798
799 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
800     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
801     This->Dirty = FALSE;
802     This->dirtyRect.left   = This->currentDesc.Width;
803     This->dirtyRect.top    = This->currentDesc.Height;
804     This->dirtyRect.right  = 0;
805     This->dirtyRect.bottom = 0;
806     TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left, 
807           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
808     return D3D_OK;
809 }
810
811 /**
812  *   Slightly inefficient way to handle multiple dirty rects but it works :)
813  */
814 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
815     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
816     This->Dirty = TRUE;
817     if (NULL != pDirtyRect) {
818         This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
819         This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
820         This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
821         This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
822     } else {
823         This->dirtyRect.left   = 0;
824         This->dirtyRect.top    = 0;
825         This->dirtyRect.right  = This->currentDesc.Width;
826         This->dirtyRect.bottom = This->currentDesc.Height;
827     }
828     TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Dirty, This->dirtyRect.left, 
829           This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
830     return D3D_OK;
831 }
832
833 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IUnknown *container) {
834     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
835     TRACE("Setting container to %p from %p\n", container, This->container);
836     This->container = container;
837     return D3D_OK;    
838 }
839
840 /* TODO: replace this function with context management routines */
841 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL  inTexture) {
842     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
843     
844     This->inPBuffer = inPBuffer;
845     This->inTexture = inTexture;
846     return D3D_OK;
847 }
848
849 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
850 {
851     /* IUnknown */
852     IWineD3DSurfaceImpl_QueryInterface,
853     IWineD3DSurfaceImpl_AddRef,
854     IWineD3DSurfaceImpl_Release,
855     /* IWineD3DResource */
856     IWineD3DSurfaceImpl_GetParent,
857     IWineD3DSurfaceImpl_GetDevice,
858     IWineD3DSurfaceImpl_SetPrivateData,
859     IWineD3DSurfaceImpl_GetPrivateData,
860     IWineD3DSurfaceImpl_FreePrivateData,
861     IWineD3DSurfaceImpl_SetPriority,
862     IWineD3DSurfaceImpl_GetPriority,
863     IWineD3DSurfaceImpl_PreLoad,
864     IWineD3DSurfaceImpl_GetType,
865     /* IWineD3DSurface */    
866     IWineD3DSurfaceImpl_GetContainer,
867     IWineD3DSurfaceImpl_GetDesc,
868     IWineD3DSurfaceImpl_LockRect,
869     IWineD3DSurfaceImpl_UnlockRect,
870     IWineD3DSurfaceImpl_GetDC,
871     IWineD3DSurfaceImpl_ReleaseDC,
872     /* Internal use: */
873     IWineD3DSurfaceImpl_CleanDirtyRect,
874     IWineD3DSurfaceImpl_AddDirtyRect,
875     IWineD3DSurfaceImpl_LoadTexture,
876     IWineD3DSurfaceImpl_SaveSnapshot,
877     IWineD3DSurfaceImpl_SetContainer,
878     IWineD3DSurfaceImpl_SetPBufferState    
879 };