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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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");
85 ULONG WINAPI IWineD3DSwapChainImpl_Release(IWineD3DSwapChain *iface) {
86 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
88 refCount = InterlockedDecrement(&This->ref);
89 TRACE("(%p) : ReleaseRef to %ld\n", This, refCount);
91 IUnknown* bufferParent;
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);
103 if(This->backBuffer) {
104 IWineD3DSurface_SetContainer(This->backBuffer, 0);
105 IWineD3DSurface_GetParent(This->backBuffer, &bufferParent);
106 IUnknown_Release(bufferParent); /* once for the get parent */
107 if(IUnknown_Release(bufferParent) > 0){
108 FIXME("(%p) Something's still holding the back buffer\n",This);
112 /* Clean up the context */
113 /* check that we are the current context first */
114 if(glXGetCurrentContext() == This->glCtx){
115 glXMakeCurrent(This->display, None, NULL);
117 glXDestroyContext(This->display, This->glCtx);
118 /* IUnknown_Release(This->parent); This should only apply to the primary swapchain,
119 all others are crated by the caller, so releasing the parent should cause
120 the child to be released, not the other way around!
122 HeapFree(GetProcessHeap(), 0, This);
127 HRESULT WINAPI IWineD3DSwapChainImpl_GetParent(IWineD3DSwapChain *iface, IUnknown ** ppParent){
128 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
129 *ppParent = This->parent;
130 IUnknown_AddRef(*ppParent);
131 TRACE("(%p) returning %p\n", This , *ppParent);
135 /*IWineD3DSwapChain parts follow: */
136 HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
137 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
141 if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect);
142 /* TODO: If only source rect or dest rect are supplied then clip the window to match */
143 TRACE("preseting display %p, drawable %ld\n", This->display, This->drawable);
145 /* Don't call checkGLcall, as glGetError is not applicable here */
146 if (hDestWindowOverride && This->win_handle != hDestWindowOverride) {
147 /* Set this swapchain up to point to the new destination.. */
148 #ifdef USE_CONTEXT_MANAGER
149 /* TODO: use a context mamager */
152 /* FIXME: Never access */
153 IWineD3DSwapChainImpl *swapChainImpl;
154 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)This->wineD3DDevice, 0 , (IWineD3DSwapChain **)&swapChainImpl);
155 FIXME("Unable to render to a destination window %p\n", hDestWindowOverride );
156 if(This == swapChainImpl){
157 /* FIXME: this will be fixed by moving to a context management system */
158 FIXME("Cannot change the target of the implicit swapchain\n");
161 XVisualInfo template;
163 Display *oldDisplay = This->display;
164 GLXContext oldContext = This->glCtx;
166 GLXContext currentContext;
167 Drawable currentDrawable;
168 hDc = GetDC(hDestWindowOverride);
169 This->win_handle = hDestWindowOverride;
170 This->win = (Window)GetPropA( hDestWindowOverride, "__wine_x11_whole_window" );
172 TRACE("Creating a new context for the window %p\n", hDestWindowOverride);
174 TRACE("Desctroying context %p %p\n", This->display, This->render_ctx);
181 This->display = get_display(hDc);
182 TRACE("Got display%p for %p %p\n", This->display, hDc, hDestWindowOverride);
183 ReleaseDC(hDestWindowOverride, hDc);
184 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
185 This->visInfo = XGetVisualInfo(This->display, VisualIDMask, &template, &num);
186 if (NULL == This->visInfo) {
187 ERR("cannot really get XVisual\n");
189 return WINED3DERR_NOTAVAILABLE;
191 /* Now we have problems? well not really we just need to know what the implicit context is */
192 /* now destroy the old context and create a new one (we should really copy the buffers over, and do the whole make current thing! */
193 /* destroy the active context?*/
194 TRACE("Creating new context for %p %p %p\n",This->display, This->visInfo, swapChainImpl->glCtx);
195 This->glCtx = glXCreateContext(This->display, This->visInfo, swapChainImpl->glCtx, GL_TRUE);
197 if (NULL == This->glCtx) {
198 ERR("cannot create glxContext\n");
200 This->drawable = This->win;
201 This->render_ctx = This->glCtx;
202 /* Setup some default states TODO: apply the stateblock to the new context */
203 /** save current context and drawable **/
204 currentContext = glXGetCurrentContext();
205 currentDrawable = glXGetCurrentDrawable();
207 if (glXMakeCurrent(This->display, This->win, This->glCtx) == False) {
208 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", This->display, This->glCtx, This->win);
211 checkGLcall("glXMakeCurrent");
213 /* Clear the screen */
214 glClearColor(0.0, 0.0, 0.0, 0.0);
215 checkGLcall("glClearColor");
220 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
221 checkGLcall("glClear");
223 glColor3f(1.0, 1.0, 1.0);
224 checkGLcall("glColor3f");
226 glEnable(GL_LIGHTING);
227 checkGLcall("glEnable");
229 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
230 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
232 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
233 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
235 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
236 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
238 /* If this swapchain is currently the active context then make this swapchain active */
239 if(IWineD3DSurface_GetContainer(This->wineD3DDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmp) == WINED3D_OK){
240 if(tmp != (IUnknown *)This){
241 glXMakeCurrent(This->display, currentDrawable, currentContext);
242 checkGLcall("glXMakeCurrent");
244 IUnknown_Release(tmp);
246 /* reset the context */
247 glXMakeCurrent(This->display, currentDrawable, currentContext);
248 checkGLcall("glXMakeCurrent");
250 /* delete the old contxt*/
251 glXDestroyContext(oldDisplay, oldContext); /* Should this happen on an active context? seems a bad idea */
254 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapChainImpl);
259 /* 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. */
261 glXSwapBuffers(This->display, This->drawable); /* TODO: cycle through the swapchain buffers */
263 TRACE("glXSwapBuffers called, Starting new frame\n");
265 if (TRACE_ON(d3d_fps))
267 static long prev_time, frames;
269 DWORD time = GetTickCount();
271 /* every 1.5 seconds */
272 if (time - prev_time > 1500) {
273 TRACE_(d3d_fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
279 #if defined(FRAME_DEBUGGING)
281 if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) {
284 FIXME("Enabling D3D Trace\n");
285 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1);
286 #if defined(SHOW_FRAME_MAKEUP)
287 FIXME("Singe Frame snapshots Starting\n");
288 isDumpingFrames = TRUE;
289 glClear(GL_COLOR_BUFFER_BIT);
292 #if defined(SINGLE_FRAME_DEBUGGING)
294 #if defined(SHOW_FRAME_MAKEUP)
295 FIXME("Singe Frame snapshots Finishing\n");
296 isDumpingFrames = FALSE;
298 FIXME("Singe Frame trace complete\n");
299 DeleteFileA("C:\\D3DTRACE");
300 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
306 #if defined(SHOW_FRAME_MAKEUP)
307 FIXME("Single Frame snapshots Finishing\n");
308 isDumpingFrames = FALSE;
310 FIXME("Disabling D3D Trace\n");
311 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
318 /* Although this is not strictly required, a simple demo showed this does occur
319 on (at least non-debug) d3d */
320 if (This->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD) {
324 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
327 TRACE("Clearing z/stencil buffer\n");
329 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0x00, 1.0, 0);
332 ((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags |= SFLAG_GLDIRTY;
333 ((IWineD3DSurfaceImpl *) This->backBuffer)->Flags |= SFLAG_GLDIRTY;
335 TRACE("returning\n");
339 HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
340 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
341 WINED3DFORMAT d3dformat;
344 WINED3DSURFACE_DESC desc;
345 glDescriptor *glDescription;
347 TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
349 memset(&desc, 0, sizeof(desc));
351 desc.Height = &height;
352 desc.Format = &d3dformat;
353 #if 0 /* TODO: make sure that this swapchains context is active */
354 IWineD3DDevice_ActivateSwapChainContext(This->wineD3DDevice, iface);
356 IWineD3DSurface_GetDesc(pDestSurface, &desc);
357 /* make sure that the front buffer is the active read buffer */
358 glReadBuffer(GL_FRONT);
359 /* Read the pixels from the buffer into the surfaces memory */
360 IWineD3DSurface_GetGlDesc(pDestSurface, &glDescription);
361 glReadPixels(glDescription->target,
362 glDescription->level,
365 glDescription->glFormat,
366 glDescription->glType,
367 (void *)IWineD3DSurface_GetData(pDestSurface));
372 HRESULT WINAPI IWineD3DSwapChainImpl_GetBackBuffer(IWineD3DSwapChain *iface, UINT iBackBuffer, WINED3DBACKBUFFER_TYPE Type, IWineD3DSurface **ppBackBuffer) {
374 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
376 *ppBackBuffer = This->backBuffer;
377 TRACE("(%p) : BackBuf %d Type %d returning %p\n", This, iBackBuffer, Type, *ppBackBuffer);
379 if (iBackBuffer > This->presentParms.BackBufferCount - 1) {
380 TRACE("Back buffer count out of range\n");
381 /* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it here
382 * in wined3d to avoid problems in other libs
384 *ppBackBuffer = NULL;
385 return WINED3DERR_INVALIDCALL;
388 /* Note inc ref on returned surface */
389 if(*ppBackBuffer) IWineD3DSurface_AddRef(*ppBackBuffer);
394 HRESULT WINAPI IWineD3DSwapChainImpl_GetRasterStatus(IWineD3DSwapChain *iface, WINED3DRASTER_STATUS *pRasterStatus) {
395 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
396 static BOOL showFixmes = TRUE;
397 pRasterStatus->InVBlank = TRUE;
398 pRasterStatus->ScanLine = 0;
399 /* No openGL equivalent */
401 FIXME("(%p) : stub (once)\n", This);
407 HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, WINED3DDISPLAYMODE*pMode) {
408 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
412 pMode->Width = GetSystemMetrics(SM_CXSCREEN);
413 pMode->Height = GetSystemMetrics(SM_CYSCREEN);
414 pMode->RefreshRate = 85; /* FIXME: How to identify? */
416 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
417 bpp = GetDeviceCaps(hdc, BITSPIXEL);
421 case 8: pMode->Format = D3DFMT_R8G8B8; break;
422 case 16: pMode->Format = D3DFMT_R5G6B5; break;
423 case 24: /*pMode->Format = D3DFMT_R8G8B8; break; */ /* 32bpp and 24bpp can be aliased for X */
424 case 32: pMode->Format = D3DFMT_A8R8G8B8; break;
426 FIXME("Unrecognized display mode format\n");
427 pMode->Format = D3DFMT_UNKNOWN;
430 TRACE("(%p) : returning w(%d) h(%d) rr(%d) fmt(%u,%s)\n", This, pMode->Width, pMode->Height, pMode->RefreshRate,
431 pMode->Format, debug_d3dformat(pMode->Format));
435 HRESULT WINAPI IWineD3DSwapChainImpl_GetDevice(IWineD3DSwapChain *iface, IWineD3DDevice**ppDevice) {
436 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
438 *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
440 /* Note Calling this method will increase the internal reference count
441 on the IDirect3DDevice9 interface. */
442 IWineD3DDevice_AddRef(*ppDevice);
443 TRACE("(%p) : returning %p\n", This, *ppDevice);
447 HRESULT WINAPI IWineD3DSwapChainImpl_GetPresentParameters(IWineD3DSwapChain *iface, WINED3DPRESENT_PARAMETERS *pPresentationParameters) {
448 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
449 TRACE("(%p)\n", This);
450 *pPresentationParameters->BackBufferWidth = This->presentParms.BackBufferWidth;
451 *pPresentationParameters->BackBufferHeight = This->presentParms.BackBufferHeight;
452 *pPresentationParameters->BackBufferFormat = This->presentParms.BackBufferFormat;
453 *pPresentationParameters->BackBufferCount = This->presentParms.BackBufferCount;
454 *pPresentationParameters->MultiSampleType = This->presentParms.MultiSampleType;
455 *pPresentationParameters->MultiSampleQuality = This->presentParms.MultiSampleQuality;
456 *pPresentationParameters->SwapEffect = This->presentParms.SwapEffect;
457 *pPresentationParameters->hDeviceWindow = This->presentParms.hDeviceWindow;
458 *pPresentationParameters->Windowed = This->presentParms.Windowed;
459 *pPresentationParameters->EnableAutoDepthStencil = This->presentParms.EnableAutoDepthStencil;
460 *pPresentationParameters->Flags = This->presentParms.Flags;
461 *pPresentationParameters->FullScreen_RefreshRateInHz = This->presentParms.FullScreen_RefreshRateInHz;
462 *pPresentationParameters->PresentationInterval = This->presentParms.PresentationInterval;
466 HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST WINED3DGAMMARAMP *pRamp){
468 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
470 TRACE("(%p) : pRamp@%p flags(%ld)\n", This, pRamp, Flags);
471 hDC = GetDC(This->win_handle);
472 SetDeviceGammaRamp(hDC, (LPVOID)pRamp);
473 ReleaseDC(This->win_handle, hDC);
478 HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, WINED3DGAMMARAMP *pRamp){
480 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
482 TRACE("(%p) : pRamp@%p\n", This, pRamp);
483 hDC = GetDC(This->win_handle);
484 GetDeviceGammaRamp(hDC, pRamp);
485 ReleaseDC(This->win_handle, hDC);
491 IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
494 IWineD3DSwapChainImpl_QueryInterface,
495 IWineD3DSwapChainImpl_AddRef,
496 IWineD3DSwapChainImpl_Release,
497 /* IWineD3DSwapChain */
498 IWineD3DSwapChainImpl_GetParent,
499 IWineD3DSwapChainImpl_GetDevice,
500 IWineD3DSwapChainImpl_Present,
501 IWineD3DSwapChainImpl_GetFrontBufferData,
502 IWineD3DSwapChainImpl_GetBackBuffer,
503 IWineD3DSwapChainImpl_GetRasterStatus,
504 IWineD3DSwapChainImpl_GetDisplayMode,
505 IWineD3DSwapChainImpl_GetPresentParameters,
506 IWineD3DSwapChainImpl_SetGammaRamp,
507 IWineD3DSwapChainImpl_GetGammaRamp