d3d8: Render state additions.
[wine/multimedia.git] / dlls / wined3d / swapchain.c
blobd5bbfc347c80085e412c326c46c842afc1b7075c
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_IWineD3DSwapChain)){
71 IWineD3DSwapChainImpl_AddRef(iface);
72 if(ppobj == NULL){
73 ERR("Query interface called but now data allocated\n");
74 return E_NOINTERFACE;
76 *ppobj = This;
77 return D3D_OK;
79 return E_NOINTERFACE;
83 ULONG WINAPI IWineD3DSwapChainImpl_Release(IWineD3DSwapChain *iface) {
84 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
85 DWORD refCount;
86 refCount = InterlockedDecrement(&This->ref);
87 TRACE("(%p) : ReleaseRef to %ld\n", This, refCount);
88 if (refCount == 0) {
89 IUnknown* bufferParent;
91 /* tell the device that we've been released */
92 IWineD3DDevice_SwapChainReleased((IWineD3DDevice *)This->wineD3DDevice, iface);
94 /* release the ref to the front and back buffer parents */
95 IWineD3DSurface_GetParent(This->frontBuffer, &bufferParent);
96 IUnknown_Release(bufferParent); /* once for the get parent */
97 if(IUnknown_Release(bufferParent) > 0){
98 FIXME("(%p) Something's still holding the front buffer\n",This);
101 IWineD3DSurface_GetParent(This->backBuffer, &bufferParent);
102 IUnknown_Release(bufferParent); /* once for the get parent */
103 if(IUnknown_Release(bufferParent) > 0){
104 FIXME("(%p) Something's still holding the back buffer\n",This);
106 /* Clean up the context */
107 /* check that we are the current context first */
108 if(glXGetCurrentContext() == This->glCtx){
109 glXMakeCurrent(This->display, None, NULL);
111 glXDestroyContext(This->display, This->glCtx);
112 /* IUnknown_Release(This->parent); This should only apply to the primary swapchain,
113 all others are crated by the caller, so releasing the parent should cause
114 the child to be released, not the other way around!
116 HeapFree(GetProcessHeap(), 0, This);
118 return refCount;
121 HRESULT WINAPI IWineD3DSwapChainImpl_GetParent(IWineD3DSwapChain *iface, IUnknown ** ppParent){
122 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
123 *ppParent = This->parent;
124 IUnknown_AddRef(*ppParent);
125 TRACE("(%p) returning %p\n", This , *ppParent);
126 return D3D_OK;
129 /*IWineD3DSwapChain parts follow: */
130 HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) {
131 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
133 ENTER_GL();
135 if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect);
136 /* TODO: If only source rect or dest rect are supplied then clip the window to match */
137 TRACE("preseting display %p, drawable %ld\n", This->display, This->drawable);
139 /* Don't call checkGLcall, as glGetError is not applicable here */
140 if (hDestWindowOverride && This->win_handle != hDestWindowOverride) {
141 /* Set this swapchain up to point to the new destination.. */
142 #ifdef USE_CONTEXT_MANAGER
143 /* TODO: use a context mamager */
144 #endif
146 /* FIXME: Never access */
147 IWineD3DSwapChainImpl *swapChainImpl;
148 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)This->wineD3DDevice, 0 , (IWineD3DSwapChain **)&swapChainImpl);
149 FIXME("Unable to render to a destination window %p\n", hDestWindowOverride );
150 if(This == swapChainImpl){
151 /* FIXME: this will be fixed by moving to a context management system */
152 FIXME("Cannot change the target of the implicit swapchain\n");
153 }else{
154 HDC hDc;
155 XVisualInfo template;
156 int num;
157 Display *oldDisplay = This->display;
158 GLXContext oldContext = This->glCtx;
159 IUnknown* tmp;
160 GLXContext currentContext;
161 Drawable currentDrawable;
162 hDc = GetDC(hDestWindowOverride);
163 This->win_handle = hDestWindowOverride;
164 This->win = (Window)GetPropA( hDestWindowOverride, "__wine_x11_whole_window" );
166 TRACE("Creating a new context for the window %p\n", hDestWindowOverride);
167 ENTER_GL();
168 TRACE("Desctroying context %p %p\n", This->display, This->render_ctx);
172 LEAVE_GL();
173 ENTER_GL();
175 This->display = get_display(hDc);
176 TRACE("Got display%p for %p %p\n", This->display, hDc, hDestWindowOverride);
177 ReleaseDC(hDestWindowOverride, hDc);
178 template.visualid = (VisualID)GetPropA(GetDesktopWindow(), "__wine_x11_visual_id");
179 This->visInfo = XGetVisualInfo(This->display, VisualIDMask, &template, &num);
180 if (NULL == This->visInfo) {
181 ERR("cannot really get XVisual\n");
182 LEAVE_GL();
183 return D3DERR_NOTAVAILABLE;
185 /* Now we have problems? well not really we just need to know what the implicit context is */
186 /* now destroy the old context and create a new one (we should really copy the buffers over, and do the whole make current thing! */
187 /* destroy the active context?*/
188 TRACE("Creating new context for %p %p %p\n",This->display, This->visInfo, swapChainImpl->glCtx);
189 This->glCtx = glXCreateContext(This->display, This->visInfo, swapChainImpl->glCtx, GL_TRUE);
191 if (NULL == This->glCtx) {
192 ERR("cannot create glxContext\n");
194 This->drawable = This->win;
195 This->render_ctx = This->glCtx;
196 /* Setup some default states TODO: apply the stateblock to the new context */
197 /** save current context and drawable **/
198 currentContext = glXGetCurrentContext();
199 currentDrawable = glXGetCurrentDrawable();
201 if (glXMakeCurrent(This->display, This->win, This->glCtx) == False) {
202 ERR("Error in setting current context (display %p context %p drawable %ld)!\n", This->display, This->glCtx, This->win);
205 checkGLcall("glXMakeCurrent");
207 /* Clear the screen */
208 glClearColor(0.0, 0.0, 0.0, 0.0);
209 checkGLcall("glClearColor");
210 glClearIndex(0);
211 glClearDepth(1);
212 glClearStencil(0);
214 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
215 checkGLcall("glClear");
217 glColor3f(1.0, 1.0, 1.0);
218 checkGLcall("glColor3f");
220 glEnable(GL_LIGHTING);
221 checkGLcall("glEnable");
223 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
224 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
226 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
227 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
229 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
230 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
232 /* If this swapchain is currently the active context then make this swapchain active */
233 if(IWineD3DSurface_GetContainer(This->wineD3DDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&tmp) == D3D_OK){
234 if(tmp != (IUnknown *)This){
235 glXMakeCurrent(This->display, currentDrawable, currentContext);
236 checkGLcall("glXMakeCurrent");
238 IUnknown_Release(tmp);
239 }else{
240 /* reset the context */
241 glXMakeCurrent(This->display, currentDrawable, currentContext);
242 checkGLcall("glXMakeCurrent");
244 /* delete the old contxt*/
245 glXDestroyContext(oldDisplay, oldContext); /* Should this happen on an active context? seems a bad idea */
246 LEAVE_GL();
248 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapChainImpl);
253 /* 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. */
255 glXSwapBuffers(This->display, This->drawable); /* TODO: cycle through the swapchain buffers */
257 TRACE("glXSwapBuffers called, Starting new frame\n");
258 /* FPS support */
259 if (TRACE_ON(d3d_fps))
261 static long prev_time, frames;
263 DWORD time = GetTickCount();
264 frames++;
265 /* every 1.5 seconds */
266 if (time - prev_time > 1500) {
267 TRACE_(d3d_fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time));
268 prev_time = time;
269 frames = 0;
273 #if defined(FRAME_DEBUGGING)
275 if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) {
276 if (!isOn) {
277 isOn = TRUE;
278 FIXME("Enabling D3D Trace\n");
279 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1);
280 #if defined(SHOW_FRAME_MAKEUP)
281 FIXME("Singe Frame snapshots Starting\n");
282 isDumpingFrames = TRUE;
283 glClear(GL_COLOR_BUFFER_BIT);
284 #endif
286 #if defined(SINGLE_FRAME_DEBUGGING)
287 } else {
288 #if defined(SHOW_FRAME_MAKEUP)
289 FIXME("Singe Frame snapshots Finishing\n");
290 isDumpingFrames = FALSE;
291 #endif
292 FIXME("Singe Frame trace complete\n");
293 DeleteFileA("C:\\D3DTRACE");
294 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
295 #endif
297 } else {
298 if (isOn) {
299 isOn = FALSE;
300 #if defined(SHOW_FRAME_MAKEUP)
301 FIXME("Single Frame snapshots Finishing\n");
302 isDumpingFrames = FALSE;
303 #endif
304 FIXME("Disabling D3D Trace\n");
305 __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0);
309 #endif
311 LEAVE_GL();
312 /* Although this is not strictly required, a simple demo showed this does occur
313 on (at least non-debug) d3d */
314 if (This->presentParms.SwapEffect & D3DSWAPEFFECT_DISCARD) {
316 TRACE("Clearing\n");
318 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0);
320 } else {
321 TRACE("Clearing z/stencil buffer\n");
323 IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER, 0x00, 1.0, 0);
326 TRACE("returning\n");
327 return D3D_OK;
330 HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) {
331 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
332 WINED3DFORMAT d3dformat;
333 UINT width;
334 UINT height;
335 WINED3DSURFACE_DESC desc;
336 glDescriptor *glDescription;
338 TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface);
339 ENTER_GL();
340 memset(&desc, 0, sizeof(desc));
341 desc.Width = &width;
342 desc.Height = &height;
343 desc.Format = &d3dformat;
344 #if 0 /* TODO: make sure that this swapchains context is active */
345 IWineD3DDevice_ActivateSwapChainContext(This->wineD3DDevice, iface);
346 #endif
347 IWineD3DSurface_GetDesc(pDestSurface, &desc);
348 /* make sure that the front buffer is the active read buffer */
349 glReadBuffer(GL_FRONT);
350 /* Read the pixels from the buffer into the surfaces memory */
351 IWineD3DSurface_GetGlDesc(pDestSurface, &glDescription);
352 glReadPixels(glDescription->target,
353 glDescription->level,
354 width,
355 height,
356 glDescription->glFormat,
357 glDescription->glType,
358 (void *)IWineD3DSurface_GetData(pDestSurface));
359 LEAVE_GL();
360 return D3D_OK;
363 HRESULT WINAPI IWineD3DSwapChainImpl_GetBackBuffer(IWineD3DSwapChain *iface, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IWineD3DSurface **ppBackBuffer) {
365 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
367 *ppBackBuffer = This->backBuffer;
368 TRACE("(%p) : BackBuf %d Type %d returning %p\n", This, iBackBuffer, Type, *ppBackBuffer);
370 if (iBackBuffer > This->presentParms.BackBufferCount - 1) {
371 FIXME("Only one backBuffer currently supported\n");
372 return D3DERR_INVALIDCALL;
375 /* Note inc ref on returned surface */
376 IWineD3DSurface_AddRef(*ppBackBuffer);
377 return D3D_OK;
381 HRESULT WINAPI IWineD3DSwapChainImpl_GetRasterStatus(IWineD3DSwapChain *iface, D3DRASTER_STATUS*pRasterStatus) {
382 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
383 static BOOL showFixmes = TRUE;
384 pRasterStatus->InVBlank = TRUE;
385 pRasterStatus->ScanLine = 0;
386 /* No openGL equivalent */
387 if(showFixmes) {
388 FIXME("(%p) : stub (once)\n", This);
389 showFixmes = FALSE;
391 return D3D_OK;
394 HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, D3DDISPLAYMODE*pMode) {
395 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
396 HDC hdc;
397 int bpp = 0;
399 pMode->Width = GetSystemMetrics(SM_CXSCREEN);
400 pMode->Height = GetSystemMetrics(SM_CYSCREEN);
401 pMode->RefreshRate = 85; /* FIXME: How to identify? */
403 hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
404 bpp = GetDeviceCaps(hdc, BITSPIXEL);
405 DeleteDC(hdc);
407 switch (bpp) {
408 case 8: pMode->Format = D3DFMT_R8G8B8; break;
409 case 16: pMode->Format = D3DFMT_R5G6B5; break;
410 case 24: /*pMode->Format = D3DFMT_R8G8B8; break; */ /* 32bpp and 24bpp can be aliased for X */
411 case 32: pMode->Format = D3DFMT_A8R8G8B8; break;
412 default:
413 FIXME("Unrecognized display mode format\n");
414 pMode->Format = D3DFMT_UNKNOWN;
417 TRACE("(%p) : returning w(%d) h(%d) rr(%d) fmt(%u,%s)\n", This, pMode->Width, pMode->Height, pMode->RefreshRate,
418 pMode->Format, debug_d3dformat(pMode->Format));
419 return D3D_OK;
422 HRESULT WINAPI IWineD3DSwapChainImpl_GetDevice(IWineD3DSwapChain *iface, IWineD3DDevice**ppDevice) {
423 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
425 *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
427 /* Note Calling this method will increase the internal reference count
428 on the IDirect3DDevice9 interface. */
429 IWineD3DDevice_AddRef(*ppDevice);
430 TRACE("(%p) : returning %p\n", This, *ppDevice);
431 return D3D_OK;
434 HRESULT WINAPI IWineD3DSwapChainImpl_GetPresentParameters(IWineD3DSwapChain *iface, D3DPRESENT_PARAMETERS *pPresentationParameters) {
435 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
436 FIXME("(%p) : copy\n", This);
437 memcpy(pPresentationParameters, &This->presentParms, sizeof(D3DPRESENT_PARAMETERS));
438 return D3D_OK;
441 HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST D3DGAMMARAMP *pRamp){
443 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
444 HDC hDC;
445 TRACE("(%p) : pRamp@%p flags(%ld)\n", This, pRamp, Flags);
446 hDC = GetDC(This->win_handle);
447 SetDeviceGammaRamp(hDC, (LPVOID)pRamp);
448 ReleaseDC(This->win_handle, hDC);
449 return D3D_OK;
453 HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, D3DGAMMARAMP *pRamp){
455 IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface;
456 HDC hDC;
457 TRACE("(%p) : pRamp@%p\n", This, pRamp);
458 hDC = GetDC(This->win_handle);
459 GetDeviceGammaRamp(hDC, pRamp);
460 ReleaseDC(This->win_handle, hDC);
461 return D3D_OK;
466 IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl =
468 /* IUnknown */
469 IWineD3DSwapChainImpl_QueryInterface,
470 IWineD3DSwapChainImpl_AddRef,
471 IWineD3DSwapChainImpl_Release,
472 /* IWineD3DSwapChain */
473 IWineD3DSwapChainImpl_GetParent,
474 IWineD3DSwapChainImpl_GetDevice,
475 IWineD3DSwapChainImpl_Present,
476 IWineD3DSwapChainImpl_GetFrontBufferData,
477 IWineD3DSwapChainImpl_GetBackBuffer,
478 IWineD3DSwapChainImpl_GetRasterStatus,
479 IWineD3DSwapChainImpl_GetDisplayMode,
480 IWineD3DSwapChainImpl_GetPresentParameters,
481 IWineD3DSwapChainImpl_SetGammaRamp,
482 IWineD3DSwapChainImpl_GetGammaRamp