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 TRACE("returning\n");
336 HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
337 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
338 WINED3DFORMAT d3dformat;
341 WINED3DSURFACE_DESC desc;
342 glDescriptor *glDescription;
344 TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
346 memset(&desc, 0, sizeof(desc));
348 desc.Height = &height;
349 desc.Format = &d3dformat;
350 #if 0 /* TODO: make sure that this swapchains context is active */
351 IWineD3DDevice_ActivateSwapChainContext(This->wineD3DDevice, iface);
353 IWineD3DSurface_GetDesc(pDestSurface, &desc);
354 /* make sure that the front buffer is the active read buffer */
355 glReadBuffer(GL_FRONT);
356 /* Read the pixels from the buffer into the surfaces memory */
357 IWineD3DSurface_GetGlDesc(pDestSurface, &glDescription);
358 glReadPixels(glDescription->target,
359 glDescription->level,
362 glDescription->glFormat,
363 glDescription->glType,
364 (void *)IWineD3DSurface_GetData(pDestSurface));
369 HRESULT WINAPI IWineD3DSwapChainImpl_GetBackBuffer(IWineD3DSwapChain *iface, UINT iBackBuffer, WINED3DBACKBUFFER_TYPE Type, IWineD3DSurface **ppBackBuffer) {
371 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
373 *ppBackBuffer = This->backBuffer;
374 TRACE("(%p) : BackBuf %d Type %d returning %p\n", This, iBackBuffer, Type, *ppBackBuffer);
376 if (iBackBuffer > This->presentParms.BackBufferCount - 1) {
377 TRACE("Back buffer count out of range\n");
378 /* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it here
379 * in wined3d to avoid problems in other libs
381 *ppBackBuffer = NULL;
382 return WINED3DERR_INVALIDCALL;
385 /* Note inc ref on returned surface */
386 if(*ppBackBuffer) IWineD3DSurface_AddRef(*ppBackBuffer);
391 HRESULT WINAPI IWineD3DSwapChainImpl_GetRasterStatus(IWineD3DSwapChain *iface, WINED3DRASTER_STATUS *pRasterStatus) {
392 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
393 static BOOL showFixmes = TRUE;
394 pRasterStatus->InVBlank = TRUE;
395 pRasterStatus->ScanLine = 0;
396 /* No openGL equivalent */
398 FIXME("(%p) : stub (once)\n", This);
404 HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, WINED3DDISPLAYMODE*pMode) {
405 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
409 pMode->Width = GetSystemMetrics(SM_CXSCREEN);
410 pMode->Height = GetSystemMetrics(SM_CYSCREEN);
411 pMode->RefreshRate = 85; /* FIXME: How to identify? */
413 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
414 bpp = GetDeviceCaps(hdc, BITSPIXEL);
418 case 8: pMode->Format = D3DFMT_R8G8B8; break;
419 case 16: pMode->Format = D3DFMT_R5G6B5; break;
420 case 24: /*pMode->Format = D3DFMT_R8G8B8; break; */ /* 32bpp and 24bpp can be aliased for X */
421 case 32: pMode->Format = D3DFMT_A8R8G8B8; break;
423 FIXME("Unrecognized display mode format\n");
424 pMode->Format = D3DFMT_UNKNOWN;
427 TRACE("(%p) : returning w(%d) h(%d) rr(%d) fmt(%u,%s)\n", This, pMode->Width, pMode->Height, pMode->RefreshRate,
428 pMode->Format, debug_d3dformat(pMode->Format));
432 HRESULT WINAPI IWineD3DSwapChainImpl_GetDevice(IWineD3DSwapChain *iface, IWineD3DDevice**ppDevice) {
433 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
435 *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
437 /* Note Calling this method will increase the internal reference count
438 on the IDirect3DDevice9 interface. */
439 IWineD3DDevice_AddRef(*ppDevice);
440 TRACE("(%p) : returning %p\n", This, *ppDevice);
444 HRESULT WINAPI IWineD3DSwapChainImpl_GetPresentParameters(IWineD3DSwapChain *iface, WINED3DPRESENT_PARAMETERS *pPresentationParameters) {
445 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
446 TRACE("(%p)\n", This);
447 *pPresentationParameters->BackBufferWidth = This->presentParms.BackBufferWidth;
448 *pPresentationParameters->BackBufferHeight = This->presentParms.BackBufferHeight;
449 *pPresentationParameters->BackBufferFormat = This->presentParms.BackBufferFormat;
450 *pPresentationParameters->BackBufferCount = This->presentParms.BackBufferCount;
451 *pPresentationParameters->MultiSampleType = This->presentParms.MultiSampleType;
452 *pPresentationParameters->MultiSampleQuality = This->presentParms.MultiSampleQuality;
453 *pPresentationParameters->SwapEffect = This->presentParms.SwapEffect;
454 *pPresentationParameters->hDeviceWindow = This->presentParms.hDeviceWindow;
455 *pPresentationParameters->Windowed = This->presentParms.Windowed;
456 *pPresentationParameters->EnableAutoDepthStencil = This->presentParms.EnableAutoDepthStencil;
457 *pPresentationParameters->Flags = This->presentParms.Flags;
458 *pPresentationParameters->FullScreen_RefreshRateInHz = This->presentParms.FullScreen_RefreshRateInHz;
459 *pPresentationParameters->PresentationInterval = This->presentParms.PresentationInterval;
463 HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST WINED3DGAMMARAMP *pRamp){
465 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
467 TRACE("(%p) : pRamp@%p flags(%ld)\n", This, pRamp, Flags);
468 hDC = GetDC(This->win_handle);
469 SetDeviceGammaRamp(hDC, (LPVOID)pRamp);
470 ReleaseDC(This->win_handle, hDC);
475 HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, WINED3DGAMMARAMP *pRamp){
477 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
479 TRACE("(%p) : pRamp@%p\n", This, pRamp);
480 hDC = GetDC(This->win_handle);
481 GetDeviceGammaRamp(hDC, pRamp);
482 ReleaseDC(This->win_handle, hDC);
488 IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
491 IWineD3DSwapChainImpl_QueryInterface,
492 IWineD3DSwapChainImpl_AddRef,
493 IWineD3DSwapChainImpl_Release,
494 /* IWineD3DSwapChain */
495 IWineD3DSwapChainImpl_GetParent,
496 IWineD3DSwapChainImpl_GetDevice,
497 IWineD3DSwapChainImpl_Present,
498 IWineD3DSwapChainImpl_GetFrontBufferData,
499 IWineD3DSwapChainImpl_GetBackBuffer,
500 IWineD3DSwapChainImpl_GetRasterStatus,
501 IWineD3DSwapChainImpl_GetDisplayMode,
502 IWineD3DSwapChainImpl_GetPresentParameters,
503 IWineD3DSwapChainImpl_SetGammaRamp,
504 IWineD3DSwapChainImpl_GetGammaRamp