Store a pointer to the currently selected phys bitmap in the device
[wine] / dlls / d3d8 / surface.c
1 /*
2  * IDirect3DSurface8 implementation
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2002-2003 Raphael Junqueira
6  * Copyright 2004 Christian Costa
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #define COBJMACROS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "wingdi.h"
36 #include "wine/debug.h"
37
38 #include "d3d8_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
41
42 /* IDirect3DVolume IUnknown parts follow: */
43 HRESULT WINAPI IDirect3DSurface8Impl_QueryInterface(LPDIRECT3DSURFACE8 iface,REFIID riid,LPVOID *ppobj)
44 {
45     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
46
47     if (IsEqualGUID(riid, &IID_IUnknown)
48         || IsEqualGUID(riid, &IID_IDirect3DSurface8)) {
49         IDirect3DSurface8Impl_AddRef(iface);
50         *ppobj = This;
51         return D3D_OK;
52     }
53
54     WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
55     return E_NOINTERFACE;
56 }
57
58 ULONG WINAPI IDirect3DSurface8Impl_AddRef(LPDIRECT3DSURFACE8 iface) {
59     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
60     ULONG ref = InterlockedIncrement(&This->ref);
61
62     TRACE("(%p) : AddRef from %ld\n", This, ref - 1);
63
64     return ref;
65 }
66
67 ULONG WINAPI IDirect3DSurface8Impl_Release(LPDIRECT3DSURFACE8 iface) {
68     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
69     ULONG ref = InterlockedDecrement(&This->ref);
70
71     TRACE("(%p) : ReleaseRef to %ld\n", This, ref);
72
73     if (ref == 0) {
74       HeapFree(GetProcessHeap(), 0, This->allocatedMemory);
75       HeapFree(GetProcessHeap(), 0, This);
76     }
77     return ref;
78 }
79
80 /* IDirect3DSurface8: */
81 HRESULT WINAPI IDirect3DSurface8Impl_GetDevice(LPDIRECT3DSURFACE8 iface, IDirect3DDevice8** ppDevice) {
82     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
83     TRACE("(%p) : returning %p\n", This, This->Device);
84     *ppDevice = (LPDIRECT3DDEVICE8) This->Device;
85     /**
86      * Note  Calling this method will increase the internal reference count 
87      * on the IDirect3DDevice8 interface. 
88      */
89     IDirect3DDevice8Impl_AddRef(*ppDevice);
90     return D3D_OK;
91 }
92
93 HRESULT WINAPI IDirect3DSurface8Impl_SetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
94     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
95     FIXME("(%p) : stub\n", This);    
96     return D3D_OK;
97 }
98
99 HRESULT WINAPI IDirect3DSurface8Impl_GetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
100     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
101     FIXME("(%p) : stub\n", This);    
102     return D3D_OK;
103 }
104
105 HRESULT WINAPI IDirect3DSurface8Impl_FreePrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid) {
106     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
107     FIXME("(%p) : stub\n", This);    
108     return D3D_OK;
109 }
110
111 HRESULT WINAPI IDirect3DSurface8Impl_GetContainer(LPDIRECT3DSURFACE8 iface, REFIID riid, void** ppContainer) {
112     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
113     HRESULT res;
114     res = IUnknown_QueryInterface(This->Container, riid, ppContainer);
115     if (E_NOINTERFACE == res) { 
116       /**
117        * If the surface is created using CreateImageSurface, CreateRenderTarget, 
118        * or CreateDepthStencilSurface, the surface is considered stand alone. In this case, 
119        * GetContainer will return the Direct3D device used to create the surface. 
120        */
121       res = IUnknown_QueryInterface(This->Container, &IID_IDirect3DDevice8, ppContainer);
122     }
123     TRACE("(%p) : returning %p\n", This, *ppContainer);
124     return res;
125 }
126
127 HRESULT WINAPI IDirect3DSurface8Impl_GetDesc(LPDIRECT3DSURFACE8 iface, D3DSURFACE_DESC *pDesc) {
128     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
129
130     TRACE("(%p) : copying into %p\n", This, pDesc);
131     memcpy(pDesc, &This->myDesc, sizeof(D3DSURFACE_DESC));
132     return D3D_OK;
133 }
134
135 HRESULT WINAPI IDirect3DSurface8Impl_LockRect(LPDIRECT3DSURFACE8 iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
136     HRESULT hr;
137     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
138   
139     /* fixme: should we really lock as such? */
140     if (This->inTexture && This->inPBuffer) {
141         FIXME("Warning: Surface is in texture memory or pbuffer\n");
142         This->inTexture = 0;
143         This->inPBuffer = 0;
144     }
145     
146     if (FALSE == This->lockable) {
147       /* Note: UpdateTextures calls CopyRects which calls this routine to populate the 
148             texture regions, and since the destination is an unlockable region we need
149             to tolerate this                                                           */
150       TRACE("Warning: trying to lock unlockable surf@%p\n", This);  
151       /*return D3DERR_INVALIDCALL; */
152     }
153
154     if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer || This->Device->depthStencilBuffer) {
155       if (This == This->Device->backBuffer) {
156         TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
157       } else if (This == This->Device->frontBuffer) {
158         TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
159       } else if (This == This->Device->renderTarget) {
160         TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
161       } else if (This == This->Device->depthStencilBuffer) {
162         TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
163       }
164     } else {
165       TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
166     }
167
168     /* DXTn formats don't have exact pitches as they are to the new row of blocks,
169          where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt3/5)      
170           ie pitch = (width/4) * bytes per block                                  */
171     if (This->myDesc.Format == D3DFMT_DXT1) /* DXT1 is 8 bytes per block */
172         pLockedRect->Pitch = (This->myDesc.Width/4) * 8;
173     else if (This->myDesc.Format == D3DFMT_DXT3 || This->myDesc.Format == D3DFMT_DXT5) /* DXT3/5 is 16 bytes per block */
174         pLockedRect->Pitch = (This->myDesc.Width/4) * 16;
175     else
176         pLockedRect->Pitch = This->bytesPerPixel * This->myDesc.Width;  /* Bytes / row */    
177
178     if (NULL == pRect) {
179       pLockedRect->pBits = This->allocatedMemory;
180       This->lockedRect.left   = 0;
181       This->lockedRect.top    = 0;
182       This->lockedRect.right  = This->myDesc.Width;
183       This->lockedRect.bottom = This->myDesc.Height;
184       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);
185     } else {
186       TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
187
188       if (This->myDesc.Format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
189           pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel/2));
190       } else {
191           pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
192       }
193       This->lockedRect.left   = pRect->left;
194       This->lockedRect.top    = pRect->top;
195       This->lockedRect.right  = pRect->right;
196       This->lockedRect.bottom = pRect->bottom;
197     }
198
199
200     if (0 == This->myDesc.Usage) { /* classic surface */
201
202       /* Nothing to do ;) */
203
204     } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage && !(Flags&D3DLOCK_DISCARD)) { /* render surfaces */
205       
206       if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer) {
207         GLint  prev_store;
208         GLenum prev_read;
209         
210         ENTER_GL();
211
212         /**
213          * for render->surface copy begin to begin of allocatedMemory
214          * unlock can be more easy
215          */
216         pLockedRect->pBits = This->allocatedMemory;
217         
218         glFlush();
219         vcheckGLcall("glFlush");
220         glGetIntegerv(GL_READ_BUFFER, &prev_read);
221         vcheckGLcall("glIntegerv");
222         glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
223         vcheckGLcall("glIntegerv");
224
225         if (This == This->Device->backBuffer) {
226           glReadBuffer(GL_BACK);
227         } else if (This == This->Device->frontBuffer || This == This->Device->renderTarget) {
228           glReadBuffer(GL_FRONT);
229         } else if (This == This->Device->depthStencilBuffer) {
230           ERR("Stencil Buffer lock unsupported for now\n");
231         }
232         vcheckGLcall("glReadBuffer");
233
234         {
235           long j;
236           GLenum format = D3DFmt2GLFmt(This->Device, This->myDesc.Format);
237           GLenum type   = D3DFmt2GLType(This->Device, This->myDesc.Format);
238           for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
239             glReadPixels(This->lockedRect.left, 
240                          This->lockedRect.bottom - j - 1, 
241                          This->lockedRect.right - This->lockedRect.left, 
242                          1,
243                          format, 
244                          type, 
245                          (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
246             vcheckGLcall("glReadPixels");
247           }
248         }
249
250         glReadBuffer(prev_read);
251         vcheckGLcall("glReadBuffer");
252
253         LEAVE_GL();
254
255       } else {
256         FIXME("unsupported locking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
257       }
258
259     } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
260
261       FIXME("TODO stencil depth surface locking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
262
263     } else {
264       FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
265     }
266
267     if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
268       /* Don't dirtify */
269     } else {
270       /**
271        * Dirtify on lock
272        * as seen in msdn docs
273        */
274       IDirect3DSurface8Impl_AddDirtyRect(iface, &This->lockedRect);
275
276       /** Dirtify Container if needed */
277       if (NULL != This->Container) {
278         IDirect3DBaseTexture8* cont = NULL;
279         hr = IUnknown_QueryInterface(This->Container, &IID_IDirect3DBaseTexture8, (void**) &cont);
280         
281         if (SUCCEEDED(hr) && NULL != cont) {
282           IDirect3DBaseTexture8Impl_SetDirty(cont, TRUE);
283           IDirect3DBaseTexture8_Release(cont);
284           cont = NULL;
285         }
286       }
287     }
288
289     TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
290
291     This->locked = TRUE;
292     return D3D_OK;
293 }
294
295 HRESULT WINAPI IDirect3DSurface8Impl_UnlockRect(LPDIRECT3DSURFACE8 iface) {
296     GLint skipBytes = 0;
297     IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
298
299     if (FALSE == This->locked) {
300       ERR("trying to Unlock an unlocked surf@%p\n", This);  
301       return D3DERR_INVALIDCALL;
302     }
303
304     if (This == This->Device->backBuffer || This == This->Device->frontBuffer || This->Device->depthStencilBuffer || This == This->Device->renderTarget) {
305       if (This == This->Device->backBuffer) {
306         TRACE("(%p, backBuffer) : dirtyfied(%d)\n", This, This->Dirty);
307       } else if (This == This->Device->frontBuffer) {
308         TRACE("(%p, frontBuffer) : dirtyfied(%d)\n", This, This->Dirty);
309       } else if (This == This->Device->depthStencilBuffer) {
310         TRACE("(%p, stencilBuffer) : dirtyfied(%d)\n", This, This->Dirty);
311       } else if (This == This->Device->renderTarget) {
312         TRACE("(%p, renderTarget) : dirtyfied(%d)\n", This, This->Dirty);
313       }
314     } else {
315       TRACE("(%p) : dirtyfied(%d)\n", This, This->Dirty);
316     }
317
318     if (FALSE == This->Dirty) {
319       TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
320       goto unlock_end;
321     }
322
323     if (0 == This->myDesc.Usage) { /* classic surface */
324       /**
325        * nothing to do
326        * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
327        */
328     } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage) { /* render surfaces */
329
330       if (This == This->Device->backBuffer || This == This->Device->frontBuffer || This == This->Device->renderTarget) {
331         GLint  prev_store;
332         GLenum prev_draw;
333         GLint  prev_rasterpos[4];
334
335         ENTER_GL();
336         
337         glFlush();
338         vcheckGLcall("glFlush");
339         glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
340         vcheckGLcall("glIntegerv");
341         glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
342         vcheckGLcall("glIntegerv");
343         glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
344         vcheckGLcall("glIntegerv");
345         glPixelZoom(1.0, -1.0);
346         vcheckGLcall("glPixelZoom");
347
348         /* glDrawPixels transforms the raster position as though it was a vertex -
349            we want to draw at screen position 0,0 - Set up ortho (rhw) mode as   
350            per drawprim (and leave set - it will sort itself out due to last_was_rhw */
351         if (!This->Device->last_was_rhw) {
352
353             double X, Y, height, width, minZ, maxZ;
354             This->Device->last_was_rhw = TRUE;
355
356             /* Transformed already into viewport coordinates, so we do not need transform
357                matrices. Reset all matrices to identity and leave the default matrix in world 
358                mode.                                                                         */
359             glMatrixMode(GL_MODELVIEW);
360             checkGLcall("glMatrixMode");
361             glLoadIdentity();
362             checkGLcall("glLoadIdentity");
363
364             glMatrixMode(GL_PROJECTION);
365             checkGLcall("glMatrixMode");
366             glLoadIdentity();
367             checkGLcall("glLoadIdentity");
368
369             /* Set up the viewport to be full viewport */
370             X      = This->Device->StateBlock->viewport.X;
371             Y      = This->Device->StateBlock->viewport.Y;
372             height = This->Device->StateBlock->viewport.Height;
373             width  = This->Device->StateBlock->viewport.Width;
374             minZ   = This->Device->StateBlock->viewport.MinZ;
375             maxZ   = This->Device->StateBlock->viewport.MaxZ;
376             TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
377             glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
378             checkGLcall("glOrtho");
379
380             /* Window Coord 0 is the middle of the first pixel, so translate by half
381                a pixel (See comment above glTranslate below)                         */
382             glTranslatef(0.5, 0.5, 0);
383             checkGLcall("glTranslatef(0.5, 0.5, 0)");
384         }
385
386         if (This == This->Device->backBuffer) {
387           glDrawBuffer(GL_BACK);
388         } else if (This == This->Device->frontBuffer || This == This->Device->renderTarget) {
389           glDrawBuffer(GL_FRONT);
390         }
391         vcheckGLcall("glDrawBuffer");
392
393     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
394     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
395     glPixelStorei(GL_UNPACK_ROW_LENGTH, This->myDesc.Width);
396
397     /* And back buffers are not blended */
398     glDisable(GL_BLEND);
399
400         glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
401         vcheckGLcall("glRasterPos2f");
402         switch (This->myDesc.Format) {
403         case D3DFMT_R5G6B5:
404           {
405             glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
406                          GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->allocatedMemory);
407             vcheckGLcall("glDrawPixels");
408           }
409           break;
410         case D3DFMT_R8G8B8:
411           {
412             glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
413                          GL_RGB, GL_UNSIGNED_BYTE, This->allocatedMemory);
414             vcheckGLcall("glDrawPixels");
415           }
416           break;
417         case D3DFMT_A8R8G8B8:
418           {
419             glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
420             vcheckGLcall("glPixelStorei");
421             glDrawPixels(This->lockedRect.right - This->lockedRect.left, (This->lockedRect.bottom - This->lockedRect.top)-1,
422                          GL_BGRA, GL_UNSIGNED_BYTE, This->allocatedMemory);
423             vcheckGLcall("glDrawPixels");
424             glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
425             vcheckGLcall("glPixelStorei");
426           }
427           break;
428         default:
429           FIXME("Unsupported Format %u in locking func\n", This->myDesc.Format);
430         }
431
432         glPixelZoom(1.0,1.0);
433         vcheckGLcall("glPixelZoom");
434         glDrawBuffer(prev_draw);
435         vcheckGLcall("glDrawBuffer");
436         glRasterPos3iv(&prev_rasterpos[0]);
437         vcheckGLcall("glRasterPos3iv");
438
439     /* Reset to previous pack row length / blending state */
440     glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
441     if (This->Device->StateBlock->renderstate[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
442
443         LEAVE_GL();
444
445         /** restore clean dirty state */
446         IDirect3DSurface8Impl_CleanDirtyRect(iface);
447
448       } else {
449         FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
450       }
451
452     } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
453     
454       if (This == This->Device->depthStencilBuffer) {
455         FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
456       } else {
457         FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
458       }
459
460     } else {
461       FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
462     }
463
464 unlock_end:
465     This->locked = FALSE;
466     memset(&This->lockedRect, 0, sizeof(RECT));
467     return D3D_OK;
468 }
469
470
471 IDirect3DSurface8Vtbl Direct3DSurface8_Vtbl =
472 {
473     IDirect3DSurface8Impl_QueryInterface,
474     IDirect3DSurface8Impl_AddRef,
475     IDirect3DSurface8Impl_Release,
476     IDirect3DSurface8Impl_GetDevice,
477     IDirect3DSurface8Impl_SetPrivateData,
478     IDirect3DSurface8Impl_GetPrivateData,
479     IDirect3DSurface8Impl_FreePrivateData,
480     IDirect3DSurface8Impl_GetContainer,
481     IDirect3DSurface8Impl_GetDesc,
482     IDirect3DSurface8Impl_LockRect,
483     IDirect3DSurface8Impl_UnlockRect,
484 };
485
486
487 HRESULT WINAPI IDirect3DSurface8Impl_LoadTexture(LPDIRECT3DSURFACE8 iface, UINT gl_target, UINT gl_level) {
488   IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
489
490   if (This->inTexture)
491     return D3D_OK;
492   if (This->inPBuffer) {
493     ENTER_GL();
494     if (gl_level != 0)
495       FIXME("Surface in texture is only supported for level 0\n");
496     else if (This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8 ||
497         This->myDesc.Format == D3DFMT_DXT1 || This->myDesc.Format == D3DFMT_DXT3 ||
498         This->myDesc.Format == D3DFMT_DXT5)
499       FIXME("Format %d not supported\n", This->myDesc.Format);
500     else {
501         glCopyTexImage2D(gl_target,
502                          0,
503                          D3DFmt2GLIntFmt(This->Device,
504                          This->myDesc.Format),
505                          0,
506                          0,/*This->surfaces[j][i]->myDesc.Height-1,*/
507                          This->myDesc.Width,
508                          This->myDesc.Height,
509                          0);
510         TRACE("Updating target %d\n", gl_target);
511         This->inTexture = TRUE;
512     }
513     LEAVE_GL();
514     return D3D_OK;
515   }
516   
517   if ((This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8) && 
518       !GL_SUPPORT_DEV(EXT_PALETTED_TEXTURE, This->Device)) {
519     /**
520      * wanted a paletted texture and not really support it in HW 
521      * so software emulation code begin
522      */
523     UINT i;
524     PALETTEENTRY* pal = This->Device->palettes[This->Device->currentPalette];
525     VOID* surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->myDesc.Width * This->myDesc.Height * sizeof(DWORD));
526     BYTE* dst = surface;
527     BYTE* src = (BYTE*) This->allocatedMemory;
528           
529     for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
530       BYTE color = *src++;
531       *dst++ = pal[color].peRed;
532       *dst++ = pal[color].peGreen;
533       *dst++ = pal[color].peBlue;
534       if (This->myDesc.Format == D3DFMT_A8P8)
535         *dst++ = pal[color].peFlags; 
536       else
537         *dst++ = 0xFF; 
538     }
539
540     ENTER_GL();
541     
542     TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
543           gl_target,
544           gl_level, 
545           GL_RGBA,
546           This->myDesc.Width, 
547           This->myDesc.Height, 
548           0, 
549           GL_RGBA,
550           GL_UNSIGNED_BYTE,
551           surface);
552     glTexImage2D(gl_target,
553                  gl_level, 
554                  GL_RGBA,
555                  This->myDesc.Width,
556                  This->myDesc.Height,
557                  0,
558                  GL_RGBA,
559                  GL_UNSIGNED_BYTE,
560                  surface);
561     checkGLcall("glTexImage2D");
562     HeapFree(GetProcessHeap(), 0, surface);
563
564     LEAVE_GL();
565
566     return D3D_OK;    
567   }
568
569   if (This->myDesc.Format == D3DFMT_DXT1 || 
570       This->myDesc.Format == D3DFMT_DXT3 || 
571       This->myDesc.Format == D3DFMT_DXT5) {
572     if (GL_SUPPORT_DEV(EXT_TEXTURE_COMPRESSION_S3TC, This->Device)) {
573       TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
574             gl_target, 
575             gl_level, 
576             D3DFmt2GLIntFmt(This->Device, This->myDesc.Format), 
577             This->myDesc.Width, 
578             This->myDesc.Height, 
579             0, 
580             This->myDesc.Size,
581             This->allocatedMemory);
582       
583       ENTER_GL();
584
585       GL_EXTCALL_DEV(glCompressedTexImage2DARB, This->Device)(gl_target, 
586                                                               gl_level, 
587                                                               D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
588                                                               This->myDesc.Width,
589                                                               This->myDesc.Height,
590                                                               0,
591                                                               This->myDesc.Size,
592                                                               This->allocatedMemory);
593       checkGLcall("glCommpressedTexTexImage2D");
594
595       LEAVE_GL();
596     } else {
597       FIXME("Using DXT1/3/5 without advertized support\n");
598     }
599   } else {
600
601     TRACE("Calling glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
602           gl_target, 
603           gl_level, 
604           debug_d3dformat(This->myDesc.Format),
605           D3DFmt2GLIntFmt(This->Device, This->myDesc.Format), 
606           This->myDesc.Width, 
607           This->myDesc.Height, 
608           0, 
609           D3DFmt2GLFmt(This->Device, This->myDesc.Format), 
610           D3DFmt2GLType(This->Device, This->myDesc.Format),
611           This->allocatedMemory);
612
613     ENTER_GL();
614
615     glTexImage2D(gl_target, 
616                  gl_level,
617                  D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
618                  This->myDesc.Width,
619                  This->myDesc.Height,
620                  0,
621                  D3DFmt2GLFmt(This->Device, This->myDesc.Format),
622                  D3DFmt2GLType(This->Device, This->myDesc.Format),
623                  This->allocatedMemory);
624     checkGLcall("glTexImage2D");
625
626     LEAVE_GL();
627
628 #if 0
629     {
630       static unsigned int gen = 0;
631       char buffer[4096];
632       ++gen;
633       if ((gen % 10) == 0) {
634         snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, gl_target, gl_level, gen);
635         IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This, buffer);
636       }
637       /*
638        * debugging crash code
639       if (gen == 250) {
640         void** test = NULL;
641         *test = 0;
642       }
643       */
644     }
645 #endif
646   }
647
648   return D3D_OK;
649 }
650
651 #include <errno.h>
652 HRESULT WINAPI IDirect3DSurface8Impl_SaveSnapshot(LPDIRECT3DSURFACE8 iface, const char* filename) {
653   FILE* f = NULL;
654   ULONG i;
655   IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
656
657   f = fopen(filename, "w+");
658   if (NULL == f) {
659     ERR("opening of %s failed with: %s\n", filename, strerror(errno));
660     return D3DERR_INVALIDCALL;
661   }
662
663   TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->myDesc.Format));
664
665   fprintf(f, "P6\n%u %u\n255\n", This->myDesc.Width, This->myDesc.Height);
666   switch (This->myDesc.Format) {
667   case D3DFMT_X8R8G8B8:
668   case D3DFMT_A8R8G8B8:
669     {
670       DWORD color;
671       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
672         color = ((DWORD*) This->allocatedMemory)[i];
673         fputc((color >> 16) & 0xFF, f);
674         fputc((color >>  8) & 0xFF, f);
675         fputc((color >>  0) & 0xFF, f);
676       }
677     }
678     break;
679   case D3DFMT_R8G8B8:
680     {
681       BYTE* color;
682       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
683         color = ((BYTE*) This->allocatedMemory) + (3 * i);
684         fputc((color[0]) & 0xFF, f);
685         fputc((color[1]) & 0xFF, f);
686         fputc((color[2]) & 0xFF, f);
687       }
688     }
689     break;
690   case D3DFMT_A1R5G5B5: 
691     {
692       WORD color;
693       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
694         color = ((WORD*) This->allocatedMemory)[i];
695         fputc(((color >> 10) & 0x1F) * 255 / 31, f);
696         fputc(((color >>  5) & 0x1F) * 255 / 31, f);
697         fputc(((color >>  0) & 0x1F) * 255 / 31, f);
698       }
699     }
700     break;
701   case D3DFMT_A4R4G4B4:
702     {
703       WORD color;
704       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
705         color = ((WORD*) This->allocatedMemory)[i];
706         fputc(((color >>  8) & 0x0F) * 255 / 15, f);
707         fputc(((color >>  4) & 0x0F) * 255 / 15, f);
708         fputc(((color >>  0) & 0x0F) * 255 / 15, f);
709       }
710     }
711     break;
712
713   case D3DFMT_R5G6B5: 
714     {
715       WORD color;
716       for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
717         color = ((WORD*) This->allocatedMemory)[i];
718         fputc(((color >> 11) & 0x1F) * 255 / 31, f);
719         fputc(((color >>  5) & 0x3F) * 255 / 63, f);
720         fputc(((color >>  0) & 0x1F) * 255 / 31, f);
721       }
722     }
723     break;
724   default: 
725     FIXME("Unimplemented dump mode format(%u,%s)\n", This->myDesc.Format, debug_d3dformat(This->myDesc.Format));
726   }
727   fclose(f);
728   return D3D_OK;
729 }
730
731 HRESULT WINAPI IDirect3DSurface8Impl_CleanDirtyRect(LPDIRECT3DSURFACE8 iface) {
732   IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
733   This->Dirty = FALSE;
734   This->dirtyRect.left   = This->myDesc.Width;
735   This->dirtyRect.top    = This->myDesc.Height;
736   This->dirtyRect.right  = 0;
737   This->dirtyRect.bottom = 0;
738   return D3D_OK;
739 }
740
741 /**
742  * Raphael:
743  *   very stupid way to handle multiple dirty rects but it works :)
744  */
745 extern HRESULT WINAPI IDirect3DSurface8Impl_AddDirtyRect(LPDIRECT3DSURFACE8 iface, CONST RECT* pDirtyRect) {
746   IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface;
747   This->Dirty = TRUE;
748   if (NULL != pDirtyRect) {
749     This->dirtyRect.left   = min(This->dirtyRect.left,   pDirtyRect->left);
750     This->dirtyRect.top    = min(This->dirtyRect.top,    pDirtyRect->top);
751     This->dirtyRect.right  = max(This->dirtyRect.right,  pDirtyRect->right);
752     This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
753   } else {
754     This->dirtyRect.left   = 0;
755     This->dirtyRect.top    = 0;
756     This->dirtyRect.right  = This->myDesc.Width;
757     This->dirtyRect.bottom = This->myDesc.Height;
758   }
759   return D3D_OK;
760 }