2 *IDirect3DSwapChain9 implementation
4 *Copyright 2002-2003 Jason Edmeades
5 *Copyright 2002-2003 Raphael Junqueira
6 *Copyright 2005 Oliver Stieber
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.
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.
18 *You should have received a copy of the GNU Lesser General Public
19 *License along with this library; if not, write to the Free Software
20 *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wined3d_private.h"
27 /* TODO: move to shared header (or context manager )*/
28 /* x11drv GDI escapes */
29 #define X11DRV_ESCAPE 6789
30 enum x11drv_escape_codes
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 */
37 /* retrieve the X display to use on a given DC */
38 inline static Display *get_display( HDC hdc )
41 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
43 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
44 sizeof(display), (LPSTR)&display )) display = NULL;
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)*/
53 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
54 WINE_DECLARE_DEBUG_CHANNEL(d3d_fps);
57 /* IDirect3DSwapChain IUnknown parts follow: */
58 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);
65 HRESULT WINAPI IWineD3DSwapChainImpl_QueryInterface(IWineD3DSwapChain *iface, REFIID riid, LPVOID *ppobj)
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);
74 ERR("Query interface called but now data allocated\n");
84 ULONG WINAPI IWineD3DSwapChainImpl_Release(IWineD3DSwapChain *iface) {
85 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
87 refCount = InterlockedDecrement(&This->ref);
88 TRACE("(%p) : ReleaseRef to %ld\n", This, refCount);
90 IUnknown* bufferParent;
92 /* tell the device that we've been released */
93 IWineD3DDevice_SwapChainReleased((IWineD3DDevice *)This->wineD3DDevice, iface);
95 /* release the ref to the front and back buffer parents */
96 IWineD3DSurface_SetContainer(This->frontBuffer, 0);
97 IWineD3DSurface_GetParent(This->frontBuffer, &bufferParent);
98 IUnknown_Release(bufferParent); /* once for the get parent */
99 if(IUnknown_Release(bufferParent) > 0){
100 FIXME("(%p) Something's still holding the front buffer\n",This);
103 IWineD3DSurface_SetContainer(This->backBuffer, 0);
104 IWineD3DSurface_GetParent(This->backBuffer, &bufferParent);
105 IUnknown_Release(bufferParent); /* once for the get parent */
106 if(IUnknown_Release(bufferParent) > 0){
107 FIXME("(%p) Something's still holding the back buffer\n",This);
109 /* Clean up the context */
110 /* check that we are the current context first */
111 if(glXGetCurrentContext() == This->glCtx){
112 glXMakeCurrent(This->display, None, NULL);
114 glXDestroyContext(This->display, This->glCtx);
115 /* IUnknown_Release(This->parent); This should only apply to the primary swapchain,
116 all others are crated by the caller, so releasing the parent should cause
117 the child to be released, not the other way around!
119 HeapFree(GetProcessHeap(), 0, This);
124 HRESULT WINAPI IWineD3DSwapChainImpl_GetParent(IWineD3DSwapChain *iface, IUnknown ** ppParent){
125 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
126 *ppParent = This->parent;
127 IUnknown_AddRef(*ppParent);
128 TRACE("(%p) returning %p\n", This , *ppParent);
132 /*IWineD3DSwapChain parts follow: */
133 HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
134 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
138 if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect);
139 /* TODO: If only source rect or dest rect are supplied then clip the window to match */
140 TRACE("preseting display %p, drawable %ld\n", This->display, This->drawable);
142 /* Don't call checkGLcall, as glGetError is not applicable here */
143 if (hDestWindowOverride && This->win_handle != hDestWindowOverride) {
144 /* Set this swapchain up to point to the new destination.. */
145 #ifdef USE_CONTEXT_MANAGER
146 /* TODO: use a context mamager */
149 /* FIXME: Never access */
150 IWineD3DSwapChainImpl *swapChainImpl;
151 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)This->wineD3DDevice, 0 , (IWineD3DSwapChain **)&swapChainImpl);
152 FIXME("Unable to render to a destination window %p\n", hDestWindowOverride );
153 if(This == swapChainImpl){
154 /* FIXME: this will be fixed by moving to a context management system */
155 FIXME("Cannot change the target of the implicit swapchain\n");
158 XVisualInfo template;
160 Display *oldDisplay = This->display;
161 GLXContext oldContext = This->glCtx;
163 GLXContext currentContext;
164 Drawable currentDrawable;
165 hDc = GetDC(hDestWindowOverride);
166 This->win_handle = hDestWindowOverride;
167 This->win = (Window)GetPropA( hDestWindowOverride, "__wine_x11_whole_window" );
169 TRACE("Creating a new context for the window %p\n", hDestWindowOverride);
171 TRACE("Desctroying context %p %p\n", This->display, This->render_ctx);
178 This->display = get_display(hDc);
179 TRACE("Got display%p for %p %p\n", This->display, hDc, hDestWindowOverride);
180 ReleaseDC(hDestWindowOverride, hDc);
181 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
182 This->visInfo = XGetVisualInfo(This->display, VisualIDMask, &template, &num);
183 if (NULL == This->visInfo) {
184 ERR("cannot really get XVisual\n");
186 return WINED3DERR_NOTAVAILABLE;
188 /* Now we have problems? well not really we just need to know what the implicit context is */
189 /* now destroy the old context and create a new one (we should really copy the buffers over, and do the whole make current thing! */
190 /* destroy the active context?*/
191 TRACE("Creating new context for %p %p %p\n",This->display, This->visInfo, swapChainImpl->glCtx);
192 This->glCtx = glXCreateContext(This->display, This->visInfo, swapChainImpl->glCtx, GL_TRUE);
194 if (NULL == This->glCtx) {
195 ERR("cannot create glxContext\n");
197 This->drawable = This->win;
198 This->render_ctx = This->glCtx;
199 /* Setup some default states TODO: apply the stateblock to the new context */
200 /** save current context and drawable **/
201 currentContext = glXGetCurrentContext();
202 currentDrawable = glXGetCurrentDrawable();
204 if (glXMakeCurrent(This->display, This->win, This->glCtx) == False) {
205 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", This->display, This->glCtx, This->win);
208 checkGLcall("glXMakeCurrent");
210 /* Clear the screen */
211 glClearColor(0.0, 0.0, 0.0, 0.0);
212 checkGLcall("glClearColor");
217 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
218 checkGLcall("glClear");
220 glColor3f(1.0, 1.0, 1.0);
221 checkGLcall("glColor3f");
223 glEnable(GL_LIGHTING);
224 checkGLcall("glEnable");
226 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
227 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
229 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
230 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
232 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
233 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
235 /* If this swapchain is currently the active context then make this swapchain active */
236 if(IWineD3DSurface_GetContainer(This->wineD3DDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmp) == WINED3D_OK){
237 if(tmp != (IUnknown *)This){
238 glXMakeCurrent(This->display, currentDrawable, currentContext);
239 checkGLcall("glXMakeCurrent");
241 IUnknown_Release(tmp);
243 /* reset the context */
244 glXMakeCurrent(This->display, currentDrawable, currentContext);
245 checkGLcall("glXMakeCurrent");
247 /* delete the old contxt*/
248 glXDestroyContext(oldDisplay, oldContext); /* Should this happen on an active context? seems a bad idea */
251 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapChainImpl);
256 /* 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. */
258 glXSwapBuffers(This->display, This->drawable); /* TODO: cycle through the swapchain buffers */
260 TRACE("glXSwapBuffers called, Starting new frame\n");
262 if (TRACE_ON(d3d_fps))
264 static long prev_time, frames;
266 DWORD time = GetTickCount();
268 /* every 1.5 seconds */
269 if (time - prev_time > 1500) {
270 TRACE_(d3d_fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
276 #if defined(FRAME_DEBUGGING)
278 if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) {
281 FIXME("Enabling D3D Trace\n");
282 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1);
283 #if defined(SHOW_FRAME_MAKEUP)
284 FIXME("Singe Frame snapshots Starting\n");
285 isDumpingFrames = TRUE;
286 glClear(GL_COLOR_BUFFER_BIT);
289 #if defined(SINGLE_FRAME_DEBUGGING)
291 #if defined(SHOW_FRAME_MAKEUP)
292 FIXME("Singe Frame snapshots Finishing\n");
293 isDumpingFrames = FALSE;
295 FIXME("Singe Frame trace complete\n");
296 DeleteFileA("C:\\D3DTRACE");
297 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
303 #if defined(SHOW_FRAME_MAKEUP)
304 FIXME("Single Frame snapshots Finishing\n");
305 isDumpingFrames = FALSE;
307 FIXME("Disabling D3D Trace\n");
308 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
315 /* Although this is not strictly required, a simple demo showed this does occur
316 on (at least non-debug) d3d */
317 if (This->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD) {
321 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
324 TRACE("Clearing z/stencil buffer\n");
326 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0x00, 1.0, 0);
329 TRACE("returning\n");
333 HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
334 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
335 WINED3DFORMAT d3dformat;
338 WINED3DSURFACE_DESC desc;
339 glDescriptor *glDescription;
341 TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
343 memset(&desc, 0, sizeof(desc));
345 desc.Height = &height;
346 desc.Format = &d3dformat;
347 #if 0 /* TODO: make sure that this swapchains context is active */
348 IWineD3DDevice_ActivateSwapChainContext(This->wineD3DDevice, iface);
350 IWineD3DSurface_GetDesc(pDestSurface, &desc);
351 /* make sure that the front buffer is the active read buffer */
352 glReadBuffer(GL_FRONT);
353 /* Read the pixels from the buffer into the surfaces memory */
354 IWineD3DSurface_GetGlDesc(pDestSurface, &glDescription);
355 glReadPixels(glDescription->target,
356 glDescription->level,
359 glDescription->glFormat,
360 glDescription->glType,
361 (void *)IWineD3DSurface_GetData(pDestSurface));
366 HRESULT WINAPI IWineD3DSwapChainImpl_GetBackBuffer(IWineD3DSwapChain *iface, UINT iBackBuffer, WINED3DBACKBUFFER_TYPE Type, IWineD3DSurface **ppBackBuffer) {
368 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
370 *ppBackBuffer = This->backBuffer;
371 TRACE("(%p) : BackBuf %d Type %d returning %p\n", This, iBackBuffer, Type, *ppBackBuffer);
373 if (iBackBuffer > This->presentParms.BackBufferCount - 1) {
374 FIXME("Only one backBuffer currently supported\n");
375 return WINED3DERR_INVALIDCALL;
378 /* Note inc ref on returned surface */
379 IWineD3DSurface_AddRef(*ppBackBuffer);
384 HRESULT WINAPI IWineD3DSwapChainImpl_GetRasterStatus(IWineD3DSwapChain *iface, WINED3DRASTER_STATUS *pRasterStatus) {
385 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
386 static BOOL showFixmes = TRUE;
387 pRasterStatus->InVBlank = TRUE;
388 pRasterStatus->ScanLine = 0;
389 /* No openGL equivalent */
391 FIXME("(%p) : stub (once)\n", This);
397 HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, WINED3DDISPLAYMODE*pMode) {
398 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
402 pMode->Width = GetSystemMetrics(SM_CXSCREEN);
403 pMode->Height = GetSystemMetrics(SM_CYSCREEN);
404 pMode->RefreshRate = 85; /* FIXME: How to identify? */
406 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
407 bpp = GetDeviceCaps(hdc, BITSPIXEL);
411 case 8: pMode->Format = D3DFMT_R8G8B8; break;
412 case 16: pMode->Format = D3DFMT_R5G6B5; break;
413 case 24: /*pMode->Format = D3DFMT_R8G8B8; break; */ /* 32bpp and 24bpp can be aliased for X */
414 case 32: pMode->Format = D3DFMT_A8R8G8B8; break;
416 FIXME("Unrecognized display mode format\n");
417 pMode->Format = D3DFMT_UNKNOWN;
420 TRACE("(%p) : returning w(%d) h(%d) rr(%d) fmt(%u,%s)\n", This, pMode->Width, pMode->Height, pMode->RefreshRate,
421 pMode->Format, debug_d3dformat(pMode->Format));
425 HRESULT WINAPI IWineD3DSwapChainImpl_GetDevice(IWineD3DSwapChain *iface, IWineD3DDevice**ppDevice) {
426 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
428 *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
430 /* Note Calling this method will increase the internal reference count
431 on the IDirect3DDevice9 interface. */
432 IWineD3DDevice_AddRef(*ppDevice);
433 TRACE("(%p) : returning %p\n", This, *ppDevice);
437 HRESULT WINAPI IWineD3DSwapChainImpl_GetPresentParameters(IWineD3DSwapChain *iface, WINED3DPRESENT_PARAMETERS *pPresentationParameters) {
438 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
439 TRACE("(%p)\n", This);
440 *pPresentationParameters->BackBufferWidth = This->presentParms.BackBufferWidth;
441 *pPresentationParameters->BackBufferHeight = This->presentParms.BackBufferHeight;
442 *pPresentationParameters->BackBufferFormat = This->presentParms.BackBufferFormat;
443 *pPresentationParameters->BackBufferCount = This->presentParms.BackBufferCount;
444 *pPresentationParameters->MultiSampleType = This->presentParms.MultiSampleType;
445 *pPresentationParameters->MultiSampleQuality = This->presentParms.MultiSampleQuality;
446 *pPresentationParameters->SwapEffect = This->presentParms.SwapEffect;
447 *pPresentationParameters->hDeviceWindow = This->presentParms.hDeviceWindow;
448 *pPresentationParameters->Windowed = This->presentParms.Windowed;
449 *pPresentationParameters->EnableAutoDepthStencil = This->presentParms.EnableAutoDepthStencil;
450 *pPresentationParameters->Flags = This->presentParms.Flags;
451 *pPresentationParameters->FullScreen_RefreshRateInHz = This->presentParms.FullScreen_RefreshRateInHz;
452 *pPresentationParameters->PresentationInterval = This->presentParms.PresentationInterval;
456 HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST WINED3DGAMMARAMP *pRamp){
458 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
460 TRACE("(%p) : pRamp@%p flags(%ld)\n", This, pRamp, Flags);
461 hDC = GetDC(This->win_handle);
462 SetDeviceGammaRamp(hDC, (LPVOID)pRamp);
463 ReleaseDC(This->win_handle, hDC);
468 HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, WINED3DGAMMARAMP *pRamp){
470 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
472 TRACE("(%p) : pRamp@%p\n", This, pRamp);
473 hDC = GetDC(This->win_handle);
474 GetDeviceGammaRamp(hDC, pRamp);
475 ReleaseDC(This->win_handle, hDC);
481 IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
484 IWineD3DSwapChainImpl_QueryInterface,
485 IWineD3DSwapChainImpl_AddRef,
486 IWineD3DSwapChainImpl_Release,
487 /* IWineD3DSwapChain */
488 IWineD3DSwapChainImpl_GetParent,
489 IWineD3DSwapChainImpl_GetDevice,
490 IWineD3DSwapChainImpl_Present,
491 IWineD3DSwapChainImpl_GetFrontBufferData,
492 IWineD3DSwapChainImpl_GetBackBuffer,
493 IWineD3DSwapChainImpl_GetRasterStatus,
494 IWineD3DSwapChainImpl_GetDisplayMode,
495 IWineD3DSwapChainImpl_GetPresentParameters,
496 IWineD3DSwapChainImpl_SetGammaRamp,
497 IWineD3DSwapChainImpl_GetGammaRamp