wined3d: Avoid crashing when ProcessVertices is called with NULL vertex declaration.
[wine] / dlls / wined3d / swapchain.c
1 /*
2  *IDirect3DSwapChain9 implementation
3  *
4  *Copyright 2002-2003 Jason Edmeades
5  *Copyright 2002-2003 Raphael Junqueira
6  *Copyright 2005 Oliver Stieber
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wined3d_private.h"
25
26
27 /* TODO: move to shared header (or context manager )*/
28 /* x11drv GDI escapes */
29 #define X11DRV_ESCAPE 6789
30 enum x11drv_escape_codes
31 {
32     X11DRV_GET_DISPLAY,   /* get X11 display for a DC */
33     X11DRV_GET_DRAWABLE,  /* get current drawable for a DC */
34     X11DRV_GET_FONT,      /* get current X font for a DC */
35 };
36
37 /* retrieve the X display to use on a given DC */
38 inline static Display *get_display( HDC hdc )
39 {
40     Display *display;
41     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
42
43     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
44                     sizeof(display), (LPSTR)&display )) display = NULL;
45     return display;
46 }
47
48 /*TODO: some of the additional parameters may be required to
49     set the gamma ramp (for some weird reason microsoft have left swap gammaramp in device
50     but it operates on a swapchain, it may be a good idea to move it to IWineD3DSwapChain for IWineD3D)*/
51
52
53 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
54 WINE_DECLARE_DEBUG_CHANNEL(fps);
55
56
57 /* IDirect3DSwapChain IUnknown parts follow: */
58 static ULONG WINAPI IWineD3DSwapChainImpl_AddRef(IWineD3DSwapChain *iface) {
59     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
60     DWORD refCount = InterlockedIncrement(&This->ref);
61     TRACE("(%p) : AddRef increasing from %ld\n", This, refCount - 1);
62     return refCount;
63 }
64
65 static HRESULT WINAPI IWineD3DSwapChainImpl_QueryInterface(IWineD3DSwapChain *iface, REFIID riid, LPVOID *ppobj)
66 {
67     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
68     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj);
69     if (IsEqualGUID(riid, &IID_IUnknown)
70         || IsEqualGUID(riid, &IID_IWineD3DBase)
71         || IsEqualGUID(riid, &IID_IWineD3DSwapChain)){
72         IWineD3DSwapChainImpl_AddRef(iface);
73         if(ppobj == NULL){
74             ERR("Query interface called but now data allocated\n");
75             return E_NOINTERFACE;
76         }
77         *ppobj = This;
78         return WINED3D_OK;
79     }
80     *ppobj = NULL;
81     return E_NOINTERFACE;
82 }
83
84
85 static ULONG WINAPI IWineD3DSwapChainImpl_Release(IWineD3DSwapChain *iface) {
86     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
87     DWORD refCount;
88     refCount = InterlockedDecrement(&This->ref);
89     TRACE("(%p) : ReleaseRef to %ld\n", This, refCount);
90     if (refCount == 0) {
91         IUnknown* bufferParent;
92
93         /* release the ref to the front and back buffer parents */
94         if(This->frontBuffer) {
95             IWineD3DSurface_SetContainer(This->frontBuffer, 0);
96             IWineD3DSurface_GetParent(This->frontBuffer, &bufferParent);
97             IUnknown_Release(bufferParent); /* once for the get parent */
98             if(IUnknown_Release(bufferParent) > 0){
99                 FIXME("(%p) Something's still holding the front buffer\n",This);
100             }
101         }
102
103         if(This->backBuffer) {
104             int i;
105             for(i = 0; i < This->presentParms.BackBufferCount; i++) {
106                 IWineD3DSurface_SetContainer(This->backBuffer[i], 0);
107                 IWineD3DSurface_GetParent(This->backBuffer[i], &bufferParent);
108                 IUnknown_Release(bufferParent); /* once for the get parent */
109                 if(IUnknown_Release(bufferParent) > 0){
110                     FIXME("(%p) Something's still holding the back buffer\n",This);
111                 }
112             }
113         }
114
115         /* Clean up the context */
116         /* check that we are the current context first */
117         if(glXGetCurrentContext() == This->glCtx){
118             glXMakeCurrent(This->display, None, NULL);
119         }
120         glXDestroyContext(This->display, This->glCtx);
121         /* IUnknown_Release(This->parent); This should only apply to the primary swapchain,
122          all others are crated by the caller, so releasing the parent should cause
123          the child to be released, not the other way around!
124          */
125         HeapFree(GetProcessHeap(), 0, This);
126     }
127     return refCount;
128 }
129
130 static HRESULT WINAPI IWineD3DSwapChainImpl_GetParent(IWineD3DSwapChain *iface, IUnknown ** ppParent){
131     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
132     *ppParent = This->parent;
133     IUnknown_AddRef(*ppParent);
134     TRACE("(%p) returning %p\n", This , *ppParent);
135     return WINED3D_OK;
136 }
137
138 /*IWineD3DSwapChain parts follow: */
139 static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
140     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
141
142     ENTER_GL();
143
144     /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */
145     if(This->wineD3DDevice->bCursorVisible && This->wineD3DDevice->cursorTexture) {
146         IWineD3DSurfaceImpl cursor;
147         RECT destRect = {This->wineD3DDevice->xScreenSpace - This->wineD3DDevice->xHotSpot,
148                          This->wineD3DDevice->yScreenSpace - This->wineD3DDevice->yHotSpot,
149                          This->wineD3DDevice->xScreenSpace + This->wineD3DDevice->cursorWidth - This->wineD3DDevice->xHotSpot,
150                          This->wineD3DDevice->yScreenSpace + This->wineD3DDevice->cursorHeight - This->wineD3DDevice->yHotSpot};
151         TRACE("Rendering the cursor. Creating fake surface at %p\n", &cursor);
152         /* Build a fake surface to call the Blitting code. It is not possible to use the interface passed by
153          * the application because we are only supposed to copy the information out. Using a fake surface
154          * allows to use the Blitting engine and avoid copying the whole texture -> render target blitting code.
155          */
156         memset(&cursor, 0, sizeof(cursor));
157         cursor.lpVtbl = &IWineD3DSurface_Vtbl;
158         cursor.resource.ref = 1;
159         cursor.resource.wineD3DDevice = This->wineD3DDevice;
160         cursor.resource.pool = WINED3DPOOL_SCRATCH;
161         cursor.resource.format = WINED3DFMT_A8R8G8B8;
162         cursor.resource.resourceType = WINED3DRTYPE_SURFACE;
163         cursor.glDescription.textureName = This->wineD3DDevice->cursorTexture;
164         cursor.glDescription.target = GL_TEXTURE_2D;
165         cursor.glDescription.level = 0;
166         cursor.currentDesc.Width = This->wineD3DDevice->cursorWidth;
167         cursor.currentDesc.Height = This->wineD3DDevice->cursorHeight;
168         cursor.glRect.left = 0;
169         cursor.glRect.top = 0;
170         cursor.glRect.right = cursor.currentDesc.Width;
171         cursor.glRect.bottom = cursor.currentDesc.Height;
172         /* The cursor must have pow2 sizes */
173         cursor.pow2Width = cursor.currentDesc.Width;
174         cursor.pow2Height = cursor.currentDesc.Height;
175         /* DDBLT_KEYSRC will cause BltOverride to enable the alpha test with GL_NOTEQUAL, 0.0,
176          * which is exactly what we want :-)
177          */
178         IWineD3DSurface_Blt(This->backBuffer[0], &destRect, (IWineD3DSurface *) &cursor, NULL, DDBLT_KEYSRC, NULL);
179     }
180
181     if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect);
182     /* TODO: If only source rect or dest rect are supplied then clip the window to match */
183     TRACE("preseting display %p, drawable %ld\n", This->display, This->drawable);
184
185     /* Don't call checkGLcall, as glGetError is not applicable here */
186     if (hDestWindowOverride && This->win_handle != hDestWindowOverride) {
187         /* Set this swapchain up to point to the new destination.. */
188 #ifdef USE_CONTEXT_MANAGER
189             /* TODO: use a context mamager */
190 #endif
191
192             /* FIXME: Never access */
193             IWineD3DSwapChainImpl *swapChainImpl;
194             IWineD3DDevice_GetSwapChain((IWineD3DDevice *)This->wineD3DDevice, 0 , (IWineD3DSwapChain **)&swapChainImpl);
195             FIXME("Unable to render to a destination window %p\n", hDestWindowOverride );
196             if(This == swapChainImpl){
197                 /* FIXME: this will be fixed by moving to a context management system */
198                 FIXME("Cannot change the target of the implicit swapchain\n");
199             }else{
200                 HDC               hDc;
201                 XVisualInfo       template;
202                 int               num;
203                 Display          *oldDisplay = This->display;
204                 GLXContext        oldContext = This->glCtx;
205                 IUnknown*         tmp;
206                 GLXContext        currentContext;
207                 Drawable          currentDrawable;
208                 hDc                          = GetDC(hDestWindowOverride);
209                 This->win_handle             = hDestWindowOverride;
210                 This->win                    = (Window)GetPropA( hDestWindowOverride, "__wine_x11_whole_window" );
211
212                 TRACE("Creating a new context for the window %p\n", hDestWindowOverride);
213                 ENTER_GL();
214                 TRACE("Desctroying context %p %p\n", This->display, This->render_ctx);
215
216
217
218                 LEAVE_GL();
219                 ENTER_GL();
220
221                 This->display    = get_display(hDc);
222                 TRACE("Got display%p  for  %p %p\n",  This->display, hDc, hDestWindowOverride);
223                 ReleaseDC(hDestWindowOverride, hDc);
224                 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
225                 This->visInfo   = XGetVisualInfo(This->display, VisualIDMask, &template, &num);
226                 if (NULL == This->visInfo) {
227                     ERR("cannot really get XVisual\n");
228                     LEAVE_GL();
229                     return WINED3DERR_NOTAVAILABLE;
230                 }
231                 /* Now we have problems? well not really we just need to know what the implicit context is */
232                 /* now destroy the old context and create a new one (we should really copy the buffers over, and do the whole make current thing! */
233                 /* destroy the active context?*/
234                 TRACE("Creating new context for %p %p %p\n",This->display, This->visInfo, swapChainImpl->glCtx);
235                 This->glCtx = glXCreateContext(This->display, This->visInfo, swapChainImpl->glCtx, GL_TRUE);
236
237                 if (NULL == This->glCtx) {
238                     ERR("cannot create glxContext\n");
239                 }
240                 This->drawable     = This->win;
241                 This->render_ctx   = This->glCtx;
242                 /* Setup some default states TODO: apply the stateblock to the new context */
243                 /** save current context and drawable **/
244                 currentContext  =   glXGetCurrentContext();
245                 currentDrawable =   glXGetCurrentDrawable();
246
247                 if (glXMakeCurrent(This->display, This->win, This->glCtx) == False) {
248                     ERR("Error in setting current context (display %p context %p drawable %ld)!\n", This->display, This->glCtx, This->win);
249                 }
250
251                 checkGLcall("glXMakeCurrent");
252
253                 /* Clear the screen */
254                 glClearColor(0.0, 0.0, 0.0, 0.0);
255                 checkGLcall("glClearColor");
256                 glClearIndex(0);
257                 glClearDepth(1);
258                 glClearStencil(0);
259
260                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
261                 checkGLcall("glClear");
262
263                 glColor3f(1.0, 1.0, 1.0);
264                 checkGLcall("glColor3f");
265
266                 glEnable(GL_LIGHTING);
267                 checkGLcall("glEnable");
268
269                 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
270                 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
271
272                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
273                 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
274
275                 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
276                 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
277
278                 /* If this swapchain is currently the active context then make this swapchain active */
279                 if(IWineD3DSurface_GetContainer(This->wineD3DDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmp) == WINED3D_OK){
280                     if(tmp != (IUnknown *)This){
281                         glXMakeCurrent(This->display, currentDrawable, currentContext);
282                         checkGLcall("glXMakeCurrent");
283                     }
284                     IUnknown_Release(tmp);
285                 }else{
286                     /* reset the context */
287                     glXMakeCurrent(This->display, currentDrawable, currentContext);
288                     checkGLcall("glXMakeCurrent");
289                 }
290                 /* delete the old contxt*/
291                 glXDestroyContext(oldDisplay, oldContext); /* Should this happen on an active context? seems a bad idea */
292                 LEAVE_GL();
293             }
294             IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapChainImpl);
295
296         }
297
298
299         /* TODO: The slow way, save the data to memory, create a new context for the destination window, transfer the data cleanup, it may be a good idea to the move this swapchain over to the using the target winows context so that it runs faster in feature. */
300
301     glXSwapBuffers(This->display, This->drawable); /* TODO: cycle through the swapchain buffers */
302
303     TRACE("glXSwapBuffers called, Starting new frame\n");
304     /* FPS support */
305     if (TRACE_ON(fps))
306     {
307         static long prev_time, frames;
308
309         DWORD time = GetTickCount();
310         frames++;
311         /* every 1.5 seconds */
312         if (time - prev_time > 1500) {
313             TRACE_(fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
314             prev_time = time;
315             frames = 0;
316         }
317     }
318
319 #if defined(FRAME_DEBUGGING)
320 {
321     if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) {
322         if (!isOn) {
323             isOn = TRUE;
324             FIXME("Enabling D3D Trace\n");
325             __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1);
326 #if defined(SHOW_FRAME_MAKEUP)
327             FIXME("Singe Frame snapshots Starting\n");
328             isDumpingFrames = TRUE;
329             glClear(GL_COLOR_BUFFER_BIT);
330 #endif
331
332 #if defined(SINGLE_FRAME_DEBUGGING)
333         } else {
334 #if defined(SHOW_FRAME_MAKEUP)
335             FIXME("Singe Frame snapshots Finishing\n");
336             isDumpingFrames = FALSE;
337 #endif
338             FIXME("Singe Frame trace complete\n");
339             DeleteFileA("C:\\D3DTRACE");
340             __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
341 #endif
342         }
343     } else {
344         if (isOn) {
345             isOn = FALSE;
346 #if defined(SHOW_FRAME_MAKEUP)
347             FIXME("Single Frame snapshots Finishing\n");
348             isDumpingFrames = FALSE;
349 #endif
350             FIXME("Disabling D3D Trace\n");
351             __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
352         }
353     }
354 }
355 #endif
356
357     LEAVE_GL();
358     /* Although this is not strictly required, a simple demo showed this does occur
359        on (at least non-debug) d3d                                                  */
360     if (This->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD) {
361
362         TRACE("Clearing\n");
363
364         IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
365
366     } else {
367         TRACE("Clearing z/stencil buffer\n");
368
369         IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0x00, 1.0, 0);
370     }
371
372     if(!(((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags   & SFLAG_GLDIRTY) ||
373        !(((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_GLDIRTY) ) {
374         /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying */
375         IWineD3DSurfaceImpl *front = (IWineD3DSurfaceImpl *) This->frontBuffer;
376         IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0];
377         BOOL frontdirty = front->Flags & SFLAG_GLDIRTY;
378         BOOL backdirty = back->Flags & SFLAG_GLDIRTY;
379
380         /* Flip the DC */
381         {
382             HDC tmp;
383             tmp = front->hDC;
384             front->hDC = back->hDC;
385             back->hDC = tmp;
386         }
387
388         /* Flip the DIBsection */
389         {
390             HBITMAP tmp;
391             tmp = front->dib.DIBsection;
392             front->dib.DIBsection = back->dib.DIBsection;
393             back->dib.DIBsection = tmp;
394         }
395
396         /* Flip the surface data */
397         {
398             void* tmp;
399
400             tmp = front->dib.bitmap_data;
401             front->dib.bitmap_data = back->dib.bitmap_data;
402             back->dib.bitmap_data = tmp;
403
404             tmp = front->resource.allocatedMemory;
405             front->resource.allocatedMemory = back->resource.allocatedMemory;
406             back->resource.allocatedMemory = tmp;
407         }
408
409         /* client_memory should not be different, but just in case */
410         {
411             BOOL tmp;
412             tmp = front->dib.client_memory;
413             front->dib.client_memory = back->dib.client_memory;
414             back->dib.client_memory = tmp;
415         }
416         if(frontdirty) back->Flags |= SFLAG_GLDIRTY;
417         else back->Flags &= ~SFLAG_GLDIRTY;
418         if(backdirty) front->Flags |= SFLAG_GLDIRTY;
419         else front->Flags &= ~SFLAG_GLDIRTY;
420     }
421
422     TRACE("returning\n");
423     return WINED3D_OK;
424 }
425
426 static HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
427     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
428     WINED3DFORMAT d3dformat;
429     UINT width;
430     UINT height;
431     WINED3DSURFACE_DESC desc;
432     glDescriptor *glDescription;
433
434     TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
435     ENTER_GL();
436     memset(&desc, 0, sizeof(desc));
437     desc.Width =  &width;
438     desc.Height = &height;
439     desc.Format = &d3dformat;
440 #if 0 /* TODO: make sure that this swapchains context is active */
441     IWineD3DDevice_ActivateSwapChainContext(This->wineD3DDevice, iface);
442 #endif
443     IWineD3DSurface_GetDesc(pDestSurface, &desc);
444     /* make sure that the front buffer is the active read buffer */
445     glReadBuffer(GL_FRONT);
446     /* Read the pixels from the buffer into the surfaces memory */
447     IWineD3DSurface_GetGlDesc(pDestSurface, &glDescription);
448     glReadPixels(glDescription->target,
449                 glDescription->level,
450                 width,
451                 height,
452                 glDescription->glFormat,
453                 glDescription->glType,
454                 (void *)IWineD3DSurface_GetData(pDestSurface));
455     LEAVE_GL();
456     return WINED3D_OK;
457 }
458
459 static HRESULT WINAPI IWineD3DSwapChainImpl_GetBackBuffer(IWineD3DSwapChain *iface, UINT iBackBuffer, WINED3DBACKBUFFER_TYPE Type, IWineD3DSurface **ppBackBuffer) {
460
461     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
462
463     if (iBackBuffer > This->presentParms.BackBufferCount - 1) {
464         TRACE("Back buffer count out of range\n");
465         /* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it here
466          * in wined3d to avoid problems in other libs
467          */
468         *ppBackBuffer = NULL;
469         return WINED3DERR_INVALIDCALL;
470     }
471
472     *ppBackBuffer = This->backBuffer[iBackBuffer];
473     TRACE("(%p) : BackBuf %d Type %d  returning %p\n", This, iBackBuffer, Type, *ppBackBuffer);
474
475     /* Note inc ref on returned surface */
476     if(*ppBackBuffer) IWineD3DSurface_AddRef(*ppBackBuffer);
477     return WINED3D_OK;
478
479 }
480
481 static HRESULT WINAPI IWineD3DSwapChainImpl_GetRasterStatus(IWineD3DSwapChain *iface, WINED3DRASTER_STATUS *pRasterStatus) {
482     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
483     static BOOL showFixmes = TRUE;
484     pRasterStatus->InVBlank = TRUE;
485     pRasterStatus->ScanLine = 0;
486     /* No openGL equivalent */
487     if(showFixmes) {
488         FIXME("(%p) : stub (once)\n", This);
489         showFixmes = FALSE;
490     }
491     return WINED3D_OK;
492 }
493
494 static HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, WINED3DDISPLAYMODE*pMode) {
495     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
496     HDC                 hdc;
497     int                 bpp = 0;
498
499     pMode->Width        = GetSystemMetrics(SM_CXSCREEN);
500     pMode->Height       = GetSystemMetrics(SM_CYSCREEN);
501     pMode->RefreshRate  = 85; /* FIXME: How to identify? */
502
503     hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
504     bpp = GetDeviceCaps(hdc, BITSPIXEL);
505     DeleteDC(hdc);
506
507     switch (bpp) {
508     case  8: pMode->Format       = D3DFMT_R8G8B8; break;
509     case 16: pMode->Format       = D3DFMT_R5G6B5; break;
510     case 24: /*pMode->Format       = D3DFMT_R8G8B8; break; */ /* 32bpp and 24bpp can be aliased for X */
511     case 32: pMode->Format       = D3DFMT_A8R8G8B8; break;
512     default:
513        FIXME("Unrecognized display mode format\n");
514        pMode->Format       = D3DFMT_UNKNOWN;
515     }
516
517     TRACE("(%p) : returning w(%d) h(%d) rr(%d) fmt(%u,%s)\n", This, pMode->Width, pMode->Height, pMode->RefreshRate,
518     pMode->Format, debug_d3dformat(pMode->Format));
519     return WINED3D_OK;
520 }
521
522 static HRESULT WINAPI IWineD3DSwapChainImpl_GetDevice(IWineD3DSwapChain *iface, IWineD3DDevice**ppDevice) {
523     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
524
525     *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
526
527     /* Note  Calling this method will increase the internal reference count
528        on the IDirect3DDevice9 interface. */
529     IWineD3DDevice_AddRef(*ppDevice);
530     TRACE("(%p) : returning %p\n", This, *ppDevice);
531     return WINED3D_OK;
532 }
533
534 static HRESULT WINAPI IWineD3DSwapChainImpl_GetPresentParameters(IWineD3DSwapChain *iface, WINED3DPRESENT_PARAMETERS *pPresentationParameters) {
535     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
536     TRACE("(%p)\n", This);
537     *pPresentationParameters->BackBufferWidth = This->presentParms.BackBufferWidth;
538     *pPresentationParameters->BackBufferHeight = This->presentParms.BackBufferHeight;
539     *pPresentationParameters->BackBufferFormat = This->presentParms.BackBufferFormat;
540     *pPresentationParameters->BackBufferCount = This->presentParms.BackBufferCount;
541     *pPresentationParameters->MultiSampleType = This->presentParms.MultiSampleType;
542     *pPresentationParameters->MultiSampleQuality = This->presentParms.MultiSampleQuality;
543     *pPresentationParameters->SwapEffect = This->presentParms.SwapEffect;
544     *pPresentationParameters->hDeviceWindow = This->presentParms.hDeviceWindow;
545     *pPresentationParameters->Windowed = This->presentParms.Windowed;
546     *pPresentationParameters->EnableAutoDepthStencil = This->presentParms.EnableAutoDepthStencil;
547     *pPresentationParameters->Flags = This->presentParms.Flags;
548     *pPresentationParameters->FullScreen_RefreshRateInHz = This->presentParms.FullScreen_RefreshRateInHz;
549     *pPresentationParameters->PresentationInterval = This->presentParms.PresentationInterval;
550     return WINED3D_OK;
551 }
552
553 static HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST WINED3DGAMMARAMP *pRamp){
554
555     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
556     HDC hDC;
557     TRACE("(%p) : pRamp@%p flags(%ld)\n", This, pRamp, Flags);
558     hDC = GetDC(This->win_handle);
559     SetDeviceGammaRamp(hDC, (LPVOID)pRamp);
560     ReleaseDC(This->win_handle, hDC);
561     return WINED3D_OK;
562
563 }
564
565 static HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, WINED3DGAMMARAMP *pRamp){
566
567     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
568     HDC hDC;
569     TRACE("(%p) : pRamp@%p\n", This, pRamp);
570     hDC = GetDC(This->win_handle);
571     GetDeviceGammaRamp(hDC, pRamp);
572     ReleaseDC(This->win_handle, hDC);
573     return WINED3D_OK;
574
575 }
576
577
578 IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
579 {
580     /* IUnknown */
581     IWineD3DSwapChainImpl_QueryInterface,
582     IWineD3DSwapChainImpl_AddRef,
583     IWineD3DSwapChainImpl_Release,
584     /* IWineD3DSwapChain */
585     IWineD3DSwapChainImpl_GetParent,
586     IWineD3DSwapChainImpl_GetDevice,
587     IWineD3DSwapChainImpl_Present,
588     IWineD3DSwapChainImpl_GetFrontBufferData,
589     IWineD3DSwapChainImpl_GetBackBuffer,
590     IWineD3DSwapChainImpl_GetRasterStatus,
591     IWineD3DSwapChainImpl_GetDisplayMode,
592     IWineD3DSwapChainImpl_GetPresentParameters,
593     IWineD3DSwapChainImpl_SetGammaRamp,
594     IWineD3DSwapChainImpl_GetGammaRamp
595 };