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_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);
102 IWineD3DSurface_GetParent(This->backBuffer, &bufferParent);
103 IUnknown_Release(bufferParent); /* once for the get parent */
104 if(IUnknown_Release(bufferParent) > 0){
105 FIXME("(%p) Something's still holding the back buffer\n",This);
107 /* Clean up the context */
108 /* check that we are the current context first */
109 if(glXGetCurrentContext() == This->glCtx){
110 glXMakeCurrent(This->display, None, NULL);
112 glXDestroyContext(This->display, This->glCtx);
113 /* IUnknown_Release(This->parent); This should only apply to the primary swapchain,
114 all others are crated by the caller, so releasing the parent should cause
115 the child to be released, not the other way around!
117 HeapFree(GetProcessHeap(), 0, This);
122 HRESULT WINAPI IWineD3DSwapChainImpl_GetParent(IWineD3DSwapChain *iface, IUnknown ** ppParent){
123 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
124 *ppParent = This->parent;
125 IUnknown_AddRef(*ppParent);
126 TRACE("(%p) returning %p\n", This , *ppParent);
130 /*IWineD3DSwapChain parts follow: */
131 HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
132 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
136 if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect);
137 /* TODO: If only source rect or dest rect are supplied then clip the window to match */
138 TRACE("preseting display %p, drawable %ld\n", This->display, This->drawable);
140 /* Don't call checkGLcall, as glGetError is not applicable here */
141 if (hDestWindowOverride && This->win_handle != hDestWindowOverride) {
142 /* Set this swapchain up to point to the new destination.. */
143 #ifdef USE_CONTEXT_MANAGER
144 /* TODO: use a context mamager */
147 /* FIXME: Never access */
148 IWineD3DSwapChainImpl *swapChainImpl;
149 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)This->wineD3DDevice, 0 , (IWineD3DSwapChain **)&swapChainImpl);
150 FIXME("Unable to render to a destination window %p\n", hDestWindowOverride );
151 if(This == swapChainImpl){
152 /* FIXME: this will be fixed by moving to a context management system */
153 FIXME("Cannot change the target of the implicit swapchain\n");
156 XVisualInfo template;
158 Display *oldDisplay = This->display;
159 GLXContext oldContext = This->glCtx;
161 GLXContext currentContext;
162 Drawable currentDrawable;
163 hDc = GetDC(hDestWindowOverride);
164 This->win_handle = hDestWindowOverride;
165 This->win = (Window)GetPropA( hDestWindowOverride, "__wine_x11_whole_window" );
167 TRACE("Creating a new context for the window %p\n", hDestWindowOverride);
169 TRACE("Desctroying context %p %p\n", This->display, This->render_ctx);
176 This->display = get_display(hDc);
177 TRACE("Got display%p for %p %p\n", This->display, hDc, hDestWindowOverride);
178 ReleaseDC(hDestWindowOverride, hDc);
179 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
180 This->visInfo = XGetVisualInfo(This->display, VisualIDMask, &template, &num);
181 if (NULL == This->visInfo) {
182 ERR("cannot really get XVisual\n");
184 return D3DERR_NOTAVAILABLE;
186 /* Now we have problems? well not really we just need to know what the implicit context is */
187 /* now destroy the old context and create a new one (we should really copy the buffers over, and do the whole make current thing! */
188 /* destroy the active context?*/
189 TRACE("Creating new context for %p %p %p\n",This->display, This->visInfo, swapChainImpl->glCtx);
190 This->glCtx = glXCreateContext(This->display, This->visInfo, swapChainImpl->glCtx, GL_TRUE);
192 if (NULL == This->glCtx) {
193 ERR("cannot create glxContext\n");
195 This->drawable = This->win;
196 This->render_ctx = This->glCtx;
197 /* Setup some default states TODO: apply the stateblock to the new context */
198 /** save current context and drawable **/
199 currentContext = glXGetCurrentContext();
200 currentDrawable = glXGetCurrentDrawable();
202 if (glXMakeCurrent(This->display, This->win, This->glCtx) == False) {
203 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", This->display, This->glCtx, This->win);
206 checkGLcall("glXMakeCurrent");
208 /* Clear the screen */
209 glClearColor(0.0, 0.0, 0.0, 0.0);
210 checkGLcall("glClearColor");
215 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
216 checkGLcall("glClear");
218 glColor3f(1.0, 1.0, 1.0);
219 checkGLcall("glColor3f");
221 glEnable(GL_LIGHTING);
222 checkGLcall("glEnable");
224 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
225 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
227 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
228 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
230 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
231 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
233 /* If this swapchain is currently the active context then make this swapchain active */
234 if(IWineD3DSurface_GetContainer(This->wineD3DDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmp) == D3D_OK){
235 if(tmp != (IUnknown *)This){
236 glXMakeCurrent(This->display, currentDrawable, currentContext);
237 checkGLcall("glXMakeCurrent");
239 IUnknown_Release(tmp);
241 /* reset the context */
242 glXMakeCurrent(This->display, currentDrawable, currentContext);
243 checkGLcall("glXMakeCurrent");
245 /* delete the old contxt*/
246 glXDestroyContext(oldDisplay, oldContext); /* Should this happen on an active context? seems a bad idea */
249 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapChainImpl);
254 /* 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. */
256 glXSwapBuffers(This->display, This->drawable); /* TODO: cycle through the swapchain buffers */
258 TRACE("glXSwapBuffers called, Starting new frame\n");
260 if (TRACE_ON(d3d_fps))
262 static long prev_time, frames;
264 DWORD time = GetTickCount();
266 /* every 1.5 seconds */
267 if (time - prev_time > 1500) {
268 TRACE_(d3d_fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
274 #if defined(FRAME_DEBUGGING)
276 if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) {
279 FIXME("Enabling D3D Trace\n");
280 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1);
281 #if defined(SHOW_FRAME_MAKEUP)
282 FIXME("Singe Frame snapshots Starting\n");
283 isDumpingFrames = TRUE;
284 glClear(GL_COLOR_BUFFER_BIT);
287 #if defined(SINGLE_FRAME_DEBUGGING)
289 #if defined(SHOW_FRAME_MAKEUP)
290 FIXME("Singe Frame snapshots Finishing\n");
291 isDumpingFrames = FALSE;
293 FIXME("Singe Frame trace complete\n");
294 DeleteFileA("C:\\D3DTRACE");
295 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
301 #if defined(SHOW_FRAME_MAKEUP)
302 FIXME("Single Frame snapshots Finishing\n");
303 isDumpingFrames = FALSE;
305 FIXME("Disabling D3D Trace\n");
306 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
313 /* Although this is not strictly required, a simple demo showed this does occur
314 on (at least non-debug) d3d */
315 if (This->presentParms.SwapEffect & D3DSWAPEFFECT_DISCARD) {
319 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
322 TRACE("Clearing z/stencil buffer\n");
324 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0x00, 1.0, 0);
327 TRACE("returning\n");
331 HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
332 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
333 WINED3DFORMAT d3dformat;
336 WINED3DSURFACE_DESC desc;
337 glDescriptor *glDescription;
339 TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
341 memset(&desc, 0, sizeof(desc));
343 desc.Height = &height;
344 desc.Format = &d3dformat;
345 #if 0 /* TODO: make sure that this swapchains context is active */
346 IWineD3DDevice_ActivateSwapChainContext(This->wineD3DDevice, iface);
348 IWineD3DSurface_GetDesc(pDestSurface, &desc);
349 /* make sure that the front buffer is the active read buffer */
350 glReadBuffer(GL_FRONT);
351 /* Read the pixels from the buffer into the surfaces memory */
352 IWineD3DSurface_GetGlDesc(pDestSurface, &glDescription);
353 glReadPixels(glDescription->target,
354 glDescription->level,
357 glDescription->glFormat,
358 glDescription->glType,
359 (void *)IWineD3DSurface_GetData(pDestSurface));
364 HRESULT WINAPI IWineD3DSwapChainImpl_GetBackBuffer(IWineD3DSwapChain *iface, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IWineD3DSurface **ppBackBuffer) {
366 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
368 *ppBackBuffer = This->backBuffer;
369 TRACE("(%p) : BackBuf %d Type %d returning %p\n", This, iBackBuffer, Type, *ppBackBuffer);
371 if (iBackBuffer > This->presentParms.BackBufferCount - 1) {
372 FIXME("Only one backBuffer currently supported\n");
373 return D3DERR_INVALIDCALL;
376 /* Note inc ref on returned surface */
377 IWineD3DSurface_AddRef(*ppBackBuffer);
382 HRESULT WINAPI IWineD3DSwapChainImpl_GetRasterStatus(IWineD3DSwapChain *iface, D3DRASTER_STATUS*pRasterStatus) {
383 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
384 static BOOL showFixmes = TRUE;
385 pRasterStatus->InVBlank = TRUE;
386 pRasterStatus->ScanLine = 0;
387 /* No openGL equivalent */
389 FIXME("(%p) : stub (once)\n", This);
395 HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, D3DDISPLAYMODE*pMode) {
396 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
400 pMode->Width = GetSystemMetrics(SM_CXSCREEN);
401 pMode->Height = GetSystemMetrics(SM_CYSCREEN);
402 pMode->RefreshRate = 85; /* FIXME: How to identify? */
404 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
405 bpp = GetDeviceCaps(hdc, BITSPIXEL);
409 case 8: pMode->Format = D3DFMT_R8G8B8; break;
410 case 16: pMode->Format = D3DFMT_R5G6B5; break;
411 case 24: /*pMode->Format = D3DFMT_R8G8B8; break; */ /* 32bpp and 24bpp can be aliased for X */
412 case 32: pMode->Format = D3DFMT_A8R8G8B8; break;
414 FIXME("Unrecognized display mode format\n");
415 pMode->Format = D3DFMT_UNKNOWN;
418 TRACE("(%p) : returning w(%d) h(%d) rr(%d) fmt(%u,%s)\n", This, pMode->Width, pMode->Height, pMode->RefreshRate,
419 pMode->Format, debug_d3dformat(pMode->Format));
423 HRESULT WINAPI IWineD3DSwapChainImpl_GetDevice(IWineD3DSwapChain *iface, IWineD3DDevice**ppDevice) {
424 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
426 *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
428 /* Note Calling this method will increase the internal reference count
429 on the IDirect3DDevice9 interface. */
430 IWineD3DDevice_AddRef(*ppDevice);
431 TRACE("(%p) : returning %p\n", This, *ppDevice);
435 HRESULT WINAPI IWineD3DSwapChainImpl_GetPresentParameters(IWineD3DSwapChain *iface, D3DPRESENT_PARAMETERS *pPresentationParameters) {
436 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
437 FIXME("(%p) : copy\n", This);
438 memcpy(pPresentationParameters, &This->presentParms, sizeof(D3DPRESENT_PARAMETERS));
442 HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST D3DGAMMARAMP *pRamp){
444 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
446 TRACE("(%p) : pRamp@%p flags(%ld)\n", This, pRamp, Flags);
447 hDC = GetDC(This->win_handle);
448 SetDeviceGammaRamp(hDC, (LPVOID)pRamp);
449 ReleaseDC(This->win_handle, hDC);
454 HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, D3DGAMMARAMP *pRamp){
456 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
458 TRACE("(%p) : pRamp@%p\n", This, pRamp);
459 hDC = GetDC(This->win_handle);
460 GetDeviceGammaRamp(hDC, pRamp);
461 ReleaseDC(This->win_handle, hDC);
467 IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
470 IWineD3DSwapChainImpl_QueryInterface,
471 IWineD3DSwapChainImpl_AddRef,
472 IWineD3DSwapChainImpl_Release,
473 /* IWineD3DSwapChain */
474 IWineD3DSwapChainImpl_GetParent,
475 IWineD3DSwapChainImpl_GetDevice,
476 IWineD3DSwapChainImpl_Present,
477 IWineD3DSwapChainImpl_GetFrontBufferData,
478 IWineD3DSwapChainImpl_GetBackBuffer,
479 IWineD3DSwapChainImpl_GetRasterStatus,
480 IWineD3DSwapChainImpl_GetDisplayMode,
481 IWineD3DSwapChainImpl_GetPresentParameters,
482 IWineD3DSwapChainImpl_SetGammaRamp,
483 IWineD3DSwapChainImpl_GetGammaRamp