gphoto2.ds: Added Norwegian Bokmål resources.
[wine/wine-kai.git] / dlls / wined3d / swapchain.c
blob1b8e4d96a103b5d6e14ab85e242755847e8a3525
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 static 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 static 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 WINED3D_OK;
80 *ppobj = NULL;
81 return E_NOINTERFACE;
85 static ULONG WINAPI IWineD3DSwapChainImpl_Release(IWineD3DSwapChain *iface) {
86 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
87 DWORD refCount;
88 refCount = InterlockedDecrement(&This->ref);
89 TRACE("(%p) : ReleaseRef to %ld\n", This, refCount);
90 if (refCount == 0) {
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);
124 return refCount;
127 static 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);
132 return WINED3D_OK;
135 /*IWineD3DSwapChain parts follow: */
136 static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
137 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
139 ENTER_GL();
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 */
150 #endif
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");
159 }else{
160 HDC hDc;
161 XVisualInfo template;
162 int num;
163 Display *oldDisplay = This->display;
164 GLXContext oldContext = This->glCtx;
165 IUnknown* tmp;
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);
173 ENTER_GL();
174 TRACE("Desctroying context %p %p\n", This->display, This->render_ctx);
178 LEAVE_GL();
179 ENTER_GL();
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");
188 LEAVE_GL();
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");
216 glClearIndex(0);
217 glClearDepth(1);
218 glClearStencil(0);
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);
245 }else{
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 */
252 LEAVE_GL();
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");
264 /* FPS support */
265 if (TRACE_ON(d3d_fps))
267 static long prev_time, frames;
269 DWORD time = GetTickCount();
270 frames++;
271 /* every 1.5 seconds */
272 if (time - prev_time > 1500) {
273 TRACE_(d3d_fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
274 prev_time = time;
275 frames = 0;
279 #if defined(FRAME_DEBUGGING)
281 if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) {
282 if (!isOn) {
283 isOn = TRUE;
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);
290 #endif
292 #if defined(SINGLE_FRAME_DEBUGGING)
293 } else {
294 #if defined(SHOW_FRAME_MAKEUP)
295 FIXME("Singe Frame snapshots Finishing\n");
296 isDumpingFrames = FALSE;
297 #endif
298 FIXME("Singe Frame trace complete\n");
299 DeleteFileA("C:\\D3DTRACE");
300 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
301 #endif
303 } else {
304 if (isOn) {
305 isOn = FALSE;
306 #if defined(SHOW_FRAME_MAKEUP)
307 FIXME("Single Frame snapshots Finishing\n");
308 isDumpingFrames = FALSE;
309 #endif
310 FIXME("Disabling D3D Trace\n");
311 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
315 #endif
317 LEAVE_GL();
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) {
322 TRACE("Clearing\n");
324 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
326 } else {
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");
336 return WINED3D_OK;
339 static HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
340 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
341 WINED3DFORMAT d3dformat;
342 UINT width;
343 UINT height;
344 WINED3DSURFACE_DESC desc;
345 glDescriptor *glDescription;
347 TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
348 ENTER_GL();
349 memset(&desc, 0, sizeof(desc));
350 desc.Width = &width;
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);
355 #endif
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,
363 width,
364 height,
365 glDescription->glFormat,
366 glDescription->glType,
367 (void *)IWineD3DSurface_GetData(pDestSurface));
368 LEAVE_GL();
369 return WINED3D_OK;
372 static 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);
390 return WINED3D_OK;
394 static 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 */
400 if(showFixmes) {
401 FIXME("(%p) : stub (once)\n", This);
402 showFixmes = FALSE;
404 return WINED3D_OK;
407 static HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, WINED3DDISPLAYMODE*pMode) {
408 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
409 HDC hdc;
410 int bpp = 0;
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);
418 DeleteDC(hdc);
420 switch (bpp) {
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;
425 default:
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));
432 return WINED3D_OK;
435 static 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);
444 return WINED3D_OK;
447 static 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;
463 return WINED3D_OK;
466 static HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST WINED3DGAMMARAMP *pRamp){
468 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
469 HDC hDC;
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);
474 return WINED3D_OK;
478 static HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, WINED3DGAMMARAMP *pRamp){
480 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
481 HDC hDC;
482 TRACE("(%p) : pRamp@%p\n", This, pRamp);
483 hDC = GetDC(This->win_handle);
484 GetDeviceGammaRamp(hDC, pRamp);
485 ReleaseDC(This->win_handle, hDC);
486 return WINED3D_OK;
491 IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
493 /* IUnknown */
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