Call TSXFlush after setting DGA palette, so it updates immediately.
[wine] / dlls / ddraw / dsurface / x11.c
1 /*              DirectDrawSurface Xlib implementation
2  *
3  * Copyright 1997-2000 Marcus Meissner
4  * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5  */
6 #include "config.h"
7 #include "winerror.h"
8
9 #include <unistd.h>
10 #include <assert.h>
11 #include <fcntl.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15
16 #include "options.h"
17 #include "debugtools.h"
18 #include "x11_private.h"
19 #include "bitmap.h"
20
21 #ifdef HAVE_OPENGL
22 /* for d3d texture stuff */
23 # include "mesa_private.h"
24 #endif
25
26 DEFAULT_DEBUG_CHANNEL(ddraw);
27
28 #define VISIBLE(x) (SDDSCAPS(x) & (DDSCAPS_VISIBLE|DDSCAPS_PRIMARYSURFACE))
29
30 #define DDPRIVATE(x) x11_dd_private *ddpriv = ((x11_dd_private*)(x)->private)
31 #define DPPRIVATE(x) x11_dp_private *dppriv = ((x11_dp_private*)(x)->private)
32 #define DSPRIVATE(x) x11_ds_private *dspriv = ((x11_ds_private*)(x)->private)
33
34 static BYTE Xlib_TouchData(LPVOID data)
35 {
36     /* this is a function so it doesn't get optimized out */
37     return *(BYTE*)data;
38 }
39
40 /******************************************************************************
41  *              IDirectDrawSurface methods
42  *
43  * Since DDS3 and DDS2 are supersets of DDS, we implement DDS3 and let
44  * DDS and DDS2 use those functions. (Function calls did not change (except
45  * using different DirectDrawSurfaceX version), just added flags and functions)
46  */
47 HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_QueryInterface(
48     LPDIRECTDRAWSURFACE4 iface,REFIID refiid,LPVOID *obj
49 ) {
50     ICOM_THIS(IDirectDrawSurface4Impl,iface);
51
52     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj);
53     
54     /* All DirectDrawSurface versions (1, 2, 3 and 4) use
55      * the same interface. And IUnknown does that too of course.
56      */
57     if ( IsEqualGUID( &IID_IDirectDrawSurface4, refiid )        ||
58          IsEqualGUID( &IID_IDirectDrawSurface3, refiid )        ||
59          IsEqualGUID( &IID_IDirectDrawSurface2, refiid )        ||
60          IsEqualGUID( &IID_IDirectDrawSurface,  refiid )        ||
61          IsEqualGUID( &IID_IUnknown,            refiid )
62     ) {
63             *obj = This;
64             IDirectDrawSurface4_AddRef(iface);
65
66             TRACE("  Creating IDirectDrawSurface interface (%p)\n", *obj);
67             return S_OK;
68     }
69 #ifdef HAVE_OPENGL
70     if ( IsEqualGUID( &IID_IDirect3DTexture2, refiid ) ) {
71         /* Texture interface */
72         *obj = d3dtexture2_create(This);
73         IDirectDrawSurface4_AddRef(iface);
74         TRACE("  Creating IDirect3DTexture2 interface (%p)\n", *obj);
75         return S_OK;
76     }
77     if ( IsEqualGUID( &IID_IDirect3DTexture, refiid ) ) {
78         /* Texture interface */
79         *obj = d3dtexture_create(This);
80         IDirectDrawSurface4_AddRef(iface);
81         TRACE("  Creating IDirect3DTexture interface (%p)\n", *obj);
82         return S_OK;
83     }
84 #endif /* HAVE_OPENGL */
85     FIXME("(%p):interface for IID %s NOT found!\n",This,debugstr_guid(refiid));
86     return OLE_E_ENUM_NOMORE;
87 }
88
89 HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Lock(
90     LPDIRECTDRAWSURFACE4 iface,LPRECT lprect,LPDDSURFACEDESC lpddsd,DWORD flags, HANDLE hnd
91 ) {
92     ICOM_THIS(IDirectDrawSurface4Impl,iface);
93     DSPRIVATE(This);
94     DDPRIVATE(This->s.ddraw);
95     
96     /* DO NOT AddRef the surface! Lock/Unlock are NOT guaranteed to come in 
97      * matched pairs! - Marcus Meissner 20000509 */
98     TRACE("(%p)->Lock(%p,%p,%08lx,%08lx)\n",This,lprect,lpddsd,flags,(DWORD)hnd);
99     if (flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY))
100         WARN("(%p)->Lock(%p,%p,%08lx,%08lx)\n",
101                      This,lprect,lpddsd,flags,(DWORD)hnd);
102
103     /* First, copy the Surface description */
104     *lpddsd = This->s.surface_desc;
105     TRACE("locked surface: height=%ld, width=%ld, pitch=%ld\n",
106           lpddsd->dwHeight,lpddsd->dwWidth,lpddsd->lPitch);
107
108     /* If asked only for a part, change the surface pointer */
109     if (lprect) {
110         TRACE(" lprect: %dx%d-%dx%d\n",
111                 lprect->top,lprect->left,lprect->bottom,lprect->right
112         );
113         if ((lprect->top < 0) ||
114             (lprect->left < 0) ||
115             (lprect->bottom < 0) ||
116             (lprect->right < 0)) {
117           ERR(" Negative values in LPRECT !!!\n");
118           IDirectDrawSurface4_Release(iface);
119           return DDERR_INVALIDPARAMS;
120         }
121         lpddsd->u1.lpSurface=(LPVOID)((char*)This->s.surface_desc.u1.lpSurface+
122                 (lprect->top*This->s.surface_desc.lPitch) +
123                 lprect->left*GET_BPP(This->s.surface_desc));
124     } else
125         assert(This->s.surface_desc.u1.lpSurface);
126     /* wait for any previous operations to complete */
127 #ifdef HAVE_LIBXXSHM
128     if (dspriv->image && VISIBLE(This) && ddpriv->xshm_active) {
129 /*
130         int compl = InterlockedExchange( &(ddpriv->xshm_compl), 0 );
131         if (compl) X11DRV_EVENT_WaitShmCompletion( compl );
132 */
133         X11DRV_EVENT_WaitShmCompletions( ddpriv->drawable );
134     }
135 #endif
136
137     return DD_OK;
138 }
139
140 static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) {
141   DSPRIVATE(This);
142   DDPRIVATE(This->s.ddraw);
143   if (This->s.ddraw->d.pixel_convert != NULL)
144     This->s.ddraw->d.pixel_convert(This->s.surface_desc.u1.lpSurface,
145                                    dspriv->image->data,
146                                    This->s.surface_desc.dwWidth,
147                                    This->s.surface_desc.dwHeight,
148                                    This->s.surface_desc.lPitch,
149                                    This->s.palette);
150
151   /* if the DIB section is in GdiMod state, we must
152    * touch the surface to get any updates from the DIB */
153   Xlib_TouchData(dspriv->image->data);
154 #ifdef HAVE_LIBXXSHM
155     if (ddpriv->xshm_active) {
156 /*
157         X11DRV_EVENT_WaitReplaceShmCompletion( &(ddpriv->xshm_compl), This->s.ddraw->d.drawable );
158 */
159         /* let WaitShmCompletions track 'em for now */
160         /* (you may want to track it again whenever you implement DX7's partial
161         * surface locking, where threads have concurrent access) */
162         X11DRV_EVENT_PrepareShmCompletion( ddpriv->drawable );
163         TSXShmPutImage(display,
164             ddpriv->drawable,
165             DefaultGCOfScreen(X11DRV_GetXScreen()),
166             dspriv->image,
167             0, 0, 0, 0,
168             dspriv->image->width,
169             dspriv->image->height,
170             True
171         );
172         /* make sure the image is transferred ASAP */
173         TSXFlush(display);
174     } else
175 #endif
176         TSXPutImage(    
177             display,
178             ddpriv->drawable,
179             DefaultGCOfScreen(X11DRV_GetXScreen()),
180             dspriv->image,
181             0, 0, 0, 0,
182             dspriv->image->width,
183             dspriv->image->height
184         );
185 }
186
187 HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Unlock(
188     LPDIRECTDRAWSURFACE4 iface,LPVOID surface
189 ) {
190     ICOM_THIS(IDirectDrawSurface4Impl,iface);
191     DDPRIVATE(This->s.ddraw);
192     DSPRIVATE(This);
193     TRACE("(%p)->Unlock(%p)\n",This,surface);
194
195     /*if (!This->s.ddraw->d.paintable)
196         return DD_OK; */
197
198     /* Only redraw the screen when unlocking the buffer that is on screen */
199     if (dspriv->image && VISIBLE(This)) {
200         Xlib_copy_surface_on_screen(This);
201         if (This->s.palette) {
202             DPPRIVATE(This->s.palette);
203             if(dppriv->cm)
204                 TSXSetWindowColormap(display,ddpriv->drawable,dppriv->cm);
205         }
206     }
207     /* DO NOT Release the surface! Lock/Unlock are NOT guaranteed to come in 
208      * matched pairs! - Marcus Meissner 20000509 */
209     return DD_OK;
210 }
211
212 HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_Flip(
213     LPDIRECTDRAWSURFACE4 iface,LPDIRECTDRAWSURFACE4 flipto,DWORD dwFlags
214 ) {
215     ICOM_THIS(IDirectDrawSurface4Impl,iface);
216     XImage      *image;
217     DDPRIVATE(This->s.ddraw);
218     DSPRIVATE(This);
219     x11_ds_private      *fspriv;
220     LPBYTE      surf;
221     IDirectDrawSurface4Impl* iflipto=(IDirectDrawSurface4Impl*)flipto;
222
223     TRACE("(%p)->Flip(%p,%08lx)\n",This,iflipto,dwFlags);
224     if (!This->s.ddraw->d.paintable)
225         return DD_OK;
226
227     iflipto = _common_find_flipto(This,iflipto);
228     fspriv = (x11_ds_private*)iflipto->private;
229
230     /* We need to switch the lowlevel surfaces, for xlib this is: */
231     /* The surface pointer */
232     surf                                = This->s.surface_desc.u1.lpSurface;
233     This->s.surface_desc.u1.lpSurface   = iflipto->s.surface_desc.u1.lpSurface;
234     iflipto->s.surface_desc.u1.lpSurface        = surf;
235
236     /* the associated ximage */
237     image               = dspriv->image;
238     dspriv->image       = fspriv->image;
239     fspriv->image       = image;
240
241 #ifdef HAVE_LIBXXSHM
242     if (ddpriv->xshm_active) {
243 /*
244         int compl = InterlockedExchange( &(ddpriv->xshm_compl), 0 );
245         if (compl) X11DRV_EVENT_WaitShmCompletion( compl );
246 */
247         X11DRV_EVENT_WaitShmCompletions( ddpriv->drawable );
248     }
249 #endif
250     Xlib_copy_surface_on_screen(This);
251     if (iflipto->s.palette) {
252         DPPRIVATE(iflipto->s.palette);
253         if (dppriv->cm)
254             TSXSetWindowColormap(display,ddpriv->drawable,dppriv->cm);
255     }
256     return DD_OK;
257 }
258
259 /* The IDirectDrawSurface4::SetPalette method attaches the specified
260  * DirectDrawPalette object to a surface. The surface uses this palette for all
261  * subsequent operations. The palette change takes place immediately.
262  */
263 HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_SetPalette(
264     LPDIRECTDRAWSURFACE4 iface,LPDIRECTDRAWPALETTE pal
265 ) {
266     ICOM_THIS(IDirectDrawSurface4Impl,iface);
267     DDPRIVATE(This->s.ddraw);
268     IDirectDrawPaletteImpl* ipal=(IDirectDrawPaletteImpl*)pal;
269     x11_dp_private      *dppriv;
270     int i;
271
272     TRACE("(%p)->(%p)\n",This,ipal);
273
274     if (ipal == NULL) {
275         if( This->s.palette != NULL )
276             IDirectDrawPalette_Release((IDirectDrawPalette*)This->s.palette);
277         This->s.palette = ipal;
278         return DD_OK;
279     }
280     dppriv = (x11_dp_private*)ipal->private;
281
282     if (!dppriv->cm &&
283         (This->s.ddraw->d.screen_pixelformat.u.dwRGBBitCount<=8)
284     ) {
285         dppriv->cm = TSXCreateColormap(
286             display,
287             ddpriv->drawable,
288             DefaultVisualOfScreen(X11DRV_GetXScreen()),
289             AllocAll
290         );
291         if (!Options.managed)
292             TSXInstallColormap(display,dppriv->cm);
293
294         for (i=0;i<256;i++) {
295             XColor xc;
296
297             xc.red              = ipal->palents[i].peRed<<8;
298             xc.blue             = ipal->palents[i].peBlue<<8;
299             xc.green    = ipal->palents[i].peGreen<<8;
300             xc.flags    = DoRed|DoBlue|DoGreen;
301             xc.pixel    = i;
302             TSXStoreColor(display,dppriv->cm,&xc);
303         }
304         TSXInstallColormap(display,dppriv->cm);
305     }
306     /* According to spec, we are only supposed to 
307      * AddRef if this is not the same palette.
308      */
309     if ( This->s.palette != ipal ) {
310         if( ipal != NULL )
311             IDirectDrawPalette_AddRef( (IDirectDrawPalette*)ipal );
312         if( This->s.palette != NULL )
313             IDirectDrawPalette_Release( (IDirectDrawPalette*)This->s.palette );
314         This->s.palette = ipal; 
315         /* Perform the refresh, only if a palette was created */
316         if (dppriv->cm)
317           TSXSetWindowColormap(display,ddpriv->drawable,dppriv->cm);
318
319         if (This->s.hdc != 0) {
320             /* hack: set the DIBsection color map */
321             BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr(This->s.DIBsection, BITMAP_MAGIC);
322             X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *)bmp->dib;
323             dib->colorMap = This->s.palette ? This->s.palette->screen_palents : NULL;
324             GDI_HEAP_UNLOCK(This->s.DIBsection);
325         }
326     }
327     return DD_OK;
328 }
329
330 ULONG WINAPI Xlib_IDirectDrawSurface4Impl_Release(LPDIRECTDRAWSURFACE4 iface) {
331     ICOM_THIS(IDirectDrawSurface4Impl,iface);
332     DSPRIVATE(This);
333     DDPRIVATE(This->s.ddraw);
334
335     TRACE( "(%p)->() decrementing from %lu.\n", This, This->ref );
336     if (--(This->ref))
337         return This->ref;
338
339     IDirectDraw2_Release((IDirectDraw2*)This->s.ddraw);
340
341     if (dspriv->image != NULL) {
342         if (This->s.ddraw->d.pixel_convert != NULL) {
343             /* In pixel conversion mode, there are 2 buffers to release. */
344             VirtualFree(This->s.surface_desc.u1.lpSurface, 0, MEM_RELEASE);
345
346 #ifdef HAVE_LIBXXSHM
347             if (ddpriv->xshm_active) {
348                 TSXShmDetach(display, &(dspriv->shminfo));
349                 TSXDestroyImage(dspriv->image);
350                 shmdt(dspriv->shminfo.shmaddr);
351             } else
352 #endif
353             {
354                 HeapFree(GetProcessHeap(),0,dspriv->image->data);
355                 dspriv->image->data = NULL;
356                 TSXDestroyImage(dspriv->image);
357             }
358         } else {
359             dspriv->image->data = NULL;
360
361 #ifdef HAVE_LIBXXSHM
362             if (ddpriv->xshm_active) {
363                 VirtualFree(dspriv->image->data, 0, MEM_RELEASE);
364                 TSXShmDetach(display, &(dspriv->shminfo));
365                 TSXDestroyImage(dspriv->image);
366                 shmdt(dspriv->shminfo.shmaddr);
367             } else
368 #endif
369             {
370                 VirtualFree(This->s.surface_desc.u1.lpSurface, 0, MEM_RELEASE);
371                 TSXDestroyImage(dspriv->image);
372             }
373         }
374         dspriv->image = 0;
375     } else
376         VirtualFree(This->s.surface_desc.u1.lpSurface, 0, MEM_RELEASE);
377
378     if (This->s.palette)
379         IDirectDrawPalette_Release((IDirectDrawPalette*)This->s.palette);
380
381     /* Free the DIBSection (if any) */
382     if (This->s.hdc != 0) {
383         /* hack: restore the original DIBsection color map */
384         BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr(This->s.DIBsection, BITMAP_MAGIC);
385         X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *)bmp->dib;
386         dib->colorMap = dspriv->oldDIBmap;
387         GDI_HEAP_UNLOCK(This->s.DIBsection);
388
389         SelectObject(This->s.hdc, This->s.holdbitmap);
390         DeleteDC(This->s.hdc);
391         DeleteObject(This->s.DIBsection);
392     }
393
394     /* Free the clipper if present */
395     if(This->s.lpClipper)
396         IDirectDrawClipper_Release(This->s.lpClipper);
397     HeapFree(GetProcessHeap(),0,This->private);
398     HeapFree(GetProcessHeap(),0,This);
399     return S_OK;
400 }
401
402 HRESULT WINAPI Xlib_IDirectDrawSurface4Impl_GetDC(LPDIRECTDRAWSURFACE4 iface,HDC* lphdc) {
403     ICOM_THIS(IDirectDrawSurface4Impl,iface);
404     DSPRIVATE(This);
405     int was_ok = This->s.hdc != 0;
406     HRESULT result = IDirectDrawSurface4Impl_GetDC(iface,lphdc);
407     if (This->s.hdc && !was_ok) {
408         /* hack: take over the DIBsection color map */
409         BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr(This->s.DIBsection, BITMAP_MAGIC);
410         X11DRV_DIBSECTION *dib = (X11DRV_DIBSECTION *)bmp->dib;
411         dspriv->oldDIBmap = dib->colorMap;
412         dib->colorMap = This->s.palette ? This->s.palette->screen_palents : NULL;
413         GDI_HEAP_UNLOCK(This->s.DIBsection);
414     }
415     return result;
416 }
417
418 ICOM_VTABLE(IDirectDrawSurface4) xlib_dds4vt = 
419 {
420     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
421     Xlib_IDirectDrawSurface4Impl_QueryInterface,
422     IDirectDrawSurface4Impl_AddRef,
423     Xlib_IDirectDrawSurface4Impl_Release,
424     IDirectDrawSurface4Impl_AddAttachedSurface,
425     IDirectDrawSurface4Impl_AddOverlayDirtyRect,
426     IDirectDrawSurface4Impl_Blt,
427     IDirectDrawSurface4Impl_BltBatch,
428     IDirectDrawSurface4Impl_BltFast,
429     IDirectDrawSurface4Impl_DeleteAttachedSurface,
430     IDirectDrawSurface4Impl_EnumAttachedSurfaces,
431     IDirectDrawSurface4Impl_EnumOverlayZOrders,
432     Xlib_IDirectDrawSurface4Impl_Flip,
433     IDirectDrawSurface4Impl_GetAttachedSurface,
434     IDirectDrawSurface4Impl_GetBltStatus,
435     IDirectDrawSurface4Impl_GetCaps,
436     IDirectDrawSurface4Impl_GetClipper,
437     IDirectDrawSurface4Impl_GetColorKey,
438     Xlib_IDirectDrawSurface4Impl_GetDC,
439     IDirectDrawSurface4Impl_GetFlipStatus,
440     IDirectDrawSurface4Impl_GetOverlayPosition,
441     IDirectDrawSurface4Impl_GetPalette,
442     IDirectDrawSurface4Impl_GetPixelFormat,
443     IDirectDrawSurface4Impl_GetSurfaceDesc,
444     IDirectDrawSurface4Impl_Initialize,
445     IDirectDrawSurface4Impl_IsLost,
446     Xlib_IDirectDrawSurface4Impl_Lock,
447     IDirectDrawSurface4Impl_ReleaseDC,
448     IDirectDrawSurface4Impl_Restore,
449     IDirectDrawSurface4Impl_SetClipper,
450     IDirectDrawSurface4Impl_SetColorKey,
451     IDirectDrawSurface4Impl_SetOverlayPosition,
452     Xlib_IDirectDrawSurface4Impl_SetPalette,
453     Xlib_IDirectDrawSurface4Impl_Unlock,
454     IDirectDrawSurface4Impl_UpdateOverlay,
455     IDirectDrawSurface4Impl_UpdateOverlayDisplay,
456     IDirectDrawSurface4Impl_UpdateOverlayZOrder,
457     IDirectDrawSurface4Impl_GetDDInterface,
458     IDirectDrawSurface4Impl_PageLock,
459     IDirectDrawSurface4Impl_PageUnlock,
460     IDirectDrawSurface4Impl_SetSurfaceDesc,
461     IDirectDrawSurface4Impl_SetPrivateData,
462     IDirectDrawSurface4Impl_GetPrivateData,
463     IDirectDrawSurface4Impl_FreePrivateData,
464     IDirectDrawSurface4Impl_GetUniquenessValue,
465     IDirectDrawSurface4Impl_ChangeUniquenessValue
466 };