ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

swapchain.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2002-2003 Jason Edmeades
00003  * Copyright 2002-2003 Raphael Junqueira
00004  * Copyright 2005 Oliver Stieber
00005  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
00006  * Copyright 2011 Henri Verbeet for CodeWeavers
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 #include "config.h"
00024 #include "wined3d_private.h"
00025 
00026 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
00027 WINE_DECLARE_DEBUG_CHANNEL(fps);
00028 
00029 /* Do not call while under the GL lock. */
00030 static void swapchain_cleanup(struct wined3d_swapchain *swapchain)
00031 {
00032     struct wined3d_display_mode mode;
00033     UINT i;
00034 
00035     TRACE("Destroying swapchain %p.\n", swapchain);
00036 
00037     wined3d_swapchain_set_gamma_ramp(swapchain, 0, &swapchain->orig_gamma);
00038 
00039     /* Release the swapchain's draw buffers. Make sure swapchain->back_buffers[0]
00040      * is the last buffer to be destroyed, FindContext() depends on that. */
00041     if (swapchain->front_buffer)
00042     {
00043         surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
00044         if (wined3d_surface_decref(swapchain->front_buffer))
00045             WARN("Something's still holding the front buffer (%p).\n", swapchain->front_buffer);
00046         swapchain->front_buffer = NULL;
00047     }
00048 
00049     if (swapchain->back_buffers)
00050     {
00051         i = swapchain->desc.backbuffer_count;
00052 
00053         while (i--)
00054         {
00055             surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_NONE, NULL);
00056             if (wined3d_surface_decref(swapchain->back_buffers[i]))
00057                 WARN("Something's still holding back buffer %u (%p).\n", i, swapchain->back_buffers[i]);
00058         }
00059         HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
00060         swapchain->back_buffers = NULL;
00061     }
00062 
00063     for (i = 0; i < swapchain->num_contexts; ++i)
00064     {
00065         context_destroy(swapchain->device, swapchain->context[i]);
00066     }
00067     HeapFree(GetProcessHeap(), 0, swapchain->context);
00068 
00069     /* Restore the screen resolution if we rendered in fullscreen.
00070      * This will restore the screen resolution to what it was before creating
00071      * the swapchain. In case of d3d8 and d3d9 this will be the original
00072      * desktop resolution. In case of d3d7 this will be a NOP because ddraw
00073      * sets the resolution before starting up Direct3D, thus orig_width and
00074      * orig_height will be equal to the modes in the presentation params. */
00075     if (!swapchain->desc.windowed && swapchain->desc.auto_restore_display_mode)
00076     {
00077         mode.width = swapchain->orig_width;
00078         mode.height = swapchain->orig_height;
00079         mode.refresh_rate = 0;
00080         mode.format_id = swapchain->orig_fmt;
00081         wined3d_device_set_display_mode(swapchain->device, 0, &mode);
00082     }
00083 
00084     if (swapchain->backup_dc)
00085     {
00086         TRACE("Destroying backup wined3d window %p, dc %p.\n", swapchain->backup_wnd, swapchain->backup_dc);
00087 
00088         ReleaseDC(swapchain->backup_wnd, swapchain->backup_dc);
00089         DestroyWindow(swapchain->backup_wnd);
00090     }
00091 }
00092 
00093 ULONG CDECL wined3d_swapchain_incref(struct wined3d_swapchain *swapchain)
00094 {
00095     ULONG refcount = InterlockedIncrement(&swapchain->ref);
00096 
00097     TRACE("%p increasing refcount to %u.\n", swapchain, refcount);
00098 
00099     return refcount;
00100 }
00101 
00102 /* Do not call while under the GL lock. */
00103 ULONG CDECL wined3d_swapchain_decref(struct wined3d_swapchain *swapchain)
00104 {
00105     ULONG refcount = InterlockedDecrement(&swapchain->ref);
00106 
00107     TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
00108 
00109     if (!refcount)
00110     {
00111         swapchain_cleanup(swapchain);
00112         swapchain->parent_ops->wined3d_object_destroyed(swapchain->parent);
00113         HeapFree(GetProcessHeap(), 0, swapchain);
00114     }
00115 
00116     return refcount;
00117 }
00118 
00119 void * CDECL wined3d_swapchain_get_parent(const struct wined3d_swapchain *swapchain)
00120 {
00121     TRACE("swapchain %p.\n", swapchain);
00122 
00123     return swapchain->parent;
00124 }
00125 
00126 HRESULT CDECL wined3d_swapchain_set_window(struct wined3d_swapchain *swapchain, HWND window)
00127 {
00128     if (!window)
00129         window = swapchain->device_window;
00130     if (window == swapchain->win_handle)
00131         return WINED3D_OK;
00132 
00133     TRACE("Setting swapchain %p window from %p to %p.\n",
00134             swapchain, swapchain->win_handle, window);
00135     swapchain->win_handle = window;
00136 
00137     return WINED3D_OK;
00138 }
00139 
00140 HRESULT CDECL wined3d_swapchain_present(struct wined3d_swapchain *swapchain,
00141         const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
00142         const RGNDATA *dirty_region, DWORD flags)
00143 {
00144     TRACE("swapchain %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
00145             swapchain, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
00146             dst_window_override, dirty_region, flags);
00147 
00148     wined3d_swapchain_set_window(swapchain, dst_window_override);
00149 
00150     return swapchain->swapchain_ops->swapchain_present(swapchain,
00151             src_rect, dst_rect, dirty_region, flags);
00152 }
00153 
00154 HRESULT CDECL wined3d_swapchain_get_front_buffer_data(const struct wined3d_swapchain *swapchain,
00155         struct wined3d_surface *dst_surface)
00156 {
00157     struct wined3d_surface *src_surface;
00158     RECT src_rect, dst_rect;
00159 
00160     TRACE("swapchain %p, dst_surface %p.\n", swapchain, dst_surface);
00161 
00162     src_surface = swapchain->front_buffer;
00163     SetRect(&src_rect, 0, 0, src_surface->resource.width, src_surface->resource.height);
00164     dst_rect = src_rect;
00165 
00166     if (swapchain->desc.windowed)
00167     {
00168         MapWindowPoints(swapchain->win_handle, NULL, (POINT *)&dst_rect, 2);
00169         FIXME("Using destination rect %s in windowed mode, this is likely wrong.\n",
00170                 wine_dbgstr_rect(&dst_rect));
00171     }
00172 
00173     return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, &src_rect, 0, NULL, WINED3D_TEXF_POINT);
00174 }
00175 
00176 HRESULT CDECL wined3d_swapchain_get_back_buffer(const struct wined3d_swapchain *swapchain,
00177         UINT back_buffer_idx, enum wined3d_backbuffer_type type, struct wined3d_surface **back_buffer)
00178 {
00179     TRACE("swapchain %p, back_buffer_idx %u, type %#x, back_buffer %p.\n",
00180             swapchain, back_buffer_idx, type, back_buffer);
00181 
00182     /* Return invalid if there is no backbuffer array, otherwise it will
00183      * crash when ddraw is used (there swapchain->back_buffers is always
00184      * NULL). We need this because this function is called from
00185      * stateblock_init_default_state() to get the default scissorrect
00186      * dimensions. */
00187     if (!swapchain->back_buffers || back_buffer_idx >= swapchain->desc.backbuffer_count)
00188     {
00189         WARN("Invalid back buffer index.\n");
00190         /* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it
00191          * here in wined3d to avoid problems in other libs. */
00192         *back_buffer = NULL;
00193         return WINED3DERR_INVALIDCALL;
00194     }
00195 
00196     *back_buffer = swapchain->back_buffers[back_buffer_idx];
00197     if (*back_buffer)
00198         wined3d_surface_incref(*back_buffer);
00199 
00200     TRACE("Returning back buffer %p.\n", *back_buffer);
00201 
00202     return WINED3D_OK;
00203 }
00204 
00205 HRESULT CDECL wined3d_swapchain_get_raster_status(const struct wined3d_swapchain *swapchain,
00206         struct wined3d_raster_status *raster_status)
00207 {
00208     static BOOL warned;
00209     /* No OpenGL equivalent */
00210     if (!warned)
00211     {
00212         FIXME("swapchain %p, raster_status %p stub!\n", swapchain, raster_status);
00213         warned = TRUE;
00214     }
00215 
00216     /* Obtaining the raster status is a widely implemented but optional
00217      * feature. When this method returns OK StarCraft 2 expects the
00218      * raster_status->InVBlank value to actually change over time. To prevent
00219      * StarCraft 2 from running in an infinite loop at startup this method
00220      * returns INVALIDCALL. */
00221     return WINED3DERR_INVALIDCALL;
00222 }
00223 
00224 HRESULT CDECL wined3d_swapchain_get_display_mode(const struct wined3d_swapchain *swapchain,
00225         struct wined3d_display_mode *mode)
00226 {
00227     HRESULT hr;
00228 
00229     TRACE("swapchain %p, mode %p.\n", swapchain, mode);
00230 
00231     hr = wined3d_get_adapter_display_mode(swapchain->device->wined3d, swapchain->device->adapter->ordinal, mode);
00232 
00233     TRACE("Returning w %u, h %u, refresh rate %u, format %s.\n",
00234             mode->width, mode->height, mode->refresh_rate, debug_d3dformat(mode->format_id));
00235 
00236     return hr;
00237 }
00238 
00239 struct wined3d_device * CDECL wined3d_swapchain_get_device(const struct wined3d_swapchain *swapchain)
00240 {
00241     TRACE("swapchain %p.\n", swapchain);
00242 
00243     return swapchain->device;
00244 }
00245 
00246 HRESULT CDECL wined3d_swapchain_get_desc(const struct wined3d_swapchain *swapchain,
00247         struct wined3d_swapchain_desc *desc)
00248 {
00249     TRACE("swapchain %p, desc %p.\n", swapchain, desc);
00250 
00251     *desc = swapchain->desc;
00252 
00253     return WINED3D_OK;
00254 }
00255 
00256 HRESULT CDECL wined3d_swapchain_set_gamma_ramp(const struct wined3d_swapchain *swapchain,
00257         DWORD flags, const struct wined3d_gamma_ramp *ramp)
00258 {
00259     HDC dc;
00260 
00261     TRACE("swapchain %p, flags %#x, ramp %p.\n", swapchain, flags, ramp);
00262 
00263     if (flags)
00264         FIXME("Ignoring flags %#x.\n", flags);
00265 
00266     dc = GetDC(swapchain->device_window);
00267     SetDeviceGammaRamp(dc, (void *)ramp);
00268     ReleaseDC(swapchain->device_window, dc);
00269 
00270     return WINED3D_OK;
00271 }
00272 
00273 HRESULT CDECL wined3d_swapchain_get_gamma_ramp(const struct wined3d_swapchain *swapchain,
00274         struct wined3d_gamma_ramp *ramp)
00275 {
00276     HDC dc;
00277 
00278     TRACE("swapchain %p, ramp %p.\n", swapchain, ramp);
00279 
00280     dc = GetDC(swapchain->device_window);
00281     GetDeviceGammaRamp(dc, ramp);
00282     ReleaseDC(swapchain->device_window, dc);
00283 
00284     return WINED3D_OK;
00285 }
00286 
00287 /* A GL context is provided by the caller */
00288 static void swapchain_blit(const struct wined3d_swapchain *swapchain,
00289         struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect)
00290 {
00291     struct wined3d_surface *backbuffer = swapchain->back_buffers[0];
00292     UINT src_w = src_rect->right - src_rect->left;
00293     UINT src_h = src_rect->bottom - src_rect->top;
00294     GLenum gl_filter;
00295     const struct wined3d_gl_info *gl_info = context->gl_info;
00296     RECT win_rect;
00297     UINT win_h;
00298 
00299     TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n",
00300             swapchain, context, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect));
00301 
00302     if (src_w == dst_rect->right - dst_rect->left && src_h == dst_rect->bottom - dst_rect->top)
00303         gl_filter = GL_NEAREST;
00304     else
00305         gl_filter = GL_LINEAR;
00306 
00307     GetClientRect(swapchain->win_handle, &win_rect);
00308     win_h = win_rect.bottom - win_rect.top;
00309 
00310     if (gl_info->fbo_ops.glBlitFramebuffer && is_identity_fixup(backbuffer->resource.format->color_fixup))
00311     {
00312         DWORD location = SFLAG_INTEXTURE;
00313 
00314         if (backbuffer->resource.multisample_type)
00315         {
00316             location = SFLAG_INRB_RESOLVED;
00317             surface_load_location(backbuffer, location, NULL);
00318         }
00319 
00320         ENTER_GL();
00321         context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, backbuffer, NULL, location);
00322         glReadBuffer(GL_COLOR_ATTACHMENT0);
00323         context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
00324 
00325         context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
00326         context_set_draw_buffer(context, GL_BACK);
00327         context_invalidate_state(context, STATE_FRAMEBUFFER);
00328 
00329         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00330         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
00331         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
00332         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
00333         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
00334 
00335         glDisable(GL_SCISSOR_TEST);
00336         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
00337 
00338         /* Note that the texture is upside down */
00339         gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
00340                 dst_rect->left, win_h - dst_rect->top, dst_rect->right, win_h - dst_rect->bottom,
00341                 GL_COLOR_BUFFER_BIT, gl_filter);
00342         checkGLcall("Swapchain present blit(EXT_framebuffer_blit)\n");
00343         LEAVE_GL();
00344     }
00345     else
00346     {
00347         struct wined3d_device *device = swapchain->device;
00348         struct wined3d_context *context2;
00349         float tex_left = src_rect->left;
00350         float tex_top = src_rect->top;
00351         float tex_right = src_rect->right;
00352         float tex_bottom = src_rect->bottom;
00353 
00354         context2 = context_acquire(device, swapchain->back_buffers[0]);
00355         context_apply_blit_state(context2, device);
00356 
00357         if (backbuffer->flags & SFLAG_NORMCOORD)
00358         {
00359             tex_left /= src_w;
00360             tex_right /= src_w;
00361             tex_top /= src_h;
00362             tex_bottom /= src_h;
00363         }
00364 
00365         if (is_complex_fixup(backbuffer->resource.format->color_fixup))
00366             gl_filter = GL_NEAREST;
00367 
00368         ENTER_GL();
00369         context_apply_fbo_state_blit(context2, GL_FRAMEBUFFER, swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
00370 
00371         /* Set up the texture. The surface is not in a wined3d_texture
00372          * container, so there are no D3D texture settings to dirtify. */
00373         device->blitter->set_shader(device->blit_priv, context2, backbuffer);
00374         glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MIN_FILTER, gl_filter);
00375         glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MAG_FILTER, gl_filter);
00376 
00377         context_set_draw_buffer(context, GL_BACK);
00378 
00379         /* Set the viewport to the destination rectandle, disable any projection
00380          * transformation set up by context_apply_blit_state(), and draw a
00381          * (-1,-1)-(1,1) quad.
00382          *
00383          * Back up viewport and matrix to avoid breaking last_was_blit
00384          *
00385          * Note that context_apply_blit_state() set up viewport and ortho to
00386          * match the surface size - we want the GL drawable(=window) size. */
00387         glPushAttrib(GL_VIEWPORT_BIT);
00388         glViewport(dst_rect->left, win_h - dst_rect->bottom, dst_rect->right, win_h - dst_rect->top);
00389         glMatrixMode(GL_PROJECTION);
00390         glPushMatrix();
00391         glLoadIdentity();
00392 
00393         glBegin(GL_QUADS);
00394             /* bottom left */
00395             glTexCoord2f(tex_left, tex_bottom);
00396             glVertex2i(-1, -1);
00397 
00398             /* top left */
00399             glTexCoord2f(tex_left, tex_top);
00400             glVertex2i(-1, 1);
00401 
00402             /* top right */
00403             glTexCoord2f(tex_right, tex_top);
00404             glVertex2i(1, 1);
00405 
00406             /* bottom right */
00407             glTexCoord2f(tex_right, tex_bottom);
00408             glVertex2i(1, -1);
00409         glEnd();
00410 
00411         glPopMatrix();
00412         glPopAttrib();
00413 
00414         device->blitter->unset_shader(context->gl_info);
00415         checkGLcall("Swapchain present blit(manual)\n");
00416         LEAVE_GL();
00417 
00418         context_release(context2);
00419     }
00420 }
00421 
00422 static HRESULT swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT *src_rect_in,
00423         const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags)
00424 {
00425     const struct wined3d_fb_state *fb = &swapchain->device->fb;
00426     const struct wined3d_gl_info *gl_info;
00427     struct wined3d_context *context;
00428     RECT src_rect, dst_rect;
00429     BOOL render_to_fbo;
00430 
00431     context = context_acquire(swapchain->device, swapchain->back_buffers[0]);
00432     if (!context->valid)
00433     {
00434         context_release(context);
00435         WARN("Invalid context, skipping present.\n");
00436         return WINED3D_OK;
00437     }
00438 
00439     gl_info = context->gl_info;
00440 
00441     /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */
00442     if (swapchain->device->bCursorVisible &&
00443         swapchain->device->cursorTexture &&
00444         !swapchain->device->hardwareCursor)
00445     {
00446         struct wined3d_surface cursor;
00447         RECT destRect =
00448         {
00449             swapchain->device->xScreenSpace - swapchain->device->xHotSpot,
00450             swapchain->device->yScreenSpace - swapchain->device->yHotSpot,
00451             swapchain->device->xScreenSpace + swapchain->device->cursorWidth - swapchain->device->xHotSpot,
00452             swapchain->device->yScreenSpace + swapchain->device->cursorHeight - swapchain->device->yHotSpot,
00453         };
00454         TRACE("Rendering the cursor. Creating fake surface at %p\n", &cursor);
00455         /* Build a fake surface to call the Blitting code. It is not possible to use the interface passed by
00456          * the application because we are only supposed to copy the information out. Using a fake surface
00457          * allows to use the Blitting engine and avoid copying the whole texture -> render target blitting code.
00458          */
00459         memset(&cursor, 0, sizeof(cursor));
00460         cursor.resource.ref = 1;
00461         cursor.resource.device = swapchain->device;
00462         cursor.resource.pool = WINED3D_POOL_SCRATCH;
00463         cursor.resource.format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
00464         cursor.resource.type = WINED3D_RTYPE_SURFACE;
00465         cursor.texture_name = swapchain->device->cursorTexture;
00466         cursor.texture_target = GL_TEXTURE_2D;
00467         cursor.texture_level = 0;
00468         cursor.resource.width = swapchain->device->cursorWidth;
00469         cursor.resource.height = swapchain->device->cursorHeight;
00470         /* The cursor must have pow2 sizes */
00471         cursor.pow2Width = cursor.resource.width;
00472         cursor.pow2Height = cursor.resource.height;
00473         /* The surface is in the texture */
00474         cursor.flags |= SFLAG_INTEXTURE;
00475         /* DDBLT_KEYSRC will cause BltOverride to enable the alpha test with GL_NOTEQUAL, 0.0,
00476          * which is exactly what we want :-)
00477          */
00478         if (swapchain->desc.windowed)
00479             MapWindowPoints(NULL, swapchain->win_handle, (POINT *)&destRect, 2);
00480         wined3d_surface_blt(swapchain->back_buffers[0], &destRect,
00481                 &cursor, NULL, WINEDDBLT_KEYSRC, NULL, WINED3D_TEXF_POINT);
00482     }
00483 
00484     if (swapchain->device->logo_surface)
00485     {
00486         struct wined3d_surface *src_surface = swapchain->device->logo_surface;
00487         RECT rect = {0, 0, src_surface->resource.width, src_surface->resource.height};
00488 
00489         /* Blit the logo into the upper left corner of the drawable. */
00490         wined3d_surface_blt(swapchain->back_buffers[0], &rect, src_surface, &rect,
00491                  WINEDDBLT_KEYSRC, NULL, WINED3D_TEXF_POINT);
00492     }
00493 
00494     TRACE("Presenting HDC %p.\n", context->hdc);
00495 
00496     render_to_fbo = swapchain->render_to_fbo;
00497 
00498     if (src_rect_in)
00499     {
00500         src_rect = *src_rect_in;
00501         if (!render_to_fbo && (src_rect.left || src_rect.top
00502                 || src_rect.right != swapchain->desc.backbuffer_width
00503                 || src_rect.bottom != swapchain->desc.backbuffer_height))
00504         {
00505             render_to_fbo = TRUE;
00506         }
00507     }
00508     else
00509     {
00510         src_rect.left = 0;
00511         src_rect.top = 0;
00512         src_rect.right = swapchain->desc.backbuffer_width;
00513         src_rect.bottom = swapchain->desc.backbuffer_height;
00514     }
00515 
00516     if (dst_rect_in)
00517         dst_rect = *dst_rect_in;
00518     else
00519         GetClientRect(swapchain->win_handle, &dst_rect);
00520 
00521     if (!render_to_fbo && (dst_rect.left || dst_rect.top
00522             || dst_rect.right != swapchain->desc.backbuffer_width
00523             || dst_rect.bottom != swapchain->desc.backbuffer_height))
00524         render_to_fbo = TRUE;
00525 
00526     /* Rendering to a window of different size, presenting partial rectangles,
00527      * or rendering to a different window needs help from FBO_blit or a textured
00528      * draw. Render the swapchain to a FBO in the future.
00529      *
00530      * Note that FBO_blit from the backbuffer to the frontbuffer cannot solve
00531      * all these issues - this fails if the window is smaller than the backbuffer.
00532      */
00533     if (!swapchain->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO)
00534     {
00535         surface_load_location(swapchain->back_buffers[0], SFLAG_INTEXTURE, NULL);
00536         surface_modify_location(swapchain->back_buffers[0], SFLAG_INDRAWABLE, FALSE);
00537         swapchain->render_to_fbo = TRUE;
00538         swapchain_update_draw_bindings(swapchain);
00539     }
00540 
00541     if (swapchain->render_to_fbo)
00542     {
00543         /* This codepath should only be hit with the COPY swapeffect. Otherwise a backbuffer-
00544          * window size mismatch is impossible(fullscreen) and src and dst rectangles are
00545          * not allowed(they need the COPY swapeffect)
00546          *
00547          * The DISCARD swap effect is ok as well since any backbuffer content is allowed after
00548          * the swap. */
00549         if (swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_FLIP)
00550             FIXME("Render-to-fbo with WINED3D_SWAP_EFFECT_FLIP\n");
00551 
00552         swapchain_blit(swapchain, context, &src_rect, &dst_rect);
00553     }
00554 
00555     if (swapchain->num_contexts > 1)
00556         wglFinish();
00557     SwapBuffers(context->hdc); /* TODO: cycle through the swapchain buffers */
00558 
00559     TRACE("SwapBuffers called, Starting new frame\n");
00560     /* FPS support */
00561     if (TRACE_ON(fps))
00562     {
00563         DWORD time = GetTickCount();
00564         ++swapchain->frames;
00565 
00566         /* every 1.5 seconds */
00567         if (time - swapchain->prev_time > 1500)
00568         {
00569             TRACE_(fps)("%p @ approx %.2ffps\n",
00570                     swapchain, 1000.0 * swapchain->frames / (time - swapchain->prev_time));
00571             swapchain->prev_time = time;
00572             swapchain->frames = 0;
00573         }
00574     }
00575 
00576     /* This is disabled, but the code left in for debug purposes.
00577      *
00578      * Since we're allowed to modify the new back buffer on a D3DSWAPEFFECT_DISCARD flip,
00579      * we can clear it with some ugly color to make bad drawing visible and ease debugging.
00580      * The Debug runtime does the same on Windows. However, a few games do not redraw the
00581      * screen properly, like Max Payne 2, which leaves a few pixels undefined.
00582      *
00583      * Tests show that the content of the back buffer after a discard flip is indeed not
00584      * reliable, so no game can depend on the exact content. However, it resembles the
00585      * old contents in some way, for example by showing fragments at other locations. In
00586      * general, the color theme is still intact. So Max payne, which draws rather dark scenes
00587      * gets a dark background image. If we clear it with a bright ugly color, the game's
00588      * bug shows up much more than it does on Windows, and the players see single pixels
00589      * with wrong colors.
00590      * (The Max Payne bug has been confirmed on Windows with the debug runtime) */
00591     if (FALSE && swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_DISCARD)
00592     {
00593         static const struct wined3d_color cyan = {0.0f, 1.0f, 1.0f, 1.0f};
00594 
00595         TRACE("Clearing the color buffer with cyan color\n");
00596 
00597         wined3d_device_clear(swapchain->device, 0, NULL,
00598                 WINED3DCLEAR_TARGET, &cyan, 1.0f, 0);
00599     }
00600 
00601     if (!swapchain->render_to_fbo && ((swapchain->front_buffer->flags & SFLAG_INSYSMEM)
00602             || (swapchain->back_buffers[0]->flags & SFLAG_INSYSMEM)))
00603     {
00604         /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying
00605          * Doesn't work with render_to_fbo because we're not flipping
00606          */
00607         struct wined3d_surface *front = swapchain->front_buffer;
00608         struct wined3d_surface *back = swapchain->back_buffers[0];
00609 
00610         if(front->resource.size == back->resource.size) {
00611             DWORD fbflags;
00612             flip_surface(front, back);
00613 
00614             /* Tell the front buffer surface that is has been modified. However,
00615              * the other locations were preserved during that, so keep the flags.
00616              * This serves to update the emulated overlay, if any. */
00617             fbflags = front->flags;
00618             surface_modify_location(front, SFLAG_INDRAWABLE, TRUE);
00619             front->flags = fbflags;
00620         }
00621         else
00622         {
00623             surface_modify_location(front, SFLAG_INDRAWABLE, TRUE);
00624             surface_modify_location(back, SFLAG_INDRAWABLE, TRUE);
00625         }
00626     }
00627     else
00628     {
00629         surface_modify_location(swapchain->front_buffer, SFLAG_INDRAWABLE, TRUE);
00630         /* If the swapeffect is DISCARD, the back buffer is undefined. That means the SYSMEM
00631          * and INTEXTURE copies can keep their old content if they have any defined content.
00632          * If the swapeffect is COPY, the content remains the same. If it is FLIP however,
00633          * the texture / sysmem copy needs to be reloaded from the drawable
00634          */
00635         if (swapchain->desc.swap_effect == WINED3D_SWAP_EFFECT_FLIP)
00636             surface_modify_location(swapchain->back_buffers[0], swapchain->back_buffers[0]->draw_binding, TRUE);
00637     }
00638 
00639     if (fb->depth_stencil)
00640     {
00641         if (swapchain->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
00642                 || fb->depth_stencil->flags & SFLAG_DISCARD)
00643         {
00644             surface_modify_ds_location(fb->depth_stencil, SFLAG_LOST,
00645                     fb->depth_stencil->resource.width,
00646                     fb->depth_stencil->resource.height);
00647             if (fb->depth_stencil == swapchain->device->onscreen_depth_stencil)
00648             {
00649                 wined3d_surface_decref(swapchain->device->onscreen_depth_stencil);
00650                 swapchain->device->onscreen_depth_stencil = NULL;
00651             }
00652         }
00653     }
00654 
00655     context_release(context);
00656 
00657     TRACE("returning\n");
00658     return WINED3D_OK;
00659 }
00660 
00661 static const struct wined3d_swapchain_ops swapchain_gl_ops =
00662 {
00663     swapchain_gl_present,
00664 };
00665 
00666 /* Helper function that blits the front buffer contents to the target window. */
00667 void x11_copy_to_screen(const struct wined3d_swapchain *swapchain, const RECT *rect)
00668 {
00669     const struct wined3d_surface *front;
00670     POINT offset = {0, 0};
00671     HDC src_dc, dst_dc;
00672     RECT draw_rect;
00673     HWND window;
00674 
00675     TRACE("swapchain %p, rect %s.\n", swapchain, wine_dbgstr_rect(rect));
00676 
00677     front = swapchain->front_buffer;
00678     if (!(front->resource.usage & WINED3DUSAGE_RENDERTARGET))
00679         return;
00680 
00681     if (front->flags & SFLAG_LOCKED)
00682         ERR("Trying to blit a mapped surface.\n");
00683 
00684     TRACE("Copying surface %p to screen.\n", front);
00685 
00686     src_dc = front->hDC;
00687     window = swapchain->win_handle;
00688     dst_dc = GetDCEx(window, 0, DCX_CLIPSIBLINGS | DCX_CACHE);
00689 
00690     /* Front buffer coordinates are screen coordinates. Map them to the
00691      * destination window if not fullscreened. */
00692     if (swapchain->desc.windowed)
00693         ClientToScreen(window, &offset);
00694 
00695     TRACE("offset %s.\n", wine_dbgstr_point(&offset));
00696 
00697     draw_rect.left = 0;
00698     draw_rect.right = front->resource.width;
00699     draw_rect.top = 0;
00700     draw_rect.bottom = front->resource.height;
00701 
00702     if (rect)
00703         IntersectRect(&draw_rect, &draw_rect, rect);
00704 
00705     BitBlt(dst_dc, draw_rect.left - offset.x, draw_rect.top - offset.y,
00706             draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top,
00707             src_dc, draw_rect.left, draw_rect.top, SRCCOPY);
00708     ReleaseDC(window, dst_dc);
00709 }
00710 
00711 static HRESULT swapchain_gdi_present(struct wined3d_swapchain *swapchain, const RECT *src_rect_in,
00712         const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags)
00713 {
00714     struct wined3d_surface *front, *back;
00715 
00716     if (!swapchain->back_buffers)
00717     {
00718         WARN("Swapchain doesn't have a backbuffer, returning WINED3DERR_INVALIDCALL\n");
00719         return WINED3DERR_INVALIDCALL;
00720     }
00721     front = swapchain->front_buffer;
00722     back = swapchain->back_buffers[0];
00723 
00724     /* Flip the DC. */
00725     {
00726         HDC tmp;
00727         tmp = front->hDC;
00728         front->hDC = back->hDC;
00729         back->hDC = tmp;
00730     }
00731 
00732     /* Flip the DIBsection. */
00733     {
00734         HBITMAP tmp;
00735         tmp = front->dib.DIBsection;
00736         front->dib.DIBsection = back->dib.DIBsection;
00737         back->dib.DIBsection = tmp;
00738     }
00739 
00740     /* Flip the surface data. */
00741     {
00742         void *tmp;
00743 
00744         tmp = front->dib.bitmap_data;
00745         front->dib.bitmap_data = back->dib.bitmap_data;
00746         back->dib.bitmap_data = tmp;
00747 
00748         tmp = front->resource.allocatedMemory;
00749         front->resource.allocatedMemory = back->resource.allocatedMemory;
00750         back->resource.allocatedMemory = tmp;
00751 
00752         if (front->resource.heapMemory)
00753             ERR("GDI Surface %p has heap memory allocated.\n", front);
00754 
00755         if (back->resource.heapMemory)
00756             ERR("GDI Surface %p has heap memory allocated.\n", back);
00757     }
00758 
00759     /* FPS support */
00760     if (TRACE_ON(fps))
00761     {
00762         static LONG prev_time, frames;
00763         DWORD time = GetTickCount();
00764 
00765         ++frames;
00766 
00767         /* every 1.5 seconds */
00768         if (time - prev_time > 1500)
00769         {
00770             TRACE_(fps)("@ approx %.2ffps\n", 1000.0 * frames / (time - prev_time));
00771             prev_time = time;
00772             frames = 0;
00773         }
00774     }
00775 
00776     x11_copy_to_screen(swapchain, NULL);
00777 
00778     return WINED3D_OK;
00779 }
00780 
00781 static const struct wined3d_swapchain_ops swapchain_gdi_ops =
00782 {
00783     swapchain_gdi_present,
00784 };
00785 
00786 void swapchain_update_render_to_fbo(struct wined3d_swapchain *swapchain)
00787 {
00788     RECT client_rect;
00789 
00790     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO)
00791         return;
00792 
00793     if (!swapchain->desc.backbuffer_count)
00794     {
00795         TRACE("Single buffered rendering.\n");
00796         swapchain->render_to_fbo = FALSE;
00797         return;
00798     }
00799 
00800     GetClientRect(swapchain->win_handle, &client_rect);
00801 
00802     TRACE("Backbuffer %ux%u, window %ux%u.\n",
00803             swapchain->desc.backbuffer_width,
00804             swapchain->desc.backbuffer_height,
00805             client_rect.right, client_rect.bottom);
00806     TRACE("Multisample type %#x, quality %#x.\n",
00807             swapchain->desc.multisample_type,
00808             swapchain->desc.multisample_quality);
00809 
00810     if (!wined3d_settings.always_offscreen && !swapchain->desc.multisample_type
00811             && swapchain->desc.backbuffer_width == client_rect.right
00812             && swapchain->desc.backbuffer_height == client_rect.bottom)
00813     {
00814         TRACE("Backbuffer dimensions match window dimensions, rendering onscreen.\n");
00815         swapchain->render_to_fbo = FALSE;
00816         return;
00817     }
00818 
00819     TRACE("Rendering to FBO.\n");
00820     swapchain->render_to_fbo = TRUE;
00821 }
00822 
00823 /* Do not call while under the GL lock. */
00824 static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, WINED3DSURFTYPE surface_type,
00825         struct wined3d_device *device, struct wined3d_swapchain_desc *desc,
00826         void *parent, const struct wined3d_parent_ops *parent_ops)
00827 {
00828     const struct wined3d_adapter *adapter = device->adapter;
00829     const struct wined3d_format *format;
00830     struct wined3d_display_mode mode;
00831     BOOL displaymode_set = FALSE;
00832     RECT client_rect;
00833     HWND window;
00834     HRESULT hr;
00835     UINT i;
00836 
00837     if (desc->backbuffer_count > WINED3DPRESENT_BACK_BUFFER_MAX)
00838     {
00839         FIXME("The application requested %u back buffers, this is not supported.\n",
00840                 desc->backbuffer_count);
00841         return WINED3DERR_INVALIDCALL;
00842     }
00843 
00844     if (desc->backbuffer_count > 1)
00845     {
00846         FIXME("The application requested more than one back buffer, this is not properly supported.\n"
00847                 "Please configure the application to use double buffering (1 back buffer) if possible.\n");
00848     }
00849 
00850     switch (surface_type)
00851     {
00852         case SURFACE_GDI:
00853             swapchain->swapchain_ops = &swapchain_gdi_ops;
00854             break;
00855 
00856         case SURFACE_OPENGL:
00857             swapchain->swapchain_ops = &swapchain_gl_ops;
00858             break;
00859 
00860         default:
00861             ERR("Invalid surface type %#x.\n", surface_type);
00862             return WINED3DERR_INVALIDCALL;
00863     }
00864 
00865     window = desc->device_window ? desc->device_window : device->create_parms.focus_window;
00866 
00867     swapchain->device = device;
00868     swapchain->parent = parent;
00869     swapchain->parent_ops = parent_ops;
00870     swapchain->ref = 1;
00871     swapchain->win_handle = window;
00872     swapchain->device_window = window;
00873 
00874     wined3d_get_adapter_display_mode(device->wined3d, adapter->ordinal, &mode);
00875     swapchain->orig_width = mode.width;
00876     swapchain->orig_height = mode.height;
00877     swapchain->orig_fmt = mode.format_id;
00878     format = wined3d_get_format(&adapter->gl_info, mode.format_id);
00879 
00880     GetClientRect(window, &client_rect);
00881     if (desc->windowed
00882             && (!desc->backbuffer_width || !desc->backbuffer_height
00883             || desc->backbuffer_format == WINED3DFMT_UNKNOWN))
00884     {
00885 
00886         if (!desc->backbuffer_width)
00887         {
00888             desc->backbuffer_width = client_rect.right;
00889             TRACE("Updating width to %u.\n", desc->backbuffer_width);
00890         }
00891 
00892         if (!desc->backbuffer_height)
00893         {
00894             desc->backbuffer_height = client_rect.bottom;
00895             TRACE("Updating height to %u.\n", desc->backbuffer_height);
00896         }
00897 
00898         if (desc->backbuffer_format == WINED3DFMT_UNKNOWN)
00899         {
00900             desc->backbuffer_format = swapchain->orig_fmt;
00901             TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->orig_fmt));
00902         }
00903     }
00904     swapchain->desc = *desc;
00905     swapchain_update_render_to_fbo(swapchain);
00906 
00907     TRACE("Creating front buffer.\n");
00908     hr = device->device_parent->ops->create_rendertarget(device->device_parent, parent,
00909             swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height,
00910             swapchain->desc.backbuffer_format, swapchain->desc.multisample_type,
00911             swapchain->desc.multisample_quality, TRUE /* Lockable */,
00912             &swapchain->front_buffer);
00913     if (FAILED(hr))
00914     {
00915         WARN("Failed to create front buffer, hr %#x.\n", hr);
00916         goto err;
00917     }
00918 
00919     surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_SWAPCHAIN, swapchain);
00920     if (surface_type == SURFACE_OPENGL)
00921     {
00922         surface_modify_location(swapchain->front_buffer, SFLAG_INDRAWABLE, TRUE);
00923     }
00924 
00925     /* MSDN says we're only allowed a single fullscreen swapchain per device,
00926      * so we should really check to see if there is a fullscreen swapchain
00927      * already. Does a single head count as full screen? */
00928 
00929     if (!desc->windowed)
00930     {
00931         struct wined3d_display_mode mode;
00932 
00933         /* Change the display settings */
00934         mode.width = desc->backbuffer_width;
00935         mode.height = desc->backbuffer_height;
00936         mode.format_id = desc->backbuffer_format;
00937         mode.refresh_rate = desc->refresh_rate;
00938 
00939         hr = wined3d_device_set_display_mode(device, 0, &mode);
00940         if (FAILED(hr))
00941         {
00942             WARN("Failed to set display mode, hr %#x.\n", hr);
00943             goto err;
00944         }
00945         displaymode_set = TRUE;
00946     }
00947 
00948     if (surface_type == SURFACE_OPENGL)
00949     {
00950         static const enum wined3d_format_id formats[] =
00951         {
00952             WINED3DFMT_D24_UNORM_S8_UINT,
00953             WINED3DFMT_D32_UNORM,
00954             WINED3DFMT_R24_UNORM_X8_TYPELESS,
00955             WINED3DFMT_D16_UNORM,
00956             WINED3DFMT_S1_UINT_D15_UNORM
00957         };
00958 
00959         const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
00960 
00961         swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
00962         if (!swapchain->context)
00963         {
00964             ERR("Failed to create the context array.\n");
00965             hr = E_OUTOFMEMORY;
00966             goto err;
00967         }
00968         swapchain->num_contexts = 1;
00969 
00970         /* In WGL both color, depth and stencil are features of a pixel format. In case of D3D they are separate.
00971          * You are able to add a depth + stencil surface at a later stage when you need it.
00972          * In order to support this properly in WineD3D we need the ability to recreate the opengl context and
00973          * drawable when this is required. This is very tricky as we need to reapply ALL opengl states for the new
00974          * context, need torecreate shaders, textures and other resources.
00975          *
00976          * The context manager already takes care of the state problem and for the other tasks code from Reset
00977          * can be used. These changes are way to risky during the 1.0 code freeze which is taking place right now.
00978          * Likely a lot of other new bugs will be exposed. For that reason request a depth stencil surface all the
00979          * time. It can cause a slight performance hit but fixes a lot of regressions. A fixme reminds of that this
00980          * issue needs to be fixed. */
00981         for (i = 0; i < (sizeof(formats) / sizeof(*formats)); i++)
00982         {
00983             swapchain->ds_format = wined3d_get_format(gl_info, formats[i]);
00984             swapchain->context[0] = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format);
00985             if (swapchain->context[0]) break;
00986             TRACE("Depth stencil format %s is not supported, trying next format\n",
00987                   debug_d3dformat(formats[i]));
00988         }
00989 
00990         if (!swapchain->context[0])
00991         {
00992             WARN("Failed to create context.\n");
00993             hr = WINED3DERR_NOTAVAILABLE;
00994             goto err;
00995         }
00996 
00997         if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
00998                 && (!desc->enable_auto_depth_stencil
00999                 || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id))
01000         {
01001             FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n");
01002         }
01003         context_release(swapchain->context[0]);
01004     }
01005 
01006     if (swapchain->desc.backbuffer_count > 0)
01007     {
01008         swapchain->back_buffers = HeapAlloc(GetProcessHeap(), 0,
01009                 sizeof(*swapchain->back_buffers) * swapchain->desc.backbuffer_count);
01010         if (!swapchain->back_buffers)
01011         {
01012             ERR("Failed to allocate backbuffer array memory.\n");
01013             hr = E_OUTOFMEMORY;
01014             goto err;
01015         }
01016 
01017         for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
01018         {
01019             TRACE("Creating back buffer %u.\n", i);
01020             hr = device->device_parent->ops->create_rendertarget(device->device_parent, parent,
01021                     swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height,
01022                     swapchain->desc.backbuffer_format, swapchain->desc.multisample_type,
01023                     swapchain->desc.multisample_quality, TRUE /* Lockable */,
01024                     &swapchain->back_buffers[i]);
01025             if (FAILED(hr))
01026             {
01027                 WARN("Failed to create back buffer %u, hr %#x.\n", i, hr);
01028                 goto err;
01029             }
01030 
01031             surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_SWAPCHAIN, swapchain);
01032         }
01033     }
01034 
01035     /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */
01036     if (desc->enable_auto_depth_stencil && surface_type == SURFACE_OPENGL)
01037     {
01038         TRACE("Creating depth/stencil buffer.\n");
01039         if (!device->auto_depth_stencil)
01040         {
01041             hr = device->device_parent->ops->create_depth_stencil(device->device_parent,
01042                     swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height,
01043                     swapchain->desc.auto_depth_stencil_format, swapchain->desc.multisample_type,
01044                     swapchain->desc.multisample_quality, FALSE /* FIXME: Discard */,
01045                     &device->auto_depth_stencil);
01046             if (FAILED(hr))
01047             {
01048                 WARN("Failed to create the auto depth stencil, hr %#x.\n", hr);
01049                 goto err;
01050             }
01051 
01052             surface_set_container(device->auto_depth_stencil, WINED3D_CONTAINER_NONE, NULL);
01053         }
01054     }
01055 
01056     wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma);
01057 
01058     return WINED3D_OK;
01059 
01060 err:
01061     if (displaymode_set)
01062     {
01063         DEVMODEW devmode;
01064 
01065         ClipCursor(NULL);
01066 
01067         /* Change the display settings */
01068         memset(&devmode, 0, sizeof(devmode));
01069         devmode.dmSize = sizeof(devmode);
01070         devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
01071         devmode.dmBitsPerPel = format->byte_count * CHAR_BIT;
01072         devmode.dmPelsWidth = swapchain->orig_width;
01073         devmode.dmPelsHeight = swapchain->orig_height;
01074         ChangeDisplaySettingsExW(adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
01075     }
01076 
01077     if (swapchain->back_buffers)
01078     {
01079         for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
01080         {
01081             if (swapchain->back_buffers[i])
01082             {
01083                 surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_NONE, NULL);
01084                 wined3d_surface_decref(swapchain->back_buffers[i]);
01085             }
01086         }
01087         HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
01088     }
01089 
01090     if (swapchain->context)
01091     {
01092         if (swapchain->context[0])
01093         {
01094             context_release(swapchain->context[0]);
01095             context_destroy(device, swapchain->context[0]);
01096             swapchain->num_contexts = 0;
01097         }
01098         HeapFree(GetProcessHeap(), 0, swapchain->context);
01099     }
01100 
01101     if (swapchain->front_buffer)
01102     {
01103         surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
01104         wined3d_surface_decref(swapchain->front_buffer);
01105     }
01106 
01107     return hr;
01108 }
01109 
01110 /* Do not call while under the GL lock. */
01111 HRESULT CDECL wined3d_swapchain_create(struct wined3d_device *device,
01112         struct wined3d_swapchain_desc *desc, WINED3DSURFTYPE surface_type,
01113         void *parent, const struct wined3d_parent_ops *parent_ops,
01114         struct wined3d_swapchain **swapchain)
01115 {
01116     struct wined3d_swapchain *object;
01117     HRESULT hr;
01118 
01119     TRACE("device %p, desc %p, swapchain %p, parent %p, surface_type %#x.\n",
01120             device, desc, swapchain, parent, surface_type);
01121 
01122     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
01123     if (!object)
01124     {
01125         ERR("Failed to allocate swapchain memory.\n");
01126         return E_OUTOFMEMORY;
01127     }
01128 
01129     hr = swapchain_init(object, surface_type, device, desc, parent, parent_ops);
01130     if (FAILED(hr))
01131     {
01132         WARN("Failed to initialize swapchain, hr %#x.\n", hr);
01133         HeapFree(GetProcessHeap(), 0, object);
01134         return hr;
01135     }
01136 
01137     TRACE("Created swapchain %p.\n", object);
01138     *swapchain = object;
01139 
01140     return WINED3D_OK;
01141 }
01142 
01143 /* Do not call while under the GL lock. */
01144 static struct wined3d_context *swapchain_create_context(struct wined3d_swapchain *swapchain)
01145 {
01146     struct wined3d_context **newArray;
01147     struct wined3d_context *ctx;
01148 
01149     TRACE("Creating a new context for swapchain %p, thread %u.\n", swapchain, GetCurrentThreadId());
01150 
01151     if (!(ctx = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format)))
01152     {
01153         ERR("Failed to create a new context for the swapchain\n");
01154         return NULL;
01155     }
01156     context_release(ctx);
01157 
01158     newArray = HeapAlloc(GetProcessHeap(), 0, sizeof(*newArray) * (swapchain->num_contexts + 1));
01159     if(!newArray) {
01160         ERR("Out of memory when trying to allocate a new context array\n");
01161         context_destroy(swapchain->device, ctx);
01162         return NULL;
01163     }
01164     memcpy(newArray, swapchain->context, sizeof(*newArray) * swapchain->num_contexts);
01165     HeapFree(GetProcessHeap(), 0, swapchain->context);
01166     newArray[swapchain->num_contexts] = ctx;
01167     swapchain->context = newArray;
01168     swapchain->num_contexts++;
01169 
01170     TRACE("Returning context %p\n", ctx);
01171     return ctx;
01172 }
01173 
01174 void swapchain_destroy_contexts(struct wined3d_swapchain *swapchain)
01175 {
01176     unsigned int i;
01177 
01178     for (i = 0; i < swapchain->num_contexts; ++i)
01179     {
01180         context_destroy(swapchain->device, swapchain->context[i]);
01181     }
01182     swapchain->num_contexts = 0;
01183 }
01184 
01185 struct wined3d_context *swapchain_get_context(struct wined3d_swapchain *swapchain)
01186 {
01187     DWORD tid = GetCurrentThreadId();
01188     unsigned int i;
01189 
01190     for (i = 0; i < swapchain->num_contexts; ++i)
01191     {
01192         if (swapchain->context[i]->tid == tid)
01193             return swapchain->context[i];
01194     }
01195 
01196     /* Create a new context for the thread */
01197     return swapchain_create_context(swapchain);
01198 }
01199 
01200 void get_drawable_size_swapchain(const struct wined3d_context *context, UINT *width, UINT *height)
01201 {
01202     /* The drawable size of an onscreen drawable is the surface size.
01203      * (Actually: The window size, but the surface is created in window size) */
01204     *width = context->current_rt->resource.width;
01205     *height = context->current_rt->resource.height;
01206 }
01207 
01208 HDC swapchain_get_backup_dc(struct wined3d_swapchain *swapchain)
01209 {
01210     if (!swapchain->backup_dc)
01211     {
01212         TRACE("Creating the backup window for swapchain %p.\n", swapchain);
01213 
01214         if (!(swapchain->backup_wnd = CreateWindowA(WINED3D_OPENGL_WINDOW_CLASS_NAME, "WineD3D fake window",
01215                 WS_OVERLAPPEDWINDOW, 10, 10, 10, 10, NULL, NULL, NULL, NULL)))
01216         {
01217             ERR("Failed to create a window.\n");
01218             return NULL;
01219         }
01220 
01221         if (!(swapchain->backup_dc = GetDC(swapchain->backup_wnd)))
01222         {
01223             ERR("Failed to get a DC.\n");
01224             DestroyWindow(swapchain->backup_wnd);
01225             swapchain->backup_wnd = NULL;
01226             return NULL;
01227         }
01228     }
01229 
01230     return swapchain->backup_dc;
01231 }
01232 
01233 void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain)
01234 {
01235     UINT i;
01236 
01237     surface_update_draw_binding(swapchain->front_buffer);
01238 
01239     for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
01240     {
01241         surface_update_draw_binding(swapchain->back_buffers[i]);
01242     }
01243 }

Generated on Sat May 26 2012 04:20:40 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.