Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenswapchain.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
1.7.6.1
|