msi: Set all folders' source paths to the root directory if the source type is compre...
[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  *Copyright 2007 Stefan Dösinger for CodeWeavers
8  *
9  *This library is free software; you can redistribute it and/or
10  *modify it under the terms of the GNU Lesser General Public
11  *License as published by the Free Software Foundation; either
12  *version 2.1 of the License, or (at your option) any later version.
13  *
14  *This library is distributed in the hope that it will be useful,
15  *but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *Lesser General Public License for more details.
18  *
19  *You should have received a copy of the GNU Lesser General Public
20  *License along with this library; if not, write to the Free Software
21  *Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wined3d_private.h"
26
27
28 /*TODO: some of the additional parameters may be required to
29     set the gamma ramp (for some weird reason microsoft have left swap gammaramp in device
30     but it operates on a swapchain, it may be a good idea to move it to IWineD3DSwapChain for IWineD3D)*/
31
32
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(fps);
35
36 #define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info
37
38 /* IDirect3DSwapChain IUnknown parts follow: */
39 static ULONG WINAPI IWineD3DSwapChainImpl_AddRef(IWineD3DSwapChain *iface) {
40     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
41     DWORD refCount = InterlockedIncrement(&This->ref);
42     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
43     return refCount;
44 }
45
46 static HRESULT WINAPI IWineD3DSwapChainImpl_QueryInterface(IWineD3DSwapChain *iface, REFIID riid, LPVOID *ppobj)
47 {
48     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
49     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj);
50     if (IsEqualGUID(riid, &IID_IUnknown)
51         || IsEqualGUID(riid, &IID_IWineD3DBase)
52         || IsEqualGUID(riid, &IID_IWineD3DSwapChain)){
53         IWineD3DSwapChainImpl_AddRef(iface);
54         if(ppobj == NULL){
55             ERR("Query interface called but now data allocated\n");
56             return E_NOINTERFACE;
57         }
58         *ppobj = This;
59         return WINED3D_OK;
60     }
61     *ppobj = NULL;
62     return E_NOINTERFACE;
63 }
64
65
66 static ULONG WINAPI IWineD3DSwapChainImpl_Release(IWineD3DSwapChain *iface) {
67     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
68     DWORD refCount;
69     refCount = InterlockedDecrement(&This->ref);
70     TRACE("(%p) : ReleaseRef to %d\n", This, refCount);
71     if (refCount == 0) {
72         IWineD3DSwapChain_Destroy(iface, D3DCB_DefaultDestroySurface);
73     }
74     return refCount;
75 }
76
77 static HRESULT WINAPI IWineD3DSwapChainImpl_GetParent(IWineD3DSwapChain *iface, IUnknown ** ppParent){
78     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
79     *ppParent = This->parent;
80     IUnknown_AddRef(*ppParent);
81     TRACE("(%p) returning %p\n", This , *ppParent);
82     return WINED3D_OK;
83 }
84
85 /*IWineD3DSwapChain parts follow: */
86 static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyRenderTarget) {
87     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
88     WINED3DDISPLAYMODE mode;
89     int i;
90
91     TRACE("Destroying swapchain %p\n", iface);
92
93     IWineD3DSwapChain_SetGammaRamp(iface, 0, &This->orig_gamma);
94
95     /* release the ref to the front and back buffer parents */
96     if(This->frontBuffer) {
97         IWineD3DSurface_SetContainer(This->frontBuffer, 0);
98         if(D3DCB_DestroyRenderTarget(This->frontBuffer) > 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             if(D3DCB_DestroyRenderTarget(This->backBuffer[i]) > 0) {
108                 FIXME("(%p) Something's still holding the back buffer\n",This);
109             }
110         }
111         HeapFree(GetProcessHeap(), 0, This->backBuffer);
112     }
113
114     for(i = 0; i < This->num_contexts; i++) {
115         DestroyContext(This->wineD3DDevice, This->context[i]);
116     }
117     /* Restore the screen resolution if we rendered in fullscreen
118      * This will restore the screen resolution to what it was before creating the swapchain. In case of d3d8 and d3d9
119      * this will be the original desktop resolution. In case of d3d7 this will be a NOP because ddraw sets the resolution
120      * before starting up Direct3D, thus orig_width and orig_height will be equal to the modes in the presentation params
121      */
122     if(This->presentParms.Windowed == FALSE) {
123         mode.Width = This->orig_width;
124         mode.Height = This->orig_height;
125         mode.RefreshRate = 0;
126         mode.Format = This->orig_fmt;
127         IWineD3DDevice_SetDisplayMode((IWineD3DDevice *) This->wineD3DDevice, 0, &mode);
128     }
129     HeapFree(GetProcessHeap(), 0, This->context);
130
131     HeapFree(GetProcessHeap(), 0, This);
132 }
133
134 static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
135     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
136     unsigned int sync;
137     int retval;
138
139
140     ActivateContext(This->wineD3DDevice, This->backBuffer[0], CTXUSAGE_RESOURCELOAD);
141
142     /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */
143     if(This->wineD3DDevice->bCursorVisible && This->wineD3DDevice->cursorTexture) {
144         IWineD3DSurfaceImpl cursor;
145         RECT destRect = {This->wineD3DDevice->xScreenSpace - This->wineD3DDevice->xHotSpot,
146                          This->wineD3DDevice->yScreenSpace - This->wineD3DDevice->yHotSpot,
147                          This->wineD3DDevice->xScreenSpace + This->wineD3DDevice->cursorWidth - This->wineD3DDevice->xHotSpot,
148                          This->wineD3DDevice->yScreenSpace + This->wineD3DDevice->cursorHeight - This->wineD3DDevice->yHotSpot};
149         TRACE("Rendering the cursor. Creating fake surface at %p\n", &cursor);
150         /* Build a fake surface to call the Blitting code. It is not possible to use the interface passed by
151          * the application because we are only supposed to copy the information out. Using a fake surface
152          * allows to use the Blitting engine and avoid copying the whole texture -> render target blitting code.
153          */
154         memset(&cursor, 0, sizeof(cursor));
155         cursor.lpVtbl = &IWineD3DSurface_Vtbl;
156         cursor.resource.ref = 1;
157         cursor.resource.wineD3DDevice = This->wineD3DDevice;
158         cursor.resource.pool = WINED3DPOOL_SCRATCH;
159         cursor.resource.format = WINED3DFMT_A8R8G8B8;
160         cursor.resource.resourceType = WINED3DRTYPE_SURFACE;
161         cursor.glDescription.textureName = This->wineD3DDevice->cursorTexture;
162         cursor.glDescription.target = GL_TEXTURE_2D;
163         cursor.glDescription.level = 0;
164         cursor.currentDesc.Width = This->wineD3DDevice->cursorWidth;
165         cursor.currentDesc.Height = This->wineD3DDevice->cursorHeight;
166         cursor.glRect.left = 0;
167         cursor.glRect.top = 0;
168         cursor.glRect.right = cursor.currentDesc.Width;
169         cursor.glRect.bottom = cursor.currentDesc.Height;
170         /* The cursor must have pow2 sizes */
171         cursor.pow2Width = cursor.currentDesc.Width;
172         cursor.pow2Height = cursor.currentDesc.Height;
173         /* The surface is in the texture */
174         cursor.Flags |= SFLAG_INTEXTURE;
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         if (This->presentParms.Windowed) {
179             MapWindowPoints(NULL, This->win_handle, (LPPOINT)&destRect, 2);
180         }
181         IWineD3DSurface_Blt(This->backBuffer[0], &destRect, (IWineD3DSurface *) &cursor, NULL, WINEDDBLT_KEYSRC, NULL, WINED3DTEXF_NONE);
182     }
183     if(This->wineD3DDevice->logo_surface) {
184         /* Blit the logo into the upper left corner of the drawable */
185         IWineD3DSurface_BltFast(This->backBuffer[0], 0, 0, This->wineD3DDevice->logo_surface, NULL, WINEDDBLTFAST_SRCCOLORKEY);
186     }
187
188     if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect);
189     /* TODO: If only source rect or dest rect are supplied then clip the window to match */
190     TRACE("presetting HDC %p\n", This->context[0]->hdc);
191
192     /* Don't call checkGLcall, as glGetError is not applicable here */
193     if (hDestWindowOverride && This->win_handle != hDestWindowOverride) {
194         WINED3DLOCKED_RECT r;
195         BYTE *mem;
196
197         TRACE("Performing dest override of swapchain %p from window %p to %p\n", This, This->win_handle, hDestWindowOverride);
198         if(This->context[0] == This->wineD3DDevice->contexts[0]) {
199             /* The primary context 'owns' all the opengl resources. Destroying and recreating that context would require downloading
200              * all opengl resources, deleting the gl resources, destroying all other contexts, then recreating all other contexts
201              * and reload the resources
202              */
203             ERR("Cannot change the destination window of the owner of the primary context\n");
204         } else {
205             This->win_handle             = hDestWindowOverride;
206
207             /* The old back buffer has to be copied over to the new back buffer. A lockrect - switchcontext - unlockrect
208              * would suffice in theory, but it is rather nasty and may cause troubles with future changes of the locking code
209              * So lock read only, copy the surface out, then lock with the discard flag and write back
210              */
211             IWineD3DSurface_LockRect(This->backBuffer[0], &r, NULL, WINED3DLOCK_READONLY);
212             mem = HeapAlloc(GetProcessHeap(), 0, r.Pitch * ((IWineD3DSurfaceImpl *) This->backBuffer[0])->currentDesc.Height);
213             memcpy(mem, r.pBits, r.Pitch * ((IWineD3DSurfaceImpl *) This->backBuffer[0])->currentDesc.Height);
214             IWineD3DSurface_UnlockRect(This->backBuffer[0]);
215
216             DestroyContext(This->wineD3DDevice, This->context[0]);
217             This->context[0] = CreateContext(This->wineD3DDevice, (IWineD3DSurfaceImpl *) This->frontBuffer, This->win_handle, FALSE /* pbuffer */, &This->presentParms);
218
219             IWineD3DSurface_LockRect(This->backBuffer[0], &r, NULL, WINED3DLOCK_DISCARD);
220             memcpy(r.pBits, mem, r.Pitch * ((IWineD3DSurfaceImpl *) This->backBuffer[0])->currentDesc.Height);
221             HeapFree(GetProcessHeap(), 0, mem);
222             IWineD3DSurface_UnlockRect(This->backBuffer[0]);
223         }
224     }
225
226     SwapBuffers(This->context[0]->hdc); /* TODO: cycle through the swapchain buffers */
227
228     TRACE("SwapBuffers called, Starting new frame\n");
229     /* FPS support */
230     if (TRACE_ON(fps))
231     {
232         DWORD time = GetTickCount();
233         This->frames++;
234         /* every 1.5 seconds */
235         if (time - This->prev_time > 1500) {
236             TRACE_(fps)("%p @ approx %.2ffps\n", This, 1000.0*This->frames/(time - This->prev_time));
237             This->prev_time = time;
238             This->frames = 0;
239         }
240     }
241
242 #if defined(FRAME_DEBUGGING)
243 {
244     if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) {
245         if (!isOn) {
246             isOn = TRUE;
247             FIXME("Enabling D3D Trace\n");
248             __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1);
249 #if defined(SHOW_FRAME_MAKEUP)
250             FIXME("Singe Frame snapshots Starting\n");
251             isDumpingFrames = TRUE;
252             ENTER_GL();
253             glClear(GL_COLOR_BUFFER_BIT);
254             LEAVE_GL();
255 #endif
256
257 #if defined(SINGLE_FRAME_DEBUGGING)
258         } else {
259 #if defined(SHOW_FRAME_MAKEUP)
260             FIXME("Singe Frame snapshots Finishing\n");
261             isDumpingFrames = FALSE;
262 #endif
263             FIXME("Singe Frame trace complete\n");
264             DeleteFileA("C:\\D3DTRACE");
265             __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
266 #endif
267         }
268     } else {
269         if (isOn) {
270             isOn = FALSE;
271 #if defined(SHOW_FRAME_MAKEUP)
272             FIXME("Single Frame snapshots Finishing\n");
273             isDumpingFrames = FALSE;
274 #endif
275             FIXME("Disabling D3D Trace\n");
276             __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
277         }
278     }
279 }
280 #endif
281
282     /* This is disabled, but the code left in for debug purposes.
283      *
284      * Since we're allowed to modify the new back buffer on a D3DSWAPEFFECT_DISCARD flip,
285      * we can clear it with some ugly color to make bad drawing visible and ease debugging.
286      * The Debug runtime does the same on Windows. However, a few games do not redraw the
287      * screen properly, like Max Payne 2, which leaves a few pixels undefined.
288      *
289      * Tests show that the content of the back buffer after a discard flip is indeed not
290      * reliable, so no game can depend on the exact content. However, it resembles the
291      * old contents in some way, for example by showing fragments at other locations. In
292      * general, the color theme is still intact. So Max payne, which draws rather dark scenes
293      * gets a dark background image. If we clear it with a bright ugly color, the game's
294      * bug shows up much more than it does on Windows, and the players see single pixels
295      * with wrong colors.
296      * (The Max Payne bug has been confirmed on Windows with the debug runtime)
297      */
298     if (FALSE && This->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD) {
299         TRACE("Clearing the color buffer with cyan color\n");
300
301         IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL,
302                               WINED3DCLEAR_TARGET, 0xff00ffff, 1.0, 0);
303     }
304
305     if(((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags   & SFLAG_INSYSMEM ||
306        ((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_INSYSMEM ) {
307         /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying */
308         IWineD3DSurfaceImpl *front = (IWineD3DSurfaceImpl *) This->frontBuffer;
309         IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0];
310         BOOL frontuptodate = front->Flags & SFLAG_INSYSMEM;
311         BOOL backuptodate = back->Flags & SFLAG_INSYSMEM;
312
313         if(front->resource.size == back->resource.size) {
314             /* Flip the DC */
315             {
316                 HDC tmp;
317                 tmp = front->hDC;
318                 front->hDC = back->hDC;
319                 back->hDC = tmp;
320             }
321
322             /* Flip the DIBsection */
323             {
324                 HBITMAP tmp;
325                 BOOL hasDib = front->Flags & SFLAG_DIBSECTION;
326                 tmp = front->dib.DIBsection;
327                 front->dib.DIBsection = back->dib.DIBsection;
328                 back->dib.DIBsection = tmp;
329
330                 if(back->Flags & SFLAG_DIBSECTION) front->Flags |= SFLAG_DIBSECTION;
331                 else front->Flags &= ~SFLAG_DIBSECTION;
332                 if(hasDib) back->Flags |= SFLAG_DIBSECTION;
333                 else back->Flags &= ~SFLAG_DIBSECTION;
334             }
335
336             /* Flip the surface data */
337             {
338                 void* tmp;
339
340                 tmp = front->dib.bitmap_data;
341                 front->dib.bitmap_data = back->dib.bitmap_data;
342                 back->dib.bitmap_data = tmp;
343
344                 tmp = front->resource.allocatedMemory;
345                 front->resource.allocatedMemory = back->resource.allocatedMemory;
346                 back->resource.allocatedMemory = tmp;
347
348                 tmp = front->resource.heapMemory;
349                 front->resource.heapMemory = back->resource.heapMemory;
350                 back->resource.heapMemory = tmp;
351             }
352
353             /* Flip the PBO */
354             {
355                 DWORD tmp_flags = front->Flags;
356
357                 GLuint tmp_pbo = front->pbo;
358                 front->pbo = back->pbo;
359                 back->pbo = tmp_pbo;
360
361                 if(back->Flags & SFLAG_PBO)
362                     front->Flags |= SFLAG_PBO;
363                 else
364                     front->Flags &= ~SFLAG_PBO;
365
366                 if(tmp_flags & SFLAG_PBO)
367                     back->Flags |= SFLAG_PBO;
368                 else
369                     back->Flags &= ~SFLAG_PBO;
370             }
371
372             /* client_memory should not be different, but just in case */
373             {
374                 BOOL tmp;
375                 tmp = front->dib.client_memory;
376                 front->dib.client_memory = back->dib.client_memory;
377                 back->dib.client_memory = tmp;
378             }
379             if(frontuptodate) back->Flags |= SFLAG_INSYSMEM;
380             else back->Flags &= ~SFLAG_INSYSMEM;
381             if(backuptodate) front->Flags |= SFLAG_INSYSMEM;
382             else front->Flags &= ~SFLAG_INSYSMEM;
383         } else {
384             IWineD3DSurface_ModifyLocation((IWineD3DSurface *) front, SFLAG_INDRAWABLE, TRUE);
385             IWineD3DSurface_ModifyLocation((IWineD3DSurface *) back, SFLAG_INDRAWABLE, TRUE);
386         }
387     }
388
389     if(This->presentParms.PresentationInterval != WINED3DPRESENT_INTERVAL_IMMEDIATE && GL_SUPPORT(SGI_VIDEO_SYNC)) {
390         retval = GL_EXTCALL(glXGetVideoSyncSGI(&sync));
391         if(retval != 0) {
392             ERR("glXGetVideoSyncSGI failed(retval = %d\n", retval);
393         }
394
395         switch(This->presentParms.PresentationInterval) {
396             case WINED3DPRESENT_INTERVAL_DEFAULT:
397             case WINED3DPRESENT_INTERVAL_ONE:
398                 if(sync <= This->vSyncCounter) {
399                     retval = GL_EXTCALL(glXWaitVideoSyncSGI(1, 0, &This->vSyncCounter));
400                 } else {
401                     This->vSyncCounter = sync;
402                 }
403                 break;
404             case WINED3DPRESENT_INTERVAL_TWO:
405                 if(sync <= This->vSyncCounter + 1) {
406                     retval = GL_EXTCALL(glXWaitVideoSyncSGI(2, This->vSyncCounter & 0x1, &This->vSyncCounter));
407                 } else {
408                     This->vSyncCounter = sync;
409                 }
410                 break;
411             case WINED3DPRESENT_INTERVAL_THREE:
412                 if(sync <= This->vSyncCounter + 2) {
413                     retval = GL_EXTCALL(glXWaitVideoSyncSGI(3, This->vSyncCounter % 0x3, &This->vSyncCounter));
414                 } else {
415                     This->vSyncCounter = sync;
416                 }
417                 break;
418             case WINED3DPRESENT_INTERVAL_FOUR:
419                 if(sync <= This->vSyncCounter + 3) {
420                     retval = GL_EXTCALL(glXWaitVideoSyncSGI(4, This->vSyncCounter & 0x3, &This->vSyncCounter));
421                 } else {
422                     This->vSyncCounter = sync;
423                 }
424                 break;
425             default:
426                 FIXME("Unknown presentation interval %08x\n", This->presentParms.PresentationInterval);
427         }
428     }
429
430     TRACE("returning\n");
431     return WINED3D_OK;
432 }
433
434 static HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
435     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
436     POINT start;
437
438     TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
439
440     start.x = 0;
441     start.y = 0;
442
443     if (This->presentParms.Windowed) {
444         MapWindowPoints(This->win_handle, NULL, &start, 1);
445     }
446
447     IWineD3DSurface_BltFast(pDestSurface, start.x, start.y, This->frontBuffer, NULL, 0);
448     return WINED3D_OK;
449 }
450
451 static HRESULT WINAPI IWineD3DSwapChainImpl_GetBackBuffer(IWineD3DSwapChain *iface, UINT iBackBuffer, WINED3DBACKBUFFER_TYPE Type, IWineD3DSurface **ppBackBuffer) {
452
453     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
454
455     if (iBackBuffer > This->presentParms.BackBufferCount - 1) {
456         TRACE("Back buffer count out of range\n");
457         /* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it here
458          * in wined3d to avoid problems in other libs
459          */
460         *ppBackBuffer = NULL;
461         return WINED3DERR_INVALIDCALL;
462     }
463
464     *ppBackBuffer = This->backBuffer[iBackBuffer];
465     TRACE("(%p) : BackBuf %d Type %d  returning %p\n", This, iBackBuffer, Type, *ppBackBuffer);
466
467     /* Note inc ref on returned surface */
468     if(*ppBackBuffer) IWineD3DSurface_AddRef(*ppBackBuffer);
469     return WINED3D_OK;
470
471 }
472
473 static HRESULT WINAPI IWineD3DSwapChainImpl_GetRasterStatus(IWineD3DSwapChain *iface, WINED3DRASTER_STATUS *pRasterStatus) {
474     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
475     static BOOL showFixmes = TRUE;
476     pRasterStatus->InVBlank = TRUE;
477     pRasterStatus->ScanLine = 0;
478     /* No openGL equivalent */
479     if(showFixmes) {
480         FIXME("(%p) : stub (once)\n", This);
481         showFixmes = FALSE;
482     }
483     return WINED3D_OK;
484 }
485
486 static HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, WINED3DDISPLAYMODE*pMode) {
487     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
488     HRESULT hr;
489
490     TRACE("(%p)->(%p): Calling GetAdapterDisplayMode\n", This, pMode);
491     hr = IWineD3D_GetAdapterDisplayMode(This->wineD3DDevice->wineD3D, This->wineD3DDevice->adapter->num, pMode);
492
493     TRACE("(%p) : returning w(%d) h(%d) rr(%d) fmt(%u,%s)\n", This, pMode->Width, pMode->Height, pMode->RefreshRate,
494     pMode->Format, debug_d3dformat(pMode->Format));
495     return hr;
496 }
497
498 static HRESULT WINAPI IWineD3DSwapChainImpl_GetDevice(IWineD3DSwapChain *iface, IWineD3DDevice**ppDevice) {
499     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
500
501     *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
502
503     /* Note  Calling this method will increase the internal reference count
504        on the IDirect3DDevice9 interface. */
505     IWineD3DDevice_AddRef(*ppDevice);
506     TRACE("(%p) : returning %p\n", This, *ppDevice);
507     return WINED3D_OK;
508 }
509
510 static HRESULT WINAPI IWineD3DSwapChainImpl_GetPresentParameters(IWineD3DSwapChain *iface, WINED3DPRESENT_PARAMETERS *pPresentationParameters) {
511     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
512     TRACE("(%p)\n", This);
513
514     *pPresentationParameters = This->presentParms;
515
516     return WINED3D_OK;
517 }
518
519 static HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST WINED3DGAMMARAMP *pRamp){
520
521     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
522     HDC hDC;
523     TRACE("(%p) : pRamp@%p flags(%d)\n", This, pRamp, Flags);
524     hDC = GetDC(This->win_handle);
525     SetDeviceGammaRamp(hDC, (LPVOID)pRamp);
526     ReleaseDC(This->win_handle, hDC);
527     return WINED3D_OK;
528
529 }
530
531 static HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, WINED3DGAMMARAMP *pRamp){
532
533     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
534     HDC hDC;
535     TRACE("(%p) : pRamp@%p\n", This, pRamp);
536     hDC = GetDC(This->win_handle);
537     GetDeviceGammaRamp(hDC, pRamp);
538     ReleaseDC(This->win_handle, hDC);
539     return WINED3D_OK;
540
541 }
542
543
544 const IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
545 {
546     /* IUnknown */
547     IWineD3DSwapChainImpl_QueryInterface,
548     IWineD3DSwapChainImpl_AddRef,
549     IWineD3DSwapChainImpl_Release,
550     /* IWineD3DSwapChain */
551     IWineD3DSwapChainImpl_GetParent,
552     IWineD3DSwapChainImpl_Destroy,
553     IWineD3DSwapChainImpl_GetDevice,
554     IWineD3DSwapChainImpl_Present,
555     IWineD3DSwapChainImpl_GetFrontBufferData,
556     IWineD3DSwapChainImpl_GetBackBuffer,
557     IWineD3DSwapChainImpl_GetRasterStatus,
558     IWineD3DSwapChainImpl_GetDisplayMode,
559     IWineD3DSwapChainImpl_GetPresentParameters,
560     IWineD3DSwapChainImpl_SetGammaRamp,
561     IWineD3DSwapChainImpl_GetGammaRamp
562 };
563
564 WineD3DContext *IWineD3DSwapChainImpl_CreateContextForThread(IWineD3DSwapChain *iface) {
565     WineD3DContext *ctx;
566     IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *) iface;
567     WineD3DContext **newArray;
568
569     TRACE("Creating a new context for swapchain %p, thread %d\n", This, GetCurrentThreadId());
570
571     ctx = CreateContext(This->wineD3DDevice, (IWineD3DSurfaceImpl *) This->frontBuffer,
572                         This->context[0]->win_handle, FALSE /* pbuffer */, &This->presentParms);
573     if(!ctx) {
574         ERR("Failed to create a new context for the swapchain\n");
575         return NULL;
576     }
577
578     newArray = HeapAlloc(GetProcessHeap(), 0, sizeof(*newArray) * This->num_contexts + 1);
579     if(!newArray) {
580         ERR("Out of memory when trying to allocate a new context array\n");
581         DestroyContext(This->wineD3DDevice, ctx);
582         return NULL;
583     }
584     memcpy(newArray, This->context, sizeof(*newArray) * This->num_contexts);
585     HeapFree(GetProcessHeap(), 0, This->context);
586     newArray[This->num_contexts] = ctx;
587     This->context = newArray;
588     This->num_contexts++;
589
590     TRACE("Returning context %p\n", ctx);
591     return ctx;
592 }
593
594 void get_drawable_size_swapchain(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
595     /* The drawable size of an onscreen drawable is the surface size.
596      * (Actually: The window size, but the surface is created in window size)
597      */
598     *width = This->currentDesc.Width;
599     *height = This->currentDesc.Height;
600 }