winspool: Implement EnumMonitorsA on top of EnumMonitorsW.
[wine/multimedia.git] / dlls / wined3d / swapchain.c
blobef4e4bd822765eb3905de97ceb238221fedd514a
1 /*
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
23 #include "config.h"
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 )
40 Display *display;
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;
45 return display;
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);
62 return refCount;
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);
73 if(ppobj == NULL){
74 ERR("Query interface called but now data allocated\n");
75 return E_NOINTERFACE;
77 *ppobj = This;
78 return D3D_OK;
80 return E_NOINTERFACE;
84 ULONG WINAPI IWineD3DSwapChainImpl_Release(IWineD3DSwapChain *iface) {
85 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
86 DWORD refCount;
87 refCount = InterlockedDecrement(&This->ref);
88 TRACE("(%p) : ReleaseRef to %ld\n", This, refCount);
89 if (refCount == 0) {
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);
121 return refCount;
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);
129 return D3D_OK;
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;
136 ENTER_GL();
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 */
147 #endif
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");
156 }else{
157 HDC hDc;
158 XVisualInfo template;
159 int num;
160 Display *oldDisplay = This->display;
161 GLXContext oldContext = This->glCtx;
162 IUnknown* tmp;
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);
170 ENTER_GL();
171 TRACE("Desctroying context %p %p\n", This->display, This->render_ctx);
175 LEAVE_GL();
176 ENTER_GL();
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");
185 LEAVE_GL();
186 return D3DERR_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");
213 glClearIndex(0);
214 glClearDepth(1);
215 glClearStencil(0);
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) == D3D_OK){
237 if(tmp != (IUnknown *)This){
238 glXMakeCurrent(This->display, currentDrawable, currentContext);
239 checkGLcall("glXMakeCurrent");
241 IUnknown_Release(tmp);
242 }else{
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 */
249 LEAVE_GL();
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");
261 /* FPS support */
262 if (TRACE_ON(d3d_fps))
264 static long prev_time, frames;
266 DWORD time = GetTickCount();
267 frames++;
268 /* every 1.5 seconds */
269 if (time - prev_time > 1500) {
270 TRACE_(d3d_fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
271 prev_time = time;
272 frames = 0;
276 #if defined(FRAME_DEBUGGING)
278 if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) {
279 if (!isOn) {
280 isOn = TRUE;
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);
287 #endif
289 #if defined(SINGLE_FRAME_DEBUGGING)
290 } else {
291 #if defined(SHOW_FRAME_MAKEUP)
292 FIXME("Singe Frame snapshots Finishing\n");
293 isDumpingFrames = FALSE;
294 #endif
295 FIXME("Singe Frame trace complete\n");
296 DeleteFileA("C:\\D3DTRACE");
297 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
298 #endif
300 } else {
301 if (isOn) {
302 isOn = FALSE;
303 #if defined(SHOW_FRAME_MAKEUP)
304 FIXME("Single Frame snapshots Finishing\n");
305 isDumpingFrames = FALSE;
306 #endif
307 FIXME("Disabling D3D Trace\n");
308 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
312 #endif
314 LEAVE_GL();
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) {
319 TRACE("Clearing\n");
321 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
323 } else {
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");
330 return D3D_OK;
333 HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
334 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
335 WINED3DFORMAT d3dformat;
336 UINT width;
337 UINT height;
338 WINED3DSURFACE_DESC desc;
339 glDescriptor *glDescription;
341 TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
342 ENTER_GL();
343 memset(&desc, 0, sizeof(desc));
344 desc.Width = &width;
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);
349 #endif
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,
357 width,
358 height,
359 glDescription->glFormat,
360 glDescription->glType,
361 (void *)IWineD3DSurface_GetData(pDestSurface));
362 LEAVE_GL();
363 return D3D_OK;
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 D3DERR_INVALIDCALL;
378 /* Note inc ref on returned surface */
379 IWineD3DSurface_AddRef(*ppBackBuffer);
380 return D3D_OK;
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 */
390 if(showFixmes) {
391 FIXME("(%p) : stub (once)\n", This);
392 showFixmes = FALSE;
394 return D3D_OK;
397 HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, WINED3DDISPLAYMODE*pMode) {
398 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
399 HDC hdc;
400 int bpp = 0;
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);
408 DeleteDC(hdc);
410 switch (bpp) {
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;
415 default:
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));
422 return D3D_OK;
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);
434 return D3D_OK;
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;
453 return D3D_OK;
456 HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST WINED3DGAMMARAMP *pRamp){
458 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
459 HDC hDC;
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);
464 return D3D_OK;
468 HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, WINED3DGAMMARAMP *pRamp){
470 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
471 HDC hDC;
472 TRACE("(%p) : pRamp@%p\n", This, pRamp);
473 hDC = GetDC(This->win_handle);
474 GetDeviceGammaRamp(hDC, pRamp);
475 ReleaseDC(This->win_handle, hDC);
476 return D3D_OK;
481 IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
483 /* IUnknown */
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