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